Anuva CLI Implementation Plan
Purpose
Build a narrow anuva command-line harness in anuva-main-video-creator using
Bun, TypeScript, Commander.js, and Google zx. The CLI is the deterministic executor
used by Anuva Codex skills in interactive sessions. It operates over Linear,
Git/GitHub, repository Markdown/MkDocs, local Development-stage services, and an
existing Cloudflare Tunnel.
This plan is the input for a separate implementation task. It does not authorize Web, Python, or Unity product implementation.
Goals
- Give Codex small, named, typed operations instead of repeatedly composing SDK,
Git, GitHub CLI, MkDocs, and
cloudflaredcommands. - Make read operations cheap and machine-readable.
- Make state changes preconditioned, idempotent where practical, approval-gated, and auditable.
- Manage all four repository documentation previews and the current machine's Development-stage services.
- Replace
anuva-dev-docs/scripts/build-all-docs.ps1with oneanuva docs publishcommand while keeping canonical publication manual.
Non-goals
- A generic shell wrapper, task runner, YAML workflow interpreter, plugin host, or autonomous orchestrator.
- Product reasoning, issue-scope generation without Codex review, code generation, PR review judgment, or unattended background work.
- Cloudflare route/Access policy provisioning.
- Codex Goals, Symphony, automated browser-agent testing, Early Users deployment, or Production infrastructure.
- Replacing repository-native test commands or Playwright.
Technology decisions
| Concern | Choice | Rationale |
|---|---|---|
| Runtime/package/test | Bun + TypeScript | One fast local toolchain for a Windows-first CLI and built-in test runner. |
| Command tree/help | Commander.js | Strict options, nested subcommands, generated help, and async actions via parseAsync. |
| Finite child commands | Google zx | Readable, safely interpolated calls to git, gh, mkdocs, and cloudflared; centralized PowerShell selection on Windows. |
| Long-lived processes | Bun.spawn behind the same process adapter |
Persistent MkDocs/services/tunnel processes need PID/log ownership across CLI invocations. |
| Linear | @linear/sdk |
Strongly typed official SDK for reads and mutations. |
| GitHub | GitHub CLI (gh) |
Reuses existing user authentication and provides PR/check/merge primitives. |
| Validation | Zod plus TypeScript types | Runtime validation for config, manifests, SDK normalization, receipts, and JSON output. |
| YAML | yaml package |
Machine configuration only; never executable workflow definitions. |
Use zx only through an internal adapter. Alias its $ import clearly (for example
zx$) so it is not confused with Bun Shell. Interpolate each argument as data;
never concatenate Linear text, file paths, branch names, or user values into a raw
shell program.
Repository layout
anuva-main-video-creator/
package.json
bun.lock
tsconfig.json
src/
cli.ts
commands/
doctor.ts
context.ts
linear/
issue-get.ts
issue-list-ready.ts
issue-start.ts
issue-submit.ts
issue-complete.ts
change-complete.ts
change-create-implementation-issues.ts
work/
start.ts
pr/
create.ts
inspect.ts
checks.ts
merge.ts
docs/
ensure.ts
status.ts
validate-indexes.ts
wait.ts
links.ts
stop.ts
publish.ts
dev/
start.ts
status.ts
logs.ts
stop.ts
core/
config.ts
context.ts
errors.ts
output.ts
confirmation.ts
receipt.ts
redaction.ts
paths.ts
lock.ts
adapters/
linear.ts
git.ts
github.ts
process.ts
mkdocs.ts
cloudflare.ts
filesystem.ts
health.ts
docs-publisher/
repositories.ts
build.ts
copy.ts
index-page.ts
linear-status-page.ts
git-publish.ts
schemas/
development-config.ts
implementation-issues.ts
result.ts
process-state.ts
tests/
unit/
integration/
contract/
fixtures/
linear/
git/
mkdocs/
publisher/
Keep command handlers thin. They parse input, load context, call one application service, and render its result. SDK and process details stay behind adapters so tests can run without live Linear, GitHub, Cloudflare, or Unity access.
Command and output conventions
Global options
Defaults:
- configuration:
%APPDATA%\Anuva\development.yaml; - process state:
%LOCALAPPDATA%\Anuva\state\processes.json; - receipts/logs:
%LOCALAPPDATA%\Anuva\logs\; - repository detection: nearest Git root matched to the configured registry.
JSON envelope
{
"schemaVersion": 1,
"ok": true,
"operation": "docs.wait",
"data": {},
"warnings": [],
"receipt": {
"id": "20260714T102030Z-docs-wait-ab12",
"startedAt": "2026-07-14T10:20:30Z",
"completedAt": "2026-07-14T10:20:31Z"
}
}
Never place secrets, full process environments, Linear tokens, tunnel credentials, or database URLs in output or receipts.
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success or already in desired idempotent state |
| 2 | Invalid command input or schema |
| 3 | Missing/invalid configuration or repository context |
| 4 | Authentication/authorization failure |
| 5 | Precondition or state-transition failure |
| 6 | Required interactive confirmation missing |
| 7 | External command/service failure |
| 8 | Partial mutation requiring recovery |
| 9 | Timeout/health-check failure |
Mutation protocol
Every state-changing operation must:
- read and validate current state;
- calculate and display a dry-run plan;
- require
--confirmfor execution; - acquire a scoped lock to prevent duplicate concurrent mutation;
- perform the minimum external changes;
- re-read and verify the resulting state; and
- return a receipt plus a recovery instruction for partial failure.
--confirm proves only that the caller selected the execution form. Codex skills
must still obtain explicit user approval at workflow boundaries.
Configuration schema
schemaVersion: 1
machine: machine1
devRoot: C:\\Anuva\\dev
repositories:
anuva-main-video-creator:
path: C:\\Anuva\\dev\\anuva-main-video-creator
github: Shoonya-Game-Technologies/anuva-main-video-creator
docsPort: 4001
docsUrl: https://main1.girishd.com
anuvax-cms:
path: C:\\Anuva\\dev\\anuvax-cms
github: Shoonya-Game-Technologies/anuvax-cms
linearRepositoryLabel: anuvax-cms
docsPort: 4002
docsUrl: https://web1.girishd.com
anuva-python-server:
path: C:\\Anuva\\dev\\anuva-python-server
github: Shoonya-Game-Technologies/anuva-python-server
linearRepositoryLabel: anuva-python-server
docsPort: 4013
docsUrl: https://python1.girishd.com
anuva-unity-video-creator:
path: C:\\Anuva\\dev\\anuva-unity-video-creator
github: Shoonya-Game-Technologies/anuva-unity-video-creator
linearRepositoryLabel: anuva-unity-video-creator
docsPort: 4004
docsUrl: https://unity1.girishd.com
linear:
teamKey: ANU
states:
backlog: Backlog
ready: Ready
inProgress: In Progress
inReview: In Review
done: Done
canceled: Canceled
labels:
repositoryGroup: Repository
github:
branchPrefix: codex/
defaultRemote: origin
tunnel:
name: anuva-machine1
tokenFile: C:\\Users\\<user>\\AppData\\Local\\Anuva\\secrets\\cloudflared-anuva-machine1.token
services:
webapp:
repository: anuvax-cms
command: [bun, run, dev]
port: 3000
healthUrl: http://127.0.0.1:3000/api/health
publicUrl: https://anuva1.girishd.com
python:
repository: anuva-python-server
command: [python, -m, anuva_server]
healthUrl: http://127.0.0.1:8000/health
unity:
mode: availability-check
editorPath: C:\\Program Files\\Unity\\Hub\\Editor\\<version>\\Editor\\Unity.exe
publisher:
repository: anuva-dev-docs
outputFolders:
anuva-main-video-creator: main-video-creator
anuvax-cms: anuvax-cms
anuva-python-server: anuva-python-server
anuva-unity-video-creator: anuva-unity-video-creator
Validate absolute paths, unique ports/URLs, known repository keys, expected Linear
state names, a tunnel name, and an absolute tunnel token-file path. The YAML stores
the path only; the tunnel token stays in its ACL-restricted file. Environment
variables or tool-native credential stores supply LINEAR_API_KEY and gh
authentication.
Linear operations
Read issue
Return normalized issue ID/key/title/description, priority, state, repository label, parent/children, blockers, labels, Product Main source path, review preview URL, canonical docs URL when published, PR URL, and timestamps. Keep the SDK's internal UUID out of normal human output but retain it in typed data.
List ready issues
Filter server-side where the SDK supports it, then verify client-side:
- state equals configured
Ready; - repository label exactly matches current repository;
- issue is not archived/canceled;
- all blocking issues are Done; and
- description includes Product Main link, scope, acceptance checks, docs, and verification requirements.
Return malformed candidates separately as warnings rather than silently hiding them.
Create implementation issues
anuva linear change create-implementation-issues <manifest.json> --dry-run
anuva linear change create-implementation-issues <manifest.json> --confirm
Manifest shape:
{
"schemaVersion": 1,
"parentIssue": "ANU-310",
"changeId": "2026-07-14-render-stage-progress",
"productDocs": {
"sourcePath": "docs/changes/2026-07-14-render-stage-progress/index.md",
"previewUrl": "https://main1.girishd.com/changes/2026-07-14-render-stage-progress/",
"canonicalUrl": null
},
"issues": [
{
"clientKey": "unity",
"repository": "anuva-unity-video-creator",
"title": "Emit accurate render stage and progress events",
"description": "...",
"priority": "High",
"dependsOn": []
}
]
}
Validate all issues before creating any. Create in dependency order, set parent,
repository label, Ready state, and backlinks, then return a clientKey → Linear
ID/URL mapping. Store a deterministic marker containing Change ID + repository in
the description so a retry finds and reuses already-created issues without a
high-cardinality Change ID label. On partial failure, do not delete successful
issues; return exact recovery steps.
Named state changes
Implement only start, submit, complete, block, and unblock if/when each
is required. Avoid a generic transition --to <anything> command. start,
submit, and complete check the allowed source state, required links/artifacts,
and target state. block and unblock manage explicit issue relations without
changing the blocked issue's lifecycle state.
linear change complete is a separate named operation. It requires every
non-canceled child implementation issue to be Done, every linked PR to be merged,
and a Product Main CompletionReview.md containing acceptance evidence.
Git and GitHub operations
Start work
Preconditions: correct repository, issue ready, dependencies done, no conflicting
branch, and no unsafe dirty changes. Create codex/anu-311-<slug> from configured
base, then move Linear to In Progress. If the branch succeeds and Linear fails,
return exit 8 with the branch name and retry command.
Standalone repository changes use a typed allowlisted path:
anuva repository-change start <intake-json> --dry-run
anuva repository-change start <intake-json> --confirm
anuva repository-change docs start <issue-id> --plan <absolute-plan> --confirm
anuva repository-change docs pr create <issue-id> --plan <absolute-plan> --preview <url> --confirm
anuva repository-change docs pr ready <issue-id> --confirm
anuva repository-change complete <issue-id> --report <absolute-report> --confirm
The skill performs read-only classification. The CLI schema cannot represent
Escalate; it accepts only evidenced Not required or Required intake. Start
creates or reuses one marked, top-level, repository-labeled issue directly in In
Progress and reconciles codex/<issue-id>-<slug>.
Issue normalization distinguishes Product Main parents, implementation children, and marked standalone issues so their command families cannot cross. The common PR create/ready path accepts children and standalone issues. Child merge remains child-specific.
A Required standalone issue may own one bounded Product Main documentation branch and draft PR. Completion reuses normal check, review, mergeability, guarded-head, merge verification, base-update, and branch-cleanup contracts; orders implementation before documentation; records evidence; and moves Linear Done last. Identical retries reconcile supported partial states.
Pull requests
pr createverifies branch/issue, pushes through Git, invokesgh pr create, links the PR in Linear, and moves to In Review.pr inspectreturns PR URL/number/base/head/draft/review/mergeability/checks.pr checkswrapsgh pr checkswith stable normalized results.pr mergerequires all configured checks, no blocking review, mergeability, completion report, exact issue/PR link, and--confirm. Use a configured merge strategy and verify the merged state.
Do not stage or commit unrelated files. Initial CLI scope may require Codex to use normal Git for selective staging/commits; a future named commit operation can be added only with a clear scope contract.
Documentation preview operations
Phase 3 makes docs preview and docs verify the installed primary contracts
while retaining the Phase 2 operations below for rollback compatibility.
Preview
anuva docs preview --repository current --file <paths...> reuses a healthy
owned MkDocs process across Markdown, branch, and HEAD changes. It restarts only
for command, working-directory, port, configuration, health, or trusted
identity changes; refuses external/conflicting listeners; performs no strict
build; and returns exact local and public URLs.
Verify
anuva docs verify --repository current --file <paths...> validates root and
user-facing indexes, navigation, local links, orphans, and empty sections. It
runs one strict build for all requested pages and compares the served output
without a timestamp or restart prerequisite. An external listener is accepted
for that invocation only after every page matches and is never adopted or
terminated.
Compatibility ensure and state tracking
anuva docs ensure --repository current:
- resolve repository and
mkdocs.yml; - read configured port and public base URL;
- check the recorded PID plus command fingerprint and OS identity;
- hash the Git branch, HEAD, MkDocs configuration, and docs source tree;
- restart the owned process with
mkdocs serve -a 127.0.0.1:<port>when that generation changes, and reject any unowned listener; - wait for local HTTP success; and
- return local/public URLs, generation, and log path.
Record PID, start time, repository, generation hashes, port, executable, and log path. Never kill a PID unless its executable/start fingerprint still matches the record.
Compatibility wait and URL mapping
docs wait requires a pre-edit timestamp and a post-edit owned generation. It
builds the working tree strictly into a temporary site and compares each requested
live page with that output, rejecting stale navigation and local .md links. It
times out with the relevant build or comparison error. docs links maps paths under docs_dir according to
MkDocs use_directory_urls; reject paths outside docs_dir with a clear message.
Compatibility index hierarchy validation
anuva docs validate-indexes --repository current recursively checks every
directory under the configured docs_dir. It fails when any directory lacks an
index.md, when an index is empty, or when a documentation directory is empty.
The human and JSON result lists exact paths. This validator does not generate or
rewrite indexes; Codex owns the overview wording and links.
Strict verification
The final workflow verification runs:
Use a temp output so validation does not dirty the repository.
Development environment operations
Start
anuva dev start --with-docs --with-tunnel performs:
doctorchecks;- database availability check (do not automatically create/reset data);
- Web and Python start-or-health-check;
- Unity Editor/EXE availability check;
- all four docs
ensureoperations; cloudflared tunnel run --token-file <configured-token-file>if the configured tunnel is not already healthy;- local health checks; and
- remote URL checks that distinguish Cloudflare Access redirects from origin failures.
Do not attempt to bypass email OTP. A remote 302/Access login page can prove the
route is alive; authenticated content checks remain a user/browser action unless a
safe service token is explicitly added later.
Stop
Stop only processes started and fingerprinted by the CLI, in this order: tunnel,
Web/Python services, MkDocs. Leave PostgreSQL and Unity Editor running by default.
Require --confirm for --all.
Port build-all-docs.ps1 to anuva docs publish
The existing script at
C:\Anuva\dev\anuva-dev-docs\scripts\build-all-docs.ps1 currently builds all
four MkDocs sites, copies output into anuva-dev-docs, generates a Material-styled
root index and GitHub Project status page, and optionally commits/pushes the static
site. Port that behavior into one command:
anuva docs publish
anuva docs publish --clean
anuva docs publish --skip-linear-status
anuva docs publish --push --confirm
Parameter parity
| PowerShell parameter | CLI replacement |
|---|---|
-DevRoot |
--dev-root, default config devRoot |
-OutputRoot |
--output-root, default configured anuva-dev-docs path |
-MkDocsCommand |
--mkdocs-command, default mkdocs |
-ProjectId |
Removed; Linear team/project/filter configuration replaces GitHub Project ID |
-SkipProjectStatus |
--skip-linear-status |
-Clean |
--clean |
-PushToGitHub |
--push --confirm |
-GitRemote |
--git-remote, default origin |
-GitBranch |
--git-branch, default current branch |
-CommitMessage |
--commit-message, default timestamped message |
Required behavior parity
- Resolve and validate Dev Root and Output Root.
- Use the fixed four-repository registry and output folders.
- Build each repository independently with MkDocs strict mode into a unique temp directory; collect success/failure without losing earlier results.
- Copy generated output safely.
--cleanremoves only the resolved destination under Output Root. Add bounded Windows retries for locked files; never weaken the root-containment checks. - Discover the generated Material CSS/favicon assets and generate a root index containing repository cards and build results.
- Replace the GitHub Project page with a Linear status page grouped by repository
and state, linking issues, Product Main change docs, and PRs. When credentials
are missing or
--skip-linear-statusis used, generate a clear placeholder. - Fail the command if any repository build fails. Do not push partial output.
- With
--push, verify Output Root is exactly theanuva-dev-docsGit root, stage only generated publisher paths, skip commit when unchanged, commit, push the explicit branch, and return commit/remote/branch. - Print a summary table in human mode and a stable result array in JSON mode.
- Clean temporary directories even on failure, without touching source docs.
- After a successful push, derive canonical URLs from the publisher mapping, verify the published pages, and idempotently synchronize the managed docs-link block on affected Linear parent and implementation issues. If publication succeeds but link synchronization fails, return a partial-failure receipt and an exact retry command; never conceal the published Git state.
Migration strategy
Keep build-all-docs.ps1 during parity development. Build a golden fixture from
the current script, compare the four site trees/root index/status behavior, and run
the new command manually on both development machines. After two successful manual
publishes, replace the PowerShell script with a short deprecation message pointing
to anuva docs publish, then remove it in a later reviewed change.
Security model
- The command tree itself is the allowlist. No command accepts executable code, shell snippets, workflow YAML, arbitrary SDK method names, or arbitrary Linear state names.
- Normalize repository names and issue IDs before use.
- Resolve every filesystem mutation and prove containment under a configured root.
- Reuse GitHub CLI authentication. Give
cloudflaredonly the configured token-file path; never read, copy, print, or log the file contents. - Redact common token patterns and values sourced from secret environment names.
- Log operation names, safe arguments, identifiers, outcomes, and recovery steps; do not log full issue descriptions when unnecessary.
- Cloudflare Dashboard owns tunnels, routes, certificates, Access configuration, and token lifecycle. The CLI starts/checks only the configured remote-managed tunnel connector.
- Use per-operation locks to prevent concurrent start/merge/publish races.
Test strategy
Unit tests
- Commander parsing, required options, unknown-option rejection, help snapshots.
- Config parsing, path containment, repository detection, branch slugging.
- Linear normalization, readiness validation, transition table, manifest schema.
- MkDocs path-to-URL mapping, directory URL behavior, and recursive
index.mdhierarchy validation. - JSON envelopes, exit-code mapping, redaction, and receipts.
- Publisher root index/status HTML generation and asset selection.
Integration tests with fakes/temp repositories
- Temp Git repositories for branch/start/dirty-worktree/idempotency cases.
- Stub
gh,mkdocs, andcloudflaredexecutables capturing argv without a shell. - Fake Linear adapter for successful, rejected, duplicate, and partial mutations.
- Real small MkDocs fixture for start/wait/strict-build behavior.
- Process registry tests including stale/reused PID protection.
- Publisher build/copy/clean/locked-file retry and no-change commit behavior.
Opt-in live smoke tests
Run only with explicit environment flags and test-safe Linear/GitHub artifacts:
doctoragainst the developer machine;- read an existing Linear issue and list ready issues;
- inspect a known PR;
- start/check/stop one fixture MkDocs process;
- check the existing tunnel without changing Dashboard configuration; and
- build canonical docs without
--push.
Never run merge, completion, issue creation, service stop, or canonical push in automated tests against live systems.
Implementation phases
Phase 0: contracts and spike
- Record the CLI ADR and command/output contracts.
- Prove Bun can run Commander,
@linear/sdk, Zod, YAML, and zx on both Windows machines. - Prove zx PowerShell configuration and argument interpolation with spaces and Unicode paths.
- Capture current publisher golden output.
Exit: dependencies work on both machines and no design relies on arbitrary shell.
Phase 1: foundation and read-only operations
- Command tree, config, errors/output/receipts, redaction, repository context.
doctor,context show, Linear issue get/list-ready, PR inspect/checks.
Exit: skills can discover and inspect work entirely through stable JSON.
Phase 2: docs preview
- Process registry, docs ensure/status/wait/links/stop, strict build helper.
- Validate exact URLs through the Product Main documentation-editing workflow.
Exit: every Markdown-changing skill can satisfy the preview contract.
Phase 3: issue handoff and work start
- Implementation-issue manifest validation/creation and named Linear transitions.
work start, idempotency, locks, partial-failure receipts.
Exit: approved Product Main plans become ready repository issues, and selected issues start safely.
Phase 4: pull-request lifecycle
- PR create/link/submit, inspect/check normalization, guarded merge, completion.
Exit: one test issue completes end to end without manual Linear/GitHub bookkeeping.
Phase 5: Development environment
- Web/Python/Unity availability adapters, all docs servers, tunnel, health, logs, stop ordering, and machine-specific configuration.
Exit: $anuva-manage-development-environment start exposes healthy Development
services and gated docs routes on either machine.
Phase 6: canonical docs publisher port
- Build/copy/index/Linear status/manual Git publish parity.
- Golden comparison and two-machine manual validation.
Exit: anuva docs publish --push --confirm replaces the PowerShell entry point.
Phase 7: skill rollout
- Create/validate Product Main skills under
.agents/skills/anuva/<skill-name>/SKILL.mdand confirm Codex discovery from the repository root. - Update CMS and pilot the render-progress issue.
- Roll learned contracts to Python and Unity.
- Remove obsolete docs and PowerShell only after successful pilots.
Acceptance criteria
- [ ] CLI runs on both Windows development machines from the same repository code.
- [ ]
anuva --helpexposes only the reviewed named operations. - [ ] Every read operation has stable JSON and no secret leakage.
- [ ] Every mutation validates state, supports dry-run where meaningful, requires confirmation, verifies the outcome, and emits a receipt.
- [ ] Linear is the only issue/workflow control plane; no GitHub Project dependency remains.
- [ ] GitHub PR operations reuse
ghauthentication and block unsafe merges. - [ ] All four MkDocs servers can be ensured, checked, linked, and stopped safely.
- [ ] Documentation skills return exact machine-specific Cloudflare URLs.
- [ ] Every directory and subdirectory under each repository
docs_dircontains a non-emptyindex.md, enforced byanuva docs validate-indexes. - [ ] Development services and the named tunnel can be started/statused/logged/stopped without modifying Cloudflare Dashboard configuration.
- [ ]
anuva docs publishmatches the safe build/copy/index/manual-push behavior ofbuild-all-docs.ps1and generates Linear status instead of GitHub Project status. - [ ] Unit/integration suites pass, strict Product Main MkDocs builds, and one pilot change completes through Product Main, an implementation repo, PR, and Linear.