@akinet/akidevrule 3.7.0 → 3.9.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,55 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.9.0] - 2026-10-29
4
+
5
+ ### Added
6
+ - **WorkBuddy becomes the sixth `SKILL.md` target: `install.mjs` syncs the shared skill corpus to `~/.workbuddy-ai/skills/`, and the router's Delivery section gains a WorkBuddy row whose skill invocation also `Read`s `RULE-agent-behavior.md` once per session.** Evidence: on the owner's machine the router reached WorkBuddy only through a hand-made symlink `~/.workbuddy-ai/skills/akirule` → `~/.claude/skills/akirule`, which was gone again within the day while the app's own skill cache still pointed at that path — manual wiring is invisible to the installer and to the change sweep, so it rots silently. Root cause: WorkBuddy loads the same `SKILL.md` standard but has no `@`-import, managed block or hook surface, so neither the skill root nor the behavior floor had a delivery path in the installer. Mechanism: one more `syncAkiSkills()` call beside Kiro/Grok (real per-folder copy with managed-names-only prune, other skills untouched), and the floor carried by the artifact the installer already ships rather than by writing `app/app-config.json`, which is app-owned state and outside this repo's non-goals. Tradeoff: nothing is resident on WorkBuddy — routing and the floor still depend on the model invoking the skill, and no route gate exists there; naming `akirule` in Settings → Personalization stays a manual per-machine step. Swept together: `install.mjs`, `skills/akirule/SKILL.md` (Delivery + the `(core)` receipt row), `skills/akihelp/SKILL.md`, `README.md`, repo `CLAUDE.md`, `docs/arch/rule-delivery-architecture.md`, `docs/index.md`, plus new `docs/research/workbuddy-skill-delivery.md`, `docs/ref/fact-workbuddy-harness.md`, `docs/plan/workbuddy-skill-target.md`.
7
+ - **`tauri.B8` — Windows: a cross-compile proves it builds, never that it runs. A change touching files, paths or processes runs the test suite natively on Windows before it ships, with the runner traps named (Common Controls v6 manifest in a fresh dir, direct start, pass only on the summary line) and the five Windows semantics that broke a shipped app: append handles cannot truncate (os error 5), `canonicalize` returns verbatim `\\?\` paths, npm global bins are `.cmd`/`.ps1` shims with the package in `node_modules` beside them, `Command` starts only `.com`/`.exe`/`.bat`/`.cmd` from `PATHEXT`, and a test signals only a child it spawned.** Evidence: a Tauri desktop app shipped after `cargo xwin check` passed for x64 and arm64 and its 812 tests passed on macOS; on Windows every start of its managed CLI failed with `Access is denied (os error 5)` (the log was truncated through the append handle the child inherits; Rust std maps `append(true)` to `FILE_GENERIC_WRITE & !FILE_WRITE_DATA`, and `set_len` needs `FILE_WRITE_DATA`), and an npm-installed CLI was labelled a dev checkout at `\\?\C:\Users\<name>` because the code walked up from `<bin>.cmd` to the nearest `package.json`, the user's home folder. Running the same suite natively in a Windows 11 ARM64 VM then surfaced three more failures no compile check could: a test exe that dies at load with `0xC0000139` (it imports `comctl32!TaskDialogIndirect` and carries no manifest), a path assertion with a literal `/`, and a test using its own pid inside a kill-on-close Job Object that ended the run with exit 0 and the suite half run, i.e. a false green. Root cause: the rule corpus had no Windows section, so a green cross-compile read as Windows verification. Mechanism: one section in the existing Tauri rule, symptom first, each bullet a platform fact a model does not derive from `coding` or `test` alone; the native run is tied to `coding.B3` rung 5 and the child-process rule to `test.B3`, both pointed at, not restated. Rejected: a separate `RULE-windows.md` (every fact is reached from a Tauri/Rust project and the `tauri` route already loads on `.rs`); a CI Windows matrix as the only check (a hosted runner spends minutes and is not where a desktop dev iterates; the rule names the native run, not the host). `pattern.B3` gate: no new abstraction; the section replaces "compile passed, so it works" rather than adding a check beside it. Updated together: `payload/RULE-stack-tauri.md` address map `tauri.B1-8`; `skills/akirule/SKILL.md` `tauri` route signals gain Windows build or path, `\\?\`, `PATHEXT`, os error 5 / 193, cross-compile, npm shim (VI: lỗi trên Windows), because a Windows bug report carries none of the existing Tauri signals; `README.md` rule summary; `docs/arch/corpus-map.md` `tauri` row. Checked and unchanged: `payload/route-map.json` and `install.mjs` (the route clause and globs did not change).
8
+ - **`ui.B6` — Popups: one framework-free wrapper owns every popup (`confirm`/`alert`/`toast`/`fire`, the library loaded by a dynamic `import()`), and the look is the library's `--swal2-*` variables mapped to tokens once on `.swal2-container`, outside any `@layer`, with no per-popup class and no `!important`; the modal defaults `reverseButtons` + `focusCancel` + `heightAuto: false` skip toasts, and a toast must not replace an open confirm.** Evidence: an inventory of 11 sites on one Nuxt stack found 11 different wrapper files (758 lines), about 250 lines of near-copied theme CSS with `!important` on nearly every property, variable names that do not exist in SweetAlert2 11.26 (`--swal2-popup-box-shadow`, `--swal2-title-color`), toast offsets forced with `top … !important` in 4 places, and no wrapper setting `focusCancel`, so "focus the safe button" was required on paper and applied nowhere. Root cause: the theme was written as a per-popup class fighting the library's CSS instead of feeding its variables, so it could not be a token mapping and every site re-derived it by hand. Mechanism, each cascade claim measured in Chrome against SweetAlert2 11.26.25 with Tailwind 4.3.3, test styles inserted before the library's own `<style>` (the worst case): variables on `.swal2-container` beat the library's injected `:root` block while a `:root` mapping loses; one class outside any layer beats the library's `:where()` rules for `z-index`, `top`, `height`, `backdrop-filter` and `box-shadow`; a rule inside `@layer` loses (`padding` kept the library value); `text-left` through `customClass` stays `center` while `text-left!` applies; a class `top` loses to the unwrapped toast-position group while `--swal2-container-padding` moves the toast; the mixin focuses Cancel and puts it before Confirm, and an alert with no cancel button still focuses OK; an undefined top-inset token collapses the container to the bottom of the viewport; a toast fired over an open confirm resolves that confirm as dismissed. Rejected: a per-popup theme class with `!important` (cannot be a token mapping, and the measurements show it is unnecessary); a shared npm package for the wrapper (a public rule cannot assume shared infrastructure, and one small copied file is the whole distribution); a copy in `RULE-stack-tauri.md` (this file already governs desktop frontends). `pattern.B3` gate: subtraction first, since the per-site wrappers and theme blocks are deleted rather than packaged; every bullet carries a library fact a model cannot derive from `A2` or Law 8 alone; the z-index scale and token naming stay pointers (`stack.B5`, `A2`). The address `ui.B6` is reused: the earlier drag-and-drop section that held it was cut in favour of `pattern.A9` (3.6.0). Updated together: `payload/RULE-ui-pattern.md` address map; `payload/RULE-stack-akiNuxtCf.md` `B2` dialogs line now points to `ui.B6`; `skills/akirule/SKILL.md` `ui` route signals gain popup, dialog, modal, toast, SweetAlert2 (VI: hộp thoại, thông báo nổi), because an edit to a `.ts` popup wrapper never matches the `ui` file-extension gate. Checked and unchanged: `payload/route-map.json`, `install.mjs` (Antigravity descriptions derive from the route clause, which did not change), `docs/arch/corpus-map.md` (no lens row or group lists `ui.B` items).
9
+ - **Two gates that refuse instead of remind: `plan_lint.py` fails a release on a fully ticked plan still outside `done/`, an unticked box inside `done/`, and a `docs/index.md` link that is dead or points at a file git does not track; `ship_gate.py` refuses an `/akiship` push or deploy when the run's receipt lacks any `S0`–`S8` line, scores a step FAIL, gives a step no evidence or a hedged PASS, lacks a self-interrogation answer, or still holds an unverified `Q`.** Evidence: the painpoint survey below found the decidable violations were rules delivered and broken (44 COMPLY against 3 LOAD), and its plan's decision rule names a mechanism, never more wording, as the fix for a compliance gap; the owner's standing complaint is plans closed long ago with boxes never checked and checks skipped; the first `plan_lint` run on this repo found 10 unticked boxes in 3 plans under `done/`, and the cloud review of this release flagged 6 index links to plans and research that existed on disk but had never been added to git. Root cause: B7's fail-closed contract and `docs.B1` were text the agent reads and can skip; nothing outside the agent read the receipt or the plans. Mechanism: two scripts in `skills/akiflow/scripts/` on the `release_lint.py` grammar (`[TAG] path:line | label`, exit 0/1/2; `[CLAIM]` is a review line that never changes the exit code); `plan_lint` runs at B7 step 5 and in a new `record-lint` CI job beside `release_lint`; `ship_gate` reads the Report's first block written to a scratchpad file and its exit code decides Phase 3 step 4, so an intensity phrase cannot talk past it. `docs.B1` gains `- [-]` for an item closed without being done, reason on the line, so a deliberate deferral passes and a forgotten box does not; the 10 boxes found here were deferrals or verify steps the status line had already measured, now marked that way. Rejected: checking whether a done-claim in chat rests on a run record (judgment, not presence); a Stop hook over every reply (the owner forbade new check steps per reply, and the gate is needed only at push); gating redundant guards or reruns mechanically (each needs a judgment the remeasure on 2026-11-03 will size). Updated together: `skills/akiflow/scripts/plan_lint.py` and `ship_gate.py` (new), `payload/RULE-docs.md` (B1), `payload/RULE-release.md` (B7 step 5), `skills/akiship/SKILL.md` (Phase 2 doc sync, Phase 3 step 4, Report grammar), `README.md` (scripts list), `.github/workflows/install-smoke.yml` (`record-lint` job), three plans under `docs/plan/done/` (boxes marked `- [-]`), `docs/plan/agent-painpoints-oct28.md` (note under Not scheduled).
10
+
11
+ - **`/noyap` skill — the fix procedure behind the `[FLUFF]` card: rewrite the reply just given, or answer the current request, as the shortest text that loses no idea.** Evidence: `agent.A4` already mandates density and `[FLUFF]` existed, yet replies stayed long and the owner's note (task-1793166568668, 2026-10-28) asked for "rút gọn cực đoan … không được mất đi bất kì ý nào quan trọng"; the gap is compliance and intensity, not missing text, and a core line is barred anyway because the generated Antigravity `agent` file is already 25,790 bytes against the 24,000 cap. Mechanism: four slots in a fixed order (Answer · Open items `Q`/`T`/`N` unchanged · Evidence · Notes grouped by what the reader does with them), a unit is an idea not a sentence, a lossless test last ("would the reader believe or do anything different?"), no numeric cap, and a named never-compressed list — the `agent.A3` decision block, a verbatim rule quote with its meaning lines, the `[RULES]` receipt, passed-check names, a failing check's excerpt, a path with its gloss, a word carrying state or negation (đã/chưa/không), any shape another rule or skill mandates; harness-requested preambles and recaps are cut (`agent.B7`: brevity shapes prose, never steps). Two invocations, no persistent mode: bare `/noyap` (or the card, "dài quá") rewrites the previous reply; `/noyap <request>` answers it short the first time. The thinking-channel question is answered by construction — the rewrite's draft is on screen, a fresh answer is written into the slot order with no draft — so nothing can leak and it runs on a model without extended thinking. Rejected: a session mode (invisible, decays unnoticed, ambiguous with "rewrite"); a numeric cap (guaranteed load-bearing loss); delta-only reporting (`A4` exists to re-orient a context-switching reader); a detector script (`[FLUFF]` is judgment); extending `akilint` (mechanical by contract). Four design-time rounds: self-run `/akithink`, an Opus 5.5 clean-context challenger, revision, re-challenge — record in `docs/plan/noyap-skill.md`. Updated together: `skills/noyap/SKILL.md` (new), `skills/akilint/SKILL.md` (description no longer claims `[FLUFF]`), `skills/akihelp/SKILL.md` (painpoint rows split: padded → `/noyap`, wrapped → `/akilint`), `README.md` (skills table, entry points, layout, all six uninstall lists), `docs/arch/corpus-map.md` (Density row names the skill), `docs/index.md`. Same day, revised after the owner measured the first replies under it as longer than before and asked for 10%, at most 40%, of the replaced text with obvious and unimportant ideas gone: an Opus 5.5 `aki-challenger` seat, read-only, judged the skill against 27 replies from 12 sessions and the painpoint survey, and the three measured `/noyap` rewrites had landed at 72%, 87% and 39% (median 72%) with every idea kept. Root cause: the skill was default-allow — the four slots gave every idea a home, the deletion test ran last on ideas already placed, and "would the reader believe anything different" is passed by every true new fact; a first same-day patch (a second half of the test, passed checks dropped, a 40% budget) only stacked guards on that path. Mechanism now: the objective is "the answer, plus what the owner must do or heed", a whitelist of three (receipt · answer · what the owner must do or heed, one plain sentence each with its A4 letter) with a do-or-decide test — an idea stays only if the owner asked for it or would act or decide differently without it; leftovers are settled, never listed (doable → done before replying, unimportant → unsaid, important → self-run `/akithink` to convergence then A3's decision block); an always-cut list (passed checks, files touched, process, seat or run, scope or cost, restated content, hypotheticals, unasked reasoning, self-assessment, harness preambles); a kept-exact list (state and negation words, a failed or unverified claim as a few words on the claim, a command, path, error or version the owner needs, every mandated shape as its rule defines it); the shape persists for later replies to the owner until they ask for detail, with worker briefs, files and commit messages excluded; the owner's ratio stays as a symptom for rewrites only, mandated shapes aside, with no count, script or hook. Rejected this round: tightening the slot test a fourth time (`pattern.A8`); a word counter or Stop-hook measure (the owner forbade new check steps, and forced rewrites at 12–20% still drew objections for what they kept); moving the procedure into `agent.A4` (resident and already the most-broken rule). Closed in this release by the `agent.A4` change below. Updated together: `skills/noyap/SKILL.md`, `docs/plan/noyap-skill.md` (Decisions 2–5, Rejected, Reopen, § Revision), `README.md` (skills table, entry points), `skills/akihelp/SKILL.md`, `docs/index.md`.
12
+ - **Agent painpoint survey over 30 days of Claude Code transcripts on both machines, measure-first: `docs/research/agent-painpoints-oct28.md` (36 recurring owner-corrected behaviors ranked by rows and by distinct sessions, 8 behaviors counted mechanically, uptake per model, corrections per 100 turns split by `[RULES]` receipt, and a LOAD-fail / COMPLY-fail verdict per top-20 cluster), `docs/plan/agent-painpoints-oct28.md` (extractor v3, a regex-recall sample, the 2026-11-03 remeasure with its decision rule, agy as a later item), and the instruments `scripts/akistrict_extract.py` and `scripts/akistrict_loadcomply.py`.** Evidence: the owner's pinned order (task-1793166819433) to list every recurring agent behavior of the past month and to "đo tỉ lệ ăn rule theo model, theo lượt có [RULES] receipt, trước khi vá thêm chữ", because Opus 5.5 and Sonnet 5.5 kept violating rules that 3.8.0's `agent.B7` already targets. Result: 240 regex hits hand-tagged (185 corrections, 55 not), 36 sub-clusters in 22 code families, top by rows P01 verbose reply 29, P09 ignored order 14, P09 open items left 12, P07 redundant verify 9, P16 concluded without reading 8; where the violated rule is decidable it was resident and broken (44 COMPLY against 3 LOAD of 150 top-20 rows, 19 of 20 clusters governed by the always-loaded core), and a first-reply receipt did not lower the correction rate for Mac sonnet-5-5 (1.82 against 1.05 per 100 turns); 103 of 150 rows are undecidable because the extractor records compaction counts, not times. Mechanism: no model call anywhere (the owner's quota floor); transcripts read by one read-only Python extractor run on each machine (the Mac through an AkiMCP task, outputs read in place), tagging by cheap read-only seats under an akiflow council, every P99/NOTC row and the three largest codes ratified by the lead, two challenger passes. Rejected: patching rule wording per cluster before the remeasure (the owner's words, and the decidable evidence says the text was delivered); a `PreToolUse` gate on repeated heavy commands and a numeric cap on runs (same ground as `verify-run-record-oct28.md`); padding the list to the 50 target with singletons (44 entries, 6 short, stated on the research doc's first line; the recall sample is the route to more). Tradeoff: the `CORRECTION` regex has unmeasured recall, so every count is a lower bound and ranks among close clusters are unstable; the plan's first two items buy recall and decidability before the remeasure decides, per family, between a mechanism (compliance gap), a router or gate fix (delivery gap) and no change. Updated together: the two docs, `docs/index.md` (two rows), the two scripts under `scripts/`, and a second `## Amendments` entry in `docs/research/verify-run-record-oct28.md` holding the one non-measurement reopen trigger (a delivery miss gated by a version marker, one incident, no edit); no file under `payload/`, `skills/` or `claude/` changed in this entry. Same-day follow-up: extractor v3 (compaction and receipt timestamps, per-correction delivery fields, `--sample-unmatched`) and a 100-message hand-tagged sample put regex recall at 0.32 [0.26, 0.42], recorded in the research doc's Amendments; no rule text changed.
13
+
14
+ ### Changed
15
+ - **Claude Code's own commit and PR attribution is turned off by the installer: `install.mjs` sets `attribution` (`commit` and `pr` empty, `sessionUrl` false) in every target's `settings.json`, the settings fragment carries the same block, and `agent.B4` shrinks to a residual that names the mechanism; `payload/GEMINI.md` § 5 and `akigitcommit` keep one line each.** Evidence: the owner's pinned note (task-1793258166203) asked to stop the "Đồng tác giả: Claude" line through `~/.claude/settings.json` and to wire it into the installer; the painpoint survey still counted `Co-Authored-By` commands under an ABSOLUTE rule (at most 2 per model row), and a Claude Code 2.1.312 session with no setting still received "End git commit messages with: Co-Authored-By: Claude Fable 5.1 …" and "🤖 Generated with [Claude Code]" for PRs. Root cause: `B4` fought a standing harness instruction with text, the contest `agent.B7` documents the model losing, while the harness has had a setting for it that nobody set (`attribution`, read from the 2.1.312 binary: `commit`/`pr` strings where an empty string hides the attribution, `sessionUrl` boolean for the `Claude-Session` trailer and PR link). Mechanism: `mergeSettings()` assigns the three keys unconditionally, since the rule is ABSOLUTE, and leaves other `attribution` keys and a deprecated `includeCoAuthoredBy` alone; the preview and summary print the state; the smoke test asserts the three values after install. `B4` keeps the forbidden forms, the override of a harness that still injects one (Codex, agy, Kiro, Grok, WorkBuddy, or Claude Code after a config change) and the `git log -1 --format=%B` check; the `B7` row quoting the attribution reminder is dropped because the quote no longer reaches a session once the setting applies and B4's override clause covers its return. Rejected: `includeCoAuthoredBy: false` (the binary marks it "Deprecated: Use attribution instead", and `attribution.commit === ""` already decides first); deleting `B4` from the core (five of six harnesses have no installer-set switch, and the owner asked for a residual); keeping the `B7` row (a quote the setting removes is a dead row, and the generated Antigravity `agent` file already exceeds its cap). Updated together: `install.mjs`, `claude/fragments/settings.akidoc.fragment.json`, `.github/workflows/install-smoke.yml`, `payload/RULE-agent-behavior.md` (`B4`, `B7` table), `payload/GEMINI.md` § 5, `skills/akigitcommit/SKILL.md`, `README.md` (mermaid, install step 3, uninstall), `docs/arch/rule-delivery-architecture.md`, `docs/plan/agent-painpoints-oct28.md` (owner-ordered exception noted). Checked and unchanged: `claude/agents/aki-maker.md`, `claude/agents/aki-conduct.md`, `docs/arch/akiflow.md`, `skills/akiflow/references/harness-facts.md` (each names `B4` in one phrase that still holds).
16
+ - **`release.yml` publishes `@akinet/akidevrule` to npm through Trusted Publishing before the GitHub Release exists: three jobs `verify` → `publish` → `release`, workflow permissions `{}`, actions pinned by commit SHA, no stored npm token.** Evidence: `CLAUDE.md` § Release process ruled publishing "a manual local step" because the account has 2FA on writes and an automation token was the only CI route, which it rejected; npm Trusted Publishing (GitHub Actions OIDC) needs no token, so the stated reason no longer holds, and the owner ordered the same setup already made for `@akinet/akimcp` on 2026-10-29. Root cause: the publish was the one release step that needed a human OTP, so a tag could produce a GitHub Release for a version the registry never received (the reverse of `release.B9`'s order). Mechanism: `verify` (`contents: read`) checks tag == `package.json` version == CHANGELOG heading with `npm run check-version`, then installs the packed tarball into a scratch HOME and starts `install.mjs --help`; `publish` (`contents: read` + `id-token: write`) installs no dependency and runs only the repo's own `prepack`, installs npm 11.21.0 because trusted publishing needs 11.5.1 or newer and Node 22.14.0 ships an older npm, skips a version the registry already has, and polls `npm view` after publishing; `release` (`contents: write`) is the unchanged GitHub Release step and runs only after the registry shows the version. Rejected: an automation token in a GitHub secret (the long-lived credential the old rule refused); `npm publish <tarball>` (npm's docs do not say OIDC works with a tarball). Unverified until the first tag release runs it; a manual `npm publish` stays the fallback until then. Updated together: `.github/workflows/release.yml`, `CLAUDE.md` § Release process.
17
+ - **akiflow Step 4 — a blocker is an item with an owner, never a closing footnote: anything blocking what the anchor asked for becomes an `ITEM` with an owner seat in `checklist.md` when found, and closure may carry `DEFERRED:` only for an act no seat can perform (the owner's hands, or an act the anchor did not order).** Evidence: two consecutive council rooms closed with every remaining blocker written as a `DEFERRED:` line labelled another seat's or another session's work (a stale local tag, two shared-rule edits, an untraced number, an unverified runtime check), so the owner received a debt list nobody owned and had to order each one again; the owner's correction was that every item blocking the mission must have an owner in `checklist.md`. Root cause: the closure step checked that items closed, not that blockers found mid-run ever became items, so deferring was the cheapest way to close. Mechanism: a doctrine line beside the closure rationale, where the lead decides what reaches the owner; rejected a `council_verify.py` check, since whether a `DEFERRED:` reason names an owner-only act is judgment, not presence. Updated together: `skills/akiflow/SKILL.md` § Step 4 only (no other file under `skills/`, `claude/`, `payload/` or `docs/arch/` names DEFERRED).
18
+ - **`coding.B3` checks are gated by the claim, never by the edit: a check runs once per batch, when a claim is about to rest on it, at the tier the named doubt requires; a rerun needs a changed tree under a new claim; doubt about a recorded run is answered by opening its log; a run is reported as a record (command, exit code, log path) that belongs to the tree, not to the seat that ran it.** Evidence: the owner's correction on 2026-10-28 ("đừng có động tí là chạy test được không nhỉ? không thấy thừa à?", a months-old pain by their own words); that day an akiflow lead re-ran `npm test` (710 tests), `nuxt typecheck` and `vue-tsc` on a tree the web lane had just run them on, and a read-only audit turn ran `npx nuxt generate` (91 routes) against `zero-trust.B2`. Root cause: the old `B3` bullet read "after edits → typecheck/lint/related unit tests", a per-edit schedule that licensed a run at every touch and sat beside the bullet that forbids escalating a tier without a named doubt; the one-run bullet then licensed a rerun on "a change in between (an edit by any tool)", so ten edits were ten sanctioned runs; and no layer said a run recorded by another seat counts, so each seat re-ran to own the evidence. Mechanism: the schedule is rewritten from edit-triggered to claim-triggered on the same bullet, the rerun license now needs a new claim on a changed tree, and the run record (exit code captured with `echo "exit=$?"` — the old example's `; tail` reported `tail`'s status, so a red suite could travel as green) is named once in `B3`; akiflow's Step 5 Verify row applies it (the verifier gets each lane's record with the lead's attestation that no edit followed, opens the log, re-runs only what has no such record), `aki-maker`'s output contract reports the record. Rejected: a tree-state fingerprint (`git diff --stat`) in the record — it cannot tell two dirty trees apart and invites trusting a stale record, so the lead's attestation of no edit since replaces it; a `PreToolUse` gate denying a heavy command repeated on an unchanged tree (false denials on flake probes and environment changes; the 2026-10-20 rerun record's remeasure from 2026-11-03 decides, now counting per-edit and cross-seat reruns separately); a numeric cap on runs; new text for junk-test shapes (`test.A1`, `C1`, `C3` already name them). An Opus challenger rejected the first draft (cross-seat record in the root rule, masked exit code, weak tree-state test, a format check standing in for a log check); the shipped text is the second. Extended the same day from a session that closed six "runtime-only" hand-offs by reading code, logs and history with zero live runs (aki-mcp-sv, 2026-10-28): the ladder's rung 1 names the live-client equivalence (a path a live client exercises daily is verified by that client — name the client and the shared function), and the rerun license lets a recorded run, this session's or a live check at a named earlier commit, stand while the diff since it cannot reach what the check observed; a dependency, build-config or shared-module change reaches everything. Rejected there: a `B4` line on lint hits (`agent` §0's card semantics already say every instance, not only the cited one) and an Impact clause for self-run checks (the claim gate and the ladder's kill-test preamble already say it). Updated together: `payload/RULE-coding.md`, `payload/RULE-release.md` (B7 step 6 now points at the claim, not "the moment"), `skills/akiflow/SKILL.md` (Step 5 Verify row, the no-room closing line), `claude/agents/aki-maker.md`, `docs/arch/akiflow.md` (Phase B diagram), `docs/index.md`; decision record `docs/research/verify-run-record-oct28.md` (with its `## Amendments` entry for the extension).
19
+ - **`agent.A4` deletion test asks "would the reader do or decide anything differently with it?", and a `T` item lists only a call the owner might overrule; a call they would make the same way is carried out unsaid.** Evidence: the `/noyap` transcript review above found the old test ("information the reader does not already have") passed by every true new fact, so done-reports listed every call made and every fact learned, and the owner rejected replies at 12–20% of their original length for what they still carried. Root cause: the root rule measured novelty, not consequence, so the skill and the rule disagreed once the skill moved to a do-or-decide test. Mechanism: the test and the `T` definition reworded so the resident rule and the invoked skill apply one standard; the generated Antigravity `agent` file grows 129 bytes to 25,919 against the 24,000 cap already tracked in `docs/plan/agy-rule-loader-epistemic-floor.md`. Tradeoff: a call the agent misjudges as minor goes unsaid; the owner's correction of such a call is the reopen trigger. Updated together: `payload/RULE-agent-behavior.md`, `docs/arch/corpus-map.md` (Density row), `docs/plan/noyap-skill.md` § Revision, `docs/index.md`.
20
+ - **Runtime-only risk is run before it can be called unverified: `coding.B3` sends it to ladder rung 5 (the app on a port of its own, the touched flow exercised, the process stopped before reporting), and `release.B7` step 7 scores `unverified` only what survives rung 5; an unverified flow the accumulation touched blocks push and deploy as a `Q`, and no completion-intensity phrasing waives that (`release.B8`), except a production-only flow (no local, preview or staging run can reach it, the missing dependency named), which B11 checks right after deploy with its rollback stated first.** Evidence: the 2026-10-28 incident in the `### Removed` entry below; deleting the dev-server ban alone left the chain that shipped it intact, as a clean-context Opus 5.5 `aki-judge` review of the diff from 3.8.0 found: `coding.B3`'s runtime bullet went straight from "runtime risk" to an unverified `N`, skipping rung 5; `release.B7` step 7 called "Untested but I expect it works" a valid gate output; `akiship` carried it as a note; and B8's completion-intensity phrasing still unlocked the push. Root cause: "unverified" was a terminal state any seat could reach without trying to run anything, and the gate treated it as passable. Mechanism: the same bullets now route through rung 5 first, and `akiship` Phase 3 step 4 adds "no touched flow left unverified" to the push/deploy condition. Rung 1's live-client equivalence now holds only for code that client runs (name the commit; close only when the diff since cannot reach the path), since a production client says nothing about code the diff just changed; the human hand-off names visual rendering and live integration only when rung 5 cannot reach them (no rendering tool, a credential only the owner holds). Rejected: an unverified item as an `N` with push allowed (the incident's exact path); blocking every deploy on a production-only flow (deadlock, since no local run can reach it; B11 plus a stated rollback covers it). Fixed in the same review: `/noyap` keeps the one-line run record a done-claim rests on, which its "cut passed checks" list had removed; `akiflow` Step 4 no longer lists push, tag and publish as owner-hands-only, which contradicted `release.B9`; `coding.B4` points at the `agent.A4` deletion test instead of quoting its old wording. A second clean-context review closed four more paths: an undefined "production-only" that could relabel a locally reachable flow; B8's stop-only list read as letting the hold drop to a note; "every flow exercised" read as a dev server for statically settled work (now only flows whose risk cannot be settled statically); and rung 5 read as web-only (now also a CLI, binary or installer against a scratch HOME). A run that spends paid credits stays an `agent.B3` ask, reported as a `Q`. Updated together: `payload/RULE-coding.md` (B3 runtime bullet, rung 1, hand-off line; B4 preamble), `payload/RULE-release.md` (B7 step 7, B8 completion-intensity bullet), `skills/akiship/SKILL.md` (Phase 2 verification line, Phase 3 step 4, Report), `claude/agents/aki-maker.md` (output contract), `skills/noyap/SKILL.md`, `skills/akiflow/SKILL.md` (Step 4 DEFERRED line), `README.md` (akiship row). Checked and unchanged: `docs.C2` (an audit marks runtime-only findings unverified because an audit runs nothing), `docs/arch/akiflow.md` and `docs/arch/corpus-map.md` (neither names step 7, the hand-off line or DEFERRED's examples).
21
+ - **`stack.B5` — z-index is one `--z-*` scale ordered modal < dialog < toast, applied as `z-[var(--z-*)]` in templates or `z-index: var(--z-*)` in CSS, because Tailwind v4 builds a `z-<name>` utility only from a `--z-index-<name>` theme key; stacking local to a component stays a plain utility, max-int only for UI injected into third-party pages, and the built CSS is grepped for the toast rule.** Evidence: in a desktop frontend on Tailwind 4.3.3 a toast sat under an open modal because `z-toast` emitted no CSS; the project's scale was named `--z-*`, so `z-toast`, `z-modal` and the rest produced nothing. Root cause: Tailwind v4's `z` utility reads only the `--z-index` theme namespace (`themeKeys:["--z-index"]` in its dist), and the old line, "a scientific z-index system (`--z-index` variables)", read either as "name the scale `--z-index`" or as "variables exist, so the class works"; the second reading ships a dead class with no build error. Mechanism: one `--z-*` scale referenced through `var()`, so the same token works in a template arbitrary value and in plain CSS, with a fixed order so a toast is never under a modal, drawer or dialog; the built-CSS grep is the check because a missing utility fails silently. Rejected: renaming the theme keys to `--z-index-*` so `z-toast` resolves (works, but splits one token into two forms: the named utility in templates, `var(--z-index-*)` in CSS and arbitrary values), and a `--z-index-*` alias beside the scale (the same split, now named in the line); restating a full chrome order (topbar, sidebar, chat panel) in a public rule (that order is a site's own layout convention, so the line keeps only the steps every popup stack needs). Sharpened the same day after a review: the line names which SweetAlert2 selector takes which step, because a site that copies the popup CSS block without a `--z-dialog` token gets an invalid `z-index` and the dialog falls under the open modal; it bounds `z-10` to one component's own box; and the check is two-sided, because the built-CSS grep passes while another layer still carries a dead `z-<step>` class. Updated together: `payload/RULE-stack-akiNuxtCf.md` `B5` (the radius sentence moves to its own bullet, unchanged); `payload/RULE-ui-pattern.md` `A2` now points to `stack.B5` instead of restating the scale. Checked and unchanged: `skills/akirule/SKILL.md` (the `ui` route already carries modal, toast and design token, no missing concept), `docs/arch/corpus-map.md`, `payload/route-map.json`, `install.mjs` (none references the line); `docs/research/public-private-abc-restructure.md` keeps its historical wording.
22
+
23
+ ### Removed
24
+ - **`coding.B3` no longer says a dev server or a live network call "stays user-triggered"; the agent may run the app to verify a change, and `aki-maker` no longer forbids a build or dev server on its own initiative.** Evidence: on 2026-10-28 a two-repo release session (web app plus compute hub) pushed a version to production that broke in the first real use: video files were refused at upload, two new engines would not open, and the local dev server crashed on a missing column. Nobody had opened the app. The agent handed the UI check to the owner because the rule said a dev server is the owner's call, and the release gate (`release.B7` step 7) accepts "unverified" as a passing output. So under a "finish everything, then release" order the check fell to no one. Root cause: the sentence came into the shared corpus on 2026-07-23 (`bb34dfe`), moved from a machine-local file with "cost and side effects are the user's call" as its only reason and no incident behind it; the 2026-09 change that freed build and test (`release.B7` step 6) left it in place. Mechanism: deletion only. The real costs it guarded are already owned elsewhere: paid calls by `agent.B3` (ask before spending credits), leftover processes by `agent.B1` (what you create, you remove), and proportion by `coding.B3`'s first bullet (never a dev server to catch what a typecheck catches). The narrow guards specific to this machine (own port, never the owner's running server, stop it before reporting) stay in the owner's local file. Rejected: keeping the ban and adding a release exception, because two rules pointing opposite ways is the gap that caused the failure. Checked and unchanged: `METHOD-audit-zero-trust.md` step 2 (an audit runs detectors, not the app), `skills/aki-article-writer/references/article-workflow.md:364` (says no dev server is *needed*, not forbidden). Updated together: `payload/RULE-coding.md`, `claude/agents/aki-maker.md`.
25
+
26
+ ### Fixed
27
+ - **`scythe.py` closes a Markdown code fence only on a bare run of the opening character at least as long as the opening run, as CommonMark specifies, so a three-backtick line inside a four-backtick block is content.** Evidence: on 2026-10-22 a plan doc whose four-backtick template held a three-backtick `css` block drew 4 `[WRAP]` findings on CSS declarations (`.a {` followed by an indented property) and left the prose after the block unlinted, because the inner fence closed the outer one and the outer closing fence then opened a new block. `agent.C3` itself tells authors to fence copy-ready artifacts with four backticks precisely because they contain fences, so the lint punished the form the corpus requires. Root cause: the fence matcher toggled on any line starting with three backticks or tildes and never compared the closing run with the opening one. Mechanism: the opening run (`` `{3,} `` or `~{3,}`) is kept; inside a block only a line whose run uses the same character, is at least that long and carries no info string closes it; everything else is body, linted as before when the fence names a language. Rejected: a per-file exemption or an ignore marker (hides real wraps after the block; the parser was wrong, not the doc); counting only backticks (tilde fences follow the same rule). Verified: a fixture with a four-backtick `markdown` block holding a three-backtick `css` block, a wrapped prose pair, a `js` block with a wrapped comment and a tilde block: the old script reports the false `[WRAP]` at the CSS lines plus the three real findings, the new one only the three real findings; `--all` over this repo, two other standards corpora and one app's `docs/` gives byte-identical output before and after apart from that fixture; the plan doc that surfaced it is now clean. Updated together: `skills/akiflow/scripts/scythe.py` only; no rule text, address or route changed.
28
+ - **Antigravity 1.4.7 now loads the two stack rules and routes from the router's full text: `globs` is rendered as one quoted comma-separated string, every generated description carries the route clause plus the full bilingual `Signals` column, `skills.json` registers one absolute `agskills` entry and expands and deduplicates leading-`~/` paths without removing anything else, `payload/GEMINI.md` gains one narrow negative-claim rule and the canonical lookup boundary, and the agy model facts are re-labelled by evidence class.** Evidence: the agy 1.4.7 log (`cli-20261026_173837.log`) records `cannot unmarshal !!seq into string` for both `glob` rules because `install.mjs` emitted YAML sequences, so neither stack rule could attach by file match; the generated `akirule-deep-think.md` had no `Signals` (the installer parsed only the clause column), and `METHOD-deep-think.md` stayed unrouted in the session that made an unverified capability claim; `~/.gemini/config/skills.json` carried tilde and absolute duplicates of the same root; `scripts/test-agy-bias.sh` still defaulted to `gemini-3.7-flash-high` and `harness-facts.md` still listed the 4-6 Claude slugs while `agy models` lists `gemini-3.8-flash-*`, `claude-opus-5-5-*` and `claude-sonnet-5-5-*`. Root cause: one hand-written YAML shape that predates the vendor's string-only `globs`, a router parser that returned a single column although the table has two, an installer that appended the tilde form on purpose, and model facts recorded without separating a live `agy models` listing from strings read out of the binary. Mechanism: `AG_RULE_MAP` keeps each entry's globs as an array and renders `JSON.stringify(globs.join(", "))` (3 Tauri and 9 Nuxt patterns, none added or removed); `routerRoutes()` returns `{ clause, signals }` per row and both consumers read it (the install summary uses `clause` only); `updateSkillsJson()` appends the absolute own root, expands a leading `~/` through the existing `expandTilde`, drops later entries with an already-seen absolute path and spreads each survivor so extra fields and order stay; `GEMINI.md` § 7 adds "no closed-world negative claims" (a pretrained prior or one tool schema never proves a capability is absent; check the authoritative current source or mark the claim unverified) and § 3 restores `and passes no judgment` to the lookup exemption; `harness-facts.md` lists the 1.4.7 live-visible slugs, marks `gemini-3.1-pro-*`, `gemini-3.1-flash-lite-preview` and the `-max` Claude slugs `[obs-static]` (registered in the binary, never invoked), records the `invoke_subagent` tier words (`inherit`, `flash_lite`, `flash`, `pro`) as the contract rather than any server-side backend such as `M322`, and gives the headless command for a specific model; re-verified on agy 1.4.8 (2026-10-28), the same slug families stay live-visible, the live consumer rows that named `gemini-3.1-pro-*` now name `gemini-4-argon-*` (also the pro-tier example in `scripts/test-agy-bias.sh`), and a new `harness-facts.md` § agy quota by plan records the per-plan structure read from `agy -p "/usage"` and the `RetrieveUserQuotaSummary` / `GetUserStatus` RPCs (Free: `weekly` only, no `5h` bucket and no `Gemini 4 Argon` group; Pro: `5h` + `weekly` plus a separate weekly-only `Gemini 4 Argon` group; Ultra: `5h` + `weekly` with Argon merged into `Gemini Models`). Rejected: embedding the globs as a YAML flow sequence (still a sequence); a second hand-kept signal table (the drift this fixes); stripping tilde or legacy `claudedoc` entries (foreign config, not installer garbage); new text in `agent.B2` or `agent.A3` (the existing source-of-truth and verification rules own it; reopen on a reproducible miss after this lands); a `how/why not` trigger (an explanation without judgment stays a lookup). Verified: the extended installer smoke fails 24 collected assertions against the previous `install.mjs` and passes against this one, and a scratch-HOME install shows `globs` as one string, all 19 router rows reproduced in their descriptions and no `[object Object]`; a seeded `skills.json` (tilde entry, its absolute duplicate, a foreign entry) holds two entries after two installs, the second run byte-identical; no live `agy` call was made, so injection by glob and the routing canaries are unverified. Not fixed here: the generated `akirule-agent-behavior.md` (25,790 bytes) and `akirule-release.md` (49,607 bytes before this change, the plan's F2 figure; 49,966 after the Signals were added) still exceed the 24,000-byte per-file cap (`docs/plan/agy-rule-loader-epistemic-floor.md` Phase B). Updated together: `install.mjs`, `payload/GEMINI.md`, `skills/akiflow/references/harness-facts.md`, `scripts/test-agy-bias.sh`, `.github/workflows/install-smoke.yml`, `docs/arch/rule-delivery-architecture.md`, `docs/research/rule-delivery-force-load-sep25.md` and `docs/research/core-floor-promotion-aug6.md` (dated amendments), `docs/index.md`, the plan's status; `README.md`, `claude/agents/aki-hands.md` and `skills/akiflow/SKILL.md` were checked and needed no change.
29
+
30
+ ## [3.8.0] - 2026-10-20
31
+
32
+ ### Added
33
+ - **The installer offers an accuracy-first config for rtk, opt-in: a terminal prompt defaulting to no, `--rtk` to say yes without one, and one summary line either way** (`install.mjs`, `README.md` § Optional: rtk, `coding.B3` one bullet). Evidence: on the dev box rtk 0.50.0, hooked into Claude Code's Bash tool, merged two `ls` listings and cut `jq` lines at 120 characters while an agent was reading them as evidence; the research (`docs/research/rtk-output-loss-oct19.md`) measured the rest raw against filtered — `ls` drops names ending in `.` with no marker, `grep` 211 of 480 lines, `git diff` 610 of 7,541, `git log` 10 commits with no "more" line — and found the recall hints followed 3 times in 480 elisions; upstream has no lossless mode (#1313 open since 2026-04) and counts dropped bytes as savings. Root cause: rtk's built-in Rust filters run before any `filters.toml`, so the only lossless control is `[hooks] exclude_commands` in its `config.toml`, which nobody sets by hand. Mechanism: `rtkDetect()` runs `rtk config` and takes the path from its `Config:` line (macOS keeps the file under `~/Library/Application Support/rtk/`, Linux under `~/.config/rtk/`, verified on both), the question is asked before "Installing..." so the run has no mid-install prompt, and `rtkConfigure()` makes the smallest change — no file → write, no `[hooks]` → append, `[hooks]` without the key → insert it, the user's own `exclude_commands` → keep and list what is missing, a `# akidevrule: rtk off` line → skip; the file is backed up like `settings.json` and the backup dropped on success. The `coding.B3` bullet covers what stays compressed: output carrying an elision marker is a sample, rerun raw before a count, quote, failure list or absence claim is taken from it. Rejected: writing the config on every install (shared third-party config and the repo's Non-goals on personal settings — the owner's ruling is ask, default no); a `[retriever]` table in the managed content (the Mac runs rtk 0.47.0 with no sqlite store; left as a README line for 0.50+); lossless `filters.toml` overrides (unreachable for the Rust filters, and any edit silently cancels `rtk trust`); recommending against rtk (the noise class saves real context at no cost to evidence). Verified: sandbox-`HOME` fixture with a fake `rtk` on `PATH` (absent → hint; present without `--rtk` → untouched; `--rtk` → written; re-run → byte-identical, no backup left; other table → appended; `[hooks]` without key → inserted; user list → kept with missing names; opt-out → skipped), then real rtk 0.50.0 reading the generated file through `XDG_CONFIG_HOME` with the hook JSON: `ls`, `grep -rn`, `git -C … diff`, `jq`, `cd … && ls | head` pass raw and `git status` is still rewritten; the same cases run in `install-smoke.yml` on all three OSes; the exclusion is honoured from rtk 0.47.0 (changelog, and the same hook test on the Mac) through 1.0.1 (the dev box upgraded and re-tested the same day: `sh -c 'ls -la'` still raw, `RTK_DISABLED=1` still honoured), with the Windows path (`%APPDATA%\rtk`) taken from rtk's `user_dirs.rs` rather than observed. Updated together: `README.md` (TOC, install step 7, § Optional: rtk, uninstall), `docs/arch/rule-delivery-architecture.md` installer paragraph, `docs/arch/corpus-map.md` "what a passing check proves" lens, `docs/index.md`, `docs/plan/rtk-accuracy-first.md` (executed, P4 scheduled), `docs/plan/full-file-reads.md` F5/V3, the research doc's `## Amendments` (macOS path, Mac version).
34
+
35
+ ### Changed
36
+ - **`agent.B1` names pull requests, deploys and tags beside commits and pushes, and adds "the request is the whole scope": a step the request did not name — the PR after a commit, the push after a fix, the deploy after a build, the usual next step of a workflow — is not taken because it is customary or looks helpful; finish what was named, then stop and report (`A3`).** Evidence: on 2026-10-08 the owner asked an agent for one added comment line in a repository and the agent also opened a pull request (PR #1) nobody had asked for; the owner's correction was that his instruction outranks both harness instructions and the model's trained habits. Root cause: `B1` listed commits and pushes but not PRs or deploys, and nothing said that a workflow's customary next step is still an unrequested step — `B7` covered harness text only, so a habit learned in training read as neither an instruction nor a violation. Mechanism: one widened bullet and one new bullet in `B1`, plus one sentence in `B6` ranking the model's trained defaults (the workflow it usually follows, the next step it usually takes, a convention from other projects) below every instruction, since they are not instructions at all. Rejected: a new `B8` section (restates `B1`/`A3`; the gap was two missing nouns and one missing concept); a `B7` table row (`B7` quotes harness text, and a trained habit has no quotable source). Updated together: this entry only; no address, route or signal changed.
37
+ - **`agent.C5` reduced to two rules plus the existing `scripts/` line: no file the task can do without and none outside the scratchpad, one session folder only where the harness gives none; `agent.B1`'s "what you create, you remove" now covers anything the agent or a command it ran created outside the harness scratchpad and says nothing about the scratchpad itself.** Evidence: across 516 of the owner's Claude Code transcripts (2026-10-20), 528 `rm` commands in 131 transcripts mostly deleted the agent's own throwaway files (scratchpad 288, `/tmp` 97), and a machine-local command gate spent 143 of its 212 permission prompts on `rm -rf` confirmations that stalled unattended runs; the owner's standing order (one session scratch folder, no `.bak` copies or `verify`/`shots` folders) had no home in the corpus. Root cause: the corpus itself ordered the deletion — `B1` listed temp files among what the agent must remove and the previous `C5` said to delete the session folder before reporting — while the harness already discards its scratchpad, so every run paid a create-then-`rm` cycle and, under a command gate, a prompt. Mechanism: subtraction first — `B1` trades its file-type list for a scope — anything the agent or a command it ran created outside the harness scratchpad — so a throwaway written in the project tree, `/tmp` or the home directory, or a tool's own output (`npm pack`'s `.tgz`, a screenshot), is still removed by the agent while the scratchpad is left to the harness, `C5` shrinks from six bullets to two rules plus the `scripts/` line, and the scratchpad's lifetime is the harness's default; the prompt itself was removed where it is raised, by teaching the machine-local gate that an `rm` confined to temp locations is not a danger. Rejected: a new hook that denies scratchpad `rm` (a second gate layered on the one that prompts — the fix belongs in the gate that asks); dropping files from `B1` entirely (prevention only: a throwaway written outside the scratchpad in breach of `C5` then had no removal duty, and `test.B3`, which applies `B1` to a suite's temp dirs, outgrew its own root); a closing `git status` step or an end-of-session untracked-file hook (one more ritual or layer, blind to ignored files, and a hook cannot tell the agent's files from the owner's work in progress — reopen only if `/akiopen` keeps finding untracked side copies); a fixed absolute scratch path (each harness and machine differs); a rule forbidding hand-cleaning of the scratchpad (a layer over the harness default; once the command gate stopped prompting on temp `rm`, the cleanup costs one call and no prompt). Updated together: `claude/agents/aki-maker.md` and `claude/agents/aki-hands.md` (`C5` gloss), `docs/research/agent-churn-temp-rerun-oct20.md`.
38
+ - **`coding.B3`: one run per change state.** Evidence: in the same 516 transcripts, 507 of 2,522 verification runs (20%) repeated the same check type with no edit by any tool in between; 396 of those (78%) followed a run whose output had been piped through `grep`/`head`/`tail`, a subagent ran in between in only 8 (1%), and a byte-identical rerun happened once — the waste is output thrown away by a filter, not distrust of a worker. Root cause: `B3` said which check fits which moment but nothing about keeping a run's output, so the filter discarded evidence and the only way back was another run. Mechanism: a long check runs once with its output kept in the scratchpad and later questions grep that file; a rerun needs an intervening change or a written reason (flakiness probe, baseline, raw output after an elision marker) — the one case `agent.C5` names for writing a file. Rejected: a transcript lint (a count cannot tell a legitimate flake probe from waste); banning output filters (they keep the context small). Updated together: `docs/research/agent-churn-temp-rerun-oct20.md`.
39
+ - **The path → rule map is one data file, `payload/route-map.json` (installed to `~/.aki/akidevrule/route-map.json`), read by `aki-route-guard.mjs`, `scripts/second_hop_audit.py` and `skills/akiflow/scripts/suite_lint.py` instead of three copies in code.** Evidence: the map lived only as code in the hook (`CODE_EXT`, `FRONTEND_EXT`, `TEST_NAME`, `TEST_DIR`, `routesFor`, `isUngatedPath`, `isNuxtProject`, nothing exported), and the audit's hand copy had already drifted from it — no `ui` for `.tsx`/`.jsx`/`.svelte`, `docs` only under `docs/`, no `content` route, `stack` on every `.vue` with no Nuxt condition, no `stack` for `.ts`, a shorter code-extension list — so the read rates the audit printed described a different set of edits than the gate denied; `suite_lint.py` expanded a directory with a third copy of the test signature; AkiMCP's rule gate must push the same routed rules to web AIs that have no hook and knows only `CLAUDE.md`/`AGENTS.md`. Root cause: the mapping was written as logic in the one consumer that existed first, so each later consumer copied it. Mechanism: one JSON file, `routes` (each with `rules` and any of `ext`, `name`, `nameRe`, `dirRe` + `dirSkipExt`, plus `projectHas`, file names of which any one must exist at the project root) and `ungated` (path segments, prefixes, directory names); regexes use only syntax JavaScript and Python read alike; every directory route matches the project-relative path; the hook fails open when the file is missing, the two scripts exit 2 with a message. The harness-config-dir and outside-project checks stay in the hook, a deviation from the plan's D2, which listed them as data flags: only the hook needs them, and AkiMCP's gate uses the segment/prefix/dir list alone. Rejected: exporting `routesFor` as a module (Python and AkiMCP cannot import it, and AkiMCP would execute code from `~/.claude/hooks/`, which exists only where Claude Code assets are installed); AkiMCP keeping its own copy (the audit's copy already drifted); leaving the audit on its copy (it keeps measuring something other than the gate). Verified: 17 sample paths plus 2 Nuxt cases (test files, `src/x.js`, `docs/spec/a.md`, `a.tsx`, `pages/a.vue` with and without `nuxt.config.ts`, `src-tauri/x.json`, `locales/vi.json`, `~/.aki/x.md`, `/tmp/x.js`, a path outside `cwd`) gave byte-identical deny lists before and after; with the map file removed every edit is allowed. The audit's numbers change once and are not comparable across the switch: on the Mac's transcripts, in the "before" era, sessions routed to `docs` went 94 → 128 (any `.md` now, not only under `docs/`), `stack` 41 → 40, `tauri` 6 → 8, and a `content` route appears. Updated together: `payload/route-map.json` (new), `claude/hooks/aki-route-guard.mjs`, `scripts/second_hop_audit.py`, `skills/akiflow/scripts/suite_lint.py`, `skills/akirule/SKILL.md` (delivery bullet names the file), `README.md` (gate paragraph, payload layout, hook list), `docs/arch/rule-delivery-architecture.md` (gate section), `docs/index.md`; the shipping assertion for the file in `.github/workflows/install-smoke.yml`. Plan: `docs/plan/done/route-map-json.md`; the file ships at `~/.aki/akidevrule/route-map.json` and `aki-mcp-sv` picks it up through its own plan's dependency section.
40
+ - **A rule file counts as read only when read whole: the route gate stops counting `limit`/`offset`/`head`/`sed`/`tail` reads, and on Claude Code a partial `Read` of a rule file is rewritten into a whole one (`agent.B7` gains a row for the `Read` tool description).** Evidence: on 2026-10-19 a Sonnet worker briefed to read `RULE-agent-behavior.md` and `skills/akirule/SKILL.md` called `Read` with `limit: 40` and `limit: 30`, then opened its reply `[RULES] agent,akirule,docs (brief)`, naming two files it had seen the first fifth of; baseline on the Mac (2026-10-20, `second_hop_audit.py`): main sessions 44 of 1,164 rule reads partial (3.8%), subagents 34 of 440 (7.7%); on the Linux dev box 64 of 1,345 (4.8%). Root cause: Claude Code's `Read` description says "When you already know which part of the file you need, only read that part" and `agent.B7` had no row for it; the gate matched a `Read` by file name alone, so a partial read marked the file read, and the audit counted the same way and could not see the gap; a read-only worker never meets an edit gate. Mechanism: F1 — `scanTranscript` counts a `Read` only when `offset` is absent or ≤ 1 and `limit` is absent or ≥ the file's line count, `cat`/`bat`/`less` in Bash/Shell keep counting, `head`/`sed`/`tail` never do, and the deny reason adds "A Read with limit/offset or a head/sed/tail print does not count — read the whole file." when only partial reads were found; F2 — the hook also runs on matcher `Read` (registered by `install.mjs`) and rewrites a partial `Read` of a rule file (`~/.aki/akidevrule/*.md` or a `SKILL.md` under `~/.claude/skills/`, judged on the resolved path, at most 60,000 bytes) into a whole `Read` through `PreToolUse` `updatedInput` with `permissionDecision: allow`, so there is no extra round trip; above 60,000 bytes the `Read` tool's ~25k-token cap makes a partial read the only possible one, so it passes; F3 — the `agent.B7` row, covering a file a brief names "in full" that is not a rule file, and harnesses without the hook; F6 — `second_hop_audit.py` prints `rule reads: N (partial K, P%)` for main and subagent and no longer counts a partial read as a read. F5 unchanged: Bash `cat` stays counted. F4 (receipts carrying line count and last line, `agent.A5`) is deferred: evidence of partial reads exists only on Claude Code, where F2 now removes them mechanically; reopen on a partial rule read observed in a worker on a harness without the hook (agy, Codex, Kiro) or a receipt naming a file the worker did not read whole. Rejected: deny instead of widen (a round trip per partial read, and a model may retry partially); denying `limit`/`offset` on every `Read` (partial reads of large code files are correct); wording only (the second hop was re-worded twice, 2026-08-06 and 2026-09-25, without moving the read rate); F4 now (no evidence outside Claude Code). Hardened after an adversarial review the same day: `permissionDecision: allow` skips the permission prompt, so widening applies only to the corpus's own files after `realpath` (a `../` path or a `SKILL.md` elsewhere passes untouched); the transcript records the model's original `Read` input, not `updatedInput`, so a widened read is recognised by the hook's own attachment for that tool-use id and counts as whole; the denial fail-open counts only attachments carrying `"permissionDecision":"deny"`, since the widen output also names the rule; a Bash `cat` counts only as the command word of its segment and not when piped onward (`cat x | head`, `git cat-file` no longer count). Cost: about 29 ms per non-rule `Read` (one `node` start), measured. Verified live on Claude Code 2.1.303 (2026-10-20): a `Read` of `METHOD-proportionality.md` with `limit: 5` returned all 63 lines. Updated together: `claude/hooks/aki-route-guard.mjs`, `install.mjs` (matcher, printed summary), `scripts/second_hop_audit.py`, `payload/RULE-agent-behavior.md` (`B7` row), `skills/akirule/SKILL.md` (delivery bullet), `claude/CLAUDE.md` (gate paragraph), `README.md`, `docs/arch/rule-delivery-architecture.md` (gate section, the read-only-reviewer sentence), `docs/index.md`. Plan: `docs/plan/done/full-file-reads.md`.
41
+ - **`skills/akiflow/scripts/test_lint.py` renamed `suite_lint.py`.** Evidence: the script's own name matched the `RULE-test.md` route's `^test_.*\.py$` signature, so `test_lint.py --all .` linted itself as a test file (`[EXIT]`, `[HOMEREAD]` on its own exit calls and HOME read), the route gate demanded `RULE-test.md` before any edit of it, and pytest would collect it as a test module. Root cause: the name followed the `test_*.py` convention test runners treat as a test file. Mechanism: rename inside the `<domain>_lint.py` family (`release_lint.py`) without the `test_` prefix; the installer's per-skill mirror removes the old deployed copy and the skill-script allowlist is generated from the script inventory. Rejected: narrowing the route signature (`test_*.py` is the real pytest convention and must keep routing). Updated together: `payload/RULE-test.md` (`test.D1`), `README.md` (layout), `docs/index.md`, `docs/arch/rule-delivery-architecture.md`.
42
+ - **The installer smoke test behaves the same on a developer machine as in CI.** Evidence: run locally on 2026-10-20 it failed twice where CI passes — `route gate did not deny an unread code edit` when the throwaway HOME sat under the session scratchpad, a path `route-map.json` ungates, and `rtk absent: hint line missing` when a real `rtk` was on `PATH`. Root cause: two fixtures inherited ambient state, the HOME location and the caller's `PATH` (`test.C2`). Mechanism: the gate probe edits a never-created project at the filesystem root instead of under HOME, and the rtk-absent case runs with every `PATH` entry holding an `rtk` binary removed. Rejected: documenting a required local setup (a hand-off the fixture itself can remove).
43
+ - **`agent.A3` rebuilt on one root — understand what the owner asked, act only on an order — with the turn's first state-changing call bound to naming the words that order it; an order runs to the end without asking.** Evidence: on 2026-10-20 an agent with `A3` resident turned an owner question that hid its only `?` behind a hedge ("có thể là ghi thành notes …?") into a notes edit, then answered the correction with a second unordered `git restore`; asked to classify the same messages afterwards, it classified every one correctly. Eleven corpus changes since 07-23 moved this boundary back and forth — seven limiting action, four pushing it — and 108 clauses across the corpus restate one side or the other (`docs/research/question-vs-action-oct20.md`). Root cause: recognition was never the failure; `A3` asked for a judgment at no moment, while the rules that hold (`B4`) bind a literal cue to a moment, and the corpus named no root, so each incident added a counterweight. Mechanism: the root sentence, the hedge and polite-order cues ("can you fix X?" is an order), the check before the first state-changing call (anything beyond reading and checking: no ordering words, or words that read both ways, no call), and over-asking on ordered work named as an equal failure; the reversibility bullet and the one-line-suggestion bullet are removed as duplicates of `B3` and the new `A4` `N`; on a communication turn the decision block is the answer. Rejected: a `PreToolUse` gate on question-shaped messages (a per-language heuristic beside the route gate), a turn-class marker in the receipt (self-reported), a per-turn classifier call (paid quota), moving the case lists to `METHOD-deep-think.md` or a references file (Antigravity, Codex and workers would not load it at the moment it governs).
44
+ - **`agent.A4` defines what an open item is — only what this turn cannot finish — and codes each by what the owner's silence does to it: `Q` (question · quyết) silence blocks, the owner must answer; `T` (taking it · tự làm) silence proceeds, a call the agent makes within the order, the `A3` decision block included; `N` (note · nhớ) silence changes nothing, a hold, a caution or an idea outside the order. Doable work is done, never listed; a release is one closing line once no `Q` is open; findings and options inside an analysis are numbered, never coded with these letters.** Evidence: 1,260 coded items in 298 open-item blocks across 254 Claude Code and 500 agy CLI sessions (2026-08-28 → 10-20), one letter carrying up to four meanings (`S` gate step, design option or task; `V` unverified or closed); 3,905 owner messages, of which an estimated 274 ask "done yet / why is it left", 222 ask for a shorter summary, 60 ask where an item is recorded and 54 ask what an item means or whether it matters. Root cause: `A4` gave three example letters by kind of work, so the owner had to read each item to learn whether it needed him. Mechanism: the owner's silence has exactly one consequence per item, so three letters partition every item and a new kind of work needs no fourth; listed `Q` → `T` → `N`, the owner stops reading once no `Q` is left; each letter reads in English and Vietnamese. Rejected: kind letters (`D`/`T`/`V`/`S`…), `D` (`D1` is Cloudflare's database), `P`/`W` (the owner's window handles), `S` (gate steps), `G` for "go" (a code would read as a run order; already labels goals in a plan), `M` (Apple `M1`), `H` as first applied (mixed an act only the owner's hands can do with a passive wait), announce-then-proceed outside the order (acts unordered, `A3`). Research: `docs/research/open-item-codes-oct20.md`.
45
+ - **`agent.B3` asks only for what the order did not name ("Ask before, unless the order names the step:"), and the `B7` row for "When you have enough information to act, act" adds that the sentence never turns communication into an act.** Evidence: `B3`'s list asked even when the owner's order named the step, so the already-authorized kill-test inside `A3` never reached it; the act-now sentence first appears in this machine's transcripts on 2026-09-04, when the owner reports the failure grew. The shared-standards line stays: it guards rule corpora and templates other repos consume. The documented-design line now asks only for a conflict the order did not name, so naming a change never waives the conflict it hides.
46
+ - Updated together: `payload/RULE-release.md` `B8` (pointer only, the over-asking restatement removed, the stale "durably authorized" clause replaced by `B3`'s new header), `payload/GEMINI.md` §8 and §12 (the "ambiguous task → stop and ask" line now names `A3`'s escalations, "can you fix X?" is a task, a correction of ordered work resumes it, CHECK 1 asks whether the user's words order the step instead of whether they literally name it; the file's deliberate repetition is kept), `skills/akiship/SKILL.md` (activation condition 2, a pointer; unverified leftovers are `N` items), `payload/RULE-coding.md` `B3` (runtime-unverified items and the hand-off ledger are `N` items, `Q` when a run waits on one), `agent.A3` (the decision block is a `T`), `skills/akithink/SKILL.md` (a decision record is proposed, not written, on a communication turn), `docs/arch/corpus-map.md`. Unchanged because still true: `coding.B3`'s kill-test pointer, `aki-challenger`, `aki-judge` and akiflow cite `A3`'s kill-tests, which stay.
47
+
48
+ ### Fixed
49
+ - **The installer left `*.akidevrule-backup-*` files beside every file it touched, two per file, after every run.** Evidence: a dev box carried five such files under `~/.gemini/antigravity-cli/`, `~/.kiro/settings/` and `~/.cursor/` from runs on 2026-09-26 and 2026-09-28, kept by design. Root cause: `backup()` treated a pre-write copy as a permanent artifact and `pruneBackups()` kept the two newest, so every successful run converted rollback material into clutter in the user's config directories. Mechanism: every backup made by a run is recorded and removed once that run reaches its summary; a failed run keeps them (they are then the rollback); `pruneBackups()` keeps only the current run's copy by default, so older leftovers drain on the next run that touches the file; the one exception is a `~/.gemini/GEMINI.md` that held lines the install did not manage, whose backup stays (with one older) because it is the user's only copy of those lines and the migration directive points at it. Rejected: dropping backups altogether (a merge bug in `settings.json` would then have no rollback during the run). Updated together: `README.md` install steps, `docs/arch/rule-delivery-architecture.md` GEMINI flow.
50
+ - **The route gate never counted a rule read made in Cursor, so every gated edit there was denied even after the rule file was read.** Evidence: Cursor loads hooks from `~/.claude` (`claudeUserHooks`), and its transcript stores the turn as `role: "assistant"`, the `Read` target as `path` and the shell tool as `Shell`; the hook matched only `type: "assistant"`, `file_path` and `Bash`, so no read was ever found. The three-denial fail-open did not fire either, because Cursor writes no `attachment.stdout` for the hook to count. Root cause: `scanTranscript` was written against Claude Code's transcript shape alone. Mechanism: it accepts either field name for each of the three (`type`/`role`, `file_path`/`path`, `Bash`/`Shell`); the compaction boundary is unchanged. Verified with synthetic transcripts against the hook: Cursor `Read`, Cursor `Shell` `cat`, Claude `Read`, Claude `Bash` `cat` → allowed; no read, a different rule file read, and a read followed by `compact_boundary` → denied. Rejected: a separate Cursor hook (two copies of one detection that would drift). Updated together: the hook's `scanTranscript` comment only.
51
+ - **The installer reported "rtk found, left as is — its default filters drop evidence lines…" and asked the rtk prompt again on every install, even when the rtk config already carried the managed exclude list.** Evidence: found on the owner's Mac on 2026-10-20 after rtk was upgraded to 1.0.1 — a config that already held the full `exclude_commands` list still produced the warning and the question on each run. Root cause: the "declined" state was set without reading the config file, so the installer could not tell a declined machine from a configured one. Mechanism: `rtkReadState()` classifies the file first (already in place, opt-out, or kept as the user's own list with the missing names) and `rtkConfigure()` returns that answer; the prompt is asked only when a write would be needed (no file, no `[hooks]`, or `[hooks]` without the key). Rejected: remembering the answer in a state file (the config file already is the state). Verified: sandbox `HOME` with a fake `rtk`, no TTY — managed config → "already in place", opt-out → skipped, no file → "left as is" and nothing written, `--rtk` on no file → written; the Mac's real run now prints "already in place". Updated together: `install.mjs` (`rtkReadState`, `rtkConfigure`), `.github/workflows/install-smoke.yml` (the managed-config case without `--rtk`).
52
+
3
53
  ## [3.7.0] - 2026-10-08
4
54
 
5
55
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # akidevrule
2
2
 
3
- One install command turns a fresh environment into Aki's full working baseline — for **Claude Code, Antigravity/Gemini, Codex CLI, Kiro CLI, Grok CLI, Cursor and OpenCode**, generated from one agent-neutral source: a shared rule corpus that loads itself at the right moment (Claude Code + Antigravity), plus a small set of sharp, single-purpose skills synced to every CLI that natively consumes the shared `SKILL.md` open standard.
3
+ One install command turns a fresh environment into Aki's full working baseline — for **Claude Code, Antigravity/Gemini, Codex CLI, Kiro CLI, Grok CLI, WorkBuddy, Cursor and OpenCode**, generated from one agent-neutral source: a shared rule corpus that loads itself at the right moment (Claude Code + Antigravity), plus a small set of sharp, single-purpose skills synced to every CLI that natively consumes the shared `SKILL.md` open standard.
4
4
 
5
5
  **Quick install (npm):**
6
6
 
@@ -34,6 +34,7 @@ This Git repository is the source of truth; `dev.akitao.com` is the presentation
34
34
  - [Usage model](#usage-model)
35
35
  - [Repository layout](#repository-layout)
36
36
  - [What the installer does](#what-the-installer-does)
37
+ - [Optional: rtk](#optional-rtk)
37
38
  - [Gemini / Antigravity model](#gemini--antigravity-model)
38
39
  - [What is excluded](#what-is-excluded)
39
40
  - [Why `~/.aki/akidevrule`](#why-akiakidevrule)
@@ -72,8 +73,9 @@ Interpreter convention (documented once): the installer and hooks run on `node`
72
73
  | `aki-article-writer` | `/aki-article-writer` or natural language | Per-project pipeline for publishable site prose (articles, news/blog posts, announcements, knowledge entries, including a release turned into a post): research & fact-verification, SEO metadata, JSON-LD schema, UX-psychology-aware content, a rendered-output pass on the built HTML before delivery, and a dedicated Image Scout subagent (Gemini Flash / Haiku) for search → download → visual inspection → ffmpeg processing → slug-named WebP output. One subagent per article; image work is always isolated to a separate lightweight subagent. |
73
74
  | `akidevsync-notes` | natural language | Reads/edits a project's `.akidevsync/notes.json` — the per-project task list the Aki-Dev-Sync app itself writes (list/add/pin/mark-done/edit/delete tasks) via a bundled script that preserves the app's own JSON formatting, plus a workflow for cross-checking pinned notes against a shipped release (CHANGELOG + code) before marking them done. |
74
75
  | `akilint` | `/akilint` or a penalty card | Mechanical format lint for the penalty-card classes of `RULE-agent-behavior.md` §0: hard-wrapped code comments and markdown prose (`[WRAP]`) and oversize comments (`[YAP]`, always labeled *review* — a flag for judgment against `coding.B4`, never an auto-delete verdict). Thin wrapper over the shared `scythe.py` detector (deterministic line matching, exit-code aware, cannot fabricate evidence) — the same script akiflow's `aki-conduct` seat uses, so a card name means the same thing everywhere. `[FLUFF]` (density) is content judgment and explicitly out of a script's reach. |
76
+ | `noyap` | `/noyap`, `[FLUFF]`, or "too long" in any language | Rewrites the reply just given — or answers the current request — keeping only the answer and what the owner must do or heed; every other idea is cut, never compressed or parked in a note. Leftovers are settled instead of listed (doable → done, unimportant → unsaid, important → decided after `/akithink`); passed checks, process, files touched, restated content and harness preambles are always cut; state and negation words, a failed or unverified claim, a needed command or path, and every shape another rule mandates stay exact. A rewrite lands at 10–40% of the reply it replaces, and the shape persists for later replies to the owner until they ask for detail. The fix procedure behind the `[FLUFF]` card; replies to the owner only. |
75
77
  | `akiopen` | `/akiopen` or natural language | Session-opening brief: reads the working tree, `.akidevsync/notes.json`, active `docs/plan/` files, top-level `docs/*.md` inbox files, `[Unreleased]`, and hand-off lines in one pass, then reports only what is still pending — at most seven items in a fixed problem / why-still-open / proposal / goal shape, ranked by severity. Read-only. |
76
- | `akiship` | `/akiship` | One-command full release: front-loads every check (release state, tree triage), then runs `RULE-release.md` B7's fail-closed checklist unattended (CRITICAL mandatory `Read` of `RULE-release.md` and `RULE-docs.md` first; a `S0`–`S8` receipt line with quoted evidence per step or the step counts as NOT RUN; written self-interrogation) — diff-scoped hygiene (scythe, dead code, comment doc-refs on the accumulation only), migration doctrine (`RULE-release.md` B5: detector over the diff on every release, startup-embedded migration counts, rehearsal from the PREVIOUS state) and external-action completeness, record truthfulness, build & test mirroring CI (B7 step 6), doc sync across every record surface (plans, `arch`/`feat`, README, task notes, bound standards docs), version mint or defer, registry publish for npm/crates/PyPI packages (`RULE-release.md` B9 — an OTP-gated publish is the single hand-off) — committing via `akigitcommit` with confirmation pre-answered — and ending every run with the release-copy block (`RULE-release.md` B6: headline / short / full plus an announce verdict, quoting the `releases.json` entry and GitHub Release body rather than writing a third text). **Activation is an explicit release order**: the literal token `/akiship`, or an equally explicit imperative naming the ritual for this repo ("release trọn vẹn đi") — a completion word with no release object ("làm cho trọn vẹn"), or `/akiship` inside a question, activates nothing and gets a consult (answer in chat, change nothing). Governed by the B8 contract: that order is the authorization, blockers are reported once as a batch or the run completes with zero mid-run questions, and it stops only for public-history ambiguity, unclassifiable work, or a design contradiction — an owner-worded completion criterion is derived from the anchor plus the repo's own records and decided/reported (`Decided: X · because Y · rejected Z (why) · reopen if W`), escalated only when competing readings would produce different irreversible artifacts. Push/deploy stay opt-in — named explicitly, or via completion-intensity phrasing (canonical list in `RULE-release.md` B8, e.g. "trọn vẹn") — and after any push, CI is watched to green (`RULE-release.md` B10) regardless of whether the stack deploys, and after any deploy a data path the release touched is exercised (`RULE-release.md` B11). |
78
+ | `akiship` | `/akiship` | One-command full release: front-loads every check (release state, tree triage), then runs `RULE-release.md` B7's fail-closed checklist unattended (CRITICAL mandatory `Read` of `RULE-release.md` and `RULE-docs.md` first; a `S0`–`S8` receipt line with quoted evidence per step or the step counts as NOT RUN; written self-interrogation) — diff-scoped hygiene (scythe, dead code, comment doc-refs on the accumulation only), migration doctrine (`RULE-release.md` B5: detector over the diff on every release, startup-embedded migration counts, rehearsal from the PREVIOUS state) and external-action completeness, record truthfulness, build & test mirroring CI (B7 step 6), doc sync across every record surface (plans, `arch`/`feat`, README, task notes, bound standards docs), version mint or defer, registry publish for npm/crates/PyPI packages (`RULE-release.md` B9 — an OTP-gated publish is the single hand-off) — committing via `akigitcommit` with confirmation pre-answered — and ending every run with the release-copy block (`RULE-release.md` B6: headline / short / full plus an announce verdict, quoting the `releases.json` entry and GitHub Release body rather than writing a third text). **Activation is an explicit release order**: the literal token `/akiship`, or an equally explicit imperative naming the ritual for this repo ("release trọn vẹn đi") — a completion word with no release object ("làm cho trọn vẹn"), or `/akiship` inside a question, activates nothing and gets a consult (answer in chat, change nothing). Governed by the B8 contract: that order is the authorization, blockers are reported once as a batch or the run completes with zero mid-run questions, and it stops only for public-history ambiguity, unclassifiable work, or a design contradiction — an owner-worded completion criterion is derived from the anchor plus the repo's own records and decided/reported (`Decided: X · because Y · rejected Z (why) · reopen if W`), escalated only when competing readings would produce different irreversible artifacts. Push/deploy stay opt-in — named explicitly, or via completion-intensity phrasing (canonical list in `RULE-release.md` B8, e.g. "trọn vẹn") — and are held while any flow the accumulation touched is `unverified` after a local run (`RULE-release.md` B7 step 7), reported as a `Q`; after any push, CI is watched to green (`RULE-release.md` B10) regardless of whether the stack deploys, and after any deploy a data path the release touched is exercised (`RULE-release.md` B11). |
77
79
 
78
80
  ### Five agent definitions
79
81
 
@@ -89,7 +91,7 @@ A seat used to be convened by job title and then handed rules. The order is inve
89
91
 
90
92
  A catalog is not a roster. Five files on disk make it easy to pick seats from a menu, which is the failure they were built to end — a seat is convened only when it traces to a requirement in the owner's own words.
91
93
 
92
- **Claude Code only, deliberately.** `SKILL.md` is an open standard with five implementations; an agent-definition format currently has one, so building a vendor-neutral layer over a single consumer would be exactly the speculative generality `pattern.A2` forbids. Reopen trigger: a second CLI publishing an agent format promotes `claude/agents/` to a top-level `agents/` rendered per vendor, the way `AG_RULE_MAP` already renders rules for Antigravity.
94
+ **Claude Code only, deliberately.** `SKILL.md` is an open standard with six implementations; an agent-definition format currently has one, so building a vendor-neutral layer over a single consumer would be exactly the speculative generality `pattern.A2` forbids. Reopen trigger: a second CLI publishing an agent format promotes `claude/agents/` to a top-level `agents/` rendered per vendor, the way `AG_RULE_MAP` already renders rules for Antigravity.
93
95
 
94
96
  ### A rule corpus that routes itself
95
97
 
@@ -102,9 +104,9 @@ Loading happens on two different mechanisms.
102
104
 
103
105
  **Resident — harness-embedded.** `RULE-agent-behavior.md` and the router `skills/akirule/SKILL.md` are `@`-imported by `~/.claude/CLAUDE.md`, which Claude Code reads mechanically at session start. No model decision is involved, so the behavior floor applies to every task and the routing is always present. The router joined the imports because as a skill it went uninvoked until the owner asked for it by name. `@` imports have this effect **only** inside `CLAUDE.md` — the same syntax written into a skill body looks like an import but loads nothing, because a skill body is read only after the model has already chosen to invoke the skill.
104
106
 
105
- **Everything else — routed by meaning, and gated where the artifact gives it away.** Each task turn is classified by the domains it touches and the act (create, decide, audit, ship), in any language; each route carries concept signals in English and Vietnamese as evidence, never as the test, so a paraphrase routes as well as the listed word. The one model-dependent hop left is the `Read` of a routed file, and on Claude Code the `aki-route-guard` PreToolUse hook (`claude/hooks/aki-route-guard.mjs`) enforces it for every route with an artifact signature: the first Edit/Write of each artifact type in a session — a code file (`coding` + `pattern`), `.md` (`docs`), `CHANGELOG.md` (`release`), `.vue`/`.css` (`ui`, plus `stack` in a Nuxt project), `.rs` (`tauri`), `.sql` (`db`), `locales/` (`content`) — is denied until those files have been read in that transcript; a subagent is gated on its own transcript. Zero model hops in the check, at most one denial per artifact type per session, fail-open on any error, `AKI_ROUTE_GUARD=0` disables it. `RULE-coding.md` and `RULE-pattern-core.md` were resident imports from 2026-08-06 to 2026-09-30 because the router as a skill went uninvoked; importing the router restored the routing but not the read (measured: the model read a routed file unprompted in about one session in five — `docs/research/rule-delivery-second-hop-sep29.md`), so the gate now restores the guarantee by mechanism and the two files load only on code turns. Meaning-only routes (`think`, `proportion`, `biz`, `ux`, the audits) stay on the router alone, with sensitivity deliberately high (err toward loading — a false positive costs a few tokens, a false negative causes wrong behavior). The one deliberate exception is a lookup: a turn that only reads, counts, locates or explains what exists routes nothing, because no rule's act is performed — those turns are the majority for many users of this corpus, and the tiering exists so they pay for nothing beyond the two resident files.
107
+ **Everything else — routed by meaning, and gated where the artifact gives it away.** Each task turn is classified by the domains it touches and the act (create, decide, audit, ship), in any language; each route carries concept signals in English and Vietnamese as evidence, never as the test, so a paraphrase routes as well as the listed word. The one model-dependent hop left is the `Read` of a routed file, and on Claude Code the `aki-route-guard` PreToolUse hook (`claude/hooks/aki-route-guard.mjs`) enforces it for every route with an artifact signature: the first Edit/Write of each artifact type in a session — a code file (`coding` + `pattern`), `.md` (`docs`), `CHANGELOG.md` (`release`), `.vue`/`.css` (`ui`, plus `stack` in a Nuxt project), `.rs` (`tauri`), `.sql` (`db`), `locales/` (`content`) — is denied until those files have been read whole in that transcript (a `limit`/`offset` or `head` read does not count, and the hook widens a partial `Read` of a rule file to the whole file); the path → rule map is the data file `payload/route-map.json`, not hook code; a subagent is gated on its own transcript. Zero model hops in the check, at most one denial per artifact type per session, fail-open on any error, `AKI_ROUTE_GUARD=0` disables it. `RULE-coding.md` and `RULE-pattern-core.md` were resident imports from 2026-08-06 to 2026-09-30 because the router as a skill went uninvoked; importing the router restored the routing but not the read (measured: the model read a routed file unprompted in about one session in five — `docs/research/rule-delivery-second-hop-sep29.md`), so the gate now restores the guarantee by mechanism and the two files load only on code turns. Meaning-only routes (`think`, `proportion`, `biz`, `ux`, the audits) stay on the router alone, with sensitivity deliberately high (err toward loading — a false positive costs a few tokens, a false negative causes wrong behavior). The one deliberate exception is a lookup: a turn that only reads, counts, locates or explains what exists routes nothing, because no rule's act is performed — those turns are the majority for many users of this corpus, and the tiering exists so they pay for nothing beyond the two resident files.
106
108
 
107
- - **Contextual and analytical — read on route match:** `RULE-coding.md` (code-quality floor: source of truth, changing existing code, verification and the hand-off ladder, comment budget, runtime safety), `RULE-pattern-core.md` (the 9 structural laws, decomposition, the critique gate before any abstraction), `RULE-test.md` (fewest tests: no new test by default, no new test file or folder when one fits, nothing touched the test does not own, a verdict that means what it exercised — gated on test-file edits), `RULE-docs.md` (structure and lifecycle, evidence-bound `ref/fact-*` fact docs, plus the docs-vs-code drift audit), `RULE-content-write.md` (UI copy and writing style, plus the content audit — canonical-term drift, density deletion test, i18n coverage, fact-check), `RULE-stack-akiNuxtCf.md`, `RULE-stack-tauri.md` (Tauri v2 + Rust: never-block-the-UI, version SSOT, target context, the macOS TCC/Gatekeeper boundary for spawned sidecars), `RULE-ui-pattern.md` (design-system layer: the subtraction pass that runs before the tier ladder, class taxonomy, tokens, variant API, and the audit playbook), `RULE-seo.md` (metadata, schema, sitemap, and URL form: relative at rest, absolute only where a consumer requires it), `RULE-release.md`, `RULE-db-design.md`, `RULE-biz.md` (market-facing decisions: positioning, pricing, audience) — plus the analytical methods (`METHOD-*`, loaded on route match like the rest): `METHOD-audit-flow.md` (refactors, multi-file bugs, fragile flows), `METHOD-audit-zero-trust.md` (strict mechanical-first audit: detectors before opinion, exact matches separated from pattern-level candidates), `METHOD-deep-think.md` (scope/architecture/value decisions, first-principles and critique-style thinking), `METHOD-ux-psych.md` (UX/user-behavior evaluation, onboarding and conversion flows), `METHOD-proportionality.md` (sizing a guard, limit or accepted risk against reach, capability, motive and blast radius — the lens that stops both over-engineering and client-side-limits-as-enforcement), `METHOD-audit-subtraction.md` (repo-wide "does this need to exist" sweep, terminating on two dry rounds), and `METHOD-audit-frozen-reference.md` (compliance audit for a clause naming a concrete external artifact as the canonical shape to match — resolve to an exact path, diff literally against it, never judge from memory of the rule's prose).
109
+ - **Contextual and analytical — read on route match:** `RULE-coding.md` (code-quality floor: source of truth, changing existing code, verification and the hand-off ladder, comment budget, runtime safety), `RULE-pattern-core.md` (the 9 structural laws, decomposition, the critique gate before any abstraction), `RULE-test.md` (fewest tests: no new test by default, no new test file or folder when one fits, nothing touched the test does not own, a verdict that means what it exercised — gated on test-file edits), `RULE-docs.md` (structure and lifecycle, evidence-bound `ref/fact-*` fact docs, plus the docs-vs-code drift audit), `RULE-content-write.md` (UI copy and writing style, plus the content audit — canonical-term drift, density deletion test, i18n coverage, fact-check), `RULE-stack-akiNuxtCf.md`, `RULE-stack-tauri.md` (Tauri v2 + Rust: never-block-the-UI, version SSOT, target context, the macOS TCC/Gatekeeper boundary for spawned sidecars, Windows file, path and process semantics that only a native test run exercises), `RULE-ui-pattern.md` (design-system layer: the subtraction pass that runs before the tier ladder, class taxonomy, tokens, variant API, and the audit playbook), `RULE-seo.md` (metadata, schema, sitemap, and URL form: relative at rest, absolute only where a consumer requires it), `RULE-release.md`, `RULE-db-design.md`, `RULE-biz.md` (market-facing decisions: positioning, pricing, audience) — plus the analytical methods (`METHOD-*`, loaded on route match like the rest): `METHOD-audit-flow.md` (refactors, multi-file bugs, fragile flows), `METHOD-audit-zero-trust.md` (strict mechanical-first audit: detectors before opinion, exact matches separated from pattern-level candidates), `METHOD-deep-think.md` (scope/architecture/value decisions, first-principles and critique-style thinking), `METHOD-ux-psych.md` (UX/user-behavior evaluation, onboarding and conversion flows), `METHOD-proportionality.md` (sizing a guard, limit or accepted risk against reach, capability, motive and blast radius — the lens that stops both over-engineering and client-side-limits-as-enforcement), `METHOD-audit-subtraction.md` (repo-wide "does this need to exist" sweep, terminating on two dry rounds), and `METHOD-audit-frozen-reference.md` (compliance audit for a clause naming a concrete external artifact as the canonical shape to match — resolve to an exact path, diff literally against it, never judge from memory of the rule's prose).
108
110
  - **Full load on explicit request:** asking, in any wording, to load the whole corpus reads every `RULE-*`/`METHOD-*` file at once.
109
111
 
110
112
  No harness magic beyond the `CLAUDE.md` import: routes are instructions telling Claude to Read the file from `~/.aki/akidevrule/` when the task's domain matches; the full-load request is the escape hatch.
@@ -159,6 +161,7 @@ Install once; from then on the system has two kinds of surface. **Rules load the
159
161
  | Opening a project — what is still pending here? | `/akiopen` |
160
162
  | A messy working tree that needs clean commits | `/akigitcommit` |
161
163
  | Format lint — or someone called a penalty card | `/akilint` (or just say `[WRAP]` / `[YAP]`) |
164
+ | A reply was too long — keep the answer and what I must act on, cut the rest | `/noyap` (or just say `[FLUFF]`, "dài quá") |
162
165
  | Ship a release end-to-end | `/akiship` |
163
166
  | A dense analysis worth one self-contained page | `/akihtmlreport` |
164
167
  | A researched, SEO-complete article | `/aki-article-writer` |
@@ -193,6 +196,7 @@ payload/ → installed to ~/.aki/akidevrule/
193
196
  METHOD-proportionality.md
194
197
  METHOD-audit-subtraction.md
195
198
  METHOD-audit-frozen-reference.md
199
+ route-map.json → path → rule map read by the route gate, the audit and the lint (data, not a rule)
196
200
  GEMINI.md → installed to ~/.gemini/GEMINI.md (NOT a rule file)
197
201
 
198
202
  skills/ → shared Agent Skills corpus (SKILL.md open standard), deployed
@@ -205,7 +209,9 @@ skills/ → shared Agent Skills corpus (SKILL.md open
205
209
  akiflow/scripts/council_verify.py (mechanical closure gate: ghost seats, missing evidence tags, unanswered REMINDs)
206
210
  akiflow/scripts/scythe.py (penalty-card lint [WRAP]/[YAP] — shared engine of /akilint and the enforcer's evidence sweeps)
207
211
  akiflow/scripts/release_lint.py (release-record lint: CHANGELOG section order/vocabulary/level, releases.json parity, type keys, highlight review — RULE-release.md C4, B7 step 4)
208
- akiflow/scripts/test_lint.py (test-file lint: literal /tmp, missing temp cleanup, exit calls as verdicts; sleeps, vacuous asserts, ambient ifs, HOME reads, live URLs, ports, source pins, history comments as review — RULE-test.md D1)
212
+ akiflow/scripts/plan_lint.py (plan/index lint: fully ticked plan outside done/, unticked box in done/, dead or untracked index link; plan cited by CHANGELOG with open boxes as review — RULE-docs.md B1, RULE-release.md B7 step 5)
213
+ akiflow/scripts/ship_gate.py (akiship push gate: refuses push/deploy on a missing S0–S8 line, FAIL, evidence-free or hedged PASS, missing self-interrogation, or an open unverified Q — RULE-release.md B7, B8)
214
+ akiflow/scripts/suite_lint.py (test-file lint: literal /tmp, missing temp cleanup, exit calls as verdicts; sleeps, vacuous asserts, ambient ifs, HOME reads, live URLs, ports, source pins, history comments as review — RULE-test.md D1)
209
215
  akiflow/scripts/*.sh (transitional Unix wrappers, one per script above — each execs its .py sibling)
210
216
  akiflow/references/harness-facts.md (subagent/cost/model facts, with sources)
211
217
  akithink/SKILL.md
@@ -213,6 +219,7 @@ skills/ → shared Agent Skills corpus (SKILL.md open
213
219
  akihelp/SKILL.md
214
220
  akigitcommit/SKILL.md
215
221
  akilint/SKILL.md
222
+ noyap/SKILL.md
216
223
  akiopen/SKILL.md
217
224
  akiship/SKILL.md
218
225
  aki-article-writer/SKILL.md
@@ -232,7 +239,7 @@ claude/ → Claude Code-only runtime assets, installed
232
239
  agents/aki-maker.md
233
240
  hooks/aki-update-check.mjs
234
241
  hooks/aki_version_check.mjs (shared version-status parser, imported by both the hook and install.mjs --check)
235
- hooks/aki-route-guard.mjs (PreToolUse route gate: denies the first edit of an artifact type until its routed rule was Read after the last compaction)
242
+ hooks/aki-route-guard.mjs (PreToolUse route gate: denies the first edit of an artifact type until its routed rule was Read whole after the last compaction; widens partial Reads of rule files; reads ~/.aki/akidevrule/route-map.json)
236
243
  hooks/aki-compact-reread.mjs (SessionStart on `compact` only: one notice that the rules read earlier left context)
237
244
  fragments/settings.akidoc.fragment.json (illustrative reference only — never apply manually)
238
245
 
@@ -283,7 +290,7 @@ flowchart TD
283
290
  C_SKILLS["skills/<skill_name>/SKILL.md"]
284
291
  C_AGENTS["agents/aki-*.md (copied per file, your own agents kept)"]
285
292
  C_HOOKS["hooks/ aki-update-check.mjs + aki_version_check.mjs · aki-route-guard.mjs · aki-compact-reread.mjs"]
286
- C_SET["settings.json (Permissions + Skill Overrides)"]
293
+ C_SET["settings.json (Permissions + Skill Overrides + Attribution off)"]
287
294
  end
288
295
 
289
296
  %% TARGET 3: ~/.gemini/
@@ -295,7 +302,7 @@ flowchart TD
295
302
  G_SJSON["config/skills.json (Inherits agskills, absolute path)"]
296
303
  end
297
304
 
298
- %% TARGETS 4-6: other CLIs that natively consume the SKILL.md standard
305
+ %% TARGETS 4-7: other harnesses that natively consume the SKILL.md standard
299
306
  subgraph T4["🧩 4. Codex CLI (~/.agents/skills/ + $CODEX_HOME/)"]
300
307
  X_SKILLS["<skill_name>/SKILL.md"]
301
308
  X_AGENTS["AGENTS.md managed block (behavior floor + router) + config.toml project_doc_max_bytes"]
@@ -306,6 +313,9 @@ flowchart TD
306
313
  subgraph T6["🧩 6. Grok CLI (~/.grok/skills/)"]
307
314
  R_SKILLS["<skill_name>/SKILL.md"]
308
315
  end
316
+ subgraph T7["🧩 7. WorkBuddy (~/.workbuddy-ai/skills/)"]
317
+ W_SKILLS["<skill_name>/SKILL.md"]
318
+ end
309
319
 
310
320
  INSTALL -->|"copy + prune stale"| T1
311
321
  INSTALL -->|"deploy & settings setup"| T2
@@ -313,25 +323,54 @@ flowchart TD
313
323
  INSTALL -->|"sync per skill folder"| T4
314
324
  INSTALL -->|"sync per skill folder"| T5
315
325
  INSTALL -->|"sync per skill folder"| T6
326
+ INSTALL -->|"sync per skill folder"| T7
316
327
  ```
317
328
 
318
- Targets 5-6 only get the shared skill corpus (no rule corpus / no `CLAUDE.md`/`GEMINI.md`-style overrides — those CLIs have no equivalent hard-load hook this baseline plugs into yet). Target 4 also gets the behavior floor and the router as a managed block in `$CODEX_HOME/AGENTS.md` (default `~/.codex/AGENTS.md`), the one file Codex hard-loads globally — only when that directory exists, lines of your own in the file are kept, and `project_doc_max_bytes` is written to `config.toml` when absent because Codex stops loading instruction files once global plus project files pass 32 KiB (the block alone is ~36 KB). Codex expands no `@` imports and never reads Claude's global file, so copying `~/.claude/CLAUDE.md` would deliver nothing (`docs/research/codex-instruction-delivery.md`). A project's `CLAUDE.md` stays unread unless you opt in per machine with `project_doc_fallback_filenames = ["CLAUDE.md"]`; a native `AGENTS.md` in the same directory wins over it. Each sync is scoped per skill folder name via a Node `fs` copy plus a managed-names-only prune, same never-touch-the-rest guarantee as targets 2 and 3, and runs unconditionally — harmless if that CLI isn't installed on the machine, picked up the moment it is.
329
+ Targets 5-7 only get the shared skill corpus (no rule corpus / no `CLAUDE.md`/`GEMINI.md`-style overrides — those CLIs have no equivalent hard-load hook this baseline plugs into yet). Target 4 also gets the behavior floor and the router as a managed block in `$CODEX_HOME/AGENTS.md` (default `~/.codex/AGENTS.md`), the one file Codex hard-loads globally — only when that directory exists, lines of your own in the file are kept, and `project_doc_max_bytes` is written to `config.toml` when absent because Codex stops loading instruction files once global plus project files pass 32 KiB (the block alone is ~36 KB). Codex expands no `@` imports and never reads Claude's global file, so copying `~/.claude/CLAUDE.md` would deliver nothing (`docs/research/codex-instruction-delivery.md`). A project's `CLAUDE.md` stays unread unless you opt in per machine with `project_doc_fallback_filenames = ["CLAUDE.md"]`; a native `AGENTS.md` in the same directory wins over it. Each sync is scoped per skill folder name via a Node `fs` copy plus a managed-names-only prune, same never-touch-the-rest guarantee as targets 2 and 3, and runs unconditionally — harmless if that CLI isn't installed on the machine, picked up the moment it is.
319
330
 
320
331
  1. Syncs `payload/*` into `~/.aki/akidevrule/` (Node `fs` copy, excludes `ref-ECC/`), removes stale files left by renames, syncs `agskills/` for Antigravity skill inheritance, and deploys the full TCC lookup to `~/.aki/akidevrule/docs/ref/fact-macos-codesign-tcc.md`.
321
332
  2. Deploys to **all detected Claude config directories** — `~/.claude` (default primary), all existing `~/.claude*` profile variants (e.g. `~/.claude-9rt`, `~/.claude-prx`), plus `$CLAUDE_CONFIG_DIR` or `--claude-dir <path>` if provided:
322
333
  - Syncs every skill folder under `skills/*/` (whole directory, including any `references/` or `scripts/`) into `<target>/skills/`, one named folder at a time (copy + managed-names-only prune), removing only Aki's own old/renamed skill directories (`akidoc-*`, `akiadvise`) — any other skill you already have is never touched. `skills/` is a top-level, agent-neutral folder (siblings with `payload/`, not nested under `claude/`) because SKILL.md is a shared open standard both Claude Code and Antigravity/AGY consume identically — see [docs/ref/fact-agent-skills-standard.md](docs/ref/fact-agent-skills-standard.md).
323
334
  - Copies `claude/agents/*.md` into `<target>/agents/` **file by file, never a directory mirror with `--delete`** — that folder is a shared namespace where your own agent definitions sit beside Aki's, exactly like `<target>/skills/`, so nothing you did not install is ever removed.
324
- - Replaces `<target>/CLAUDE.md` with the packaged guidance (timestamped backup first), appending this machine's source-repo path and an `@<target>/CLAUDE.local.md` import.
335
+ - Replaces `<target>/CLAUDE.md` with the packaged guidance (timestamped backup first, removed once the run succeeds), appending this machine's source-repo path and an `@<target>/CLAUDE.local.md` import.
325
336
  - Creates `<target>/CLAUDE.local.md` **only if missing** — never overwritten afterward. On profile variants (`~/.claude-*`), the template imports `@~/.claude/CLAUDE.local.md` by default so machine-wide facts are inherited. Put per-machine/per-profile rules there; they survive every reinstall.
326
- - Before the confirmation prompt or any mutation, preflights every existing JSON file it may update: each detected profile's `settings.json`, `~/.gemini/config/skills.json`, `~/.gemini/antigravity-cli/settings.json`, and `~/.gemini/settings.json`. A malformed file or non-object root aborts the install with originals untouched. After preflight, updates `<target>/settings.json` with a timestamped backup: read permission for `~/.aki/akidevrule/**`, one `Bash(<launcher> <script>*)` rule per Aki skill script per rendering (absolute and `~/`-literal — Claude Code does not expand `~` before matching), `skillOverrides.akirule = "on"`, idempotent registration of the `SessionStart` update-check hook.
327
- - Installs `<target>/hooks/aki-update-check.mjs` plus its shared parser `<target>/hooks/aki_version_check.mjs`, `<target>/hooks/aki-route-guard.mjs` registered as a `PreToolUse` hook on `Edit|MultiEdit|Write|NotebookEdit`, and `<target>/hooks/aki-compact-reread.mjs` registered as a `SessionStart` hook with matcher `compact` (all idempotent, same filter-then-push as the update check).
337
+ - Before the confirmation prompt or any mutation, preflights every existing JSON file it may update: each detected profile's `settings.json`, `~/.gemini/config/skills.json`, `~/.gemini/antigravity-cli/settings.json`, and `~/.gemini/settings.json`. A malformed file or non-object root aborts the install with originals untouched. After preflight, updates `<target>/settings.json` with a timestamped backup (removed once the run succeeds): read permission for `~/.aki/akidevrule/**`, one `Bash(<launcher> <script>*)` rule per Aki skill script per rendering (absolute and `~/`-literal — Claude Code does not expand `~` before matching), `skillOverrides.akirule = "on"`, `attribution` with empty `commit`/`pr` and `sessionUrl: false` (Claude Code then adds no `Co-Authored-By`, PR footer or session link — `agent.B4` by mechanism), idempotent registration of the `SessionStart` update-check hook.
338
+ - Installs `<target>/hooks/aki-update-check.mjs` plus its shared parser `<target>/hooks/aki_version_check.mjs`, `<target>/hooks/aki-route-guard.mjs` registered as a `PreToolUse` hook on `Edit|MultiEdit|Write|NotebookEdit` and on `Read` (the `Read` branch widens a partial read of a rule file), and `<target>/hooks/aki-compact-reread.mjs` registered as a `SessionStart` hook with matcher `compact` (all idempotent, same filter-then-push as the update check).
328
339
  3. Writes `~/.aki/akidevrule/.version` with `installed=`/`version=`/`commit=`/`branch=` and records the source-repo path in `~/.aki/akidevrule/.source-repo` — `version=` is the just-installed CHANGELOG's latest released semver, the same value `install.mjs --check` and the hook compare against remote.
329
340
  4. Installs `payload/GEMINI.md` to `~/.gemini/GEMINI.md` — Antigravity global behavior overrides, stamped with a version marker (`[AKIRULE-AG-OVERRIDES-…]`) on line 1. Generates one native rule file per `RULE-*`/`METHOD-*` under `~/.gemini/config/rules/` with YAML `trigger` frontmatter — `agent` `always_on`, the stacks `glob`, the rest `model_decision` — each description generated from its `akirule` route, so both harnesses route from one table. Deploys 11 skills directly to `~/.gemini/config/skills/` for native auto-discovery (synced per skill folder, same never-touch-the-rest guarantee as step 2), configures `~/.gemini/config/skills.json` with absolute paths as secondary, and merges skill execution permissions into `~/.gemini/antigravity-cli/settings.json` and `~/.gemini/settings.json` — a `command()` prefix rule for every `skills/*/scripts/*.py` per skill root, in both the expanded and the tilde-literal rendering (agy's matcher compares command strings literally — no glob expansion, and no tilde expansion in either direction — so a directory wildcard never matches and a rule only matches a command written the same way; see [docs/ref/fact-cli-permission-allowlist-standard.md](docs/ref/fact-cli-permission-allowlist-standard.md) §1.2) plus scoped `write_file`/`read_file` rules for the council workspace and rule corpus.
330
- 5. Syncs the same skill folders to `~/.agents/skills/` (Codex CLI, Cursor), `~/.kiro/skills/` (Kiro CLI), and `~/.grok/skills/` (Grok CLI) — each a plain global skills root these CLIs read natively, synced per skill folder name exactly like step 2. Kiro and Grok are skills-only. Codex additionally gets the managed `AGENTS.md` block and the `project_doc_max_bytes` key described above, only when `$CODEX_HOME` (default `~/.codex`) exists; the summary names the block size, the budget written or found, and a non-empty `AGENTS.override.md` that would shadow it.
341
+ 5. Syncs the same skill folders to `~/.agents/skills/` (Codex CLI, Cursor), `~/.kiro/skills/` (Kiro CLI), `~/.grok/skills/` (Grok CLI), and `~/.workbuddy-ai/skills/` (WorkBuddy) — each a plain global skills root these harnesses read natively, synced per skill folder name exactly like step 2. Kiro, Grok and WorkBuddy are skills-only; on WorkBuddy nothing is resident, so the router's Delivery section makes the skill invocation also read the behavior floor once per session ([docs/arch/rule-delivery-architecture.md](docs/arch/rule-delivery-architecture.md) § WorkBuddy). Codex additionally gets the managed `AGENTS.md` block and the `project_doc_max_bytes` key described above, only when `$CODEX_HOME` (default `~/.codex`) exists; the summary names the block size, the budget written or found, and a non-empty `AGENTS.override.md` that would shadow it.
331
342
  6. Pre-allows every Aki skill script in each harness present on the machine, one adapter per rule dialect (`lib/permissions.mjs`): `~/.kiro/settings/permissions.yaml` (a marker-delimited managed block), `~/.codex/rules/akidevrule.rules` (a file akidevrule owns), `~/.cursor/cli-config.json` (`Shell(python3:<script>*)`, never a bare `Shell(python3)`), `~/.config/opencode/opencode.json` (`permission.bash`). Every rule names one exact script, in both path renderings; entries a previous install wrote are replaced, the user's own are kept. Grok CLI and Ollama have no file-based allowlist, so nothing is written for them — [docs/ref/fact-cli-permission-allowlist-standard.md](docs/ref/fact-cli-permission-allowlist-standard.md).
332
343
 
344
+ 7. If `rtk` is on `PATH`, asks once — in a terminal only — whether to write its accuracy-first config (next section). Default, and the only answer when there is no terminal, is to leave rtk alone; the summary then prints one line saying so, with the `--rtk` flag that opts in without a prompt.
345
+
333
346
  Re-running the installer updates the same managed files cleanly.
334
347
 
348
+ ## Optional: rtk
349
+
350
+ [rtk](https://github.com/rtk-ai/rtk) is an output compressor that hooks into Claude Code's Bash tool and rewrites commands so their output comes back shorter. It is not required and the installer never installs it. What it saves is real on the noise class — `git status`, `git add/commit/push/pull`, package installs, build logs. What it costs is measured in `docs/research/rtk-output-loss-oct19.md`: its built-in filters also cut the commands an agent reads as evidence, and nothing in the shortened output says which lines are gone. Tested on rtk 0.50.0, raw against filtered: `ls` merges directories, caps at 50 entries and drops names ending in `.` with no marker; `grep` cuts lines at 80 characters and keeps 211 of 480; `find` hides dotfiles and gitignored paths; `git log` stops at 10 commits with no "more" line; `git diff` kept 610 of 7,541 lines; `jq` cuts every line at 120 characters. An agent that counts, quotes, diffs or claims "not found" from that output is wrong without knowing it, and the recovery hints rtk prints were followed 3 times in 480 elisions on the dev box. Large output needs no compressor to stay safe: Claude Code itself saves any Bash output past about 30,000 characters to a file and hands the model the path.
351
+
352
+ rtk has no lossless mode (upstream issue #1313, open since 2026-04), and its built-in filters ignore `filters.toml`. The one knob that makes them lossless is `[hooks] exclude_commands` in rtk's `config.toml`: a listed command is not rewritten at all. The installer offers to write exactly that — **accuracy over savings** — and only on an explicit yes:
353
+
354
+ | Answer | Effect |
355
+ |---|---|
356
+ | `y` in the terminal, or `--rtk` on the command line (`node install.mjs --rtk`, `npx @akinet/akidevrule@latest --rtk`) | writes the `[hooks]` table below into rtk's config (path taken from `rtk config`; `~/.config/rtk/config.toml` on Linux, `~/Library/Application Support/rtk/config.toml` on macOS, `%APPDATA%\rtk\config.toml` on Windows); an existing file is backed up first and other tables are kept; a `[hooks] exclude_commands` you wrote yourself is never touched — the summary lists what it still lacks |
357
+ | `N`, Enter, or no terminal (CI, an agent running the installer) | rtk stays exactly as it is; the summary prints one line saying so |
358
+ | a line `# akidevrule: rtk off` anywhere in the config | the installer skips rtk for good, even with `--rtk` |
359
+
360
+ ````toml
361
+ # akidevrule: accuracy-first rtk — commands whose output is evidence run unfiltered (akidevrule README § Optional: rtk)
362
+ [hooks]
363
+ exclude_commands = [
364
+ "ls", "tree", "find", "grep", "rg", "ast-grep", "wc", "diff",
365
+ "cat", "head", "tail",
366
+ "jq", "stat", "du", "df", "ps", "ssh", "rsync", "curl", "wget",
367
+ "gh", "glab", "psql", "aws", "kubectl", "oc", "docker",
368
+ "^git(\\s+-[Cc]\\s+\\S+)*\\s+(diff|log|show|stash|branch)\\b",
369
+ ]
370
+ ````
371
+
372
+ Everything not listed — `git status`/`commit`/`push`, `npm`, `cargo`, `pytest`, `make` — stays compressed, and the rule corpus covers that residue: `coding.B3` treats any output carrying an elision marker as a sample and reruns it raw (`RTK_DISABLED=1 <cmd>`) before counting or quoting from it. The exclusion list is honoured on every rtk from 0.47.0 to 1.0.1 (hook-tested on 0.47.0, 0.50.0 and 1.0.1); the 1.0 line adds pipelines, `rtk bypass`, and a licence split (Apache-2.0 CLI plus a BUSL-1.1 compression engine, free for production use; `rtk-oss` is Apache-only without the engine), none of which changes the config above. From 0.49.0 you may also enlarge the recall store, which fills in days at its default of 200 entries: `[retriever] mode = "sqlite"`, `max_entries = 2000`, `retention_days = 30` — not written by the installer, since older rtk versions have no sqlite store (they ignore the table). Decision trail: `docs/plan/rtk-accuracy-first.md`.
373
+
335
374
  ## Gemini / Antigravity model
336
375
 
337
376
  Claude Code loads the core and the router automatically (harness-guaranteed `@`-imports in `~/.claude/CLAUDE.md`). Antigravity/Gemini has no such loader, so the split is: `~/.gemini/GEMINI.md` carries **hard-loaded behavior overrides** that patch Antigravity's weak spots (unrequested artifacts, over-engineering, verbosity), native rules route the corpus with descriptions generated from the `akirule` routes, and a tiny per-project `GEMINI.md` bootstrap points the agent at that project's `CLAUDE.md` as its single source of truth. The per-project bootstrap is copied into a project by hand (it is not distributed by the installer).
@@ -341,7 +380,7 @@ Claude Code loads the core and the router automatically (harness-guaranteed `@`-
341
380
  - `ref-ECC/` — a large reference corpus, not needed for standard operation.
342
381
  - API keys, model-router tokens, localhost project permissions, unrelated personal Claude settings.
343
382
  - Automatic download/install logic — the update hook is strictly notify-only.
344
- - Any skill, rule, or file you already have that isn't part of this repo's managed set — every sync (Claude Code, Antigravity, Codex CLI, Kiro CLI, and Grok CLI skill directories included) touches only the paths/names akidevrule itself owns, never a blanket directory wipe. Verified in practice: `~/.grok/skills/` on this machine already held unrelated pre-existing skills (`best-of-n`, `docx`, `pptx`, …) and they were untouched by the sync.
383
+ - Any skill, rule, or file you already have that isn't part of this repo's managed set — every sync (Claude Code, Antigravity, Codex CLI, Kiro CLI, Grok CLI and WorkBuddy skill directories included) touches only the paths/names akidevrule itself owns, never a blanket directory wipe. Verified in practice: `~/.grok/skills/` on this machine already held unrelated pre-existing skills (`best-of-n`, `docx`, `pptx`, …) and they were untouched by the sync.
345
384
 
346
385
  ## Why `~/.aki/akidevrule`
347
386
 
@@ -352,20 +391,22 @@ No sudo, user-local, easy to inspect and delete, consistent with the Aki ecosyst
352
391
  ```bash
353
392
  rm -rf ~/.aki/akidevrule
354
393
  rm -rf ~/.aki/agent-council # /akiflow session workspaces (self-prunes at 30 days anyway)
355
- rm -rf ~/.claude/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,akiopen,akiship,aki-article-writer,akidevsync-notes}
356
- rm -rf ~/.agents/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,akiopen,akiship,aki-article-writer,akidevsync-notes} # Codex CLI
357
- rm -rf ~/.kiro/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,akiopen,akiship,aki-article-writer,akidevsync-notes} # Kiro CLI
358
- rm -rf ~/.grok/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,akiopen,akiship,aki-article-writer,akidevsync-notes} # Grok CLI (other, non-Aki skills already in this folder are untouched)
394
+ rm -rf ~/.claude/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,noyap,akiopen,akiship,aki-article-writer,akidevsync-notes}
395
+ rm -rf ~/.agents/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,noyap,akiopen,akiship,aki-article-writer,akidevsync-notes} # Codex CLI
396
+ rm -rf ~/.kiro/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,noyap,akiopen,akiship,aki-article-writer,akidevsync-notes} # Kiro CLI
397
+ rm -rf ~/.grok/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,noyap,akiopen,akiship,aki-article-writer,akidevsync-notes} # Grok CLI (other, non-Aki skills already in this folder are untouched)
398
+ rm -rf ~/.workbuddy-ai/skills/{akirule,akiflow,akithink,akihtmlreport,akihelp,akigitcommit,akilint,noyap,akiopen,akiship,aki-article-writer,akidevsync-notes} # WorkBuddy
359
399
  rm -f ~/.claude/agents/aki-{hands,judge,conduct,challenger,maker}.md # your own agents in that folder are untouched
360
400
  rm -f ~/.claude/hooks/aki-update-check.mjs ~/.claude/hooks/aki_version_check.mjs ~/.claude/hooks/aki-route-guard.mjs ~/.claude/hooks/aki-compact-reread.mjs ~/.claude/hooks/aki-update-check.py ~/.claude/hooks/aki_version_check.py
361
401
  # then delete the three entries whose command names those hooks from hooks.SessionStart and hooks.PreToolUse in ~/.claude/settings.json
362
402
  # Codex: delete the `>>> akidevrule managed` … `<<< akidevrule managed` block in ~/.codex/AGENTS.md (the rest is yours), and the project_doc_max_bytes line in ~/.codex/config.toml if unwanted
363
403
  rm -f ~/.gemini/GEMINI.md # restore from a *.akidevrule-backup-* if needed; GEMINI.local.md is left untouched
404
+ # rtk, only if you answered y: remove the `# akidevrule: accuracy-first rtk` [hooks] table from rtk's config.toml (`rtk config` prints its path)
364
405
  ```
365
406
 
366
407
  On **Windows** the same targets live under `%USERPROFILE%` (e.g. `%USERPROFILE%\.aki\akidevrule`, `%USERPROFILE%\.claude\skills\...`); remove them with `Remove-Item -Recurse -Force`.
367
408
 
368
- Then remove the akidevrule block from `~/.claude/CLAUDE.md` and its entries (permission, skillOverrides, SessionStart and PreToolUse hooks) from `~/.claude/settings.json` if desired. `~/.codex/rules/akidevrule.rules` is a whole file the installer owns and can simply be deleted.
409
+ Then remove the akidevrule block from `~/.claude/CLAUDE.md` and its entries (permission, skillOverrides, attribution, SessionStart and PreToolUse hooks) from `~/.claude/settings.json` if desired. `~/.codex/rules/akidevrule.rules` is a whole file the installer owns and can simply be deleted.
369
410
 
370
411
  ## Content for dev.akitao.com
371
412
 
package/claude/CLAUDE.md CHANGED
@@ -3,6 +3,6 @@
3
3
  @~/.aki/akidevrule/RULE-agent-behavior.md
4
4
  @~/.claude/skills/akirule/SKILL.md
5
5
 
6
- The harness embeds both at session start: the behavior floor and the router. Every other rule enters context when the model `Read`s it on a route match. For routes with an artifact signature the `aki-route-guard` PreToolUse hook denies the first Edit/Write of that artifact type in a session until the routed files were read after the last compaction — the deny reason names them; read them in full, then retry. Meaning-only routes stay model-dependent: route on meaning, load when the domain is in doubt. A turn that only reads, counts or explains what exists routes nothing.
6
+ The harness embeds both at session start: the behavior floor and the router. Every other rule enters context when the model `Read`s it on a route match. For routes with an artifact signature the `aki-route-guard` PreToolUse hook denies the first Edit/Write of that artifact type in a session until the routed files were read whole after the last compaction — the deny reason names them; read them in full, then retry. Meaning-only routes stay model-dependent: route on meaning, load when the domain is in doubt. A turn that only reads, counts or explains what exists routes nothing.
7
7
 
8
8
  Doc corpora named by short name in conversation ("UNIDOC", "the standards doc") are machine-specific: resolve them in `~/.claude/CLAUDE.local.md` before searching or asking.
@@ -13,7 +13,7 @@ If the brief asks you to decide something, return the evidence and say the quest
13
13
 
14
14
  # Rules you must read before working
15
15
 
16
- - `~/.aki/akidevrule/RULE-agent-behavior.md` — the behavior floor. `A4` (density), `B2` (verified vs assumed), `B5` (audit is read-only, never mutate git state), `C3` (never hard-wrap a logical line), `C5` (temp files only in the scratchpad).
16
+ - `~/.aki/akidevrule/RULE-agent-behavior.md` — the behavior floor. `A4` (density), `B2` (verified vs assumed), `B5` (audit is read-only, never mutate git state), `C3` (never hard-wrap a logical line), `C5` (no throwaway file the task can do without, and none outside the scratchpad).
17
17
 
18
18
  Nothing else, unless the spawning brief names a file. You inherit no router: a rule not named in your brief is a rule you do not have.
19
19
 
@@ -15,7 +15,7 @@ Change exactly what was asked. No adjacent refactors, no cleanup, no renames, no
15
15
 
16
16
  # Rules you must read before working
17
17
 
18
- - `~/.aki/akidevrule/RULE-agent-behavior.md` — the behavior floor: `B1` scope discipline, `B3` what to ask before, `B4` no model-credit trailers in any git artifact, `C3` never hard-wrap a logical line, `C5` temp files only in the scratchpad.
18
+ - `~/.aki/akidevrule/RULE-agent-behavior.md` — the behavior floor: `B1` scope discipline, `B3` what to ask before, `B4` no model-credit trailers in any git artifact, `C3` never hard-wrap a logical line, `C5` no throwaway file the task can do without, and none outside the scratchpad.
19
19
  - `~/.aki/akidevrule/RULE-coding.md` — `B2` (read the flow and its docs before changing code you did not write; confirm the intents you did *not* set out to touch still hold), `B3` (done means verified, by the narrowest tool that settles the doubt), `B4` (the comment budget — fix the name, then delete the comment).
20
20
  - `~/.aki/akidevrule/RULE-pattern-core.md` — `C1` is the definition of done at the pattern level.
21
21
  - `~/.aki/akidevrule/RULE-test.md` — only when the diff touches a test file, fixture or test config; the route gate denies the first such edit until it is read, so read it first.
@@ -32,6 +32,6 @@ A domain rule the brief named that you could not read means you should not have
32
32
  # Output contract
33
33
 
34
34
  - What changed, per file, in one line each — the change, not a narration of the edit.
35
- - The verification you actually ran, with its output. Never a build or a dev server on your own initiative: those are the owner's call (cost and side effects), and a change whose risk lives only at runtime is reported as **"unverified — needs a runtime check"** with the exact command, never as "Done" (`coding.B3`).
35
+ - The verification you actually ran, as a record (`coding.B3`): command, exit code, log path, output excerpt. A change whose risk lives only at runtime is run (`coding.B3` rung 5: the app on a port of its own, or the CLI/binary against a scratch HOME); only what survives it is reported as **"unverified — needs a runtime check"** with the exact command and the rung that failed, never as "Done".
36
36
  - Anything the brief specified that you did **not** do, and why. Silence about a skipped item reads as completion.
37
37
  - Attestation as checkable fact, not as citation: `files edited: 4 · git mutations: none · scope: only the paths named in the brief`.
@@ -11,5 +11,10 @@
11
11
  },
12
12
  "skillOverrides": {
13
13
  "akirule": "on"
14
+ },
15
+ "attribution": {
16
+ "commit": "",
17
+ "pr": "",
18
+ "sessionUrl": false
14
19
  }
15
20
  }