auren-releaseops
v0.6.6
Published
Local-first release operations CLI: ZIP intake, sync, checks, git, Supabase migrations, rollback, and release-doc generation, with an explicit approval gate before anything writes or pushes.
Maintainers
Readme
Auren ReleaseOps CLI
The local-runner-agent half of the proposed architecture (see ../docs/TECHNICAL-NOTES.md), scoped down to what's safe to ship today.
Install
Published on npm as of 2026-08-06 (Stage 10.2):
npm install -g auren-releaseops
auren-releaseops doctorCommand reference
Quick scan — full explanation and design rationale for each is in "What it does" below.
| Command | What it does |
|---|---|
| doctor | Checks this machine has git/node/npm/npx/rsync/unzip/Supabase CLI/gh CLI. No project involved. |
| locks | Lists every project currently locked by a running sync/commit/db-push/update. |
| unlock -p <project> | Force-removes a project's lock — escape hatch, normally never needed. |
| list | Lists configured projects and their capabilities. |
| scan [path] | Scans a folder for project-like subdirectories (Node, Python, WordPress/PHP, or a bare git repo), reports each one's detected tech stack, and shows which are already known to this CLI. Read-only, doesn't register anything. |
| register -p <id> [path] | Writes — creates a brand-new project in the dashboard from a local folder (runs the same detection as detect), after confirmation. For a project scan found that doesn't exist anywhere yet. |
| detect -p <project> | Scans the local checkout and proposes config (check commands, git, required env keys, health URL) — shows a diff, asks before writing. |
| pair [-i seconds] [--timeout seconds] | Pairs this machine with your organization — shows a code, waits for it to be claimed on the dashboard, saves the device credential to ~/.config/auren-releaseops/device-token. |
| diagnostics [-o file] | Full diagnostic bundle: system tools (same as doctor), dashboard connectivity, API token validity, device pairing status. |
| readiness -p <project> [-o file] | Read-only pre-flight scorecard (repo/git state, version consistency, Supabase config). |
| verify -p <project> [-o file] | Read-only post-deploy verification (origin matches HEAD, health URL, custom command). Falls back to a live-detected health URL if none is saved. |
| env-check -p <project> [-o file] | Read-only — confirms required env vars are actually configured. Falls back to live-detected keys if none are saved. |
| checks -p <project> [--smart] | Runs the project's configured build/lint/typecheck/test commands. |
| git-status -p <project> | Read-only git status. |
| changelog -p <project> [-o file] | Full changelog from recorded releases. |
| release-notes -p <project> [-o file] | Latest release notes. |
| handoff -p <project> [-o file] | Current status/handoff summary. |
| sync -p <project> [-z path] | Writes — finds an update ZIP, previews the diff, applies after confirmation. |
| rollback -p <project> [-z name] | Writes — restores from an archived ZIP, requires typing ROLLBACK. |
| cleanup -p <project> [--keep n] [--min-days n] | Writes — deletes old archived ZIPs (keeps the N most recent, anything younger than --min-days, and anything RC-tagged), requires typing CLEANUP. |
| commit -p <project> -m <message> | Writes — stage, commit, push, after one y/N showing the diff. |
| db-push -p <project> | Writes — pushes pending Supabase migrations, after confirmation (or PRODUCTION). |
| supabase-backup -p <project> [--schema-only\|--data-only] [-o path] | Read-only against the live database — dumps schema+data (or one or the other) to a local SQL file via supabase db dump. No confirmation needed. |
| gh-status -p <project> [-n count] | Read-only. Shows the latest GitHub Actions runs for the project's repo. Requires the gh CLI, authenticated. |
| pr-list -p <project> | Read-only. Lists open pull requests for the project's repo. Requires the gh CLI, authenticated. |
| report -p <project> -v <version> -z <zip> -s <status> | Writes — records a release outcome (audit trail only). |
| update -p <project> [-z path] [-m message] [-o file] | Writes — full pipeline: sync → checks → commit → db-push → archive. |
| resume -p <project> [-m message] [-o file] | Writes — resumes an interrupted update from its last checkpoint. |
| watch [-i seconds] [--once] | Polls the dashboard for remotely-queued read-only commands and runs them. |
No command has a --yes/force flag — every Writes row above always asks first. A copy of this table plus every command's full --help output is also on the Desktop: auren-releaseops-cli-commands.txt.
What it does
auren-releaseops doctor— no project involved: checks this machine actually has the tools the CLI shells out to (git, node, npm, npx, rsync, unzip, and the Supabase CLI via npx — that last one is optional, everything else is required). The first thing a new developer should run.auren-releaseops locks— no project involved: lists every project currently locked by a runningsync/commit/db-push/update/resume(project, PID, action, started time). Empty most of the time — only non-empty while something is actually mutating a project.auren-releaseops unlock -p <project>— force-removes a project's lock regardless of whether the holding process is still alive. The escape hatch for a genuinely stuck lock (e.g. this machine was killed mid-run); normally you'll never need it, since a lock left by a process that's actually died gets cleared automatically the next time you run a command against that project.auren-releaseops list— GET/api/projects, print the configured projects. Backed by the liveprojectstable.auren-releaseops register -p <id> [path]— creates a brand-new project in the dashboard directly from a local folder, for a folderscanfound that isn't registered anywhere yet. Runs the exact same detectiondetectuses (see below) against the given path (defaults to.), shows the proposed config, and — after one y/N —POSTs it to/api/projects, the same endpoint the dashboard's "Add project" form uses. Closes a real COMMERCIAL-ROADMAP Phase B3 gap ("import current project config"): before this, a discovered folder still meant retyping every field by hand into a web form. Immediately usable from this CLI, no further setup (Stage 10.11) — every other command resolves project config cloud-first now, falling back to a localprojectConfig.tsentry only when one exists, so a project created this way works right away with zero local TypeScript.auren-releaseops detect -p <project>— scans the project's local checkout instead of a developer hand-typing every field: check commands (frompackage.jsonscripts — typecheck/lint/test/build, in that order, whichever exist), git (.gitpresence), env files (.env.local/.env, whichever exist), required env keys (.env.example's declared keys, cross-referenced against realprocess.env.Xusage anywhere in the source tree so scaffolded-but-unused keys don't get suggested), and a health URL (a dedicated/api/health-style route found anywhere in the tree, including nested monorepo layouts likeapps/web/src/app/api/health/route.ts— never a guess at a bare/on an assumed port, since that risks pinging some other thing that happens to be listening there, a real false positive caught live-testing this against a genuine monorepo). Shows a diff against the current config and asks one y/N before writing anything — same gate as every write action here. Known limitation, by design, not a bug: "used somewhere in source" isn't the same as "load-bearing for the app to boot" — a complex project with many optional integrations (payment providers, AI providers, background workers) will get all of their real-but-optional env keys suggested too. Review the list before confirming, especially on projects like that.auren-releaseops pair [-i seconds] [--timeout seconds]— the CLI half of COMMERCIAL-ROADMAP Phase B1's device pairing flow (Stages 10.3-10.5). Starts a pairing session (public, no auth — this machine has no identity yet), prints a short code, and polls until a human enters that code on the dashboard's/pairpage while logged in. Once claimed, saves the real device credential to~/.config/auren-releaseops/device-token(delivered exactly once over the same polling endpoint, then cleared server-side — never re-fetchable). That credential doesn't do anything yet beyond authenticateGET /api/installations/me— there's no daemon or Agent process consuming it, this is groundwork for Phase B2.auren-releaseops report -p <project> -v <version> -z <zip> -s <status>— POST/api/releases, record an outcome. Persisted to the livereleasestable (real database, since Session 4 — no longer in-memory).auren-releaseops changelog -p <project> [-o file]— full technical changelog from every recorded release.auren-releaseops release-notes -p <project> [-o file]— short "what's new" note for just the latest release.auren-releaseops handoff -p <project> [-o file]— current status, known issues (failed releases), recommended next step.
All three are GET /api/projects/:id/<doc>, print to stdout or write to a file with -o. Together they're the Release Manager half of the product.
auren-releaseops sync -p <project> [-z path]— finds the project's update ZIP in~/Downloads/updates(or use-zfor an explicit path), extracts it safely, shows anrsyncdiff preview, and only writes to the real project folder after you typeyat an explicit confirmation prompt. There is no--yesflag on purpose. On success (applied, or no changes found), the ZIP is moved into~/Downloads/<project>_project/— matching the bash tool's per-project archive. A decline leaves the ZIP in place in~/Downloads/updatesso you can retry. After an applied sync, best-effort reports adeployedrelease to the dashboard (version parsed from the ZIP filename) — same fire-and-forget pattern asreadiness's reporting, a dashboard that's down doesn't block or fail the sync.auren-releaseops db-push -p <project>— only for the 4 projects with a Supabase workflow (myclockledger-app,web2buy,dgf,fieldos). Reads the Supabase Personal Access Token from the same macOS Keychain entry the bash tool uses (ELStudios Supabase CLI, keyed by the project's assigned alias — never written to a file), links the project, then asks one explicit y/N before runningsupabase db push. No--yesflag.auren-releaseops supabase-backup -p <project> [--schema-only|--data-only] [-o path]— links the project the same waydb-pushdoes, then runssupabase db dumpto a local SQL file (default~/Downloads/<project>_project/backups/<project>-<timestamp>.sql). Read-only against the live database — nothing remote changes, only a local file gets written, so no confirmation prompt.auren-releaseops gh-status -p <project> [-n count]— thecount(default 5) most recent GitHub Actions runs and their status, via plain HTTPS to the GitHub REST API (noghCLI needed). SetGITHUB_TOKENorGH_TOKENin the environment for private repos; public repos work unauthenticated (just more rate-limited).auren-releaseops pr-list -p <project>— every open pull request on the project's repo, same plain-HTTPS approach and token requirement asgh-status.auren-releaseops update -p <project> [-z path] [-m message] [-o file]— the full pipeline in one command: sync → checks → commit → db-push → archive, in that order, stopping the commit/db-push steps if checks fail. Every write step still asks its own explicit y/N — this just chains the same confirmed steps together instead of running each command by hand. Prints a final report (project, source ZIP, what changed, checks/git/Supabase outcome, archive path, known issues, recommended next stage) to stdout, or to a file with-o. Writes a checkpoint (~/.config/auren-releaseops/checkpoints/<project>.json) after each step. On finish, if anything actually changed, best-effort reports a release record to the dashboard (deployed/validated/failed, derived from the outcome — seederiveReleaseStatusinsrc/report.ts) — a dashboard that isn't running doesn't block or fail the command, it just doesn't get the update.auren-releaseops resume -p <project> [-m message] [-o file]— ifupdatecrashed or was interrupted partway through,resumecontinues from the last completed step instead of starting over (using the checkpointupdateleft behind). Same pipeline, same confirmations — it just skips whatever already finished. Says so and exits if there's no checkpoint, or if the last run already completed.auren-releaseops checks -p <project> [--smart]— runs the project's configured build/lint/typecheck/test commands in order, stops at the first failure and shows exactly what failed. No confirmation needed — checks don't write anything. Only 3 of 11 projects (dgf, idan-haor, fieldos) have checks configured today, matching what's real in the bash tool.--smart(Stage 8.8b, ported from~/bin/projects'smart_check_plan) looks at what actually changed viagit statusfirst — no changes or docs-only changes skip the run entirely instead of re-running a full build/test suite for a README edit. Everything else still runs the full configured set: this CLI'scheckCommandsis a flat list with no build-vs-test split, so there's no narrower "light" tier to run yet, unlike the bash tool's build-only/full distinction.auren-releaseops git-status -p <project>— read-onlygit status, no confirmation.auren-releaseops commit -p <project> -m "<message>"— stages everything, shows the staged diff, then asks one explicit y/N covering both commit and push. Decline unstages cleanly, leaving the repo exactly as it was. Only 5 of 11 projects (myclockledger-app/api/mcp, shirtov, buildmeter) have git enabled, matching the bash tool. After a successful push, best-effort reports adeployedrelease to the dashboard (version frompackage.json, falling back to the short git SHA) — same fire-and-forget pattern assync/readiness's reporting.auren-releaseops readiness -p <project> [-o file]— read-only pre-flight scorecard, distinct fromchecks: does the folder/git repo exist, is the working tree clean, does the version agree acrosspackage.jsonand the latest git tag, is Supabase configured. Each item is pass/warn/fail; a mismatch or a missing repo fails the whole scorecard. No confirmation needed — nothing here writes anything except (best-effort) reporting the result to the dashboard'scheckstable so it shows up as a badge on the project. First feature built specifically with the multi-developer SaaS product in mind rather than Liron's own 11 projects — it takesdestination/gitEnabled/supabaseRefas plain inputs, the same waysync/checks/commitalready do, so it isn't tied to any hardcoded project list.auren-releaseops rollback -p <project> [-z name]— lists a project's archived ZIPs (newest first, from the same~/Downloads/<project>_project/foldersyncarchives into), lets you pick one (or pass-zto skip the picker), previews the file diff, and requires typing the literal wordROLLBACK— not just y/N — before applying. A destructive action gets a stronger confirmation than a routine one. No archived versions means nothing to roll back to; says so and exits.auren-releaseops cleanup -p <project> [--keep n] [--min-days n]— deletes old archived ZIPs from the same~/Downloads/<project>_project/folderrollbackreads from, to reclaim disk space. Keeps the--keepmost recent (default 20), anything younger than--min-days(default 30), and anything that looks like a release-candidate build (rc/rc.1/rc-2, case-insensitive) regardless of age or count — an RC is exactly the kind of archive you don't want auto-deleted out from under you. Shows a KEEP/DELETE table with the reason for each and total reclaimable space, then requires typing the literal wordCLEANUPbefore deleting anything — same stronger-than-y/N gate asrollback. Ported from~/bin/projects'artifact_cleanup_plan(v9.3.3).auren-releaseops verify -p <project> [-o file]— post-deploy counterpart toreadiness: confirms git origin actually matches local HEAD (a realgit ls-remote, not just trustingcommit's push exited 0 — catches a silently-failed or overwritten push, which nothing else here checks for), optionally pings ahealthUrlwith retries, optionally runs averifyCommand. Both are opt-in per-project config fields. Falls back to a live-detectedhealthUrl(same detectiondetectuses) for this one run when nothing's saved — a fallback, not a write, so it needs no confirmation; nothing gets persisted,detect -p <project>still owns saving it. Read-only except for the same best-effort dashboard report asreadiness.auren-releaseops env-check -p <project> [-o file]— confirms the project'srequiredEnvKeysare actually set inenvFiles(defaults to.env.local, then.env) before you deploy. Falls back to live-detected required keys for this one run when none are saved, same asverify's health-URL fallback above — genuinely useful even on a projectdetect's own output would be too noisy to blindly save wholesale (seedetect's note below). Says so and exits if nothing's configured and nothing's detectable either.auren-releaseops watch [-i seconds] [--once]— polls the dashboard (default every 10s) for commands queued via a project's "Run" button, claims the oldest pending one, dispatches to the samereadiness/verify/env-check/checkslogic above, and reports the outcome back.--onceclaims/runs at most one pending job then exits (useful for testing or cron) instead of looping forever. This is what actually lets the dashboard operate the CLI, not just display what it already did — see "Remote command bridge" below.
Dashboard integration
readiness/verify/env-check results, and update/resume's release outcome, get reported to the dashboard automatically — always best-effort: if AUREN_API_URL (default http://localhost:3000) isn't reachable, the CLI command still completes normally and just prints a note that nothing was recorded. Nothing about the CLI's own behavior depends on the dashboard being up. See the main app's supabase/migrations/0002_checks.sql/0003_env_check_type.sql for the checks table this reports into, and src/app/page.tsx/src/app/projects/[id]/page.tsx for where it's displayed.
Run with dashboard reporting enabled: npm run start:local-env -- <command> (uses Node's --env-file=.env.local, which sets AUREN_API_URL for you) — more reliable than prefixing the env var inline on the command line.
Authentication (Stage 9.1, partial)
Set AUREN_API_TOKEN in cli/.env.local (generate one from the main app: npm run create-token) and every request the CLI makes sends it as Authorization: Bearer <token>. This is additive, not required — with no token set, every command keeps working exactly as before via the dashboard's OWNER_USER_ID fallback. A token identifies which user's data the CLI is acting on, which matters once more than one person can have an account (Stage 9.4) — today, with a single account, setting it changes nothing observable, it just proves the real per-user auth path end to end.
Stage 5 (local execution power) is complete as of this command.
Remote command bridge (Stage 9.5)
The dashboard's project pages have "Run" buttons (readiness/verification/env-audit) that queue a job in the commands table via POST /api/projects/[id]/run. Nothing happens on its own — a watch process has to be running on the machine that actually has the project checked out, polling and claiming jobs (POST /api/commands/next) and reporting results back (PATCH /api/commands/[id]). Deliberately scoped to read-only action types only: sync/commit/db-push still can't be triggered remotely, since those need a browser confirmation UI (show the diff, a second click to confirm) that doesn't exist yet — this bridge only covers actions that were already safe to run with no confirmation locally.
Project locks (Stage 8.8)
sync, commit, db-push, update, and resume all take a per-project lock before doing anything, and release it when they finish (even on error/cancel) — ported from ~/bin/projects' acquire_project_lock. This matters once a project has more than one thing that can run against it at once (a watch process picking up remote jobs, plus you running something by hand in a terminal): two of these commands can't corrupt the same repo by racing. A lock left behind by a process that genuinely died (this machine restarted, the process was killed) is detected via a real liveness check and cleared automatically the next time something tries to acquire it — you should essentially never need unlock for real, it exists as an escape hatch. See locks/unlock above.
What it deliberately does NOT do (yet)
Nothing writes without your explicit confirmation first (sync, commit, db-push) or is read-mostly by nature (checks, git-status). It still doesn't call wrangler — Cloudflare integration is on hold. The bash tool's run_update auto-chained Supabase db push and git push with no confirmation at all; that gap is now fixed in both tools (see the vault's HUMAN-APPROVAL-RULES.md for this project).
Supabase execution power will get the same confirmation-gate treatment before it's added. Track progress in ../docs/ROADMAP.md, Stage 5.
Project destination paths, ZIP-matching aliases, rsync excludes, and check commands live in src/projectConfig.ts, ported from ~/bin/projects' configure_project. Since Stage 9.3, this is the fallback, not the only source — getProjectSyncConfig checks the cloud (GET /api/projects/[id]/config, managed via the dashboard's "Add project"/edit forms) first, and only trusts it once a project has a real destination set there, merging per-field otherwise. A dashboard that's unreachable, or a project with no cloud config yet, behaves exactly as before this stage.
Local development
npm install
npm run build
npm run start -- listRequires the main app (..) running via npm run dev for the API routes to respond. To point at a non-default port, write AUREN_API_URL=http://localhost:<port> to cli/.env.local (gitignored) and run npm run start:local-env -- <command> instead — inline shell env vars aren't reliable in every environment this CLI gets run from.
