|
| 1 | +--- |
| 2 | +name: autonomy--env-creator |
| 3 | +description: Creates the capacity for an agent to load all environment variables from scratch, based on the output of autonomy--env-auditor. Use when an env audit report exists and environment loading needs to be remediated. Do not use when no audit report exists (run autonomy--env-auditor first) or when debugging a single missing variable. |
| 4 | +--- |
| 5 | + |
| 6 | +# Environment Creator |
| 7 | + |
| 8 | +Build out a repository's environment variable configuration so that an agent (or new developer) can go from zero to a fully configured `.env` in a single command. Based on findings from `autonomy--env-auditor`. |
| 9 | + |
| 10 | +Prefer one documented bootstrap path that writes local env config from the repo's real source of truth. In many repos that is `scripts/env.sh`. A `.env.example` file can still exist, but it should be secondary. |
| 11 | + |
| 12 | +## Prerequisites |
| 13 | + |
| 14 | +Read the audit report at `.agents/reports/autonomy--env-auditor-audit.md`. If no report exists, instruct the user to run `autonomy--env-auditor` first. |
| 15 | + |
| 16 | +Before changing anything: |
| 17 | + |
| 18 | +1. Assume the current local `.env` may contain the only surviving copy of a secret. |
| 19 | +2. Never delete or overwrite the active `.env` as the first step. |
| 20 | +3. Prefer improving an existing bootstrap flow over replacing it. |
| 21 | +4. Keep `.env` and backup files ignored by Git. |
| 22 | + |
| 23 | +## Step 1: Review and Classify Findings |
| 24 | + |
| 25 | +1. Read the audit report's variable inventory and findings. |
| 26 | +2. Order by severity: Critical (hard blockers) first, then High, Medium, Low. |
| 27 | +3. Classify each variable into one of two categories: |
| 28 | + |
| 29 | +| Category | Description | Example | |
| 30 | +|---|---|---| |
| 31 | +| **Provisioned Secret** | Secrets, credentials, and shared config that should come from the project's secret source | `DATABASE_URL`, `JWT_SECRET`, `STRIPE_API_KEY` | |
| 32 | +| **Local Override** | Values that are always the same for local development and can be hardcoded in the script | `NODE_ENV=development`, `LOG_FORMAT=text`, `AWS_REGION=us-west-2` | |
| 33 | + |
| 34 | +## Step 2: Confirm the Secret Source |
| 35 | + |
| 36 | +Collaborate with the user to confirm where provisioned secrets come from and how the repo should fetch them. |
| 37 | + |
| 38 | +The example below uses **AWS SSM Parameter Store** as a worked reference. If your project uses HashiCorp Vault, Doppler, 1Password CLI, GCP Secret Manager, Azure Key Vault, or another secret backend, adapt the fetch commands while following the same pattern: agree on a prefix/path, verify parameters exist, identify gaps, and confirm naming conventions. |
| 39 | + |
| 40 | +If the project uses AWS SSM, use the steps below. Otherwise adapt the same pattern to the project's secret system. |
| 41 | + |
| 42 | +1. **Agree on the SSM prefix** with the user. Convention: `/<project-name>/` (e.g., `/my-project/`, `/api-service/`). The prefix should match what Terraform or IaC uses for container secrets. |
| 43 | +2. **Verify parameters exist** by running: |
| 44 | + ```bash |
| 45 | + aws ssm get-parameters-by-path \ |
| 46 | + --path "/<project-name>/" \ |
| 47 | + --recursive \ |
| 48 | + --with-decryption \ |
| 49 | + --output json \ |
| 50 | + --region <region> | jq -r '.Parameters[].Name' |
| 51 | + ``` |
| 52 | +3. **Identify gaps:** Compare the list of SSM parameters against the audit report's variable inventory. Flag any missing parameters. |
| 53 | +4. **SSM naming convention:** Parameter names must use the env var name as the last path segment, in uppercase (e.g., `/<project-name>/DATABASE_URL`, not `/<project-name>/database_url`). This is what the script uses to derive the variable name. |
| 54 | +5. For any missing parameters, ask the user to create them (or create them together if the user has the values). Do NOT create SSM parameters containing production secrets without explicit user approval. |
| 55 | + |
| 56 | +## Step 3: Create the Primary Bootstrap Command |
| 57 | + |
| 58 | +Create or update the project's primary env bootstrap command. In many repos this is `scripts/env.sh`. The generated temp file must always end by being promoted into `.env` — either directly, or after validation. |
| 59 | + |
| 60 | +```bash |
| 61 | +#!/bin/bash |
| 62 | + |
| 63 | +# Usage: bash scripts/env.sh [--profile <aws_profile>] |
| 64 | +# |
| 65 | +# Populates .env by fetching secrets from AWS SSM Parameter Store. |
| 66 | +# AWS SSO authentication is required. |
| 67 | +# |
| 68 | +# Prerequisites: aws cli, jq |
| 69 | +# Login first: aws sso login --profile <profile> |
| 70 | + |
| 71 | +set -eo pipefail |
| 72 | + |
| 73 | +PROFILE="" |
| 74 | +ENV_FILE=".env" |
| 75 | +TMP_ENV_FILE=".env.tmp.$$" |
| 76 | +SSM_PREFIX="/<project-name>" # [CUSTOMIZE] set to the project's SSM prefix |
| 77 | +AWS_REGION="us-west-2" # [CUSTOMIZE] set to the project's AWS region |
| 78 | + |
| 79 | +# ─── Parse Arguments ──────────────────────────────────────────── |
| 80 | + |
| 81 | +while [[ $# -gt 0 ]]; do |
| 82 | + case "$1" in |
| 83 | + --profile) |
| 84 | + PROFILE="$2" |
| 85 | + shift 2 |
| 86 | + ;; |
| 87 | + *) |
| 88 | + echo "Unknown option: $1" |
| 89 | + echo "Usage: bash scripts/env.sh [--profile <aws_profile>]" |
| 90 | + exit 1 |
| 91 | + ;; |
| 92 | + esac |
| 93 | +done |
| 94 | + |
| 95 | +PROFILE_FLAG="" |
| 96 | +if [[ -n "$PROFILE" ]]; then |
| 97 | + PROFILE_FLAG="--profile $PROFILE" |
| 98 | +fi |
| 99 | + |
| 100 | +# ─── Check AWS Credentials ────────────────────────────────────── |
| 101 | + |
| 102 | +if ! aws sts get-caller-identity $PROFILE_FLAG &>/dev/null; then |
| 103 | + echo "AWS credentials not valid. Logging in..." |
| 104 | + if [[ -n "$PROFILE" ]]; then |
| 105 | + aws sso login --profile "$PROFILE" |
| 106 | + else |
| 107 | + echo "Error: No active AWS session. Run: aws sso login --profile <profile>" |
| 108 | + exit 1 |
| 109 | + fi |
| 110 | +fi |
| 111 | + |
| 112 | +# ─── Back Up Existing .env ────────────────────────────────────── |
| 113 | + |
| 114 | +if [[ -f "$ENV_FILE" ]]; then |
| 115 | + BACKUP="$ENV_FILE.bak.$(date +%Y%m%d%H%M%S)" |
| 116 | + cp "$ENV_FILE" "$BACKUP" |
| 117 | + echo "Backed up existing .env to $BACKUP" |
| 118 | +fi |
| 119 | + |
| 120 | +# ─── Start Fresh Temp File ────────────────────────────────────── |
| 121 | + |
| 122 | +rm -f "$TMP_ENV_FILE" |
| 123 | +touch "$TMP_ENV_FILE" |
| 124 | + |
| 125 | +# ─── Fetch SSM Parameters ─────────────────────────────────────── |
| 126 | + |
| 127 | +echo "Fetching SSM parameters from $SSM_PREFIX ..." |
| 128 | + |
| 129 | +aws ssm get-parameters-by-path \ |
| 130 | + --path "$SSM_PREFIX" \ |
| 131 | + --recursive \ |
| 132 | + --with-decryption \ |
| 133 | + --output json \ |
| 134 | + --region "$AWS_REGION" \ |
| 135 | + $PROFILE_FLAG | \ |
| 136 | + jq -r '.Parameters[] | (.Name | split("/") | .[-1]) as $key | select($key | test("^[A-Z]")) | "\($key)=\(.Value | @sh)"' \ |
| 137 | + >> "$TMP_ENV_FILE" |
| 138 | + |
| 139 | +if [[ ! -s "$TMP_ENV_FILE" ]]; then |
| 140 | + echo "Warning: No SSM parameters found under $SSM_PREFIX" |
| 141 | + echo "Verify the prefix and that parameters exist in the $AWS_REGION region." |
| 142 | +fi |
| 143 | + |
| 144 | +# ─── Local Development Overrides ──────────────────────────────── |
| 145 | +# Values below are appended after SSM parameters. |
| 146 | +# They either override SSM values for local dev or add variables |
| 147 | +# that don't belong in Parameter Store. |
| 148 | + |
| 149 | +cat <<'EOF' >> "$TMP_ENV_FILE" |
| 150 | +
|
| 151 | +# ─── Local Development Overrides ───────────────────────────── |
| 152 | +# These values are specific to local development and are not |
| 153 | +# stored in SSM. Edit as needed for your environment. |
| 154 | +
|
| 155 | +# NODE_ENV=development |
| 156 | +# DATABASE_URL=postgresql://localhost:5432/<project>_dev |
| 157 | +# REDIS_URL=redis://localhost:6379 |
| 158 | +# LOG_FORMAT=text |
| 159 | +EOF |
| 160 | +``` |
| 161 | + |
| 162 | +The script is not complete until one of these endings exists: |
| 163 | + |
| 164 | +1. **Preferred:** Validate `"$TMP_ENV_FILE"` and then run `mv "$TMP_ENV_FILE" "$ENV_FILE"`. |
| 165 | +2. **Minimal fallback:** If validation is skipped, still end with `mv "$TMP_ENV_FILE" "$ENV_FILE"` so the temp output becomes the active `.env`. |
| 166 | + |
| 167 | +### Adapting the Template |
| 168 | + |
| 169 | +When creating the script for a specific project: |
| 170 | + |
| 171 | +1. **Set `SSM_PREFIX`** to the project's actual prefix (from Step 2). |
| 172 | +2. **Set `AWS_REGION`** to the project's region. |
| 173 | +3. **Replace the local overrides heredoc** with the actual local override variables identified in Step 1. Uncomment lines that apply and remove placeholder examples. |
| 174 | +4. **Add any exclude filters** if certain SSM parameters should not appear in the local `.env` (e.g., production-only values). Add a `grep -vE` filter after the `jq` pipeline: |
| 175 | + ```bash |
| 176 | + grep -vE '^(PRODUCTION_ONLY_VAR|ANOTHER_VAR)=' \ |
| 177 | + ``` |
| 178 | +5. **Make the script executable:** `chmod +x scripts/env.sh` |
| 179 | +6. **Add `.env`, `.env.tmp.*`, and `.env.bak.*` to `.gitignore`** if not already present. |
| 180 | + |
| 181 | +## Step 4: Add Validation (Optional) |
| 182 | + |
| 183 | +If the project doesn't already validate environment variables at startup, add a validation step — either inside `env.sh` or as application startup logic. Promotion from the temp file to `.env` should happen only after validation. |
| 184 | + |
| 185 | +### In-script validation (recommended) |
| 186 | + |
| 187 | +Add a validation block at the end of `env.sh` that checks required variables are present in the generated temp file before promotion: |
| 188 | + |
| 189 | +```bash |
| 190 | +# ─── Validate Required Variables ───────────────────────────── |
| 191 | + |
| 192 | +echo "Validating required environment variables..." |
| 193 | +MISSING=0 |
| 194 | + |
| 195 | +for VAR in DATABASE_URL JWT_SECRET; do # ← list required vars |
| 196 | + if ! grep -q "^${VAR}=" "$TMP_ENV_FILE"; then |
| 197 | + echo " MISSING: $VAR" |
| 198 | + MISSING=$((MISSING + 1)) |
| 199 | + fi |
| 200 | +done |
| 201 | + |
| 202 | +if [[ $MISSING -gt 0 ]]; then |
| 203 | + echo "Error: $MISSING required variable(s) missing from .env" |
| 204 | + echo "Check that the SSM parameters exist under $SSM_PREFIX" |
| 205 | + rm -f "$TMP_ENV_FILE" |
| 206 | + exit 1 |
| 207 | +fi |
| 208 | + |
| 209 | +mv "$TMP_ENV_FILE" "$ENV_FILE" |
| 210 | +echo "All required variables present." |
| 211 | +``` |
| 212 | + |
| 213 | +If you skip the validation block, add a final promotion step at the end of the script: |
| 214 | + |
| 215 | +```bash |
| 216 | +mv "$TMP_ENV_FILE" "$ENV_FILE" |
| 217 | +echo "Done — wrote $ENV_FILE" |
| 218 | +``` |
| 219 | + |
| 220 | +### Application startup validation |
| 221 | + |
| 222 | +If the project has a typed config layer (e.g., Go struct, Zod schema, Pydantic model), add validation there that fails fast with a clear error naming the missing variable. |
| 223 | + |
| 224 | +## Step 5: Document in AGENTS.md and README |
| 225 | + |
| 226 | +Update the project's AGENTS.md and/or README to include: |
| 227 | + |
| 228 | +1. **How to populate `.env`:** |
| 229 | + ``` |
| 230 | + bash scripts/env.sh --profile <your-aws-profile> |
| 231 | + ``` |
| 232 | +2. **Prerequisites:** The CLI tools required by your secret backend (e.g., AWS CLI v2 and `jq` for SSM; `vault` for HashiCorp Vault; `doppler` for Doppler). |
| 233 | +3. **How to authenticate:** The login command for your secret backend (e.g., `aws sso login --profile <profile>` for AWS SSM). |
| 234 | +4. **What it does:** Fetches or assembles the local env config from the project's source of truth and writes `.env`. |
| 235 | +5. **When to re-run:** After SSM parameters are added/changed, or when setting up a new machine. |
| 236 | +6. **Recovery behavior:** The script creates a timestamped backup before replacing `.env`. If generation or validation fails, keep the prior `.env` and restore from the backup if needed. |
| 237 | + |
| 238 | +## Step 6: Verify and Archive |
| 239 | + |
| 240 | +1. If a `.env` file already exists, create a timestamped backup before verification. |
| 241 | +2. Run `bash scripts/env.sh --profile <profile>` and confirm it writes a complete `.env`. |
| 242 | +3. Start the application and verify it boots successfully. |
| 243 | +4. If generation or startup verification fails, keep the old `.env` in place or restore it from the backup before trying again. |
| 244 | +5. If a `.env.example` file exists, keep it as a reference or compatibility file only. Point it to the primary bootstrap path if helpful. |
| 245 | +6. Archive the audit report to `.agents/reports/completed/autonomy--env-auditor-audit-{YYYY-MM-DD}.md`. |
| 246 | +7. Update `docs/onboarding-checklist.md`. Optionally update `docs/skills-status.md` if the repository keeps the compatibility view. |
0 commit comments