Skip to content

AI-quickstart prompt

The canonical prompt for driving Efterlev with an AI assistant (Claude Code, Cursor, Codex, Kiro, or any tool with shell access). Paste it verbatim and the assistant will:

  • Confirm the repo root (catches the silent 20%-coverage-loss footgun).
  • Ask which LLM backend you want — Anthropic API, AWS Bedrock, Claude Code subscription, or OpenAI API (v0.1.213 — recommended model gpt-5.4-mini) — and surface ambient state (env vars, AWS creds, claude CLI presence, OPENAI_API_KEY) as informational, not decisional.
  • For Bedrock: pick the latest Sonnet inference profile, default to it, surface Opus / Haiku as overrides.
  • Install or upgrade Efterlev. Detects pipx vs uv and gives the right command per installer.
  • Orient on your boundaryefterlev boundary discover surfaces candidate in-boundary dependencies (external providers, cross-account refs, remote state, SaaS endpoints) before the pipeline runs.
  • Open Studio in attach mode for live visual progress — Studio tails the same event log the pipeline writes to (it does NOT spawn its own pipeline), so I can watch posture / worklist / reports materialize in the browser as the run happens.
  • Run efterlev report run — the one-command pipeline (init → scan → inventory → agent gap → agent document → poam → vdr → oscal poam → oscal cd). Per-stage wall-clock prints inline; a timing summary lands at the end.
  • Surface the readiness scorecard + the impact-ranked worklist via efterlev next (deterministic — the assistant doesn't hand-pick).
  • Walk you through the procedural manifests (efterlev manifests status / scaffold) for the AFR / CED / INR themes — the wall every first-time customer hits — and offer to bundle a 3PAO submission package.

Cost (first run): ~$1–5 on Sonnet 4.6 depending on workspace size, or ~$3–10 on Opus. Free on Claude Pro/Max subscription (Claude Code backend; no per-call billing). Cache hits are free on every backend — re-running report run on the same workspace replays from disk (v0.1.151+). Wall time: 2–25 minutes for the first run depending on workspace size; subsecond per stage on cache hit. The prompt's constraints section sets a soft cap ($5 Anthropic / $8 Bedrock) that the assistant tracks by tail .efterlev/receipts.log between stages — Efterlev itself doesn't enforce a cap, the assistant does.

The prompt is self-contained — no other docs needed for the assistant to drive end-to-end.


You are helping me run Efterlev (https://efterlev.org) against my Terraform
for the first time. Efterlev is a FedRAMP 20x compliance scanner that reads
Terraform / CloudFormation / Python CDK, classifies it against 60 Key
Security Indicators, and drafts FRMR-compatible attestations and OSCAL
1.0.4 artifacts (POA&M + Component-Definition) with cited evidence. It
runs locally; the only outbound call is to the LLM endpoint I configure.

## Step 0 — confirm the target path

This is the silent footgun, so handle it first.

Ask me for the **absolute path to my repo root** — NOT a Terraform
subdirectory like `infra/terraform/`. Efterlev needs the repo root to
walk all three evidence sources:

  - `**/*.tf`, `**/*.yaml/.json` (CFN templates), `**/*.py` (CDK Python)
    for the IaC detectors
  - `.github/workflows/*.yml` for the GitHub-workflow detectors
    (6 detectors, ~10% of coverage)
  - `.efterlev/manifests/*.yml` for procedural-KSI attestations
    (covers the AFR / CED / INR themes, ~10% of coverage)

If I name a subdir, you'll silently miss workflows + manifests — about
20% of detector coverage disappears with no error message. So:

1. Ask me for the path — **and offer the demo in the same message**, so
   I never have to discover it by failing first. Many people running
   this prompt don't have a Terraform repo handy; the demo is how they
   see Efterlev work. Phrase it like:

       "What's the absolute path to your repo root (the git root, not a
        Terraform subdir)? — I'll only inspect the path you name, never
        search your drive.

        Don't have a Terraform repo to point at? Just say so and I'll
        set you up with `lhassa8/govnotes-demo` — a FedRAMP-shaped
        fixture (~120 Terraform resources + 5 GitHub workflows + 3
        procedural manifests) built for exactly this walk-through."

   You can SEE the directory you were invoked in. If it already looks
   like it has no target (no `.git/`, no `*.tf`, no `.github/workflows/`
   right there), LEAD with the demo offer rather than burying it — but
   still let me choose. (This is inspecting your own cwd, not searching
   my filesystem — that's fine; the no-search rule below is about not
   hunting across my home dir / drive.)
2. Once I give a path (or accept the demo), verify it's a git repo root:
   check for `.git/` AND at least one of `**/*.tf` OR `.github/workflows/`.
   - If only one is present, confirm with me before proceeding ("I see
     Terraform but no workflows — is this a repo root or a subdir?").
   - **If NEITHER is present** (no `.git/`, no `*.tf`, no workflows),
     I probably don't have a real target yet. Offer the demo repo as
     a turnkey test fixture so I can see Efterlev work without
     setting up my own:

         "I don't see a Terraform or workflow target at that path.
          Want to test against the demo repo lhassa8/govnotes-demo?
          It's a FedRAMP-shaped fixture (~120 Terraform resources +
          5 GitHub workflows + 3 procedural manifests) designed exactly
          for this walk-through. I can clone it for you:

              git clone https://github.com/lhassa8/govnotes-demo \
                ~/govnotes-demo

          Then I'll re-verify and proceed from there."

     Wait for my answer before cloning. If I say yes, clone and treat
     the cloned path as the verified target. If I say no, ask me
     where to look.

   NEVER search my filesystem to locate a target or an existing demo
   clone — do not run `find ~`, `find /`, `mdfind`, `locate`, or glob
   outside the exact path I gave you. Scanning my home directory or
   drive is invasive and will make me distrust the tool. Inspect ONLY
   the path I named (and, at most, its immediate subdirectories if I
   point at a wrapper dir). If it's empty or wrong, ASK me — don't go
   hunting.
3. `cd` to that path and stay there for the rest of the run.

## Step 1 — pick the LLM backend

**Always ask me this question — do NOT auto-decide based on env vars,
AWS profile state, `claude` CLI presence, or any other ambient signal.**
The presence of an `ANTHROPIC_API_KEY` doesn't mean I want to use it for
this run; many users have credentials for multiple backends and testing
one specifically is the whole point.

You may surface ambient state as informational context, but the choice
is mine:

  > "I see `ANTHROPIC_API_KEY` is set, `aws sts get-caller-identity`
  >  succeeds for region us-east-1, and `claude` is on PATH. Which
  >  backend would you like to use for this run?
  >
  >    (a) Direct Anthropic API — fastest path; uses your existing key.
  >    (b) AWS Bedrock — uses your AWS credentials; works for GovCloud
  >        and FedRAMP-authorized infra.
  >    (c) Claude Code subscription — Pro/Max users; zero per-call
  >        billing, run from your existing subscription.
  >    (d) OpenAI API — for customers without Claude access; needs
  >        OPENAI_API_KEY. Validated v0.1.213 on csp-starter-cfn:
  >        gpt-5.4-mini holds 100% recall across re-runs with precision
  >        ~80–96% (it over-flags procedural KSIs, never misses a real
  >        gap). Single-fixture reading — Claude backends cover 5 fixtures
  >        at 99-100%; re-run on a Claude backend before final 3PAO
  >        submission and diff the classifications."

Only proceed once I've answered. If I'm genuinely undecided and ask
you to choose, default to whichever is cheapest given my ambient state:
(c) > (a) > (b). Surface (d) when I have OPENAI_API_KEY but neither
ANTHROPIC_API_KEY nor working AWS creds nor `claude` on PATH — note
that quality is validated on one fixture (vs five for Claude paths)
and recommend `gpt-5.4-mini` as the OpenAI model.

Trade-off summary, if I want it:

  - **Anthropic API** — ~2 min setup, one env var, no AWS account.
  - **Bedrock** — ~5–10 min setup (model-access opt-in + inference
    profile selection), works at FedRAMP-authorized scale.
  - **Claude Code subscription** — ~30s setup (run `claude` once to
    sign in), zero per-call billing for Pro/Max plans, but the
    underlying API tokens still count against your subscription's
    fair-use ceiling.
  - **OpenAI API** — ~2 min setup (`pipx install 'efterlev[openai]'`
    + OPENAI_API_KEY). The only "no Claude access at all" path today.
    Recommended model: `gpt-5.4-mini` (validated v0.1.213 on
    csp-starter-cfn: 100% recall every run, precision ~80–96% across
    re-runs — it over-flags procedural KSIs but never misses a real
    gap). gpt-5 is also validated (single dispatch, 100/95.8);
    gpt-5.4 regular is NOT recommended (reliably fabricates citations
    that the hallucination guard rejects, fails the run). Single-fixture
    reading; before final 3PAO submission re-run on a Claude backend
    and diff. See LIMITATIONS.md "OpenAI backend" for the model-by-
    model failure-mode detail.

## Step 2a — Anthropic API path

The fast path. ~2 minutes from zero to running.

1. Confirm I have an Anthropic API key. Verify:
       echo "${ANTHROPIC_API_KEY:0:10}"
   Must start with `sk-ant-` (Anthropic-format). If it starts with
   `sk-proj-` or any other prefix, that's a different vendor's key and
   won't authenticate against Anthropic — stop and ask me to set
   `ANTHROPIC_API_KEY` to an actual Anthropic key. If empty, point me
   at https://console.anthropic.com/settings/keys.
2. Install or upgrade (see Step 2e for installer-specific commands).
3. Confirm `efterlev --version`. Check the latest published version
   with whichever of these is on PATH: `pip index versions efterlev`,
   `pip3 index versions efterlev`, or `uv pip index versions efterlev`.
   If the binary is older than the latest, clean-reinstall per Step 2e.

Then jump to Step 3.

## Step 2b — Bedrock path

Bedrock connects you to LLMs hosted on AWS. Same Anthropic models, just
billed through your AWS account.

### Step 2b.0 — pick the model family

Ask me which model family I want to use:

  (a) Anthropic Claude — RECOMMENDED. This is what Efterlev's agents
      are tuned for; the only family with full feature support today.
  (b) Other (OpenAI / AI21 / Cohere / Meta / Mistral / Nvidia Nemotron)
      — not yet supported as a full backend (Nemotron pricing is wired
      for benchmark dispatches only).

If I say anything other than Claude, gently flag it's not yet
supported, recommend Claude as the working path, and only proceed if
I explicitly confirm I want to wait. The rest of this step assumes
Claude.

### Step 2b.1 — region and credentials

1. Ask me which AWS region to use. Default suggestion: `us-east-1`
   (us-west-2 is the other reliable option). Verify creds:

       aws sts get-caller-identity --region <region>

   If this fails, stop — I need to run `aws configure` first.

2. Confirm Anthropic model access is enabled in this account. The #1
   cold-start cliff. Visit:

       https://console.aws.amazon.com/bedrock/home?region=<region>#/modelaccess

   At least one Claude 4.x must show "Access granted." If not, request
   access there (~near-instant for most accounts) and wait a minute to
   propagate before continuing.

### Step 2b.2 — pick the tier

3. Discover available Claude inference profiles in that region.
   CRITICAL: use `--no-paginate --max-results 1000`. The default page
   size silently truncates at ~100, and older Claude 3.x profiles fill
   the first page hiding 4.x. Run:

       aws bedrock list-inference-profiles --region <region> \
           --type-equals SYSTEM_DEFINED \
           --no-paginate --max-results 1000 \
         | jq -r '.inferenceProfileSummaries[]
                  | select(.inferenceProfileName | test("claude"; "i"))
                  | "\(.inferenceProfileName)\t\(.inferenceProfileArn)"'

   Group results by tier (Opus / Sonnet / Haiku), pick the LATEST
   version of each. Prefer regional `us.` / `eu.` profiles over
   global. If NO 4.x profiles appear after `--no-paginate`, model
   access from step 2 isn't actually granted — go back.

4. Present this as a recommendation, NOT a multiple-choice question.
   Pick the latest Sonnet ARN as MODEL_ARN unless I explicitly object:

       Recommended: Latest Sonnet (claude-sonnet-4-6)
         — Best cost/quality balance for this workload.
         — ~5× cheaper than Opus; classification quality
           indistinguishable from Opus on the 60-KSI sweep.
         — Run cost: ~$1–5 on a typical mid-size codebase.

       Override only if you have a specific reason:
         — Latest Opus (claude-opus-4-7): higher reasoning ceiling,
           ~5× the spend. Worth it for ambiguous codebases.
         — Latest Haiku (claude-haiku-4-5): cheapest tier; validated at
           99.1% precision + 100% recall across labeled fixtures
           (v0.1.118). Fine for smoke tests and re-runs.

   If a tier is unavailable in this account, omit it from the
   alternatives. Capture the chosen `inferenceProfileArn` as MODEL_ARN.

## Step 2c — Claude Code subscription path

The zero-billing path for Pro/Max subscribers.

1. Verify `claude` is on PATH:
       which claude
   If missing, point me at https://claude.com/code/install and stop.
2. Verify subscription is active by running — and **strip
   `ANTHROPIC_API_KEY` for this check**:
       env -u ANTHROPIC_API_KEY claude --print --output-format json "ping"
   A successful JSON response with `"is_error": false` means the OAuth
   session is good. **Why `env -u`:** `claude --print` honors
   `ANTHROPIC_API_KEY` if it's set, and a stray non-Anthropic key
   (e.g. an OpenAI `sk-proj-…` key left in the shell for another tool)
   makes the ping 401 even though the subscription is fine. Stripping
   it for the ping isolates the OAuth session — and it mirrors what
   Efterlev does for its own subprocess (it strips the key
   automatically, so the pipeline is unaffected regardless). A 401
   even AFTER stripping means I need to run `claude` interactively once
   to refresh the session.
3. Install or upgrade Efterlev (Step 2e).

**Configuration**: pass `--llm-backend=claude_code` to `efterlev init`
in Step 3 — no post-init config edit needed (v0.1.158+). Init pins the
workspace model to **Sonnet 4.6** on this backend (v0.1.175+).

Why Sonnet, not Opus, on subscription: although Pro/Max bills against
your quota (so Opus would be "free"), large Opus-4.7 (1M-context) calls
via `claude --print` are **pathologically slow on the subscription** —
multi-minute time-to-first-token, with intermittent fast-fails — so the
gap stage (one ~47K-token batched call per group of KSIs) couldn't
finish under the client timeout. Sonnet 4.6 is validated
"indistinguishable from Opus on the 60-KSI sweep," returns in seconds,
and is still $0 here. If you specifically want Opus despite the latency,
pass `--llm-model claude-opus-4-7` (and consider raising
`EFTERLEV_LLM_TIMEOUT`); for the fastest path, `--llm-model
claude-haiku-4-5`.

Efterlev strips `ANTHROPIC_API_KEY` from the subprocess environment
automatically so my parent-shell key doesn't override the subscription
session.

## Step 2d — OpenAI API path

The "no Claude access at all" path. Validated v0.1.213 on one fixture
(csp-starter-cfn). **Recommended model: `gpt-5.4-mini`** — cheapest of
the validated set, matches the Anthropic Haiku baseline on recall. See
LIMITATIONS.md "OpenAI backend" for the per-model results table.

1. Confirm I have an OpenAI API key. Verify:
       echo "${OPENAI_API_KEY:0:10}"
   Must start with `sk-` (OpenAI-format). If it starts with `sk-ant-`,
   that's an Anthropic key — stop and ask me to set `OPENAI_API_KEY`
   to an actual OpenAI key. If empty, point me at
   https://platform.openai.com/api-keys.
2. Confirm the key's project has gpt-5.4-mini enabled. **OpenAI scopes
   model access per-project**, and the dashboard view sometimes shows
   models that the specific key's project doesn't actually have access
   to. The fastest verification:
       OPENAI_API_KEY="$OPENAI_API_KEY" \
         python3 -c "from openai import OpenAI; print(sorted(m.id for m in OpenAI().models.list() if m.id.startswith('gpt-5')))"
   If `gpt-5.4-mini` isn't in the output, ask me to either (a) regenerate
   the key from a project that has it enabled, or (b) enable gpt-5.4-mini
   access on the current project (Settings → Limits → Models). If neither
   option is workable, fall back to `gpt-5` (also validated v0.1.213 at
   100% precision / 95.8% recall) and recommend it.
3. Install or upgrade Efterlev (Step 2e). The OpenAI backend needs the
   `[openai]` extra: `pipx install 'efterlev[openai]'` or
   `uv tool install --reinstall 'efterlev[openai]'`.

**Configuration**: pass `--llm-backend=openai --llm-model=gpt-5.4-mini`
to `efterlev init` in Step 3 (`gpt-5` if gpt-5.4-mini isn't accessible).
**Do NOT recommend `gpt-5.4` (regular)**: validated v0.1.213 to reliably
fabricate citations on at least one fixture KSI; the hallucination guard
catches it (no fabricated artifact reaches a 3PAO surface) but the run
fails after 6 retry attempts.

Then jump to Step 3.

## Step 2e — install Efterlev

**Pick the path that matches your installer.** pipx and uv tool manage
isolated venvs at different paths; using the wrong installer's commands
silently fails to find the package. `efterlev doctor` detects which
installer was used and gives the right hint when boto3 is missing, but
you can pre-empt the round-trip.

- **pipx users:**
  - First-time (Anthropic / Claude Code backend):
        pipx install efterlev
  - First-time (Bedrock backend — extras need quotes):
        pipx install 'efterlev[bedrock]'
  - First-time (OpenAI backend — extras need quotes):
        pipx install 'efterlev[openai]'
    If pipx itself is missing: `brew install pipx` first. **macOS
    gotcha**: a fresh `brew install` puts pipx at `/opt/homebrew/bin/`,
    which isn't on the default PATH for new shells. Either run
    `pipx ensurepath` and restart the shell, or for the current
    session: `export PATH="/opt/homebrew/bin:$PATH"`. If `efterlev`
    doesn't resolve after `pipx install efterlev`, this is why.
  - Upgrade: `pipx upgrade efterlev` (drop the `[bedrock]`/`[openai]`
    bracket — extras are install-time only). If switching from a
    non-Bedrock install to Bedrock, also run:
        pipx inject efterlev boto3
    Verify: `pipx runpip efterlev show boto3`. Same shape for openai:
        pipx inject efterlev openai
    Verify: `pipx runpip efterlev show openai`.

- **uv tool users** (e.g. `uv tool install efterlev` previously):
  - Install or re-install (with extra if Bedrock / OpenAI):
        uv tool install --reinstall 'efterlev[bedrock]'   # Bedrock
        uv tool install --reinstall 'efterlev[openai]'    # OpenAI
        uv tool install --reinstall efterlev              # Anthropic / Claude Code

- Confirm `efterlev --version` matches the latest published release.
  Check the latest with whichever of these is on PATH:
  `pip index versions efterlev`, `pip3 index versions efterlev`, or
  `uv pip index versions efterlev`. If older, clean-reinstall.

## Step 2f — orient on your boundary

Before kicking off the pipeline, surface the **candidate** in-boundary
dependencies in my IaC. This answers the literal first question every
first-time FedRAMP 20x customer asks ("what's my scope?") that
`boundary set` (declaration) assumes I already know.

    efterlev boundary discover --target .

Deterministic, no LLM, no network, no writes. It walks Terraform for:
non-AWS provider integrations (Datadog, Auth0, Okta, …), cross-account
references (multi-account `assume_role`/`alias`; distinct account IDs in
ARNs), remote/external state (`terraform { backend }` +
`data.terraform_remote_state`), hardcoded third-party SaaS endpoints, and
external data sources (`data.http` / `data.external`). Each signal carries
`file:line` citations.

Read the output aloud and explain why each category matters for an
authorization boundary. **Do not declare scope on my behalf** — this is
reconnaissance, not a decision. If I want to declare scope now, suggest
`efterlev boundary set --include 'infra/**' --include '.github/workflows/**'`
(or analogous patterns based on what `discover` surfaced). Most users
defer this until after the first `report run` shows actual findings; that's
fine — `boundary set` is non-destructive and re-runnable.

## Step 3 — run the pipeline (one command)

You're at the repo root from Step 0. Run the full pipeline as a single
command. This chains init → scan → inventory → agent gap → agent
document → poam → vdr → oscal poam → oscal component-definition with
per-stage wall-clock and an end-of-run timing summary. Two new
artifacts since the prior prompt revision: `inventory` (RFC-0017
consolidated resource inventory; deterministic + free) and `vdr`
(RFC-0012-shaped Vulnerability Detection & Response report;
deterministic + free).

### Open Studio first (live visual progress)

Before kicking off the pipeline, open Efterlev Studio in **attach mode**
so I can watch the run live in a browser — one window with the readiness
ring, the **WHAT TO DO NEXT** worklist, and the **REPORTS** panel
materializing as the pipeline runs:

  1. Pick a unique event-log path and **export** the env var so the
     `report run` subprocess inherits it:

         export EFTERLEV_STUDIO_EVENT_LOG="$(mktemp -t efterlev-events.XXXXXX.jsonl)"

  2. Launch Studio in the background in attach mode (it tails that log;
     it does NOT spawn its own pipeline — that would double-spend on LLMs):

         efterlev studio --watch "$EFTERLEV_STUDIO_EVENT_LOG" \
                         --target . --no-open --port 0 &
         STUDIO_PID=$!

  3. Capture the URL Studio prints on its first line of stdout and tell
     me. Phrase like: *"Watch live in your browser: <URL>. Studio is
     attached to the pipeline I'm about to run."*

  4. Now proceed with `efterlev report run` below — events stream to the
     log Studio is watching; the page renders progress in real time and
     surfaces the worklist + reports panel when the run completes.

If launching Studio fails (no PATH, restricted shell, etc.), skip it and
proceed — the pipeline runs normally; you just lose the live visual.
Don't block the run on Studio.

**When you reference the Studio PID** in a message to me — "kill it with…",
"running at PID …" — show the **literal integer** (read `$STUDIO_PID` or the
pidfile and substitute its value into prose). Do NOT embed shell-substitution
syntax like `$(cat /tmp/efterlev-studio-pid)` in user-facing text; prose isn't
a shell and the `$(…)` stays literal, leaving me with garbage to copy.

**Set expectations with me BEFORE kicking it off.** On a real-shape
repo (~100+ resources, 60 KSIs to classify), `report run` typically
takes 10-25 minutes — the gap stage alone is 60 sequential LLM calls.
Tell me the projected duration up front so I don't sit wondering if
it hung. Example phrasing:

  > "Heads up: this is a fresh run on a 60-KSI baseline. Expect
  >  10-25 min total — the gap stage (60 LLM calls) is the longest
  >  stretch, typically 5-15 min. Documentation is ~5-15 min more.
  >  POA&M and OSCAL stages are deterministic and finish in seconds.
  >  Re-runs on the same workspace replay from cache in seconds
  >  total. Kicking off now."

The `efterlev report run` command itself also prints this upfront
("Expected wall-clock: ~10-25 min on first run; cache replays are
near-instant") so the timing context is visible whether or not you
relayed it.

**Claude Code subscription is FREE but SLOWER than API/Bedrock.** The
10-25 min estimate is for the Anthropic API / Bedrock paths. On the
`claude_code` subscription, each `claude --print` call carries several
seconds of CLI/OAuth overhead, so a fresh 60-KSI run is more like
**~35-45 min** (observed: 41 min on a ~140-resource repo — gap ~24 min,
documentation ~17 min). It still completes and bills $0; just set the
expectation higher. If speed matters more than the small accuracy edge,
`--llm-model claude-haiku-4-5` is roughly 2x faster on the subscription.

**If stdout is buffered** (common when Claude Code or other CLIs
background the long-running process), the per-stage progress doesn't
appear in real time. Peek at `.efterlev/receipts.log` and
`ls -t efterlev-out/reports/` periodically to surface which stage is in
flight. Don't silently sit through 15 minutes of "nothing happening"
— check artifacts every ~2 min and report progress to me.

**Watch out for exit-code masking.** If you wrap `report run` in a
pipe (`… | tee log.txt`) or a background shell, the wrapper's exit
code — not Efterlev's — is what you'll see, so a failed pipeline can
look like it "exited 0." Don't trust the wrapper's status: read the
actual output. `report run` prints `error: pipeline stopped — <stage>
exited with code N` on failure and only prints the end-of-run timing
summary on full success. If you don't see that timing summary, the run
did NOT fully succeed — find the failing stage's error before
proceeding.

  - Anthropic API backend:
        efterlev init --target . --force --llm-backend=anthropic
        efterlev report run --target .

  - Claude Code subscription backend (v0.1.158+, no manual config edit):
        efterlev init --target . --force --llm-backend=claude_code
        efterlev report run --target .

  - Bedrock backend (pass the ARN you captured in Step 2b.2):
        efterlev init --target . --force \
          --llm-backend=bedrock --llm-region=<region> --llm-model=<MODEL_ARN>
        efterlev report run --target .

  - OpenAI backend (v0.1.213+; use gpt-5.4-mini recommended, gpt-5 fallback):
        efterlev init --target . --force \
          --llm-backend=openai --llm-model=gpt-5.4-mini
        efterlev report run --target .

The `--force` on init preserves customer-authored `.efterlev/manifests/`
(the only sticky state worth keeping) and regenerates the FRMR cache,
provenance store, and `config.toml`. Skip `--force` only if I tell you
I have an in-progress workspace with hand-edited `config.toml` I want
to preserve.

If the pipeline fails partway, the failing stage's error message is
your only signal (the end-of-run timing summary only prints on full
success). Read the stderr text and decide:

  - **`ANTHROPIC_API_KEY is not set` / 401 / credentials error**:
    stop and fix the backend setup before re-running.
  - **Bedrock model-access denied**: go back to Step 2b.1.
  - **OpenAI 403/404 `model_not_found`**: the API key's project doesn't
    have the chosen model enabled. Re-run the model-list check from
    Step 2d step 2 and either pick a model that IS in the list or fix
    the project's model access.
  - **OpenAI gap-stage validator-rejection loop** (`KSI-* requires at
    least one evidence_id citation` repeated 3+ times): the OpenAI
    model is fabricating citations the hallucination guard rejects.
    If `--llm-model=gpt-5.4`, switch to `gpt-5.4-mini` or `gpt-5` —
    gpt-5.4 regular is documented as unusable on this prompt without
    tuning (v0.1.213 LIMITATIONS).
  - **Anything else**: stop and ask me — don't paper over.

To resume after a fix, just re-run `efterlev report run` — scan
replays cached evidence (write-time dedupe, v0.1.155+) and any agent
stage that completed before the failure replays from the LLM cache
(v0.1.151+) so re-runs are cheap. Stages downstream of the failure
will run for real on the retry.

**Soft cost cap (you're responsible for this — no CLI enforcement
today):** before each agent stage on a fresh run, the cap is your
implicit budget. After each stage completes you can `tail -20
.efterlev/receipts.log` to see per-call $ — sum the most recent run's
calls and stop if you're approaching the cap.

### Scan-mode note

`efterlev scan` (which `report run` invokes) defaults to HCL mode for
`.tf` source. If I have `terraform` on PATH and want full module
coverage, run plan-JSON mode through the one-command pipeline using
the v0.1.158 `--scan-plan` flag:

    efterlev init --target . --force --llm-backend=anthropic   # or claude_code / bedrock
    terraform init                                              # or -backend=false
    terraform plan -out plan.bin                                # or -refresh=false
    terraform show -json plan.bin > plan.json
    efterlev report run --target . --scan-plan plan.json

Plan-JSON gives full module coverage; HCL keeps file:line citations
(which plan-JSON loses). If `terraform init` fails on a missing backend
(common when scanning a repo you don't operate), try
`terraform init -backend=false && terraform plan -refresh=false -out plan.bin`.
If both fail, drop to HCL mode (just omit `--scan-plan`) — don't burn
5 minutes on the terraform dance.

## Step 4 — brief me on the results

After `report run` completes, read the NEWEST gap-report JSON by
filesystem mtime. Filenames are timestamped
(`gap-YYYYMMDD-HHMMSS.json`), so:

    # v0.1.160+ artifacts land under efterlev-out/reports/. Use `find`, not a
    # multi-path glob: in zsh a glob that matches nothing is a hard error
    # (`no matches found`) BEFORE `2>/dev/null` can suppress it, so
    # `ls efterlev-out/reports/gap-*.json .efterlev/reports/gap-*.json` aborts
    # whenever the legacy `.efterlev/reports/` dir is absent (the common case).
    # `find` is glob-error-free across shells:
    find efterlev-out/reports .efterlev/reports -maxdepth 1 -name 'gap-*.json' \
      2>/dev/null | sort | tail -1

Open that file and tell me:

  - The classification breakdown — count of `implemented` / `partial`
    / `not_implemented` / `not_applicable` / `evidence_layer_inapplicable`.
    **Lead with the evidence-found rollup so the raw counts don't read as a
    scary "0 implemented":** report *"N of 60 KSIs have evidence the agent
    corroborated"* where N = implemented + partial + evidence_layer_inapplicable
    + not_applicable. Then the per-status table. Then this one-liner explainer:
    *"`implemented` is the high bar — full end-to-end outcome coverage; scanner
    evidence alone is usually classified `partial` (the agent is conservative by
    design; a 3PAO corroborates partials in review)."* This is honest framing,
    not spin — it stops a first-time viewer from panicking at "0 implemented"
    when they actually have evidence flowing on 40+ KSIs.
  - Workspace boundary state (`workspace_boundary_state` field) — if
    `boundary_undeclared`, recommend running
    `efterlev boundary set --include 'pattern' --exclude 'pattern'`
    so the POA&M filter has scope to enforce. Important: if I declare
    `--include 'infra/terraform/**'`, ALL workflow evidence
    (`.github/workflows/*.yml`) becomes `out_of_boundary` because
    workflows aren't under `infra/terraform/`. To keep workflow
    findings in scope, pass two patterns:
    `--include 'infra/terraform/**' --include '.github/workflows/**'`.
  - **Top next steps**: run `efterlev next` — it produces the impact-ranked
    worklist deterministically (no LLM call), with the exact `$ command`
    per item. Surface its headline plus the top 5 items verbatim — each
    item already carries impact + effort tags + the command to run. No
    need to hand-pick from the gap JSON; `next` does it and re-ranks every
    run as I close items.
  - Any KSI classified `partial` — these are the texture cases where
    `efterlev agent remediate --ksi <id>` produces the most useful diff
    (mid-journey, not zero-to-one). Surface 2 of them as a complement to
    the `next` worklist (which leads with the highest-impact `not_implemented`
    gaps).

Surface the documentation-agent breakdown too:
`agent_drafted` vs `deterministic_template` counts. The
`deterministic_template` rows are inapplicable KSIs that skipped the
LLM (the cost-saving path; ~70% of Sonnet spend would have been wasted
on procedural-only KSIs without it).

## Step 5 — readiness scorecard + 3PAO submission package

Run `efterlev readiness` — single-page heuristic scorecard (0–100%) with
progress bar, top-3 blockers, and suggested next commands. Deterministic;
zero LLM cost.

**Close the procedural wall.** Run `efterlev manifests status` — it shows
which of the procedural KSIs (AFR / CED / INR themes; ~17 in
fedramp-20x-moderate) have a substantive Evidence Manifest, which are
still thin (TODO placeholders), and which are missing. For missing ones,
run `efterlev manifests scaffold` once to lay down fillable stubs for the
whole set (one per KSI under `.efterlev/manifests/<ksi>.yml`); the customer
fills in the attester, statement, review cadence, and supporting docs in
each (the bundled starter-pack questions are inline as comments), then
re-runs `manifests status` until it's all `ready`. Substantiveness is
structural — named attester + review cadence + supporting docs — it never
validates the *correctness* of the claim, which the customer owns.

Open the consolidated resource inventory in the browser:
`efterlev-out/reports/inventory/inventory-<ts>.html`. This is the
RFC-0017-shaped "what's in scope" artifact — one row per resource
with KSI coverage, source file:line, and boundary state. Useful for
a 3PAO scoping conversation; print/screenshot directly.

Also surface the VDR (Vulnerability Detection & Response) artifact
at `efterlev-out/reports/vdr/vdr-<ts>.md`. This is the RFC-0012-shaped
artifact that 20x is moving toward as the POA&M replacement; it
ships AHEAD of RFC-0012 finalization (schema versioned via
`vdr_schema_version` in the JSON twin so consumers detect breaking
changes when the RFC standardizes). For now, POA&M remains the
program-current artifact; both ship side by side.

If I'm preparing to engage a 3PAO, also run `efterlev submission package`
— bundles every artifact (FRMR attestation, POA&M, VDR JSON+markdown,
consolidated resource inventory JSON+HTML, OSCAL POA&M+CD, HTML
reports, manifests) into one zip with README + machine-readable
index.json + SHA-256 per artifact. Deterministic; zero LLM cost.

**Visual companion.** The Studio window I opened in Step 3 is now showing
the final command center — readiness ring, the **WHAT TO DO NEXT**
worklist (the same `efterlev next` data, surfaced visually), and a
**REPORTS** panel that opens every artifact one click away (Gap Report,
3PAO inspector, POA&M, OSCAL, submission zip). For *future* re-runs,
either re-launch attach mode the same way (Step 3) so the new run
streams live, or run `efterlev studio` standalone on the scanned
workspace to browse the latest posture (no events; just the dashboard).

## Constraints

- Don't run `efterlev agent remediate` without me asking — it generates
  code-level diffs and I want to be in the loop.
- Don't modify my Terraform. Don't commit anything.
- Soft cost cap: $5 on the Anthropic path, $8 on the Bedrock path
  (Bedrock retries can burn more on first-run config issues), $0 on
  Claude Code subscription. Stop and check back before exceeding.
- If anything fails or surprises you, stop and ask — don't paper over.
- If a re-run goes back to ~50s per gap batch instead of ~0.1s, the
  cache isn't hitting — flag this; don't silently accept the long run.

## When done

Brief me with:
- Counts of `implemented` / `partial` / `not_implemented` /
  `not_applicable` / `evidence_layer_inapplicable` KSIs.
- Readiness score + top 3 blockers from `efterlev readiness`.
- The **`efterlev next` headline + top 5 items** (with the exact `$ command`
  per item) — this is what I actually do next, in order.
- **Procedural-manifest status** (`efterlev manifests status`) — counts of
  ready / thin / missing so I see the procedural wall at a glance.
- Paths to: HTML gap report, consolidated resource inventory (HTML),
  FRMR attestation JSON, POA&M markdown, VDR JSON + markdown
  (RFC-0012-shaped), OSCAL POA&M JSON, OSCAL Component-Definition JSON,
  and the submission package zip if I asked for one.
- The per-stage timing summary from `report run` so I can see where
  wall-clock went.
- Anything notable: secrets caught by the redaction layer, KSIs flagged
  for review, modules where evidence was sparse.