ADR-0006 — Centralized .env Scaffold with Secrets Prompted at Generation Time
Status: accepted
Deciders: DeAcero AI Agent Guild
Date: 2026-03-18
Commits: d271ccd (fix(template): prompt for Squit API key and scaffold .env), 486c492 (fix(env): add missing env vars to .env and .env.example)
Context and Problem Statement
Cornerstone-generated projects depend on two categories of runtime secrets:
SQUIT_API_KEY— API key for the SQUIT MCP semantic SQL search service (5.7M legacy SQL objects). Without it, all discovery tools that query SQUIT (squit_client.py,sql_topology.py, etc.) fail with cryptic HTTP 401 errors.AGENTIC_TELEMETRY_URL— URL of the central Observability Service. Without it, telemetry is a no-op (by design per ADR-0003), but teams that want observability must configure it manually.
Before this ADR's resolution, the template:
- Did not include a .env file — teams had to create it from scratch
- Did not prompt for the API key at generation time — teams discovered the requirement only when a tool failed
- Had the SQUIT API key hardcoded in squit_client.py as a default argument (security anti-pattern)
- Did not include a .gitignore — teams could accidentally commit secrets
- Was missing AGENTIC_TELEMETRY_DEBUG and OTEL_EXPORTER_OTLP_ENDPOINT from .env despite being referenced in .telemetry/ code
Decision Drivers
- Secrets must never be hardcoded in source files (OWASP A02 — Cryptographic Failures)
- Teams must not have to read documentation to know what environment variables are required
- Generated
.envmust never be committed to version control - Teams that do not have a SQUIT API key must be able to generate a project and fill in the key later
- All env vars referenced in the template code must have a canonical home
Considered Options
- Template variables + pre-filled
.env— addsquit_api_keyandagentic_telemetry_urltocookiecutter.json; generate.envwith values filled in at generation time; add.gitignore - Post-generation documentation only — keep
.env.example, document manual copy step in README - Vault / secrets manager integration — integrate HashiCorp Vault or GCP Secret Manager;
.envis auto-populated at runtime from the vault - GitHub Actions secrets only — manage secrets exclusively via repo secrets, not
.env; local dev uses no secrets
Decision Outcome
Chosen option: Option 1 — Template variables + pre-filled .env at generation time.
Rationale:
- Option 2 (documentation only) relies on teams reading documentation before running tools. The SQUIT key was hardcoded precisely because teams skipped the manual copy step — this is the problem to solve.
- Option 3 (Vault/secrets manager) is the correct enterprise solution but adds significant infrastructure complexity for a Cookiecutter template targeting teams that may not have vault access configured. It is not ruled out for the future but cannot be the baseline.
- Option 4 (GitHub Actions only) leaves local development broken. Teams run discovery tools and ADR gate checks locally, not only in CI.
- Option 1 surfaces the requirement at the exact moment the team is paying attention: during
cookiecutter gh:deagentic/cornerstone. Empty values are valid — the team can press Enter and fill them in later. The pre-filled.envmakes the variable names and their purpose self-documenting.
Positive Consequences
- Teams know what secrets are required before writing a single line of code
squit_client.pyfails with a clear error message instead of a silent wrong-key HTTP 401.gitignoreprevents accidental secret commits from day one- All env vars referenced in the codebase have a single canonical location (
.env) .env.exampleserves as documentation for anyone who recreates the file
Negative Consequences
cookiecutter.jsonnow prompts for values that many teams may not have yet (SQUIT key requires requesting from the platform admin)- Teams generating a project for the first time may be confused by the prompts if they have not been onboarded
- Cookiecutter prompts do not support masked input — the API key is visible in the terminal during generation
Implementation Details
cookiecutter.json additions
{
"squit_api_key": "",
"agentic_telemetry_url": "",
"_copy_without_render": [...]
}
Empty string defaults allow skipping with Enter. The values are rendered into .env via Jinja2 at generation time.
Generated .env
SQUIT_API_KEY={{cookiecutter.squit_api_key}}
AGENTIC_TELEMETRY_URL={{cookiecutter.agentic_telemetry_url}}
AGENTIC_TELEMETRY_DEBUG=
OTEL_EXPORTER_OTLP_ENDPOINT=
All four env vars referenced across .telemetry/, emit_ci_event.py, and squit_client.py are present. Optional vars have empty defaults.
.env.example
Committed to version control as a reference file with safe example values:
SQUIT_API_KEY=your_squit_api_key_here
AGENTIC_TELEMETRY_URL=http://192.99.38.188:8000
AGENTIC_TELEMETRY_DEBUG=
OTEL_EXPORTER_OTLP_ENDPOINT=
This allows a team member who deleted their .env to reconstruct it from the example without reading documentation.
.gitignore
The generated project ships with a .gitignore that excludes .env, output/, context/, __pycache__, .pytest_cache, and standard Python artifacts. The .gitignore is checked into the template as a literal file (not rendered by cookiecutter) so it applies immediately after generation.
squit_client.py — hardcoded key removal
The default argument --key was changed from a hardcoded string to:
parser.add_argument("--key", default=os.environ.get("SQUIT_API_KEY", ""))
...
if not args.key:
print("[ERROR] SQUIT_API_KEY not set. Add it to your .env file or pass --key.", file=sys.stderr)
sys.exit(1)
This makes the missing-key failure explicit, actionable, and points teams to the correct fix.
.gitkeep for required empty directories
Three directories expected by the agent workflow are created as empty directories with .gitkeep:
output/findings/— archaeology ledger locationcontext/— run context markdown filesexperiments/— isolated experiment probes
Without .gitkeep, git does not track empty directories and the paths referenced in AGENTS.md do not exist after cloning.
Pros and Cons of Options
Option 1: Template variables + pre-filled .env (chosen)
- Good, because secrets are surfaced at generation time when the team is attentive
- Good, because all env vars have a canonical location
- Good, because
.gitignoreships from day one - Bad, because SQUIT API key is visible in terminal during generation (no masked input)
Option 2: Documentation only
- Good, because no prompts that might confuse teams without onboarding
- Bad, because teams will skip the manual step — the pre-existing hardcoded key is evidence
Option 3: Vault / secrets manager
- Good, because secrets never appear in files
- Bad, because adds infrastructure dependency not appropriate for a Cookiecutter template baseline
Option 4: GitHub Actions secrets only
- Good, because secrets are managed in a central, audited location
- Bad, because local development breaks for all discovery tools and ADR gate checks