Local Environment Control (bootstrap / doctor / reconcile)
Purpose
Make local development environments predictable and self-healing under the repo-env-contract SSOT model.
The env-localctl skill:
- validates local requirements against the repo contract (
env/contract.yaml) - checks that non-secret values and secret references exist for a chosen env
- resolves secrets via approved mechanisms (never via chat)
- generates a local env file (
.env.localor.env.<env>.local) - produces redacted LLM context (
docs/context/env/effective-<env>.json) - applies policy preflight checks from
docs/project/policy.yaml(auth_mode/preflight rules)
Hard precondition (SSOT mode gate)
Use the skill only when the project env SSOT mode is repo-env-contract.
To check the mode, read:
docs/project/env-ssot.json
If the project is not in the required mode, STOP.
If docs/project/env-ssot.json does not exist (first-time setup), run:
python3 -B -S .ai/skills/features/environment/env-contractctl/scripts/env_contractctl.py init --root .
Then re-run the local workflow.
When to use
Use when the user asks to:
- "make my local env work" / "I can't boot the service locally"
- sync local env after contract changes
- diagnose missing env vars or secret access
- regenerate
.env.localdeterministically
Avoid when:
- you need to add/rename/deprecate variables (use
env-contractctl) - you need to deploy/rotate secrets for staging/prod (use
env-cloudctl)
Invariants
- MUST NOT ask users to paste secrets into chat.
- MUST NOT write secret values into evidence artifacts.
- SHOULD write local secret material only to gitignored files (e.g.,
.env.local). - SHOULD set
.env.localpermissions to0600.
Inputs
- Contract:
env/contract.yaml - Non-secret values:
env/values/<env>.yaml(+ optionalenv/values/<env>.local.yamlfor per-developer overrides) - Secret references:
env/secrets/<env>.ref.yaml - Secret material: resolved via secret backends (e.g., mock file store, environment, or file reference)
- Policy (preflight/auth):
docs/project/policy.yaml(selectsauth_mode+preflightrules viaenv/runtime_target/workload)runtime_targetsupportslocal | ecs(remoteis accepted as an alias forecs)
Outputs (evidence + generated artifacts)
Evidence directory
Choose one evidence location (no secrets):
- Recommended:
dev-docs/active/<task-slug>/artifacts/env-local/
- Otherwise:
.ai/.tmp/env-local/<run-id>/
Evidence files (templates available in ./templates/):
00-prereq-check.md01-auth-and-secrets-check.md02-config-compile-report.md03-connectivity-smoke.md04-post-fix-summary.md
Generated artifacts
.env.local(default fordev) or.env.<env>.localdocs/context/env/effective-<env>.json(redacted; safe for LLM)
Deployment-oriented usage (cloud injection)
Use the same controller on a deploy machine to render a target env-file without writing repo-local context:
python3 -B -S .ai/skills/features/environment/env-localctl/scripts/env_localctl.py compile \
--root . \
--env staging \
--runtime-target ecs \
--workload api \
--env-file /etc/<org>/<project>/staging.env \
--no-context \
--out <EVIDENCE_DIR>/02-config-compile-report.md
Steps
Phase 0 — Confirm scope and mode
- Confirm the user's intent is local bootstrap/diagnosis.
- Confirm env SSOT mode is
repo-env-contractviadocs/project/env-ssot.json.- If not, STOP.
- Confirm target env for local run (default:
dev). - Choose evidence directory.
Phase A — Doctor (diagnose)
- Run a deterministic local doctor:
python3 -B -S .ai/skills/features/environment/env-localctl/scripts/env_localctl.py doctor \
--root . \
--env dev \
--runtime-target local \
--workload api \
--out <EVIDENCE_DIR>/00-prereq-check.md
- If doctor reports missing non-secret values, use the minimal entry point:
- Project-wide non-secret values:
env/values/dev.yaml - Per-developer overrides (gitignored):
env/values/dev.local.yaml
- If doctor reports missing secret material, use the minimal entry points:
- Ensure secret ref exists:
env/secrets/dev.ref.yaml - Provide secret material via an approved backend (never via chat)
- For tests/local demo: create
env/.secrets-store/dev/<secret_name>
- For tests/local demo: create
Phase B — Compile (generate .env.local)
- Compile and write
.env.localand redacted context:
python3 -B -S .ai/skills/features/environment/env-localctl/scripts/env_localctl.py compile \
--root . \
--env dev \
--runtime-target local \
--workload api \
--out <EVIDENCE_DIR>/02-config-compile-report.md
Phase C — Connectivity smoke (optional)
- If needed, run a light connectivity check (best-effort; safe; redacted):
python3 -B -S .ai/skills/features/environment/env-localctl/scripts/env_localctl.py connectivity \
--root . \
--env dev \
--runtime-target local \
--workload api \
--out <EVIDENCE_DIR>/03-connectivity-smoke.md
Phase D — Reconcile (idempotent repair)
- If the local
.env.localdrifted, re-run compile (idempotent). Record04-post-fix-summary.md.
Verification
- SSOT mode is
repo-env-contract - Doctor passes (no missing required keys)
-
.env.localgenerated and gitignored - No secret values written to evidence
-
docs/context/env/effective-<env>.jsongenerated (redacted) - Public central test suite passes:
node .ai/tests/run.mjs --suite environment
Boundaries
- MUST NOT modify
env/contract.yamlin theenv-localctlworkflow. - MUST NOT perform cloud-side apply/rotate/decommission.
- MUST NOT print or store secret values in logs/evidence.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.