Skip to content

[Epic] Macro & Scripting Support (Lua-based macro system) #938

Description

@AgreeDK

Background

A macro/scripting language is one of the most requested features from users
moving from GSAK. This epic tracks the work towards a modern successor to the
GSAK Macro Language, as described in the attached concept document
(OpenSAK Lua Macro System Concept v4).

In short: an embedded Lua runtime with a small, documented OpenSAK macro API.
Lua provides the language; OpenSAK provides the geocaching vocabulary. GSAK
macros are ported to Lua rather than run unchanged.

This does not depend on Geocaching.com API access. Macros can work with
everything OpenSAK already stores; only the extra fields that come from the
API (roadmap item 11) will be missing until that access exists. The macro API
must handle missing fields gracefully by returning nil rather than raising an
error (concept §9a).

This is a tracking issue. It isn't meant to be implemented in one go. Each
step below is split out into its own issue when it's picked up (created right
before the code, not all upfront), in the same way as #821.

Community use cases (the design is driven by these)

More real-world GSAK macros are welcome as comments or new use-case issues.
A goal for the migration phase is that all of the above can be ported to
OpenSAK as reference examples.

Plan

Sequencing update (Oct 2026): following feedback from @GeePa67, UI functions and per-macro saved settings (#982, #983) now come before the Macro Manager and migration support. Most GSAK macros depend on forms, so there's little to manage or port until those exist.

Step 1 — Headless command-line import (#937)

Import GPX/PQ files from a folder and/or a GSAK database without the GUI, so a
refresh can be scheduled with the OS's own tools. It covers part of the
automation demand immediately, and it moves the import logic out of the GUI
dialogs into a shared import service. The macro API's
opensak.import_gpx() will call that same service later.

Step 2 — Lua packaging spike (go/no-go)

The biggest technical risk isn't the API design. It's whether a Lua runtime
can be shipped reliably in every build artifact. Before any API work, verify
with a minimal build that runs a .lua file calling show_message() and
log():

  • Python–Lua bridge chosen (Lupa is the main candidate): licence, Python
    3.12 wheels for Windows x64, Linux x86_64, macOS arm64 and x86_64
  • Which Lua version/runtime to embed (e.g. Lua 5.4 vs. LuaJIT)
  • Bundled correctly by PyInstaller in all four artifacts
  • Works inside the MSIX package
  • macOS: native extension is signed and the .dmg still notarizes
  • Smoke test in CI on all platforms

Outcome: a documented go/no-go and the chosen bridge. If it fails, the design
is revisited before continuing.

Step 3 — SQL Query tool (#810)

A native, read-only tool (e.g. under Tools) to run an arbitrary SELECT
against the active database and view the result as a table. It's useful on
its own right away, lets users test queries interactively, and later becomes
opensak.sql_query().

Step 4 — Macro API v1: design decisions

A short design issue to settle the open questions before implementation:

  • Sandboxing: which Lua standard libraries are removed or restricted (os,
    io, load/dofile, require, …); no access to Python internals
  • Cancellation / execution limits for runaway macros (instruction-count
    hook, a Cancel button)
  • Transactions: does a macro that modifies many caches run in one
    transaction, with rollback on error? Should it prompt for a backup first?
  • Threading: how a long macro runs without freezing the GUI
  • Error reporting with macro file name and line number
  • API versioning (Requires-API metadata, concept §8)
  • Macro folder location per platform (alongside the existing data paths)
  • Mapping concept terms to OpenSAK's actual data model. For example, the
    concept's cache:add_tag(): what is OpenSAK's equivalent (user flag,
    user note, something new)?
  • Confirm the known limitation in concept §9b (raw WHERE text is not
    parameterized) is accepted for v1

Step 5 — Phase 1: proof of concept

Macros menu → Run Macro…; runs a .lua file with opensak.show_message(),
opensak.log() and read-only access to a small set of cache fields.

Step 6 — Phase 2: useful macro API

  • Cache access: current cache, cache by code, all / filtered caches
  • Filtering and selection, reusing the Filter dialog's Where tab engine
    (opensak.filter(where_sql)); sorting
  • User notes and write operations on caches (per the Step 4 decisions)
  • Import/export wrappers (GPX, CSV) on top of the shared import service from Step 1
  • Database management for Macro description: refile caches into correct database #808: database_exists, create_database,
    switch_database, move caches — thin wrappers around DatabaseManager
  • Regex functions bridged to Python re (regex_match / regex_replace /
    regex_find), since Lua patterns aren't enough for GSAK-style description parsing
  • Utilities: sleep(ms), sql_query() (from Step 3), a simple table/HTML
    report helper
  • Nil-safe field access from the start (concept §9a)

Step 7 — UI functions and saved settings

Step 8 — Phase 3: Macro Manager

Discovery of local macro files, metadata display, error display,
Edit / Open Macro Folder / Reload, and optional keyboard shortcuts. Candidate:
running a macro headless via the command line from #937 (e.g. --run-macro),
so macros can also be scheduled.

Step 9 — Phase 4: migration support

A GSAK → OpenSAK porting guide with common patterns, and the community use
cases (#808, #809, #810, #813) ported as reference macros. Optional
compatibility helpers for frequently used GSAK concepts.

Step 10 — Phase 5: extended API

More database, waypoint, coordinate and export functions, plus further form
field types, driven by real macros people send in, not a wishlist.

Out of scope for v1

Checklist

OpenSAK_Lua_Macro_System_Concept_v4.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions