Skip to content

v0.19.0

Choose a tag to compare

@github-actions github-actions released this 01 Jul 21:40
66db272

Removed

  • Removed the cron-job feature. Moadim scheduled two kinds of things —
    "cron jobs" (a schedule + a handler script) and "routines" (a schedule + an
    AI-agent prompt). The project's focus is AI-agent routines, so the cron-job
    half — the CronJob/CronStore model, the /api/v1/cron-jobs* REST routes,
    the *_cron_job MCP tools, the moadim cron-jobs CLI subcommand, the
    ~/.config/moadim/jobs/ and ~/.config/moadim/handlers/ directories, and
    the job-specific crontab block — has been removed. Routines are unaffected
    and keep their own crontab block, REST routes, MCP tools, and CLI
    subcommand. (#842)

Changed

  • list_routines omits routine prompts by default. The prompt is the
    largest field on a routine and is rarely needed when scanning a listing, so it
    bloated GET /routines responses and burned MCP context tokens on every call.
    The prompt key is now absent from list entries unless the caller opts in with
    include_prompts=true (a new boolean on the list_routines MCP tool and the
    GET /routines query string). get_routine / GET /routines/{id} are
    unaffected and always return the prompt; routine.toml persistence is
    unchanged. (#824)

Documentation

  • Added CODE_OF_CONDUCT.md. The repo had a CONTRIBUTING.md and
    SECURITY.md but no documented standard of conduct or enforcement contact,
    leaving GitHub's community-standards profile incomplete. Added a Contributor
    Covenant v2.1 code of conduct with a real reporting contact, and linked it
    from CONTRIBUTING.md. (#423)
  • The README's Bind address section now warns that the REST API and MCP
    endpoint are unauthenticated, so MOADIM_BIND_ADDR should stay on a loopback
    address: binding to a routable interface (a LAN IP or 0.0.0.0) exposes
    unauthenticated routine create/trigger — effectively remote code execution — to
    the network. Recommends an authenticating reverse proxy / firewall for remote
    access instead. (#253)

Fixed

  • The daemon never killed hung routine tmux sessions when launched via
    launchd/systemd.
    Those managers start moadim --interactive with a
    minimal PATH (e.g. macOS launchd's /usr/bin:/bin:/usr/sbin:/sbin) that
    hides a Homebrew- or npm-installed tmux. The daemon's own cleanup/watchdog
    sweep shelled out to tmux directly (no login shell), so every
    liveness/kill probe silently failed and read as "session already dead" —
    a hung run's workbench got TTL-reaped while its real tmux session and agent
    process kept running, untracked, forever. resolve_tmux_bin now also
    searches common install locations (Homebrew, /usr/local/bin,
    ~/.local/bin) when tmux isn't on PATH, and the generated launchd
    plist now sets a real PATH via EnvironmentVariables.
  • cargo build was broken on main. Two independent PRs (#804 and #805)
    each added a unused_async = "deny" entry under [lints.clippy] in
    Cargo.toml, and both merged cleanly since git's line-based merge doesn't
    understand TOML semantics. The resulting duplicate key made every cargo
    invocation fail immediately with error: duplicate key before compiling a
    single crate. Removed the duplicate entry so the workspace builds again.
  • docs/moadim.1's .TH header reported a stale moadim 0.16.0 even though
    Cargo.toml had moved on to 0.18.0 — the hand-maintained man page has no
    build-time link to the crate version, so a release could silently ship a man
    page reporting the previous version. Corrected the version token and added
    a regression test (cli::cli_tests::man_page_version_matches_cargo_pkg_version)
    that fails when the two drift again. (#556)
  • Locked the --json machine-readable contract with a regression test
    (cli::cli_tests::status_stop_cleanup_json_share_the_same_address) asserting
    status --json, stop --json, and cleanup --json all surface the same
    address value, so the three shapes can't silently drift apart again. (#245)
  • Removed two dead AppError::NotFound arms in svc_update (routines/service.rs):
    the function already checks the routine's existence once, up front, while
    holding the store's lock continuously for the rest of the call, so the two
    later re-fetches could never actually miss. The two tests written to cover
    those unreachable arms were accidental duplicates of the same first-check
    path; merged them into one svc_update_not_found_when_id_missing test that
    covers both request shapes against the real, single NotFound path.

Added

  • Machine name in health output. GET /health and the MCP health tool now
    report the daemon's resolved machine identity (from MOADIM_MACHINE,
    machine.local.toml, or hostname — same as GET /machine) in a new machine
    field, so clients can tell which machine answered without a second request. (#778)

Changed

  • Enabled the clippy::wildcard_imports lint. It flags use some::module::*;
    glob imports, which obscure where a name comes from at the call site, can
    silently change behavior when the globbed module gains a new item, and
    defeat "go to definition" tooling. Zero existing violations, so this only
    guards against the pattern creeping in going forward. No behavior change.
  • Enabled the clippy::unused_async lint. It flags async fns (and async
    closures/blocks) that never .await anything internally, which needlessly
    propagate async-ness up the call stack and pull in a Future state machine
    for work that's actually synchronous. Zero existing violations, so this only
    guards against the pattern creeping in going forward. No behavior change.
    (#803)
  • Gzip-compressed HTTP responses. The Axum router now negotiates
    Accept-Encoding and gzip-compresses response bodies via a tower-http
    CompressionLayer, cutting the ~1.1 MB SPA payload (and the OpenAPI JSON
    under /docs) several-fold on every load/refresh for clients that
    advertise gzip support. A no-op for clients that don't. (#399)
  • Bumped tower-http from 0.6.11 to 0.7.0. No source changes needed —
    the only feature used (compression-gzip's CompressionLayer) is
    API-compatible across the bump.
  • Declared rust-version = "1.88" (MSRV) in the root Cargo.toml and
    ui/Cargo.toml, matching the floor already required transitively by
    darling 0.23, so cargo install moadim on an older stable toolchain now
    fails with Cargo's clean MSRV message instead of an opaque compile error. (#326)
  • The local pre-push hook now runs cargo clippy --workspace instead of a
    bare cargo clippy. In this non-virtual workspace (the root Cargo.toml
    declares both a [package] and [workspace]), the bare form only checks
    the root moadim package, so the ui member crate was never type-checked
    or linted by the hook.
  • .github/workflows/lint.yml's clippy job now runs cargo clippy --workspace --all-targets -- -D warnings too, closing the matching gap in
    CI: previously the bare cargo clippy --all-targets only checked the root
    moadim package, so ui/Cargo.toml's [lints.clippy] all = "deny"
    posture was never enforced on PRs and a dashboard lint regression could
    merge to main fully green, only surfacing via the local hook (if a
    contributor had it installed) or at release time.
  • build_app_with_shutdown cloned store and routines into app_state,
    then cloned them again from the original bindings for the MCP service
    closure — clippy::redundant_clone flags the second pair as dead clones
    since the originals are never read afterward. Reordered to clone once
    (for the MCP closure) before moving the originals into app_state,
    dropping two unnecessary Arc clone+drop pairs per router build. No
    behavior change.

Fixed

  • Fixed the ui crate, which had silently stopped compiling: three test
    fixtures (command_palette_tests.rs, routines_tests.rs,
    schedule_heatmap_tests.rs) were missing the tags field added to
    Routine by #505, and cron_jobs::unassigned_count /
    routines::unassigned_routines_count were dead code left over from before
    #771 made the "Unassigned" machine facet a permanent filter option. None of
    this was caught because ui was outside the pre-push clippy gate and CI's
    equivalent gate had the same blind spot (now closed, see --workspace
    fix above).