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,claudeCLI 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 boundary —
efterlev boundary discoversurfaces 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.