Development Environment and Cloudflare Tunnels
The Anuva Development Process Policy owns the target machine and toolchain boundaries. Phases 2 through 5 established the packaged CLI, fixed toolchain, strict previews, installed plugin, and five-repository skill migration on machine one. Phase 6 added the reviewed minimal-rule source, completed the machine-one rules lifecycle, and delivered the clean-machine procedure. Machine-two replication is deferred because the machine is unavailable; Phase 7 proceeds only with machine-one and read-only cross-repository process acceptance and must retain that exception.
Plugin source and installed workflow
The repository-owned marketplace is .agents/plugins/marketplace.json, and its
local plugin source is plugins/anuva-development. Phase 4 Gate 1 changes that
source from readiness-only 0.1.0 to skills-only 0.2.0 with twelve shared
skills and three references. Gate 2 installed and accepted cache 0.2.0 on
machine one. Phase 4 PR
#27
merged that source as 7773e5db744e94a3ede35482c939210701f70527.
Rollback means restoring the previously validated plugin source/version, removing only the installed plugin, reinstalling it from the registered local marketplace, and confirming that a new task reports the prior version. Phase 5 verified plugin discovery and removed checked-in shared workflow copies; use the reviewed repository PR reverts as the repository-migration rollback.
The Phase 1 implementation record reports the exact commands and observed version transitions for this machine. Plugin registration, upgrade, or removal is machine configuration and must remain within the user's explicit request.
The Codex plugin page manages one active cache for this marketplace. Gate 2
therefore used merged main commit
f93461318639d19bc90b844d60de53902d580c8c as the durable 0.1.0
source-backed rollback target, recreated and discovered that cache, then
returned to Phase 4 commit
2f2cd6349d42a2689b9006d9c390f54567df34d1 and recreated 0.2.0.
The final active cache is 0.2.0. No cache or Codex configuration was edited
by hand, and PATH, CLI targets, Cloudflare, and implementation repositories
were unchanged.
Packaged CLI
Machine one currently resolves
%LOCALAPPDATA%\Anuva\bin\anuva.cmd through its inherited process PATH. The
active executable is clean build 0.2.1-g2fecf51439fc; rollback and inverse
rollback were verified, and the final state is
current=0.2.1-g2fecf51439fc with
previous=0.2.1-g3dd30bca40f1. The checksum-manifested legacy-source
directory remains installed as the original first-install recovery target.
Build and temporary-root verification are Product Main operations:
Ignored build output is written under
dist/anuva-cli/<version>-g<commit>[-dirty] with anuva.exe and a closed
artifact.json. The live installer accepts only such a local artifact, verifies
its target, byte count, SHA-256, and embedded --version identity, and rejects
dirty builds at the default installation root.
Phase 3 CLI acceptance
The first approved 0.2.1-g5c468136c28f artifact exposed a structure-validator
compatibility defect during live read-only acceptance and was rolled back
without changing sibling files. Product Main corrected exclude_docs, reachable
link, nested-parenthesis link, and structural-index handling.
Gate 2 accepted clean build 0.2.1-g3dd30bca40f1, built from
3dd30bca40f1f1269b6431b05250c9902f5da520, with size 102319616 bytes and
SHA-256
d8c08ecc4ec3c5a5e4c71a95b7588955551b6e9c9194640b68d6d14c0b5e550c.
All 109 source tests and seven packaged checks pass. The installed artifact
strictly verified Product Main, Bento, Web, Python, and Unity against their
healthy CLI-owned previews, and an authenticated browser opened every exact
machine-one HTTPS route. The real-user toolchain dry-run remains healthy with
no actions.
The acceptance changed no sibling file, Git state, tunnel, route, DNS,
certificate, Access policy, token, PATH entry, or machine tool.
Gate 3 review passed and PR
#25
merged to main as a02084cc9628973f5a965512a48486ba51c979eb.
The target user layout is:
%LOCALAPPDATA%\Anuva\
bin\anuva.cmd
cli\current
cli\previous
cli\legacy-source\anuva.cmd
cli\legacy-source\target.json
cli\versions\<build-id>\anuva.exe
cli\versions\<build-id>\artifact.json
The stable launcher contains no Product Main path. current and previous
contain only validated target identifiers: a packaged build identifier or the
literal legacy-source. Installation stages and validates a side-by-side
version before atomically replacing current. On the first packaged install it
preserves the validated Phase 1 source launcher byte-for-byte, writes its closed
checksum manifest, and sets previous=legacy-source. Rollback validates and
swaps only those two closed pointers, allowing an inverse rollback to return to
the packaged build.
Before any live installation, return the clean artifact version, full commit,
dirty state, size, SHA-256, current and proposed paths, pointer transition,
legacy-source launcher checksum, PATH effect, toolchain dry-run, and exact
rollback command. Do not invoke the installer against %LOCALAPPDATA%, run
anuva cli rollback --confirm, or run anuva toolchain bootstrap --confirm
without that concrete approval.
Read-only inspection is available through:
anuva cli status --json
anuva toolchain doctor --json
anuva toolchain snapshot --json
anuva toolchain bootstrap --dry-run
anuva skills validate --json
An inaccessible-in-sandbox result requires retry in an approved execution
context; it is not evidence that the tool is missing and must not trigger a
reinstall.
The current deployment automation scope is the Development stage only. Early Users and Production remain future architecture concerns and are not implemented by the harness yet.
For a clean second machine, follow the Windows Development Machine Bootstrap. It uses the machine-two configuration example, fixed toolchain actions, a bounded source-launcher prerequisite, the exact packaged artifact lifecycle, plugin and rules rollback, read-only Cloudflare verification, and non-secret snapshot comparison. Do not copy machine-one caches, raw Codex configuration, credentials, or working trees.
The machine-two procedure is deferred, not obsolete. When the machine becomes available, restart its preview from the then-current Product Main commit and follow the page's deferred re-entry checklist. Do not reuse the superseded uninstalled artifact, infer Cloudflare state from the old DNS failure, or claim cross-machine acceptance before the full procedure passes.
Phase 7 machine-one acceptance snapshot
Phase 7 Gate 2 completed from Product Main
117f7241f6f3e18440afdf49b11221d8fde5b80b. The installed machine-one state
did not change:
- plugin source/cache
0.2.0, twelve skills; - active CLI
0.2.1-g2fecf51439fc, previous0.2.1-g3dd30bca40f1; - canonical rules SHA-256
35eed0fb26bae95c7a45a4a1c83c119dcb012a4e5082758c1e02ef51379a4077, 9,924 bytes; and - fixed toolchain healthy with no bootstrap action.
Source verification passed 123 tests and 509 assertions. Packaged verification
passed 7 tests and 125 assertions and prepared, but did not install,
0.2.1-g117f7241f6f3, 102,319,104 bytes, SHA-256
674cadce76a84d316f04023603f74bbdc2d50169bd2620cee327c06c8a130fb1.
The 48-case rules matrix and 4 installer tests with 41 assertions also passed.
The environment-only evidence amendment was process scoped. It selected native
Windows PowerShell module directories for Bun-spawned installer tests and set
PYTHONDONTWRITEBYTECODE=1 only for the isolated five-site documentation build.
Neither setting persisted. The final repositories are clean, Bento's generated
cache is absent, and no .pyc exists in the candidate. The candidate is local
evidence only: it has 48 generated additions, 50 changes, and no removals versus
canonical Product Main output. It is not installed or published.
Per-machine topology
flowchart LR
Device["Developer phone/tablet\nCloudflare Access OTP"]
CF["Cloudflare\nAccess + Tunnel routes"]
Tunnel["One cloudflared tunnel\nfor this machine"]
Web["Web app"]
MainDocs["Main docs :4001"]
BentoDocs["Bento docs :4005"]
WebDocs["CMS docs :4002"]
PythonDocs["Python docs :4013"]
UnityDocs["Unity docs :4004"]
Python["Python server"]
Unity["Unity Editor or EXE"]
Postgres["Local PostgreSQL + pgvector"]
Device --> CF --> Tunnel
Tunnel --> Web
Tunnel --> MainDocs
Tunnel --> BentoDocs
Tunnel --> WebDocs
Tunnel --> PythonDocs
Tunnel --> UnityDocs
Web --> Python --> Unity
Web --> Postgres
Use a distinct named tunnel per machine. Dashboard-managed routes map each hostname to a loopback port, and each route is protected by Cloudflare Access. Separate tunnels prevent traffic for one hostname from being balanced across two development machines with different working trees.
See Cloudflare Tunnel and Access Setup for the one-time Dashboard configuration, Access policy, published routes, certificate coverage, token storage, and verification checklist.
Interactive command
From any Anuva repository Codex task:
The skill runs anuva dev start --with-docs --with-tunnel, which:
- checks Bun, Git, GitHub CLI, Linear credentials, MkDocs,
cloudflared, local PostgreSQL/pgvector, repository paths, and configured ports; - starts or verifies the Web app and Python server;
- verifies that the configured Unity Editor or EXE is available;
- starts all five dirty MkDocs servers;
- starts the machine's existing named Cloudflare Tunnel;
- checks local health endpoints and remote hostnames; and
- prints URLs, process IDs, health, and log locations.
Supported modes should include:
anuva dev start --with-docs --with-tunnel
anuva dev start --docs-only --with-tunnel
anuva dev status --json
anuva dev logs <service>
anuva dev stop --all --confirm
Stopping should terminate the tunnel first, then product services and docs servers. Leave PostgreSQL running unless the user explicitly requests database shutdown.
Machine-local configuration
Store non-secret configuration at %APPDATA%\Anuva\development.yaml:
schemaVersion: 1
machine: machine1
devRoot: C:\\Anuva\\dev
tunnel:
name: anuva-machine1
tokenFile: C:\\Users\\<user>\\AppData\\Local\\Anuva\\secrets\\cloudflared-anuva-machine1.token
services:
webapp:
repository: anuvax-cms
port: 3000
url: https://anuva1.girishd.com
docs:
anuva-main-video-creator: { port: 4001, url: https://main1.girishd.com }
anuva-bento: { port: 4005, url: https://bento1.girishd.com }
anuvax-cms: { port: 4002, url: https://web1.girishd.com }
anuva-python-server: { port: 4013, url: https://python1.girishd.com }
anuva-unity-video-creator: { port: 4004, url: https://unity1.girishd.com }
Do not store API keys, tunnel token values, database passwords, or OAuth tokens in this file or Git. The YAML contains only the path to the ACL-restricted tunnel token file. The CLI reads other secrets from approved environment variables or the credential mechanisms of the underlying tools.
GitHub CLI authentication
Authenticate GitHub CLI in an interactive Windows terminal with gh auth login,
then verify it with gh auth status. GitHub CLI normally reads that credential
from the Windows user keyring.
A managed Codex sandbox may be unable to read the keyring even when the same
command succeeds in the interactive terminal. A sandbox-only failure is not
evidence that the saved credential is invalid. Retry the read-only
gh auth status check with scoped sandbox escalation. If that keyring-capable
check succeeds, run subsequent GitHub-backed anuva pr operations in the same
approved context. Reauthenticate only when the keyring-capable check also fails.
anuva doctor deliberately reports this case as credentials unavailable in the
current execution context. It remains an unhealthy check for that process because
GitHub operations cannot succeed there, but it does not instruct the user to
replace a credential that may still be valid.
Linear API key
Store the Linear personal API key in the Windows user environment as
LINEAR_API_KEY. Do not copy it into development.yaml, a repository .env
file, a prompt, or a committed script.
For a persistent setup, open Edit environment variables for your account in
Windows, create a user variable named LINEAR_API_KEY, and paste the API key as
its value. Close and reopen Codex and any terminals afterward: running processes
do not inherit user-environment changes made after they started.
Alternatively, set the user variable from PowerShell. Supplying the value on the command line can retain it in shell history, so prefer the Windows editor when that history is not suitably protected.
[Environment]::SetEnvironmentVariable(
"LINEAR_API_KEY",
"<your Linear personal API key>",
[EnvironmentVariableTarget]::User
)
For only the current PowerShell process, use $env:LINEAR_API_KEY = "<key>".
This value disappears when that process exits and is not made available to an
already-running Codex process.
After reopening Codex or the terminal, verify that the key is visible without printing its value, then run the CLI diagnostics:
if ([string]::IsNullOrWhiteSpace($env:LINEAR_API_KEY)) {
throw "LINEAR_API_KEY is not available in this process"
}
bun run anuva -- doctor --json
doctor verifies that the variable is present. A read-only Linear command also
confirms that Linear accepts the key:
References: Create a remotely managed tunnel
and cloudflared tunnel run parameters.