本文へスキップ
MCP ThesaurusMCP Thesaurus

Aka Setup

コミュニティExcellent82/100申請する

Apache-2.0updated 7d ago

You are onboarding the AKA Security plugin for this machine. AKA works fully locally with zero backend and zero Docker: detection runs in-process and findings persist to a local SQLite store at /.aka/data/aka.db.

ソースウェブサイトドキュメント10

Aka Setup で何ができる?


name: aka-setup description: Set up AKA Security — calibrate notifications and detection posture from Antigravity's real activity.

AKA setup wizard

You are onboarding the AKA Security plugin for this machine. AKA works fully locally with zero backend and zero Docker: detection runs in-process and findings persist to a local SQLite store at ~/.aka/data/aka.db.

This wizard tells a calibration story: introduce AKA → show what it does → offer one retroactive scan → report the real numbers it found and the posture it recommends → apply on confirmation → show the installed summary → hand off to the dashboard. Everything the user sees is derived from their actual history — never a fabricated or demo number. When there isn't enough history to judge, the wizard falls back to a conservative severity-derived floor instead of guessing.

The false-positive/severity judgment needs the raw (unmasked) findings to rate them accurately, so it sends them to the model API through separate agy subprocesses (a large history is judged in several batches). Two things cross for each finding: its raw value, and about 120 characters of the surrounding transcript text on either side of it — re-masked first, so any other detectable secret in that window never leaves raw. The transcript file's path, the value's fingerprint, and the fingerprint key version are dropped before egress. A copy of the raw value leaves the machine, sent to the model provider like any other Antigravity prompt. You act only on the raw-free plan the subprocesses print back.

Two limits of this host are worth knowing before you consent, because they are weaker than the Claude Code and Codex plugins' equivalents:

  • The agy CLI documents no ephemeral mode. Every run is written to your conversation store under ~/.gemini/antigravity/brain/, raw values and all — the same store this backfill scans. AKA therefore deletes the judge's own conversation itself as soon as the run ends. That deletion is best effort: if the process is killed between the write and the cleanup, the conversation stays on disk until you remove it.
  • Deleting the conversation is not network isolation. It is a local-write cleanup only; it cannot recall what was already sent.

Reading history is granted in step 1; sending findings to the model is a distinct consent, collected in step 3 before the judgment pipe runs — the judge refuses to run without it.

Follow the steps below in order. Nothing is written to the policy store until step 5 (or a floor fallback in step 3 if the calibration can't complete).

Execution contract (read before step 0)

Every script prints output in three region kinds. Your job for each is fixed:

  • <<<AKA_SHOW … AKA_SHOW>>> — relay every AKA_SHOW region verbatim as your next message: paste the content between the markers exactly — a card region carries its own code fence, a plain confirmation line does not, but either way you paste exactly what's between the markers — never the marker lines, never a paraphrase or summary.
  • <<<AKA_FRAME_JSON … AKA_FRAME_JSON>>> — machine-only. Parse it if a step tells you to read a value from it; never display it.
  • Anything else on stdout — status for you (paths like Plan saved to:, errors, exit signals). Act on it; never relay it.

Collecting a decision. Wherever a step asks the user a question, ask it as a normal conversational turn with numbered options for the user to pick from. This wizard depends on no specific interactive-picker tool being available — present each option clearly and wait for the user's reply before moving on. If Antigravity exposes a native multi-choice picker in your environment, prefer that over plain text; otherwise the numbered-list form is the fallback. Never answer a question on the user's behalf.

Invariants:

  • Never write a confirmation or acknowledgement the wizard did not emit — the script's AKA_SHOW line is the confirmation.
  • Each step's AKA_SHOW regions must be relayed before you advance.
  • One question per decision; never re-ask a decision already collected.

0. Show the intro card

Run the intro script and relay its AKA_SHOW region per the execution contract: paste the content between the markers verbatim, never the marker lines. It prints a single space-aligned monospace card — name, repository, version, and what AKA adds — inside a Markdown code fence that is part of that pasted content. Keep the fence as printed and do not add another code fence, strip the fence, or reformat it (unfenced, Markdown collapses the indentation and mangles the lines).

node "${PLUGIN_ROOT}/scripts/intro.js" "${PLUGIN_ROOT}/.antigravity-plugin/plugin.json"

0b. Repo-aware posture check — tighten-only, working-tree only

Before showing any recommended posture — the start-light default table in step 2 or the calibrated posture in step 4 — look at the current project's working tree yourself, with your own file-reading tools. There is no script for this: it is your own reasoning over facts you read directly, not the triage subprocess's raw-free plan, and it needs no user interaction.

In scope: the manifest's declared frameworks/dependencies (package.json or equivalent), payment or other third-party API SDKs among them, CI config (.github/workflows/, etc.), and the presence and names of .env*/config files as a signal that secrets live on disk here — never their contents; a secret-bearing file's contents are exactly the kind of raw value this wizard never reads. Out of scope: Antigravity's own history and the local AKA store (that is the separate, consent-gated scan in steps 1/3) — no historical read, and no question or other consent interaction of any kind.

The severity-floor default map (secret/pii/financial/phi/code_flaw/custom at warn, code_context/config at monitor — the table step 2's start-light card prints) is both the floor this check is measured against and its fallback. From what you directly observe you may tighten individual categories above that floor — raise the level, never lower one below it — each tightened category carrying a one-line rationale naming the concrete evidence you found, e.g.:

Stripe + a Customer model here — financial → redact

Present the tightening on whichever recommended posture is about to render, the same "recommended base + changed-packs overlay" shape step 4b's adjust fork uses: the tightened categories raise, every other category keeps its existing recommended level, each carrying its rationale line. Where you compose the view yourself (the adjust fork, the calibrated result) this tightened recommendation IS that view; where the view is a script's AKA_SHOW card (the step-2 start-light card, relayed per the execution contract), show the tightened recommendation and its rationale lines adjacent to that card rather than rewriting the card's own printed levels.

This tightening is a display-time recommendation: it shapes the recommended posture the user reads, not a separate write. Persisting a tightened level happens only where the wizard already writes a per-category override — the adjust fork's onboard.js --posture write (step 4b), where the user picks each category's level explicitly. The keep-defaults path writes the severity floor (--floor, step 2) and the calibrated accept path applies the triage subprocess's saved plan verbatim (--confirmed --plan, step 5); neither carries the tightening on its own, so a tightened level the user wants persisted is chosen through the adjust fork. Do not bolt on an extra onboard.js --posture overlay to auto-re-persist the tightening across the other paths: it would overwrite — and so could silently downgrade — a category the user had hardened out of band (a tightening is only guaranteed to raise above the severity floor, not above the user's stored level), with no downgrade-approval gate. So the tightening is not auto-persisted across those paths — a tightened level the user wants kept is set through the adjust fork.

When nothing in the working tree is inferable, change nothing. Render the recommended posture exactly as the static frame already gives it — no rationale line and no tightened category (fail-open).

1. Offer the retroactive scan

Ask this before anything about detection posture — the posture recommendation in step 4 is derived from the answer to this question, so it has to come first. Ask it per the execution contract's decision rules: a conversational turn with numbered options, waiting for the user's reply.

Disclose the model-API egress plainly before you show the options — this is what the user is consenting to, so it must be visible before they choose. State it in your own words, without softening it: if they say yes, AKA scans the last 30 days of Antigravity history, and to rate what it finds it sends the raw, unmasked values — including any secrets — to the model API through the antigravity CLI. Name what travels with each one: its raw value, and about 120 characters of the surrounding transcript text on either side (any other secrets detected in that window are masked; the rollout file's path stays local). That is real network egress to the model provider (the same one your Antigravity session already uses), not a purely local review. A copy of each value leaves the machine. The rollouts those values came from stay on disk untouched — nothing here removes them; that is the separate redaction step in step 6. The judge's own conversation IS written to your local Antigravity history under ~/.gemini/antigravity/brain/ — this host has no ephemeral mode — and AKA deletes that conversation itself as soon as the run ends, best effort; a killed process can leave it behind. That cleanup is a local-write guard only, not network isolation. The findings are also recorded, masked, to the local store. The grant is revocable from the dashboard's Settings → Historical access, which stops future scans — it cannot recall anything already sent. Do not present the options until you have said this.

Want me to look over what Antigravity has been up to? — "I'll scan Antigravity's recent work — session rollouts, temp files, agent memory — and send what I find to the model to rate it, so I can tune what I bring you next."

Offer exactly two options:

  1. Yes, take a look — "scan my real work here; raw findings go to the model to be rated, then tune what you bring me"
  2. Not now — "start light and I'll learn as we go"

Choosing Yes, take a look records the same historical-review consent the wizard has always recorded — the identical scope (which includes the model-API judgment disclosed above), the one-time grant, and the same revocation semantics — so the simpler question broadens nothing about what AKA may access. Those granular scope and revocation details stay inspectable on request and in the dashboard, under Settings → Historical access, whose own copy repeats the model-API disclosure.

2. Save the answer, then branch

Branch on the answer from step 1. On the Yes, take a look path the onboarding writer runs, and it must run before the backfill (step 3), because the backfill script reads historicalAccess from the saved settings to decide whether it's allowed to run. Omitting --policy is deliberate — the old global redact/warn toggle no longer drives enforcement (posture is per-category now); its field is kept for backward compatibility but this wizard doesn't ask about it.

Branch on the choice:

  • If the user chose "Yes, take a look" — record the historical-review consent and continue to step 3 (which runs the scan and leads to the calibrated result in step 4). "Yes, take a look" maps to the existing full historical-review path — no access is granted beyond what that path already granted:

    node "${PLUGIN_ROOT}/scripts/onboard.js" --historical full
    
  • If the user chose "Not now" — take the start-light path. This path takes zero historical access: do not read any history, do not run the backfill, and do not record consent — nothing about the machine's past is touched. Instead present the start-light posture card, write the posture the user picks (this write is the applying frame — it stands in for step 5, which never runs here because there is no scan plan to apply), and rejoin the spine at the installed summary (step 6). Skip steps 3, 4, and 5 entirely — there is no scan to triage, no calibrated result to confirm, and no suppression plan to write. Do the following in order:

    1. Show the start-light card. Run the start-light script and relay its AKA_SHOW card per the execution contract — the ● Starting light — your detection categories heading, the full 8-pack × 4-level default posture table, the per-pack rationale, and the re-tune hint, pasted between the markers exactly as printed, fence included. It reads no history and writes nothing; it only prints the card (the severity-floor default map — secret, pii, financial, phi, code_flaw, custom at warn; code_context, config at monitor).

      node "${PLUGIN_ROOT}/scripts/start-light.js"
      
    2. Confirm or adjust. Ask — per the execution contract's decision rules — whether to keep the recommended defaults or tune individual packs:

      Set your detection categories — "Keep the defaults I'd recommend, or adjust any of them?"

      1. Keep defaults (recommended) — "the careful defaults shown above"
      2. Adjust — "change one or more levels, keep the rest as I recommend"

      If they choose Adjust, ask again — same decision rules — to collect the new level (monitor/warn/redact/block) for each pack they want to change, then merge those overrides over the severity-floor defaults to form the full 8-pack map.

    3. Write the chosen posture. The default map is the severity floor, so when the user keeps the defaults, write the floor directly; when they adjusted packs, write the merged 8-pack map:

      # Kept the recommended defaults
      node "${PLUGIN_ROOT}/scripts/onboard.js" --floor
      
      # Adjusted one or more packs — <json> is the merged 8-pack map
      node "${PLUGIN_ROOT}/scripts/onboard.js" --posture '<json>'
      

      Either write prints only ✓ Set all K detection categories (the --floor write appends — safe defaults) — which is the honest confirmation here, because nothing was scanned or suppressed. Show that line to the user; do not invent a dismissed count or any calibration counts.

    4. Rejoin the spine at the installed summary (step 6). Continue to step 6 to show the installed summary and hand off to the dashboard, using honest no-scan copy. No scan ran, so there is no surfaced count — call firstrun.js with no --surfaced flag (the same floor-fallback rule step 6 already follows when no calibration frame was emitted). Step 7 then runs as written.

3. Run the evidence triage — off-transcript judgment, nothing written yet

Model-judge consent — a distinct opt-in, asked here before the pipe. The false-positive/severity judgment runs by sending each finding to the model API through antigravity. That is a separate egress from the historical-read consent collected in step 1 (which only let AKA read the local rollouts), so it needs its own explicit grant. Before running the pipe, restate plainly what leaves the machine (the step-1 disclosure's payload: each raw value plus its masked context window; the file path stays local), then ask as a normal conversational turn with numbered options — and present both options flat: this grant sends the user's data off the machine, so do not mark either one recommended.

Send findings to the model to sort real leaks from noise? — "I'll send each detected value, plus a bit of surrounding context with any secrets in it masked, to the model to tell real leaks from routine noise. The file path stays local. This consent is saved machine-wide in AKA's settings, so it also covers the same triage step in AKA's other harness plugins on this machine — revoke it anytime from the dashboard."

  1. Yes, send them — "let the model triage what I found"
  2. No, keep it local — "skip the model triage and start from the safe defaults"

Branch on the choice:

  • If the user chose "Yes, send them" — record the model-judge consent, then run the pipe below:

    node "${PLUGIN_ROOT}/scripts/onboard.js" --model-judge-consent
    
  • If the user chose "No, keep it local" — do not run the pipe. The judge refuses to run without consent (it would only print a clean skip line and a zero-count frame), so there is no calibrated plan to confirm. Fall back to the conservative severity floor exactly as step 2's start-light path does — write the floor, tell the user the model triage was skipped, and continue to step 6 with no --surfaced flag:

    node "${PLUGIN_ROOT}/scripts/onboard.js" --floor
    

Pipe the backfill's triage stream straight into the apply-suppressions adapter in PREVIEW mode (no --confirmed):

node "${PLUGIN_ROOT}/scripts/backfill.js" --triage | node "${PLUGIN_ROOT}/scripts/apply-suppressions.js"

The backfill sweeps prior Antigravity CLI conversation transcripts (last 30 days, all conversations) and streams one masked-plus-raw triage hit per line; masked findings are recorded to the local store as a side effect. The adapter runs the false-positive/severity judgment in separate agy subprocesses that send each hit's raw value and masked context window — never its source path — to the model API (a large history is split into several batches; each run persists a conversation under ~/.gemini/antigravity/brain/, which AKA then deletes best effort — this host has no ephemeral mode), then prints back a raw-free plan you can safely show the user: the calibrated-result card (the real-count headline and the recommended posture), the per-category reasoning, the masked false positives it would suppress, any categories it skipped, and its notes.

The preview also persists that exact raw-free plan to a temp file and prints its path — a line beginning Plan saved to: <path>. Capture that path: step 5 applies this saved plan verbatim, so the confirm step performs no second scan and no second judgment. (The plan file carries only masked/fingerprint/enum data; it is deleted after a successful apply.)

Alongside the human copy, the preview also emits a machine-readable calibration frame — a single JSON block delimited by <<<AKA_FRAME_JSONAKA_FRAME_JSON>>> carrying the raw-free calibration counts and categories, plus (when the scan surfaced any) a maskedFindings array of raw-free secret-leak summaries. Do not show this block to the user (it is additive to the human copy above). Capture its counts.important value — the surfaced count — and pass it to the first-run summary in step 6 as --surfaced <count> — but only when the preview also printed a Plan saved to: path (a real calibrated plan to confirm in step 4). The Plan saved to: line is the completion signal: a preview that omits it did not calibrate a plan you can confirm. The fallback branches below carry no surfaced count; the scan-ran-clean empty state (a scan that completed but surfaced nothing) emits a zero-count frame but no plan path, so it too routes to the floor branch below rather than step 4.

Also retain the block's full text verbatim (not just the counts you read out of it) — step 6's "Review leaked keys" branch feeds this same text to the secret-leak remediation entry, which reads its own maskedFindings from it, and step 4's finding narration and step 6's secret-leak narration (both below) read the same maskedFindings array off it too. When present, the block's falsePositivePatterns array is what step 4's fixture/exception offer (below) names its pattern and count from — never invent either off-signal.

Everything you show the user in step 4 comes from this command's output. You never read the raw finding values yourself — do not echo, quote, or reconstruct them; the judge subprocesses send them to the model API and return only the raw-free plan, so they never enter this conversation.

Failed or truncated triage — never proceed silently (fallback). If this command exits non-zero, or the adapter reports a truncated / sentinel-less stream, the calibration could not complete. Do not guess a posture and do not leave setup half-applied. Apply the conservative severity floor, tell the user it happened, and continue to step 6:

node "${PLUGIN_ROOT}/scripts/onboard.js" --floor

Say plainly: the historical scan couldn't finish, so AKA is starting from the conservative severity floor (high-impact categories at warn, observe-only at monitor) instead of a calibrated posture, and it can be re-run any time with the aka-setup skill.

Nothing to calibrate. A scan that completes but surfaces nothing prints the honest scan-ran-clean card — I looked over Antigravity's recent work — nothing needs your attention right now. You're starting clean; here's what I'd recommend: over the recommended posture — with a zero-count calibration frame (its counts.important is 0) and no Plan saved to: path. A machine with no history to scan instead prints the no-history card (Nothing to learn from yet — Antigravity hasn't left any work on this machine. over the start-light table), and a scan skipped for lack of consent prints I didn't review anything — historical access wasn't granted.. In every one of these cases there's no evidence to calibrate from and no plan to confirm: show the card the adapter printed, take the floor branch (onboard.js --floor), tell the user the scan found nothing to calibrate from, and skip to step 6 (with no --surfaced, the floor-fallback rule there — nothing was surfaced to carry over). Do not continue to step 4.

Otherwise (the preview printed a Plan saved to: path) continue to step 4.

4. Show the calibrated result and get explicit confirmation — before any write

The preview output is raw-free. Lead with the calibrated-result card it printed and show it in full:

  1. The calibrated headline. The I went through Antigravity's recent work — N detections, M results worth a look. line — every count templated over the real scan (surfaced findings are the M results worth a look; the rest are routine noise a plain scanner would have screamed about). Show it verbatim; never substitute a demo number.

  2. The recommended posture. The condensed one-row-per-pack recommended view the card printed — the level AKA would set for each category. Show it in full.

    • Surface the downgrades the preview flags — this is not optional. For the recommended posture it is about to write, the preview compares each category against its stored setting and flags any that would be LOWERED from a stronger existing one (e.g. an existing block/redact dropping to warn/monitor), printing a WARNING line summarizing them. Call these out prominently: a user who hardened a category must explicitly approve weakening it before applying.
  3. The false positives to be suppressed (the human gate). The masked value, rule, and masked context for each detection the writeback would suppress — the routine noise being dismissed. This is the checkpoint that stops a genuine secret being silenced: the user reads the masked evidence and approves it.

  4. Explain what surfaced, in plain language. When the frame carries maskedFindings, walk through them — what each one is, where it showed up, and why it matters — grounded entirely in that array: every count you speak equals the frame's own count for it (counts.important/counts.total, or a specific finding kind's count), and every value you reference appears masked, exactly as the frame gives it — never a raw value, never an invented one. This is an actual explanation of the known findings, not a restatement of the headline's counts. When the frame carries no maskedFindings (nothing surfaced, or a fallback floor ran), skip this — the calibrated-result card already said so; do not invent narration over a missing signal.

  5. Offer an exception for a grounded false-positive pattern. When the frame carries falsePositivePatterns, name each group's pattern and count strictly from that signal — never invent a pattern name or fabricate a count. For each group, ask — per the execution contract's decision rules — whether to set a pre-filled exception, with a duration choice (the exception scope axis — once / temporary / permanent):

    Make an exception for <pattern> (×N)? — "This <pattern> looks like a test fixture — want me to set an exception so it stops popping up?"

    1. Once — just this once — expires in 30 minutes
    2. Temporary — for a set window, then I'll check it again
    3. Permanent — stays until you revoke it
    4. Not now — skip — I won't write anything

    Temporary needs a concrete window. once and permanent fully determine the scope on their own, but temporary does not — resolving it into the stored {scope, expiresAt, maxUses} triple requires an actual duration, and you must never invent or default one. When the user picks Temporary, follow up with a second question that offers concrete windows only — 30m / 1h / 24h (the exception scope resolver accepts <n>m/<n>h, capped at 24h; a longer bypass is a permanent grant, not a forgotten timer) — and resolve the exact chosen string through that resolver. Once and Permanent take no follow-up.

    Accepting surfaces the exact pre-filled exception — one per distinct value identity (ruleId/valueFingerprint/keyVersion) at the chosen {scope, expiresAt, maxUses} — for review, and the marked pattern is suppressed as part of the calibration plan confirmed below (the same store the aka-exceptions skill reads). A group whose displayed pattern covers more than one distinct value surfaces one exception per distinct value — never a single grant collapsing them — and a value missing its exact identity is not offered for. Declining surfaces nothing; this offer is separate from the calibration plan's suppressions confirmed below, so declining here changes nothing about that confirmation. When the frame carries no falsePositivePatterns (nothing was marked a likely false positive, or the scan was declined), skip this entirely — no offer, nothing invented (fail-open).

Then ask — per the execution contract's decision rules, never answering for the user — to confirm:

Want me to apply this? — "I'll set these levels and suppress the false positives above."

  1. Yes, apply (recommended) — write the posture and suppressions exactly as previewed.
  2. Adjust a category — "change one or more first; keep the rest as I recommend"

Do not proceed until the user picks one. On Yes, apply, continue to step 5 and apply the previewed plan verbatim — that is the confirm spine, unchanged. On Adjust a category, take the adjust fork (step 4b), which applies within the fork and rejoins the spine at the installed summary (step 6).

4b. Adjust a category — the override fork

The adjust base is the calibrated recommended posture the preview just printed — the condensed one-row-per-pack view from step 4, not the cold-start severity floor. The user changes the packs they want and keeps the rest as recommended.

  1. Collect the changes. Ask — per the execution contract's decision rules — which packs to change and to which level (monitor/warn/redact/block), one clear numbered-option question at a time.

  2. Show the adjust-confirm table. Compose the merged 8-pack map — the recommended base with the user's picks overlaid — and render the adjust-confirm card by passing the calibrated recommended posture as --recommended and that merged map as --posture. Relay its AKA_SHOW region per the execution contract — the fenced category │ recommended │ yours table, pasted between the markers exactly as printed (it is space-aligned monospace; do not add another code fence, strip the fence, or reformat it):

    node "${PLUGIN_ROOT}/scripts/start-light.js" --adjust-confirm --recommended '<recommended-json>' --posture '<merged-json>' --current '<current-json>'
    

    <recommended-json> is the calibrated recommended posture the preview printed (the adjust base) — so the recommended column shows each pack's calibrated level, and a pack calibration escalated above the floor never renders as a spurious change. <merged-json> is the full 8-pack map — that same recommended base with the user's overrides overlaid — so a changed pack reads as a different yours value and every untouched pack repeats its recommended level. <current-json> is the current object from the plan file at the path step 3 printed (Plan saved to: <path>) — the store's per-category action at preview time, the baseline the downgrade check compares against. Pass it verbatim; do not retype or summarize it.

  3. Surface any downgrade — the card computes this, you do not. With --current passed, the card itself appends the WARNING: N categories … would be LOWERED from a stronger existing setting footer whenever a pick weakens enforcement — the same rule and the same wording as the confirm gate above, from the same code. Show the card in full, footer included, and when that footer is present get explicit approval before saving. Never let an enforcement downgrade through without the user having seen it.

  4. Save or back out. Ask — per the execution contract's decision rules — with N the number of packs the user changed and M the number kept as recommended (M = 8 − N), both real — never a placeholder:

    Save your adjustments?

    1. Save adjusted — N changed, M as recommended — apply with the adjusted posture.
    2. Back to recommended — discard the changes and apply the recommended posture instead.
  5. On "Save adjusted" — produce the applying frame here, carrying the adjusted posture, then rejoin the spine at the installed summary (step 6). This fork applies within itself and stands in for step 5, so step 5 never runs on this path. First apply the previewed plan with the unchanged confirm spine, so the reviewed false positives are dismissed and the recommended base is written (the reviewed evidence packs overwrite; the severity floor fill-gaps the rest, so a pack hardened out of band is never downgraded):

    node "${PLUGIN_ROOT}/scripts/apply-suppressions.js" --confirmed --plan <path>
    

    If that --confirmed run exits non-zero (or --plan is missing/unreadable), handle it exactly as step 5 does: tell the user the write did not complete, fall back to the floor (onboard.js --floor), and continue to step 6. Do not run the overlay below on a failed spine — nothing was written, so there is no recommended base to overlay the changes onto.

    Then overwrite only the packs the user changed with their chosen levels:

    node "${PLUGIN_ROOT}/scripts/onboard.js" --posture '<changed-packs-json>'
    

    <changed-packs-json> carries only the packs the user adjusted (not the full 8-pack map), so the packs kept as recommended keep the fill-gaps-safe values the spine wrote and only the user's explicit, downgrade-approved changes overwrite.

    If that overlay exits non-zero, the spine already wrote the recommended base, so the store holds a valid posture — but not the user's overrides. Tell the user their adjustments did not save and the store holds the recommended posture, then continue to step 6. Do not report the adjusted posture as saved on a failed overlay.

    On success, present the applying-frame confirmation the spine printed — ✓ Set all 8 detection categories · set aside N routine results · Ready: … — the store now holds the adjusted posture. The overlay's own smaller ✓ Set all N detection categories line (the count of just the changed packs) is bookkeeping — do not show it; the applying frame reports the full 8-pack posture. Then continue to step 6.

    On "Back to recommended" — take the Yes, apply path instead: continue to step 5 and apply the previewed plan verbatim with no override.

Do not write anything until the user has explicitly confirmed at step 4 (Yes, apply) or saved at step 4b (Save adjusted).

5. Write the posture and suppressions

On confirmation, run the adapter again with --confirmed --plan <path>, passing the plan-file path the preview printed in step 3 (Plan saved to: <path>). It reads that saved plan back and applies it exactly as previewed — establishing the full 8-pack posture the recommended view showed (the reviewed evidence packs overwrite; the conservative severity floor fill-gaps the remaining packs, so a pack the user had already hardened out of band is never downgraded) and writing one 30-day suppression per confirmed false positive without re-running the backfill or the judge. There is deliberately no backfill.js pipe here: re-scanning and re-judging would produce a fresh, non-deterministic plan and silently defeat the human gate the user just approved.

The posture overwrite and the suppression writes are applied as a single all-or-nothing transaction: a mid-batch failure rolls back the posture change too, so the store is never left half-applied. That is why the floor fallback below is safe — a non-zero exit means nothing persisted, so re-applying the conservative floor cannot collide with a partially-written posture.

node "${PLUGIN_ROOT}/scripts/apply-suppressions.js" --confirmed --plan <path>

The script prints the applying confirmation — ✓ Set all K detection categories · set aside N routine results · Ready: … — with both counts threaded from the real write. Show that line to the user.

If --plan is missing or the file is unreadable/invalid, the adapter fails loud (non-zero) and writes nothing — it never falls back to a re-judge. Treat that like the --confirmed failure below: tell the user the write did not complete, fall back to the floor, and continue to step 6.

If the --confirmed run exits non-zero, tell the user the write did not complete, fall back to the floor (onboard.js --floor), and continue to step 6 so setup still finishes.

6. Show the installed summary and hand off to the dashboard

Run the first-run script and relay its install-complete summary AKA_SHOW region per the execution contract (live findings/recommendation counts, the health score, and the per-category posture just written or floored). The script wraps that summary in a Markdown code fence; paste it between the markers exactly as printed and do not add another code fence, strip the fence, or reformat it (it is space-aligned monospace that Markdown would otherwise collapse).

Pass the surfaced count captured from step 3's calibration frame (counts.important) as --surfaced <count> — this is the 'N worth a look' figure the script emits in its own machine-readable handoff payload — but only when step 3 carried a surfaced count forward (it printed a Plan saved to: path). If the calibration fell back to the floor (no plan path in step 3 — a fallback branch, or the scan-ran-clean empty state whose zero-count frame carries nothing to look at), omit --surfaced entirely — the script then withholds that payload rather than fabricating a count.

Alongside it, pass the surfaced live-key count — the number of surfaced live-key secret findings, which is the length of the calibration frame's maskedFindings array (absent ⇒ 0) — as --live-keys <count>. This is the narrower secret subset of the surfaced count; it gates the remediation chain-entry the handoff offers, so a calibration that surfaced only non-secret findings passes --live-keys 0 and offers no remediation.

When --surfaced is passed, the script appends that handoff payload as a single JSON block delimited by <<<AKA_FRAME_JSONAKA_FRAME_JSON>>> after the fenced card. Like step 3's calibration frame, do not show this block to the user — it is additive and machine-only; only the fenced install summary above is user-facing.

node "${PLUGIN_ROOT}/scripts/firstrun.js" --surfaced <count> --live-keys <count>

Then hand off to the dashboard. When the payload carries a positive worthALook count, ask explicitly — per the execution contract's decision rules — using that count for N:

N worth a look — want to see them in the browser?

  1. Review leaked keys — "let's deal with the exposed keys I found" — (offer this option first only when the payload's options include enter-remediation, i.e. liveKeys > 0); entering it starts the secret-leak remediation chain on the surfaced live keys. This composes with — never replaces — the dashboard handoff below, so both stay reachable.
  2. Open dashboard — "open the local dashboard on what I found"
  3. Not now — "stay here — you can open it anytime"

Use the payload's worthALook value for N verbatim — do not invent or round it. Offer Review leaked keys exactly when the payload's options carry the enter-remediation entry (never otherwise); the Open dashboard / Not now handoff is always present. If the payload was withheld (the floor fallback, or nothing surfaced), skip this handoff question rather than inventing a count.

If they choose "Review leaked keys" — run the secret-leak remediation entry's present mode, feeding it the calibration frame block you captured in step 3 (the same text maskedFindings came from) on stdin:

node "${PLUGIN_ROOT}/scripts/remediate.js" <<'AKA_FRAME'
<the <<<AKA_FRAME_JSON … AKA_FRAME_JSON>>> block captured in step 3, verbatim>
AKA_FRAME

It prints the decision as human-facing text, then a machine-readable block delimited by <<<AKA_FRAME_JSONAKA_FRAME_JSON>>> carrying the same decision structured (do not show that block to the user). The human text has three parts, all of which you show to the user verbatim, in order:

  1. the templated count line ("I found N exposed secret keys sitting in old transcripts."),
  2. the fenced finding table (provider, masked token, where, state), and
  3. inside that same fence, a most-exposed-first recommendation line and a secret-scan chaining line.

This entire human-text block is the entry's AKA_SHOW region — relay it per the execution contract, pasting it between the markers exactly as printed — do not drop the recommendation or chaining lines, and do not paraphrase.

Alongside that fenced block, explain the findings in plain language grounded in the same maskedFindings array the block came from — what each finding is and why it matters, not a bare recital of the count line above it. The same grounding discipline as step 4's narration applies here: every count you speak matches the frame's own count, and every value you reference stays masked. With no maskedFindings present there is nothing to narrate beyond the count line and table already shown — do not invent an explanation.

Then ask — per the execution contract's decision rules — offering exactly these four options, in order (each option's label maps to the --option id shown in parentheses):

  1. Redact + rotation checklist (redact-rotation-checklist)
  2. Redact only (redact-only)
  3. Set 'secret' to redact (set-secret-redact)
  4. Leave (leave)

If they chose "Redact + rotation checklist" or "Redact only" — before running the route, ask a second question presenting the standing-posture prompt, offering exactly these four options, in order (each option's label maps to the --posture level in parentheses):

Set the 'secret' detection level

  1. Redact (redact)
  2. Warn (warn)
  3. Block (block)
  4. Monitor (monitor)

Then run the entry's route mode ONCE with the chosen redact option's id AND the chosen posture level, feeding it the SAME calibration frame block again on stdin:

node "${PLUGIN_ROOT}/scripts/remediate.js" --option <id> --posture <level> <<'AKA_FRAME'
<the same block>
AKA_FRAME

Never run the route a second time for this choice — a repeat call would strike the already-redacted keys again and corrupt the reported count. Show its printed result verbatim, in order. For "Redact only" that is the redaction confirmation then the standing-posture confirmation. For "Redact + rotation checklist" it is the standing-posture confirmation then the resolved rotation-checklist summary — which reports the redaction itself, so the script does not print a separate redaction confirmation ahead of it.

If they chose "Set 'secret' to redact" or "Leave" — run the entry's route mode with the chosen option's id (the id in parentheses above, e.g. Leaveleave), feeding it the SAME calibration frame block again on stdin:

node "${PLUGIN_ROOT}/scripts/remediate.js" --option <id> <<'AKA_FRAME'
<the same block>
AKA_FRAME

Show its printed result verbatim — a standing-posture confirmation, or (choosing "Leave") a plain note that nothing changed. This entry reads its findings from the calibration frame alone and holds no wizard state of its own, so it works identically from any caller.

7. Offer the AKA CLI + local dashboard (opt-in)

Now that the plugin is set up, offer the optional AKA CLI + local dashboard — a richer, still-fully-local surface over the same ~/.aka store this plugin writes. The plugin works completely on its own; this is additive (and the path to future multi-agent support). Ask — per the execution contract's decision rules:

Want the AKA CLI + dashboard too? — "The aka CLI adds a local user interface + terminal dashboard and on-demand scans."

  1. Yes, add it (recommended) — "adds the aka command: stats, a terminal dashboard, a local user interface, and on-demand scans"
  2. Not now — "skip — you can add it anytime with the one-liner below"

Yes, add it is the install authorization — run the bootstrap installer directly, with no second question (it downloads the self-contained aka binary for their platform — no Node.js or npm required — and links it onto PATH). Run the line for their OS:

# macOS / Linux
curl -fsSL https://raw.githubusercontent.com/akasecurity/ai-tc/bin-latest/tools/installer/install.sh | sh

# Windows (PowerShell)
irm https://raw.githubusercontent.com/akasecurity/ai-tc/bin-latest/tools/installer/install.ps1 | iex

The one-liner pins to the latest published binary release tag (bin-latest), never main — each binary release (bin-v*) moves that tag to its commit, and the installer verifies the downloaded binary against the release's SHA256SUMS (fail-closed), so a corrupted or tampered download is refused. To pin an exact version instead, set AKA_INSTALL_REF=bin-v<version> before running the line. If no bin-v* release exists yet the one-liner fails closed rather than guessing.

After it completes, point them at aka init then aka dashboard. If they chose Not now, show the one-liner once so they can add it later, and move on — declining keeps the plugin fully functional standalone.

Fail open. This install is optional, so it must never derail the session. If the installer fails for any reason — Node missing, network/registry error, a non-zero exit, or the checksum check rejecting a bad download — briefly report what happened, show the one-liner so they can retry later, and continue the wizard normally. The plugin is already fully set up and works on its own; a failed CLI install changes nothing about that.

Close the wizard. The first-run summary already confirmed the saved posture and pointed at the aka-health skill. Whichever way the CLI offer went — installed, declined, or a failed install you already reported — end with one warm close: "That's it — I'm watching out for Antigravity going forward."

Before you finish, confirm every AKA_SHOW region on the path you took was relayed to the user. If you summarized one instead of pasting it, paste it now.

Known limitations

Antigravity's hook contract is narrower than Claude Code's in several ways that change what AKA can actually do. Be honest about every one of these if the user asks why something wasn't caught — never imply coverage this plugin does not have.

The IDE does not run plugin hooks. Skills and rules from a plugin load in the Antigravity IDE and show under Customizations, but the hooks.json entries appear never to fire there; hooks execute in the agy CLI. Google has not documented this either way, so treat it as observed behaviour rather than a guarantee. The practical consequence is the important part: AKA's live detection and blocking only apply to CLI sessions. Work done in the IDE is not scanned as it happens. The AKA skills still work in the IDE (they read the same local store), and the worktree scan (aka scan) and the dashboard cover IDE work after the fact.

Prompts cannot be blocked or redacted. Antigravity has no UserPromptSubmit equivalent, and its PreInvocation event — the one that fires before the model is called — carries no prompt text. No event on this host hands a hook the user's message before the model sees it, so a secret pasted into a prompt reaches the model. AKA records it (so it appears in findings and the dashboard) but cannot stop it. This is the single biggest difference from the Claude Code plugin, where a flagged prompt is blocked outright.

A redact policy blocks instead of masking. Claude Code's PreToolUse can hand back rewritten tool arguments; Antigravity's cannot — its output is { decision, reason, permissionOverrides } with no field for modified args. So when a policy says "redact", AKA denies the tool call and explains what to remove, rather than masking the value and letting the call run. This applies to file writes too, not just shell commands.

A warn is recorded but not shown inline. PreToolUse's output has no message channel (its reason accompanies a deny), so a warn policy captures and ledgers the finding without printing anything in the session. Point the user at the aka-findings skill or the dashboard to see warns.

Tool results are not scanned live. Antigravity's PostToolUse payload does not include the tool's output at all — it carries the tool call again plus a step index and an optional error. There is no way for a hook to read, rewrite, or withhold a tool result on this host. Secrets that appear in command output are therefore caught after the fact, not before the model sees them.

History is scanned; token usage is not. Because of the two gaps above, the only place prompts and tool results exist for AKA to read is the session transcript — and the historical scan reads Antigravity's real record shape, so secrets in past prompts and model messages are found by this wizard's calibration and by the backfill. Three things in that same file are still not read, and each under-reports rather than mis-reports:

  • Token usage and cost produce nothing. The transcript carries no token, model or cost field at any depth, so the reconcile worker recognizes nothing and usage reporting stays empty for Antigravity sessions. Do not tell the user their token spend is being tracked here.
  • Tool-call arguments are not scan input. A secret sitting in a run_command command line or a write_to_file body is not found by the historical scan. The live PreToolUse hook does scan those, so this gap is about past sessions, not current ones.
  • The truncated transcript copy is skipped. Each conversation stores a complete file and a truncated one; AKA reads the complete file, so nothing is double-counted. A conversation that has only the truncated copy is still scanned, but its longer records were already capped on disk and whatever was cut is not recoverable.

Live prompt capture remains impossible for the reason given above — no event on this host hands a hook the prompt text — so what the historical scan finds is what had already been written to disk.

multi_replace_file_content is not scanned. Its arguments nest the edits in a container whose shape is not documented, so AKA does not guess at it. Single -edit writes (write_to_file, replace_file_content) and shell commands (run_command) are scanned.

A hook that gets stuck denies the tool call, and it will not look like AKA. This host treats a hook that prints nothing as a deny, so AKA's hooks always print an explicit allow — on a crash, on bad input, and on their own 8-second watchdog. That watchdog is a timer, so it cannot interrupt work that blocks the thread: if the local store is heavily contended (several AKA processes writing at once), a hook can be killed by Antigravity's own 10-second timeout before it prints anything, and the user sees "Tool call denied by ". If a user reports a denial with no AKA reason attached, that is the likely cause — it is not a policy decision and there is nothing wrong with their command. Retrying usually succeeds, since the contention that caused it is transient. Do not describe AKA's fail-open guarantee to a user as absolute; it covers every hook that gets a turn on the event loop, which is everything except a thread that is already blocked.

If the plugin's hooks do not seem to fire at all, the likely cause is the ${PLUGIN_ROOT} variable in hooks.json. It is not documented for Antigravity, so each command falls back to the default CLI install location (~/.gemini/config/plugins/aka-antigravity). If the plugin was installed somewhere else, edit hooks.json and replace ${PLUGIN_ROOT:-…} with the absolute path to the plugin directory.

The reversible secret vault is not wired for Antigravity sessions, so this wizard does not offer the vault-consent step: everything AKA redacts here is one-way (the safe direction), and nothing this plugin captures is ever vaulted — even when vault consent was granted through the Claude Code wizard on the same machine. Vault pointers minted elsewhere render as literal [[aka:...]] tokens in Antigravity output (there is no display-side hook to badge them), and a pointer inside a shell command is denied rather than executed or substituted. If the user asks about recovering a redacted value, point them at the vault surfaces that do exist on this machine (aka vault show, the dashboard's Vault page) rather than implying this plugin can reveal anything.

The model-judge step needs an agy with the streaming stdin interface. It runs agy --input-format stream-json --output-format stream-json and writes the prompt to the CLI's standard input, rather than putting it on the command line. An older agy that does not accept those flags exits non-zero and the step reports agy judge subprocess failed, with no detail beyond the exit status — the subprocess's own output is deliberately discarded, because it can echo the raw findings. If a user hits that, the first thing to check is the agy version. Everything before the model pass is unaffected: the calibration questions, the consent-gated historical read and the local ruleset scan all run, and every finding is still detected and redacted locally.

On Windows, a stalled model call may not be bounded. Where agy is a batch shim (agy.cmd, what npm i -g writes), AKA has to reach it through cmd.exe. The 180-second limit applies to cmd.exe, not to the agy process it starts, so a model call that hangs can hold the step open past that limit instead of failing cleanly. If the step appears stuck with no output, that is what it looks like; interrupting it is safe, and nothing is written until the plan is confirmed. This is not specific to this plugin — the Claude Code and Codex wizards reach their own CLIs the same way — and it does not arise where agy is installed as a real executable, which AKA then runs directly.