Skip to content

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:

bun run build:cli
bun run check:packaged

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, previous 0.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:

$anuva-development:anuva-manage-development-environment start

The skill runs anuva dev start --with-docs --with-tunnel, which:

  1. checks Bun, Git, GitHub CLI, Linear credentials, MkDocs, cloudflared, local PostgreSQL/pgvector, repository paths, and configured ports;
  2. starts or verifies the Web app and Python server;
  3. verifies that the configured Unity Editor or EXE is available;
  4. starts all five dirty MkDocs servers;
  5. starts the machine's existing named Cloudflare Tunnel;
  6. checks local health endpoints and remote hostnames; and
  7. 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:

bun run anuva -- linear issue list-ready --repository current --json

References: Create a remotely managed tunnel and cloudflared tunnel run parameters.