@akasecurity/ai-tc-claude-code 0.8.1 → 0.9.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/commands/setup.md CHANGED
@@ -1,114 +1,692 @@
1
1
  ---
2
- description: Set up the AKA Control Plane plugin redaction handling and historical access
2
+ description: Set up AKA Securitycalibrate notifications and detection posture from Claude's real activity.
3
3
  ---
4
4
 
5
5
  # AKA setup wizard
6
6
 
7
- You are onboarding the AKA Control Plane plugin for this machine. AKA works
7
+ You are onboarding the AKA Security plugin for this machine. AKA works
8
8
  fully locally with **zero backend and zero Docker**: detection runs in-process
9
- and findings persist to a local SQLite store at `~/.aka/data/aka.db`. This
10
- wizard records two preferences. Ask the questions in order, then save once.
9
+ and findings persist to a local SQLite store at `~/.aka/data/aka.db`.
10
+
11
+ This wizard tells a **calibration story**: introduce AKA → show what it does →
12
+ offer one retroactive scan → report the real numbers it found and the posture it
13
+ recommends → apply on confirmation → show the installed summary → hand off to the
14
+ dashboard. Everything the user sees is derived from their _actual_ history — never
15
+ a fabricated or demo number. When there isn't enough history to judge, the wizard
16
+ falls back to a conservative severity-derived floor instead of guessing.
17
+
18
+ The false-positive/severity judgment itself runs in a **separate, transient
19
+ subprocess that writes no transcript** — the raw (unmasked) finding values are
20
+ never read into this conversation or your scannable history. You act only on the
21
+ raw-free plan that subprocess prints back.
22
+
23
+ Follow the steps below **in order**. Nothing is written to the policy store
24
+ until step 5 (or a floor fallback in step 3 if the calibration can't complete).
25
+
26
+ ## Execution contract (read before step 0)
27
+
28
+ Every script prints output in three region kinds. Your job for each is fixed:
29
+
30
+ - **`<<<AKA_SHOW … AKA_SHOW>>>`** — relay every AKA_SHOW region verbatim as your
31
+ next message: paste the content _between_ the markers exactly — a card region
32
+ carries its own code fence, a plain confirmation line does not, but either way
33
+ you paste exactly what's between the markers — never the marker lines, never a
34
+ paraphrase or summary.
35
+ - **`<<<AKA_FRAME_JSON … AKA_FRAME_JSON>>>`** — machine-only. Parse it if a step
36
+ tells you to read a value from it; never display it.
37
+ - **Anything else on stdout** — status for you (paths like `Plan saved to:`,
38
+ errors, exit signals). Act on it; never relay it.
39
+
40
+ Invariants:
41
+
42
+ - **Never write a confirmation or acknowledgement the wizard did not emit** — the
43
+ script's AKA_SHOW line is the confirmation.
44
+ - **Each step's AKA_SHOW regions must be relayed before you advance.**
45
+ - **One picker per decision; never re-ask a decision already collected.**
11
46
 
12
47
  ## 0. Show the intro card
13
48
 
14
- Run the intro script and show the user its output **exactly as printed** it is a
15
- space-aligned monospace card (name, repository, version, what AKA adds). The script
16
- already prints it inside a Markdown code fence; reproduce that verbatim and do
17
- **not** add another code fence, strip the fence, or reformat it (unfenced, Markdown
18
- collapses the indentation and mangles the `●` line). Then continue with the two
19
- questions below.
49
+ Run the intro script and relay its AKA_SHOW region per the execution contract:
50
+ paste the content between the markers verbatim, never the marker lines. It
51
+ prints a single space-aligned monospace card identity and provenance, then
52
+ what AKA does inside a Markdown code fence that is part of that pasted
53
+ content. Keep the fence as printed and do **not** add another code fence, strip
54
+ the fence, or reformat it (unfenced, Markdown collapses the indentation and
55
+ mangles the `●` lines).
20
56
 
21
57
  ```bash
22
58
  node "${CLAUDE_PLUGIN_ROOT}/scripts/intro.js" "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json"
23
59
  ```
24
60
 
25
- ## 1. Ask the two questions
26
-
27
- Use the **AskUserQuestion** toolClaude Code's built-in interactive picker — to
28
- ask both questions. The plugin can't draw its own selectable UI (it can't
61
+ ## 0b. Repo-aware posture check — tighten-only, working-tree only
62
+
63
+ Before showing any recommended posture the start-light default table in
64
+ step 2 or the calibrated posture in step 4 look at the **current project's**
65
+ working tree yourself, with your own Read/Glob tools. There is no script for
66
+ this: it is your own reasoning over facts you read directly, not the isolated
67
+ triage subprocess's raw-free plan, and it needs no user interaction.
68
+
69
+ **In scope:** the manifest's declared frameworks/dependencies
70
+ (`package.json` or equivalent), payment or other third-party API SDKs among
71
+ them, CI config (`.github/workflows/`, etc.), and the **presence and names**
72
+ of `.env*`/config files as a signal that secrets live on disk here — never
73
+ their contents; a secret-bearing file's contents are exactly the kind of raw
74
+ value this wizard never reads. **Out of scope:** Claude's own history and the
75
+ local AKA store (that is the separate, consent-gated scan in steps 1/3) — no
76
+ historical read, and no AskUserQuestion or other consent interaction of any
77
+ kind.
78
+
79
+ The severity-floor default map (secret/pii/financial/phi/code_flaw/custom at
80
+ `warn`, code_context/config at `monitor` — the table step 2's start-light card
81
+ prints) is both the **floor** this check is measured against and its
82
+ **fallback**. From what you directly observe you may **tighten** individual
83
+ categories above that floor — raise the level, never lower one below it —
84
+ each tightened category carrying a one-line rationale naming the concrete
85
+ evidence you found, e.g.:
86
+
87
+ > Stripe + a `Customer` model here — financial → redact
88
+
89
+ Present the tightening on whichever recommended posture is about to render, the
90
+ same "recommended base + changed-packs overlay" shape step 4b's adjust fork
91
+ uses: the tightened categories raise, every other category keeps its existing
92
+ recommended level, each carrying its rationale line. Where you compose the view
93
+ yourself (the adjust fork, the calibrated result) this tightened recommendation
94
+ IS that view; where the view is a script's AKA_SHOW card (the step-2
95
+ start-light card, relayed per the execution contract), show the tightened
96
+ recommendation and its rationale lines adjacent to that card rather than
97
+ rewriting the card's own printed levels.
98
+
99
+ This tightening is a **display-time recommendation**: it shapes the recommended
100
+ posture the user reads, not a separate write. Persisting a tightened level happens
101
+ only where the wizard already writes a per-category override — the adjust fork's
102
+ `onboard.js --posture` write (step 4b), where the user picks each category's level
103
+ explicitly. The keep-defaults path writes the severity floor (`--floor`, step 2)
104
+ and the calibrated accept path applies the isolated subprocess's saved plan
105
+ verbatim (`--confirmed --plan`, step 5); neither carries the tightening on its
106
+ own, so a tightened level the user wants persisted is chosen through the adjust
107
+ fork. Do **not** bolt on an extra `onboard.js --posture` overlay to auto-re-persist
108
+ the tightening across the other paths: it would overwrite — and so could silently
109
+ **downgrade** — a category the user had hardened out of band (a tightening is only
110
+ guaranteed to raise above the severity floor, not above the user's stored level),
111
+ with no downgrade-approval gate. So the tightening is not auto-persisted across
112
+ those paths — a tightened level the user wants kept is set through the adjust fork.
113
+
114
+ **When nothing in the working tree is inferable, change nothing.** Render the
115
+ recommended posture exactly as the static frame already gives it — no rationale
116
+ line and no tightened category (fail-open).
117
+
118
+ ## 1. Offer the retroactive scan
119
+
120
+ Ask this **before** anything about detection posture — the posture
121
+ recommendation in step 4 is _derived from_ the answer to this question, so it
122
+ has to come first. Use the **AskUserQuestion** tool — Claude Code's built-in
123
+ interactive picker. The plugin can't draw its own selectable UI (it can't
29
124
  capture keystrokes), so do **not** print a fake option list or ask the user to
30
- "reply with a number"; let the picker collect the answers.
125
+ "reply with a number"; let the picker collect the answer.
126
+
127
+ **Want me to look over what Claude's been up to?** — "I'll review Claude's recent work — transcripts, temp files, agent memory — to tune what I bring to you next."
128
+
129
+ Offer exactly two options:
130
+
131
+ - **Yes, take a look** — "tune what I bring you, based on Claude's real work here"
132
+ - **Not now** — "start light and I'll learn as we go"
133
+
134
+ Choosing **Yes, take a look** records the same historical-review consent the wizard has
135
+ always recorded — the identical scope, the one-time grant, and the
136
+ revocable-under-Policies semantics — so the simpler question broadens nothing
137
+ about what AKA may access. Those granular scope and revocation details stay
138
+ inspectable on request and in the dashboard.
139
+
140
+ ## 2. Save the answer, then branch
141
+
142
+ Branch on the answer from step 1. On the **Yes, take a look** path the onboarding
143
+ writer runs, and it must run **before** the backfill (step 3), because the
144
+ backfill script reads `historicalAccess` from the saved settings to decide
145
+ whether it's allowed to run. Omitting `--policy` is deliberate — the old global
146
+ redact/warn toggle no longer drives enforcement (posture is per-category now);
147
+ its field is kept for backward compatibility but this wizard doesn't ask about
148
+ it.
149
+
150
+ **Branch on the choice:**
151
+
152
+ - **If the user chose "Yes, take a look"** — record the historical-review consent and
153
+ continue to step 3 (which runs the scan and leads to the calibrated result in
154
+ step 4). "Yes, take a look" maps to the existing full historical-review path — no
155
+ access is granted beyond what that path already granted:
156
+
157
+ ```bash
158
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --historical full
159
+ ```
160
+
161
+ - **If the user chose "Not now"** — take the **start-light** path.
162
+ This path takes **zero historical access**: do **not** read any history, do
163
+ **not** run the backfill, and do **not** record consent — nothing about the
164
+ machine's past is touched.
165
+ Instead present the start-light posture card, write the posture the user picks
166
+ (this write **is** the applying frame — it stands in for step 5, which never
167
+ runs here because there is no scan plan to apply), and rejoin the spine at the
168
+ installed summary (step 6). **Skip steps 3, 4, and 5 entirely** — there is no
169
+ scan to triage, no calibrated result to confirm, and no suppression plan to
170
+ write. Do the following in order:
171
+
172
+ 1. **Show the start-light card.** Run the start-light script and relay its
173
+ AKA_SHOW card per the execution contract — the
174
+ `● Starting light — your detection categories` heading, the full 8-pack ×
175
+ 4-level default posture table, the per-pack rationale, and the re-tune
176
+ hint, pasted between the markers exactly as printed, fence included. It
177
+ reads no history and writes nothing; it only prints the card
178
+ (the severity-floor default map — secret, pii, financial, phi, code_flaw, custom at
179
+ `warn`; code_context, config at `monitor`).
180
+
181
+ ```bash
182
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/start-light.js"
183
+ ```
184
+
185
+ 2. **Confirm or adjust.** Use **AskUserQuestion** — Claude Code's built-in
186
+ picker — to let the user keep the recommended defaults or tune individual
187
+ packs. The plugin can't draw its own selectable UI, so do **not** print a
188
+ fake option list or ask the user to "reply with a number"; let the picker
189
+ collect the answer.
190
+
191
+ **Set your detection categories** — "Keep the defaults I'd recommend, or adjust any of them?"
192
+
193
+ - **Keep defaults** _(recommended)_ — "the careful defaults shown above"
194
+ - **Adjust** — "change one or more levels, keep the rest as I recommend"
195
+
196
+ If they choose **Adjust**, use AskUserQuestion again to collect the new
197
+ level (monitor/warn/redact/block) for each pack they want to change, then
198
+ merge those overrides over the severity-floor defaults to form the full 8-pack map.
199
+
200
+ 3. **Write the chosen posture.** The default map is the severity floor,
201
+ so when the user keeps the defaults, write the floor directly; when they
202
+ adjusted packs, write the merged 8-pack map:
203
+
204
+ ```bash
205
+ # Kept the recommended defaults
206
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --floor
207
+
208
+ # Adjusted one or more packs — <json> is the merged 8-pack map
209
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --posture '<json>'
210
+ ```
211
+
212
+ Either write prints only `✓ Set all K detection categories` (the `--floor`
213
+ write appends ` — safe defaults`) — which is the honest confirmation here,
214
+ because nothing was scanned or suppressed. Show that line to the user; do
215
+ **not** invent a dismissed count or any calibration counts.
216
+
217
+ 4. **Rejoin the spine at the installed summary (step 6).** Continue to step 6
218
+ to show the installed summary and hand off to the dashboard, using honest
219
+ no-scan copy. No scan ran, so there is **no surfaced count** — call
220
+ `firstrun.js` with **no `--surfaced` flag** (the same floor-fallback rule
221
+ step 6 already follows when no calibration frame was emitted). Step 7
222
+ then runs as written.
223
+
224
+ ## 3. Run the evidence triage — isolated judgment, nothing written yet
225
+
226
+ Pipe the backfill's triage stream straight into the `apply-suppressions`
227
+ adapter in **PREVIEW** mode (no `--confirmed`):
228
+
229
+ ```bash
230
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js" --triage | node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js"
231
+ ```
31
232
 
32
- Ask these two questions (a single AskUserQuestion call with both is fine):
233
+ The backfill sweeps prior Claude Code transcripts (last 30 days, all projects)
234
+ and streams one masked-plus-raw triage hit per line; masked findings are
235
+ recorded to the local store as a side effect. The adapter runs the
236
+ false-positive/severity **judgment in a separate transient subprocess** (no
237
+ transcript), then prints back a **raw-free plan** you can safely show the user:
238
+ the calibrated-result card (the real-count headline and the recommended posture),
239
+ the per-category reasoning, the masked false positives it would suppress, any
240
+ categories it skipped, and its notes.
241
+
242
+ The preview also **persists that exact raw-free plan to a temp file and prints
243
+ its path** — a line beginning `Plan saved to: <path>`. Capture that path: step 5
244
+ applies **this saved plan verbatim**, so the confirm step performs no second scan
245
+ and no second judgment. (The plan file carries only masked/fingerprint/enum data;
246
+ it is deleted after a successful apply.)
247
+
248
+ Alongside the human copy, the preview also emits a **machine-readable calibration
249
+ frame** — a single JSON block delimited by `<<<AKA_FRAME_JSON` … `AKA_FRAME_JSON>>>`
250
+ carrying the raw-free calibration counts and categories, plus (when the scan
251
+ surfaced any) a `maskedFindings` array of raw-free secret-leak summaries. Do
252
+ **not** show this block to the user (it is additive to the human copy above).
253
+ Capture its `counts.important` value — the **surfaced count** — and pass it to the
254
+ first-run summary in step 6 as `--surfaced <count>` — but **only when the preview
255
+ also printed a `Plan saved to:` path** (a real calibrated plan to confirm in step
256
+ 4). The `Plan saved to:` line is the completion signal: a preview that omits it did
257
+ not calibrate a plan you can confirm. The fallback branches below carry no
258
+ surfaced count; the scan-ran-clean empty state (a scan that completed but
259
+ surfaced nothing) emits a zero-count frame but **no plan path**, so it too routes
260
+ to the floor branch below rather than step 4.
261
+
262
+ Also **retain the block's full text verbatim** (not just the counts you read out
263
+ of it) — step 6's "Review leaked keys" branch feeds this same text to the
264
+ secret-leak remediation entry, which reads its own `maskedFindings` from it,
265
+ and step 4's finding narration and step 6's secret-leak narration (both below)
266
+ read the same `maskedFindings` array off it too. When present, the block's
267
+ `falsePositivePatterns` array is what step 4's fixture/exception offer (below)
268
+ names its pattern and count from — never invent either off-signal.
269
+
270
+ Everything you show the user in step 4 comes from **this command's output**. You
271
+ never read the raw finding values yourself — do not echo, quote, or reconstruct
272
+ them; by design they stay inside the isolated subprocess.
273
+
274
+ **Failed or truncated triage — never proceed silently (fallback).** If this
275
+ command exits non-zero, or the adapter reports a truncated / sentinel-less
276
+ stream, the calibration could **not** complete. Do not guess a posture and do
277
+ not leave setup half-applied. Apply the conservative severity floor, **tell the
278
+ user it happened**, and continue to step 6:
33
279
 
34
- **Sensitive-data handling** — "When AKA detects sensitive data on its way to a model, it should:"
280
+ ```bash
281
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --floor
282
+ ```
35
283
 
36
- - **Actively redact** `redact` _(recommended)_ replace secrets with safe
37
- placeholders before the request is sent.
38
- - **Warn only** → `warn` flag the request and let the user decide; nothing is
39
- modified automatically. (Either mode can be changed per-project later.)
284
+ Say plainly: the historical scan couldn't finish, so AKA is starting from the
285
+ conservative severity floor (high-impact categories at `warn`, observe-only at
286
+ `monitor`) instead of a calibrated posture, and it can be re-run any time with
287
+ `/aka:setup`.
288
+
289
+ **Nothing to calibrate.** A scan that **completes but surfaces nothing** prints
290
+ the honest **scan-ran-clean** card — `I looked over Claude's recent work —
291
+ nothing needs your attention right now. You're starting clean; here's what I'd
292
+ recommend:` over the recommended posture — with a zero-count calibration frame
293
+ (its `counts.important` is `0`) and **no `Plan saved to:` path**. An empty or
294
+ intentionally-skipped scan instead prints `I didn't find anything to review —
295
+ nothing to tune.`. In either case there's no evidence to calibrate from and no
296
+ plan to confirm: show the card the adapter printed, take the floor branch
297
+ (`onboard.js --floor`), tell the user the scan found nothing to calibrate from, and
298
+ skip to step 6 (with **no `--surfaced`**, the floor-fallback rule there — nothing
299
+ was surfaced to carry over). Do **not** continue to step 4.
300
+
301
+ Otherwise (the preview printed a `Plan saved to:` path) continue to step 4.
302
+
303
+ ## 4. Show the calibrated result and get explicit confirmation — before any write
304
+
305
+ The preview output is raw-free. Lead with the **calibrated-result card** it
306
+ printed and show it in full:
307
+
308
+ 1. **The calibrated headline.** The `I went through Claude's recent work — N
309
+ detections, M results worth a look.` line — every count templated over the
310
+ real scan (surfaced findings are the `M results` worth a look; the rest are
311
+ routine noise a plain scanner would have screamed about). Show it verbatim;
312
+ never substitute a demo number.
313
+ 2. **The recommended posture.** The condensed one-row-per-pack recommended view
314
+ the card printed — the level AKA would set for each category. Show it in full.
315
+ - **Surface the downgrades the preview flags — this is not optional.** For the
316
+ recommended posture it is about to write, the preview compares each category
317
+ against its stored setting and flags any that would be **LOWERED** from a
318
+ stronger existing one (e.g. an existing `block`/`redact` dropping to
319
+ `warn`/`monitor`), printing a `WARNING` line summarizing them. Call these out
320
+ prominently: a user who hardened a category must **explicitly approve weakening
321
+ it** before applying.
322
+ 3. **The false positives to be suppressed (the human gate).** The masked value,
323
+ rule, and masked context for each detection the writeback would suppress —
324
+ the routine noise being dismissed. This is the checkpoint that stops a genuine
325
+ secret being silenced: the user reads the masked evidence and approves it.
326
+ 4. **Explain what surfaced, in plain language.** When the frame carries
327
+ `maskedFindings`, walk through them — what each one is, where it showed up,
328
+ and why it matters — grounded entirely in that array: every count you speak
329
+ equals the frame's own count for it (`counts.important`/`counts.total`, or
330
+ a specific finding kind's count), and every value you reference appears
331
+ masked, exactly as the frame gives it — never a raw value, never an
332
+ invented one. This is an actual explanation of the known findings, not a
333
+ restatement of the headline's counts. When the frame carries no
334
+ `maskedFindings` (nothing surfaced, or a fallback floor ran), skip this —
335
+ the calibrated-result card already said so; do not invent narration over a
336
+ missing signal.
337
+ 5. **Offer an exception for a grounded false-positive pattern.** When the
338
+ frame carries `falsePositivePatterns`, name each group's pattern and count
339
+ **strictly from that signal** — never invent a pattern name or fabricate a
340
+ count. For each group, use **AskUserQuestion** to offer a pre-filled
341
+ exception with a duration picker (the exception scope axis — `once` /
342
+ `temporary` / `permanent`):
343
+
344
+ **Make an exception for `<pattern>` (×N)?** — "This `<pattern>` looks like a
345
+ test fixture — want me to set an exception so it stops popping up?"
346
+
347
+ - **Once** — just this once — expires in 30 minutes
348
+ - **Temporary** — for a set window, then I'll check it again
349
+ - **Permanent** — stays until you revoke it
350
+ - **Not now** — skip — I won't write anything
351
+
352
+ **Temporary needs a concrete window.** `once` and `permanent` fully determine
353
+ the scope on their own, but `temporary` does not — resolving it into the
354
+ stored `{scope, expiresAt, maxUses}` triple requires an actual duration, and
355
+ you must **never** invent or default one. When the user picks **Temporary**,
356
+ follow up with a second **AskUserQuestion** that offers concrete windows only
357
+ — `30m` / `1h` / `24h` (the exception scope resolver accepts `<n>m`/`<n>h`,
358
+ capped at 24h; a longer bypass is a `permanent` grant, not a forgotten timer)
359
+ — and resolve the exact chosen string through that resolver. **Once** and
360
+ **Permanent** take no follow-up.
361
+
362
+ Accepting surfaces the exact pre-filled exception — one **per distinct value
363
+ identity** (`ruleId`/`valueFingerprint`/`keyVersion`) at the chosen
364
+ `{scope, expiresAt, maxUses}` — for review, and the marked pattern is
365
+ suppressed as part of the calibration plan confirmed below (the same store
366
+ `/aka:exceptions` reads). A group whose displayed pattern covers more than one
367
+ distinct value surfaces one exception per distinct value — never a single
368
+ grant collapsing them — and a value missing its exact identity is not
369
+ offered for. Declining surfaces nothing; this offer is separate from the
370
+ calibration plan's suppressions confirmed below, so declining here changes
371
+ nothing about that confirmation. When the frame carries no
372
+ `falsePositivePatterns` (nothing was marked a likely false positive, or the
373
+ scan was declined), skip this entirely — no offer, nothing invented
374
+ (fail-open).
375
+
376
+ Then use **AskUserQuestion** (the real picker, never a printed numbered list) to
377
+ confirm:
378
+
379
+ **Want me to apply this?** — "I'll set these levels and suppress the false
380
+ positives above."
381
+
382
+ - **Yes, apply** _(recommended)_ — write the posture and suppressions exactly as
383
+ previewed.
384
+ - **Adjust a category** — "change one or more first; keep the rest as I
385
+ recommend"
386
+
387
+ Do **not** proceed until the user picks one. On **Yes, apply**, continue to
388
+ step 5 and apply the previewed plan verbatim — that is the confirm spine,
389
+ unchanged. On **Adjust a category**, take the **adjust fork** (step 4b), which
390
+ applies within the fork and rejoins the spine at the installed summary (step 6).
391
+
392
+ ## 4b. Adjust a category — the override fork
393
+
394
+ The **adjust base is the calibrated recommended posture the preview just
395
+ printed** — the condensed one-row-per-pack view from step 4, not the cold-start
396
+ severity floor. The user changes the packs they want and keeps the rest as
397
+ recommended.
398
+
399
+ 1. **Collect the changes.** Use **AskUserQuestion** — the built-in picker — to
400
+ ask which packs to change and to which level (monitor/warn/redact/block). The
401
+ plugin can't draw its own selectable UI, so do **not** print a fake option list
402
+ or ask the user to "reply with a number"; let the picker collect the answer.
403
+
404
+ 2. **Show the adjust-confirm table.** Compose the merged 8-pack map — the
405
+ recommended base with the user's picks overlaid — and render the adjust-confirm
406
+ card by passing the calibrated recommended posture as `--recommended` and that
407
+ merged map as `--posture`. Relay its AKA_SHOW region per the execution
408
+ contract — the fenced `category │ recommended │ yours` table, pasted between
409
+ the markers exactly as printed (it is space-aligned monospace; do **not** add
410
+ another code fence, strip the fence, or reformat it):
411
+
412
+ ```bash
413
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/start-light.js" --adjust-confirm --recommended '<recommended-json>' --posture '<merged-json>' --current '<current-json>'
414
+ ```
415
+
416
+ `<recommended-json>` is the calibrated recommended posture the preview printed
417
+ (the adjust base) — so the `recommended` column shows each pack's calibrated
418
+ level, and a pack calibration escalated above the floor never renders as a
419
+ spurious change. `<merged-json>` is the full 8-pack map — that same recommended
420
+ base with the user's overrides overlaid — so a changed pack reads as a different
421
+ `yours` value and every untouched pack repeats its recommended level.
422
+ `<current-json>` is the `current` object from the plan file at the path step 3
423
+ printed (`Plan saved to: <path>`) — the store's per-category action at preview
424
+ time, the baseline the downgrade check compares against. Pass it verbatim; do
425
+ not retype or summarize it.
426
+
427
+ 3. **Surface any downgrade — the card computes this, you do not.** With
428
+ `--current` passed, the card itself appends the `WARNING: N categories … would
429
+ be LOWERED from a stronger existing setting` footer whenever a pick weakens
430
+ enforcement — the same rule and the same wording as the confirm gate above,
431
+ from the same code. Show the card in full, footer included, and when that
432
+ footer is present get explicit approval before saving. Never let an enforcement
433
+ downgrade through without the user having seen it.
434
+
435
+ 4. **Save or back out.** Use **AskUserQuestion** with **N** the number of packs
436
+ the user changed and **M** the number kept as recommended (`M = 8 − N`), both
437
+ real — never a placeholder:
438
+
439
+ **Save your adjustments?**
440
+
441
+ - **Save adjusted — N changed, M as recommended** — apply with the adjusted
442
+ posture.
443
+ - **Back to recommended** — discard the changes and apply the recommended
444
+ posture instead.
445
+
446
+ 5. **On "Save adjusted" — produce the applying frame here, carrying the adjusted
447
+ posture, then rejoin the spine at the installed summary (step 6).** This fork
448
+ applies within itself and **stands in for step 5**, so step 5 never runs on
449
+ this path. First apply the previewed plan with the **unchanged confirm spine**,
450
+ so the reviewed false positives are dismissed and the recommended base is
451
+ written (the reviewed evidence packs overwrite; the severity floor fill-gaps the
452
+ rest, so a pack hardened out of band is never downgraded):
453
+
454
+ ```bash
455
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js" --confirmed --plan <path>
456
+ ```
457
+
458
+ If that `--confirmed` run exits non-zero (or `--plan` is missing/unreadable),
459
+ handle it exactly as step 5 does: tell the user the write did not complete, fall
460
+ back to the floor (`onboard.js --floor`), and continue to step 6. Do **not** run
461
+ the overlay below on a failed spine — nothing was written, so there is no
462
+ recommended base to overlay the changes onto.
463
+
464
+ Then overwrite **only the packs the user changed** with their chosen levels:
465
+
466
+ ```bash
467
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --posture '<changed-packs-json>'
468
+ ```
469
+
470
+ `<changed-packs-json>` carries **only** the packs the user adjusted (not the
471
+ full 8-pack map), so the packs kept as recommended keep the fill-gaps-safe
472
+ values the spine wrote and only the user's explicit, downgrade-approved changes
473
+ overwrite.
474
+
475
+ If that overlay exits non-zero, the spine already wrote the recommended base, so
476
+ the store holds a valid posture — but **not** the user's overrides. Tell the user
477
+ their adjustments did not save and the store holds the recommended posture, then
478
+ continue to step 6. Do **not** report the adjusted posture as saved on a failed
479
+ overlay.
480
+
481
+ On success, present the applying-frame confirmation the **spine** printed —
482
+ `✓ Set all 8 detection categories · set aside N routine results · Ready: …` —
483
+ the store now holds the adjusted posture. The overlay's own smaller
484
+ `✓ Set all N detection categories` line (the count of just the changed packs)
485
+ is bookkeeping — **do not show it**; the applying frame reports the full
486
+ 8-pack posture. Then continue to step 6.
487
+
488
+ **On "Back to recommended"** — take the **Yes, apply** path instead: continue
489
+ to step 5 and apply the previewed plan verbatim with no override.
490
+
491
+ Do **not** write anything until the user has explicitly confirmed at step 4
492
+ (Yes, apply) or saved at step 4b (Save adjusted).
493
+
494
+ ## 5. Write the posture and suppressions
495
+
496
+ On confirmation, run the adapter again with `--confirmed --plan <path>`, passing
497
+ the **plan-file path the preview printed in step 3** (`Plan saved to: <path>`). It
498
+ reads that saved plan back and applies it **exactly as previewed** — establishing
499
+ the **full 8-pack posture** the recommended view showed (the reviewed
500
+ evidence packs overwrite; the conservative severity floor fill-gaps the remaining
501
+ packs, so a pack the user had already hardened out of band is never downgraded) and
502
+ writing one 30-day suppression per confirmed false positive **without re-running the
503
+ backfill or the judge**. There is deliberately **no `backfill.js` pipe here**:
504
+ re-scanning and re-judging would produce a fresh, non-deterministic plan and
505
+ silently defeat the human gate the user just approved.
506
+
507
+ The posture overwrite and the suppression writes are applied as a **single
508
+ all-or-nothing transaction**: a mid-batch failure rolls back the posture change
509
+ too, so the store is never left half-applied. That is why the floor fallback below
510
+ is safe — a non-zero exit means **nothing** persisted, so re-applying the
511
+ conservative floor cannot collide with a partially-written posture.
40
512
 
41
- **Historical & memory access** — "Secrets often leak before AKA is installed. May I also review your temp files, agent memory & prior conversation transcripts?"
513
+ ```bash
514
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js" --confirmed --plan <path>
515
+ ```
42
516
 
43
- List **Grant full review** as the first (top) option:
517
+ The script prints the applying confirmation `✓ Set all K detection categories
518
+ · set aside N routine results · Ready: …` — with both counts threaded from the
519
+ real write. Show that line to the user.
520
+
521
+ If `--plan` is missing or the file is unreadable/invalid, the adapter **fails loud
522
+ (non-zero) and writes nothing** — it never falls back to a re-judge. Treat that
523
+ like the `--confirmed` failure below: tell the user the write did not complete,
524
+ fall back to the floor, and continue to step 6.
525
+
526
+ If the `--confirmed` run exits non-zero, tell the user the write did not
527
+ complete, fall back to the floor (`onboard.js --floor`), and continue to step 6
528
+ so setup still finishes.
529
+
530
+ ## 6. Show the installed summary and hand off to the dashboard
531
+
532
+ Run the first-run script and relay its **install-complete summary** AKA_SHOW
533
+ region per the execution contract (live findings/recommendation counts, the
534
+ health score, and the per-category posture just written or floored). The
535
+ script wraps that summary in a Markdown code fence; paste it between the
536
+ markers exactly as printed and do **not** add another code fence, strip the
537
+ fence, or reformat it (it is space-aligned monospace that Markdown would
538
+ otherwise collapse).
539
+
540
+ Pass the **surfaced count** captured from step 3's calibration frame
541
+ (`counts.important`) as `--surfaced <count>` — this is the 'N worth a look' figure
542
+ the script emits in its own machine-readable handoff payload — but only when step 3
543
+ carried a surfaced count forward (it printed a `Plan saved to:` path). If the
544
+ calibration fell back to the floor (no plan path in step 3 — a fallback branch, or
545
+ the scan-ran-clean empty state whose zero-count frame carries nothing to look at),
546
+ **omit `--surfaced` entirely** — the script then withholds that payload rather than
547
+ fabricating a count.
548
+
549
+ Alongside it, pass the **surfaced live-key count** — the number of surfaced
550
+ live-key secret findings, which is the length of the calibration frame's
551
+ `maskedFindings` array (absent ⇒ 0) — as `--live-keys <count>`. This is the
552
+ narrower secret subset of the surfaced count; it gates the remediation
553
+ chain-entry the handoff offers, so a calibration that surfaced only non-secret
554
+ findings passes `--live-keys 0` and offers no remediation.
555
+
556
+ When `--surfaced` is passed, the script appends that handoff payload as a single
557
+ JSON block delimited by `<<<AKA_FRAME_JSON` … `AKA_FRAME_JSON>>>` after the fenced
558
+ card. Like step 3's calibration frame, do **not** show this block to the user — it
559
+ is additive and machine-only; only the fenced install summary above is
560
+ user-facing.
44
561
 
45
- - **Grant full review** → `full` — scan scratch/temp files, agent memory & prior
46
- transcripts for leaked secrets (deepest coverage · one-time consent, revocable
47
- under Policies).
48
- - **Current session only** → `session-only` — decline historical access; AKA
49
- reviews only what this session already touches. Even if declined, AKA can still
50
- review: the **working tree** (all source, config & dotfiles in the repo), **this
51
- session** (prompts, tool calls & files Claude reads or writes now), **git
52
- history** (commits reachable from HEAD, incl. removed-but-tracked secrets), and
53
- **pointed scans** (any path you explicitly hand AKA during a run).
562
+ ```bash
563
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/firstrun.js" --surfaced <count> --live-keys <count>
564
+ ```
565
+
566
+ **Then hand off to the dashboard.** When the payload carries a positive
567
+ `worthALook` count, issue an explicit **AskUserQuestion** (the real picker, never a
568
+ printed list) using that count for `N`:
569
+
570
+ **N worth a look want to see them in the browser?**
54
571
 
55
- Map the picked labels to the flag values shown above (`redact`/`warn`,
56
- `full`/`session-only`).
572
+ - **Review leaked keys** "let's deal with the exposed keys I found"
573
+ _(offer this option first only when the payload's `options` include
574
+ `enter-remediation`, i.e. `liveKeys > 0`)_; entering it starts the
575
+ secret-leak remediation chain on the surfaced live keys. This composes with —
576
+ never replaces — the dashboard handoff below, so both stay reachable.
577
+ - **Open dashboard** — "open the local dashboard on what I found"
578
+ - **Not now** — "stay here — you can open it anytime"
57
579
 
58
- ## 2. Save the answers
580
+ Use the payload's `worthALook` value for `N` verbatim — do not invent or round it.
581
+ Offer **Review leaked keys** exactly when the payload's `options` carry the
582
+ `enter-remediation` entry (never otherwise); the **Open dashboard** / **Not now**
583
+ handoff is always present. If the payload was withheld (the floor fallback, or
584
+ nothing surfaced), skip this handoff question rather than inventing a count.
59
585
 
60
- Run the onboarding writer with the chosen values. Omit a flag to keep its
61
- default. This validates and persists to `~/.aka/settings/settings.json` (created
62
- `0600`, owner-only) and stamps the machine as onboarded:
586
+ **If they choose "Review leaked keys"** run the secret-leak remediation entry's
587
+ **present** mode, feeding it the calibration frame block you captured in step 3
588
+ (the same text `maskedFindings` came from) on stdin:
63
589
 
64
590
  ```bash
65
- node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --policy <redact|warn> --historical <full|session-only>
591
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/remediate.js" <<'AKA_FRAME'
592
+ <the <<<AKA_FRAME_JSON … AKA_FRAME_JSON>>> block captured in step 3, verbatim>
593
+ AKA_FRAME
66
594
  ```
67
595
 
68
- ## 2.5 Scan history (only if they granted full review)
69
-
70
- **Only when the user picked "Grant full review" (`historical=full`)**, run the
71
- backfill. It sweeps prior Claude Code transcripts (last 30 days, all projects)
72
- for secrets that leaked before AKA was installed and records them into the local
73
- store, so they show up in the first-run summary and `/findings`. The scan is
74
- idempotent — it skips messages already recorded — so re-running `/aka:setup` is
75
- safe and never duplicates findings. Show its output **exactly as printed** (it
76
- self-fences; do not add another fence or reformat). Skip this step entirely when
77
- they chose `session-only`.
596
+ It prints the decision as human-facing text, then a machine-readable block
597
+ delimited by `<<<AKA_FRAME_JSON` … `AKA_FRAME_JSON>>>` carrying the same decision
598
+ structured (do **not** show that block to the user). The human text has three
599
+ parts, all of which you **show to the user verbatim, in order**:
600
+
601
+ 1. the templated count line ("I found N exposed secret keys sitting in old
602
+ transcripts."),
603
+ 2. the fenced finding table (provider, masked token, where, state), and
604
+ 3. inside that same fence, a most-exposed-first recommendation line and a
605
+ secret-scan chaining line.
606
+
607
+ This entire human-text block is the entry's AKA_SHOW region — relay it per the
608
+ execution contract, pasting it between the markers exactly as printed — do not
609
+ drop the recommendation or chaining lines, and do not paraphrase.
610
+
611
+ Alongside that fenced block, explain the findings in plain language grounded
612
+ in the same `maskedFindings` array the block came from — what each finding is
613
+ and why it matters, not a bare recital of the count line above it. The same
614
+ grounding discipline as step 4's narration applies here: every count you
615
+ speak matches the frame's own count, and every value you reference stays
616
+ masked. With no `maskedFindings` present there is nothing to narrate beyond
617
+ the count line and table already shown — do not invent an explanation.
618
+
619
+ Then issue an
620
+ **AskUserQuestion** offering exactly these four options, in order (each option's
621
+ label maps to the `--option` id shown in parentheses):
622
+
623
+ - **Redact + rotation checklist** (`redact-rotation-checklist`)
624
+ - **Redact only** (`redact-only`)
625
+ - **Set 'secret' to redact** (`set-secret-redact`)
626
+ - **Leave** (`leave`)
627
+
628
+ **If they chose "Redact + rotation checklist" or "Redact only"** — before running
629
+ the route, issue a second **AskUserQuestion** presenting the standing-posture
630
+ prompt, offering exactly these four options, in order (each option's label maps
631
+ to the `--posture` level in parentheses):
632
+
633
+ **Set the 'secret' detection level**
634
+
635
+ - **Redact** (`redact`)
636
+ - **Warn** (`warn`)
637
+ - **Block** (`block`)
638
+ - **Monitor** (`monitor`)
639
+
640
+ Then run the entry's **route** mode ONCE with the chosen redact option's id AND
641
+ the chosen posture level, feeding it the SAME calibration frame block again on
642
+ stdin:
78
643
 
79
644
  ```bash
80
- node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js"
645
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/remediate.js" --option <id> --posture <level> <<'AKA_FRAME'
646
+ <the same block>
647
+ AKA_FRAME
81
648
  ```
82
649
 
83
- ## 3. Show the first-run summary
650
+ Never run the route a second time for this choice — a repeat call would strike
651
+ the already-redacted keys again and corrupt the reported count. Show its printed
652
+ result verbatim, in order. For "Redact only" that is the redaction confirmation
653
+ then the standing-posture confirmation. For "Redact + rotation checklist" it is
654
+ the standing-posture confirmation then the resolved rotation-checklist summary —
655
+ which reports the redaction itself, so the script does not print a separate
656
+ redaction confirmation ahead of it.
84
657
 
85
- Run the first-run script and show its output **exactly as printed** (the
86
- install-complete summary with live findings/recommendation counts and the health
87
- score). The script already prints it inside a Markdown code fence; reproduce that
88
- verbatim and do **not** add another code fence, strip the fence, or reformat it (it
89
- is space-aligned monospace that Markdown would otherwise collapse).
658
+ **If they chose "Set 'secret' to redact" or "Leave"** run the entry's **route**
659
+ mode with the chosen option's id (the id in parentheses above, e.g. **Leave** →
660
+ `leave`), feeding it the SAME calibration frame block again on stdin:
90
661
 
91
662
  ```bash
92
- node "${CLAUDE_PLUGIN_ROOT}/scripts/firstrun.js"
663
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/remediate.js" --option <id> <<'AKA_FRAME'
664
+ <the same block>
665
+ AKA_FRAME
93
666
  ```
94
667
 
95
- ## 3.5 Offer the AKA CLI + local dashboard (opt-in)
668
+ Show its printed result verbatim a standing-posture confirmation, or (choosing
669
+ "Leave") a plain note that nothing changed. This entry reads its findings from the
670
+ calibration frame alone and holds no wizard state of its own, so it works
671
+ identically from any caller.
672
+
673
+ ## 7. Offer the AKA CLI + local dashboard (opt-in)
96
674
 
97
675
  Now that the plugin is set up, offer the optional **AKA CLI + local dashboard** —
98
676
  a richer, still-fully-local surface over the same `~/.aka` store this plugin
99
677
  writes. The plugin works completely on its own; this is additive (and the path to
100
678
  future multi-agent support). Use **AskUserQuestion**:
101
679
 
102
- **Add the AKA CLI + dashboard?** — "Install the `aka` CLI for a local web +
103
- terminal dashboard and on-demand scans? Everything stays on your machine."
680
+ **Want the AKA CLI + dashboard too?** — "The `aka` CLI adds a local user
681
+ interface + terminal dashboard and on-demand scans."
104
682
 
105
- - **Yes, install it** _(recommended)_ — adds the `aka` binary: `aka stats`,
106
- `aka tui` (terminal dashboard), `aka dashboard` (local web UI), `aka scan`.
107
- - **Not now** — skip; it can be added anytime with the one-liner below.
683
+ - **Yes, add it** _(recommended)_ — "adds the `aka` command: stats, a terminal
684
+ dashboard, a local user interface, and on-demand scans"
685
+ - **Not now** — "skip you can add it anytime with the one-liner below"
108
686
 
109
- If they choose **Yes**, run the bootstrap installer (it ensures Node is available
110
- and installs the global CLI from the public npm registry). **Ask permission
111
- before running it**, then run the line for their OS:
687
+ **Yes, add it** is the install authorization run the bootstrap installer
688
+ directly, with no second picker (it ensures Node is available and installs the
689
+ global CLI from the public npm registry). Run the line for their OS:
112
690
 
113
691
  ```bash
114
692
  # macOS / Linux
@@ -136,8 +714,10 @@ what happened, show the one-liner so they can retry later, and continue the
136
714
  wizard normally. The plugin is already fully set up and works on its own; a
137
715
  failed CLI install changes nothing about that.
138
716
 
139
- ## 4. Report the result
717
+ **Close the wizard.** The first-run summary already confirmed the saved posture
718
+ and pointed at `/health`. Whichever way the CLI offer went — installed,
719
+ declined, or a failed install you already reported — end with one warm close:
720
+ "That's it — I'm watching out for Claude going forward."
140
721
 
141
- - The first-run summary already confirms the saved handling and points at
142
- `/health`. Add at most one short sentence: detection runs locally and nothing
143
- leaves the machine.
722
+ Before you finish, confirm every AKA_SHOW region on the path you took was
723
+ relayed to the user. If you summarized one instead of pasting it, paste it now.