From 77184ca2aeb56e88fddc7267b1d53124acc83783 Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Tue, 21 Apr 2026 20:07:06 +0800 Subject: [PATCH 1/5] =?UTF-8?q?fix(audit-h1):=20correct=20README=20counts?= =?UTF-8?q?=20=E2=80=94=204=20hooks,=207=20skills,=2012=20agents;=20docume?= =?UTF-8?q?nt=20compose-solution=20+=20tomd-preread?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README line 3: 'three pre-wired hooks ... six portable skills' → 'four ... seven' - README table row: hooks 3→4 (adds tomd-preread), skills 6→7 (adds compose-solution) - README step 6: 'three hooks and six skills' → 'four hooks and seven skills' - README pipeline paragraph: 'Three hooks enforce' → 'Four hooks enforce' + tomd-preread bullet - install.sh post-install message: '3 hooks' → '4 hooks' (tomd-preread added) --- README.md | 11 ++++++----- install.sh | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c623d41..949fb71 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # KeiSeiKit — Constructor-Pattern Agent Kit for Claude Code -KeiSeiKit is a drop-in agent fleet for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, three pre-wired hooks, and six portable skills including an interactive `/new-agent` wizard. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit. +KeiSeiKit is a drop-in agent fleet for [Claude Code](https://claude.com/claude-code). It ships a curated set of composable behavioral blocks, a Rust assembler that builds agent `.md` files from TOML manifests deterministically, four pre-wired hooks, and seven portable skills including an interactive `/new-agent` wizard. Everything follows a Constructor Pattern: one file per concern, manifests as single source of truth, and the generated agent files are regenerated on every relevant edit. The kit is MIT-licensed and fully generic — install it on a fresh machine and you get a sane 12-agent fleet (implementers, critics, researchers, cost-guardians, and more — all namespaced under `kei-*` so they won't collide with your own same-named agents), a wizard for spinning up new project specialists, and a build pipeline that keeps every agent derivable from its manifest. @@ -25,7 +25,7 @@ cd KeiSeiKit 3. Copies generic manifests (skips if you already have a manifest with that name) 4. Builds the Rust assembler (`cargo build --release`) 5. Generates agent `.md` files in-place with `AGENT_ROOT=~/.claude/agents assemble --in-place` -6. Copies the three hooks and six skills +6. Copies the four hooks and seven skills After install, the only remaining step is merging `settings-snippet.json` into your `~/.claude/settings.json` to activate the hooks. You can do this automatically with `./install.sh --activate-hooks` or answer `y` at the end-of-install TTY prompt. @@ -37,8 +37,8 @@ After install, the only remaining step is merging `settings-snippet.json` into y |---|---:|---| | Behavioral blocks | 33 | `baseline`, `evidence-grading`, `rule-math-first`, `stack-rust-axum`, `deploy-modal`, `api-fal-ai`, ... | | Generic agents (manifests) | 12 | `kei-code-implementer`, `kei-critic`, `kei-validator`, `kei-security-auditor`, `kei-architect`, `kei-researcher`, `kei-ml-implementer`, `kei-cost-guardian`, `kei-modal-runner`, ... | -| Hooks | 3 | `assemble-agents` (PostToolUse), `assemble-validate` (PreToolUse Bash), `no-hand-edit-agents` (PreToolUse Edit/Write) | -| Skills | 6 | `new-agent`, `research`, `test-gen`, `pr-review`, `refactor`, `debug-deep` | +| Hooks | 4 | `assemble-agents` (PostToolUse), `assemble-validate` (PreToolUse Bash), `no-hand-edit-agents` (PreToolUse Edit/Write), `tomd-preread` (PreToolUse Read) | +| Skills | 7 | `new-agent`, `research`, `test-gen`, `pr-review`, `refactor`, `debug-deep`, `compose-solution` | Of the 33 blocks, the **8 base blocks** (`baseline`, `evidence-grading`, `memory-protocol`, `rule-pre-dev-gate`, `rule-test-first`, `rule-error-budget`, `rule-double-audit`, `rule-math-first`) are referenced directly by the 12 shipped manifests. The remaining **25 blocks** (`stack-*`, `deploy-*`, `api-*`, `scraper-*`, `domain-*`) are a library consumed by the `/new-agent` wizard: when you compose a project specialist, the wizard picks the appropriate stack / deploy / API / scraper / domain blocks and emits a manifest that references them. The kit's generic 12 agents do not import them by default. @@ -74,11 +74,12 @@ Then one free-text prompt for slug + description + path + gotchas. The wizard co Block edit (_blocks/.md) <-- triggers rebuild of ALL agents ``` -Three hooks enforce the pipeline: +Four hooks enforce the pipeline: - **`assemble-agents`** (PostToolUse, Write/Edit) — rebuilds the affected agent(s) whenever a manifest or a block changes. No manual rebuild needed. - **`assemble-validate`** (PreToolUse, Bash) — blocks `git commit` inside `~/.claude` if any manifest fails validation. Keeps the repo in a buildable state at all times. - **`no-hand-edit-agents`** (PreToolUse, Edit/Write) — refuses edits to any `.md` under `~/.claude/agents/` that starts with the `` marker, pointing you at the manifest instead. Override with `AGENT_MIGRATION=1` for emergencies only. +- **`tomd-preread`** (PreToolUse, Read) — auto-converts opaque binary formats (`.docx`, `.doc`, `.xlsx`, `.pptx`, `.csv`) to markdown via the `tomd` primitive and redirects Claude to read the cached `.md` instead. Cache under `$KEISEI_TOMD_CACHE` (default `/tmp/keisei-tomd-cache`). Degrades silently if `jq` or the primitive is absent. ## Adding custom blocks diff --git a/install.sh b/install.sh index 40c271b..ac8ccbb 100755 --- a/install.sh +++ b/install.sh @@ -383,7 +383,7 @@ else NEXT STEP: merge settings-snippet.json into ~/.claude/settings.json ========================================================================== - KeiSeiKit ships 3 hooks (assemble-agents, assemble-validate, no-hand-edit). + KeiSeiKit ships 4 hooks (assemble-agents, assemble-validate, no-hand-edit, tomd-preread). To activate them, merge entries from: $KIT_DIR/settings-snippet.json into your: From a23cde32a8f3623040bef2adbd00f8f139cac91d Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Tue, 21 Apr 2026 20:07:42 +0800 Subject: [PATCH 2/5] fix(audit-h2,h3): remove bare-name bypass in compose-solution phase-2; backup settings.json in activate_hooks - phase-2-decompose.md: delete 'or researcher if that agent is present in the user's global fleet' clause that silently bypassed the kei-namespace. Replace with an explicit prefer-kei note warning that bare 'researcher' matches only the user's personal fleet and may have divergent handoffs. - install.sh activate_hooks(): call backup_file "$target" on the merge path (after the 'create new' early-return) so ERR-trap rollback can restore the pre-merge settings.json. Previously an ERR in the jq-merge or mv left no backup pair to restore. --- install.sh | 4 ++++ skills/compose-solution/phase-2-decompose.md | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/install.sh b/install.sh index ac8ccbb..6432f92 100755 --- a/install.sh +++ b/install.sh @@ -142,6 +142,10 @@ activate_hooks() { say "created $target from snippet (no prior settings.json)" return 0 fi + # Merge path: back up the pre-merge settings.json so rollback can restore + # it if a later step ERR-traps. The "create new" path above exits before + # reaching here, so backup_file is only invoked when $target exists. + backup_file "$target" # Merge: walk each matcher-group in PostToolUse / PreToolUse, append hooks, # unique_by command. jq filter is written for readability, not golf. tmp="$(mktemp "$target.XXXXXX")" diff --git a/skills/compose-solution/phase-2-decompose.md b/skills/compose-solution/phase-2-decompose.md index 00fe324..d7f6cf1 100644 --- a/skills/compose-solution/phase-2-decompose.md +++ b/skills/compose-solution/phase-2-decompose.md @@ -8,9 +8,11 @@ independently researched and composed. For heavy / deep-domain / unfamiliar-domain tasks, delegate to the `research` skill (`skills/research/SKILL.md`, Variant C "Deep decomposition" is the pattern — Wave 0 decomposition, then Wave 1 per-component -exploration). Invoke via the Agent tool with `subagent_type: kei-researcher` -(or `researcher` if that agent is present in the user's global fleet). Pass -`DESC` as the research question with the constraint: +exploration). Invoke via the Agent tool with `subagent_type: kei-researcher`. +Always prefer `kei-researcher` when it exists in the kit; bare `researcher` +matches only the user's personal fleet and may have divergent handoffs — do +not fall back to it silently. Pass `DESC` as the research question with the +constraint: > Decompose into 2-5 orthogonal components, each with a 1-line description > and 3-5 distinctive keywords suitable for grep prior-art search. From d155afc554b175a8fc8df5fc8f72e0b8d3a2c32a Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Tue, 21 Apr 2026 20:09:24 +0800 Subject: [PATCH 3/5] fix(audit-m): tomd cache path-salt; bridges respects rollback; rollback rm-rf guard; placeholder URLs; research skill role-tag note; stack frontend-gap doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - M1 (RULE 0.4): replace fabricated URLs 'https://example.invalid/PROJECT-D' and 'https://…/PROJECT-D' with plain text ('user's personal CLI predecessor'). - M2: tomd-preread cache key = basename + mtime + 8-char shasum of full path, so two files with the same basename+mtime at different paths no longer collide. Portable shasum shim; falls back to 'nohash' if shasum absent. - M3: install.sh --with-bridges gated on ROLLED_BACK=0 so bridges are NOT emitted into $PWD after an ERR-trap rollback. - M4: rollback() guards rm -rf "$orig" behind an existence check. - M5: skills/research/SKILL.md front-matter note — role tags like 'web-researcher' / 'meta-critic' are ad-hoc prompt labels for the generic kei-researcher subagent, NOT separate manifests. Prevents fruitless grep in _manifests/. - M6: README adds a 'Frontend-stack coverage gap' callout listing the planned-but-not-shipped frameworks (React-Vite, Vue-Nuxt, SvelteKit, Astro, Angular, plain-web). - M7: no-hand-edit-agents.sh documents at case block that the GENERATED marker is the SOLE source of truth — legacy unmarked .md files pass silently by design; re-run the assembler to adopt them. --- README.md | 4 +++- _primitives/README.md | 6 +++--- hooks/no-hand-edit-agents.sh | 10 +++++++++- hooks/tomd-preread.sh | 9 +++++++-- install.sh | 12 +++++++++++- skills/research/SKILL.md | 7 +++++++ 6 files changed, 40 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 949fb71..7efda4e 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ After install, the only remaining step is merging `settings-snippet.json` into y Of the 33 blocks, the **8 base blocks** (`baseline`, `evidence-grading`, `memory-protocol`, `rule-pre-dev-gate`, `rule-test-first`, `rule-error-budget`, `rule-double-audit`, `rule-math-first`) are referenced directly by the 12 shipped manifests. The remaining **25 blocks** (`stack-*`, `deploy-*`, `api-*`, `scraper-*`, `domain-*`) are a library consumed by the `/new-agent` wizard: when you compose a project specialist, the wizard picks the appropriate stack / deploy / API / scraper / domain blocks and emits a manifest that references them. The kit's generic 12 agents do not import them by default. +> **Frontend-stack coverage gap.** The shipped `stack-*` blocks currently cover Next.js and Flutter. Pure frontend frameworks (React-Vite, Vue-Nuxt, SvelteKit, Astro, Angular, plain-web) are planned as a follow-up; contributions are welcome via PR. Blocks stay in a single `_blocks/` directory — no opt-in split planned. + ## Creating a new agent Run the wizard in Claude Code: @@ -145,7 +147,7 @@ All paths are idempotent: existing bridge files in the project are skipped, neve `_primitives/` holds first-class building blocks that agents and pipelines depend on — executable utilities, not behavioral markdown. Currently one primitive ships with the kit: -- `tomd` — universal non-native-format → markdown converter (PDF, DOCX, XLSX, PPTX, CSV, code, images with OCR). Ported from [KeiAgent](https://example.invalid/KeiAgent) with KeiSeiKit-style error tags and a configurable cache directory (`KEISEI_TOMD_CACHE`, default `/tmp/keisei-tomd-cache`). +- `tomd` — universal non-native-format → markdown converter (PDF, DOCX, XLSX, PPTX, CSV, code, images with OCR). Ported from the KeiAgent project (user's personal CLI predecessor) with KeiSeiKit-style error tags and a configurable cache directory (`KEISEI_TOMD_CACHE`, default `/tmp/keisei-tomd-cache`). The matching hook `hooks/tomd-preread.sh` is a `PreToolUse(Read)` entry that auto-redirects Claude to a cached markdown conversion when a Read targets an opaque binary format — no agent has to know about `tomd` explicitly, but any agent that *does* need to shell out can invoke `~/.claude/agents/_primitives/tomd.sh report.pdf > report.md` directly. diff --git a/_primitives/README.md b/_primitives/README.md index 7383e19..dcc1548 100644 --- a/_primitives/README.md +++ b/_primitives/README.md @@ -11,9 +11,9 @@ programs installed at `$HOME/.claude/agents/_primitives/` by `install.sh`. |---|---|---| | `tomd.sh` | Universal non-native-format → markdown converter (PDF, DOCX, XLSX, PPTX, CSV, images, code). | `~/.claude/agents/_primitives/tomd.sh ` | -`tomd.sh` is ported from [KeiAgent](https://…/KeiAgent) `bin/keiagent-tomd` — -same format matrix, KeiSeiKit-style error tags (`[tomd]`), configurable -cache directory (`KEISEI_TOMD_CACHE`). +`tomd.sh` is ported from the KeiAgent project (user's personal CLI +predecessor) `bin/keiagent-tomd` — same format matrix, KeiSeiKit-style +error tags (`[tomd]`), configurable cache directory (`KEISEI_TOMD_CACHE`). ## Hook integration diff --git a/hooks/no-hand-edit-agents.sh b/hooks/no-hand-edit-agents.sh index 92b89bd..b12456d 100755 --- a/hooks/no-hand-edit-agents.sh +++ b/hooks/no-hand-edit-agents.sh @@ -21,13 +21,21 @@ FILE=$(jq -r '.tool_input.file_path // empty') # Only care about files directly under ~/.claude/agents/*.md # (not blocks/, manifests/, assembler/, template, generated preview) +# +# NOTE on staleness: we use the `` marker +# on line 1 as the SOLE SOURCE OF TRUTH for "is this file generated?". +# Legacy agent .md files that were produced before the assembler existed +# (and therefore lack the marker) will pass this hook silently. That is +# intentional — the marker is how the assembler self-declares ownership, +# and any file without it is assumed hand-authored. Re-run the assembler +# to adopt an older file into the managed set. case "$FILE" in "$HOME/.claude/agents/_"*) exit 0 ;; "$HOME/.claude/agents/"*.md) ;; *) exit 0 ;; esac -# Detect generated marker in the first 10 lines +# Detect generated marker in the first 10 lines (sole truth — see NOTE above) if [ -f "$FILE" ] && head -10 "$FILE" | grep -q 'GENERATED by _assembler'; then NAME=$(basename "$FILE" .md) echo "[no-hand-edit-agents] BLOCKED: $FILE is generated." >&2 diff --git a/hooks/tomd-preread.sh b/hooks/tomd-preread.sh index e8ceb17..362cf2a 100755 --- a/hooks/tomd-preread.sh +++ b/hooks/tomd-preread.sh @@ -32,10 +32,15 @@ esac mkdir -p "$CACHE_DIR" -# Cache key: basename + mtime. Portable stat for macOS + Linux. +# Cache key: basename + mtime + short path-hash. Path-hash disambiguates +# two files with the same basename+mtime at different paths (otherwise they +# would collide and Claude would silently read the wrong conversion). +# Portable stat for macOS + Linux; portable shasum shim. BASENAME=$(basename "$FILE") MTIME=$(stat -f %m "$FILE" 2>/dev/null || stat -c %Y "$FILE" 2>/dev/null || echo 0) -MD_FILE="$CACHE_DIR/${BASENAME%.*}-${MTIME}.md" +PATH_HASH=$(printf '%s' "$FILE" | shasum 2>/dev/null | cut -c1-8) +[ -n "$PATH_HASH" ] || PATH_HASH="nohash" +MD_FILE="$CACHE_DIR/${BASENAME%.*}-${MTIME}-${PATH_HASH}.md" if [ ! -s "$MD_FILE" ]; then "$TOMD" "$FILE" > "$MD_FILE" 2>/dev/null || true diff --git a/install.sh b/install.sh index 6432f92..fee3810 100755 --- a/install.sh +++ b/install.sh @@ -80,7 +80,11 @@ rollback() { orig="${pair%%|*}" bak="${pair#*|}" if [ -e "$bak" ]; then - rm -rf "$orig" + # Guard rm -rf: only remove $orig if it actually exists as a file or + # directory. Harmless either way, but explicit is safer than brittle. + if [ -d "$orig" ] || [ -f "$orig" ]; then + rm -rf "$orig" + fi mv "$bak" "$orig" say " restored $orig from $bak" fi @@ -353,6 +357,12 @@ elif [ -t 0 ] && [ -t 1 ]; then fi # --- optional: render cross-tool bridges into $PWD ------------------------- +# If a prior step ERR-trapped into rollback(), we MUST NOT keep writing into +# $PWD — the install is now aborted, and bridges should not land as +# collateral on a failed run. rollback() sets ROLLED_BACK=1 before returning. +if [ "${ROLLED_BACK:-0}" = "1" ]; then + exit 2 +fi if [[ "$WITH_BRIDGES" == "1" ]]; then if [[ -f "./install.sh" && -d "./_bridges" ]]; then warn "not generating bridges — you are in the KeiSeiKit repo, not a project directory" diff --git a/skills/research/SKILL.md b/skills/research/SKILL.md index 319f5dc..ca72a6d 100644 --- a/skills/research/SKILL.md +++ b/skills/research/SKILL.md @@ -4,6 +4,13 @@ description: Deep research on any topic using parallel agents, web search, and c argument-hint: --- +> **Role-tag convention.** Names like `web-researcher`, `meta-critic`, +> `arch-analyst`, `{component}-critic` that appear later in this skill are +> ad-hoc role tags passed to the generic `kei-researcher` subagent inside +> its prompt — they are NOT separate manifests in the kit. Do not grep for +> them in `_manifests/`; they will not be found. The only manifest behind +> every research teammate is `kei-researcher`. + # Deep Research Skill You are conducting deep research on: $ARGUMENTS From ab70b8344d91fff605c247a7b019868268535e84 Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Tue, 21 Apr 2026 20:10:04 +0800 Subject: [PATCH 4/5] fix(audit-l): agent count drift in install.sh and compose-solution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - L1: install.sh post-install banners '~14 generated agents' → '12 generated agents' (both the activated-path and the manual-merge-path copies). - L2: skills/compose-solution/SKILL.md handoff reference '14 kit agents' → '12 kit agents'. - L3: README /new-agent section rephrases 'via option-pickers' to call out that the 6 questions are grouped into multiple option-picker batches (two AskUserQuestion calls) rather than six separate prompts. --- README.md | 2 +- install.sh | 4 ++-- skills/compose-solution/SKILL.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7efda4e..3e09aa2 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Run the wizard in Claude Code: /new-agent ``` -You'll be asked (via option-pickers, not free-text): +You'll be asked (via multiple option-picker batches, not free-text) — each batch groups several click-only questions into a single `AskUserQuestion` call: 1. Project stack (Rust CLI / axum / SwiftUI / Flutter / FastAPI / Next.js / Go / Embedded / Python ML) 2. Deploy target (local-only / EC2 / Cloudflare / Modal / Docker / none) diff --git a/install.sh b/install.sh index fee3810..b7ed068 100755 --- a/install.sh +++ b/install.sh @@ -383,7 +383,7 @@ if [ "$DID_ACTIVATE" = "1" ]; then ========================================================================== To verify install: - ls $AGENTS_DIR/*.md # should show ~14 generated agents + ls $AGENTS_DIR/*.md # should show 12 generated agents $AGENTS_DIR/_assembler/target/release/assemble --validate To create a new project-specialist agent: @@ -407,7 +407,7 @@ else ./install.sh --activate-hooks To verify install: - ls $AGENTS_DIR/*.md # should show ~14 generated agents + ls $AGENTS_DIR/*.md # should show 12 generated agents $AGENTS_DIR/_assembler/target/release/assemble --validate To create a new project-specialist agent: diff --git a/skills/compose-solution/SKILL.md b/skills/compose-solution/SKILL.md index 2595e0a..192e50d 100644 --- a/skills/compose-solution/SKILL.md +++ b/skills/compose-solution/SKILL.md @@ -116,6 +116,6 @@ Future invocations benefit from the K new blocks — kit is now smarter by K blo architectural decomposition if `research` is overkill - `_blocks/baseline.md`, `_blocks/rule-math-first.md` — block templates (Phase 6a shape references) -- `_manifests/kei-*.toml` — 14 kit agents (Phase 7b handoff references) +- `_manifests/kei-*.toml` — 12 kit agents (Phase 7b handoff references) - `_bridges/*.tmpl` — 11 tool bridges (architecture Phase 5 may reference them for agent-creation flows) From fba0436fb911af4acc427d65b070ef02721ebb2e Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Tue, 21 Apr 2026 20:11:37 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix(audit-h1):=20one=20more=20stale=20'thre?= =?UTF-8?q?e=20shell=20hooks'=20=E2=86=92=20'four=20shell=20hooks'=20in=20?= =?UTF-8?q?prerequisites?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e09aa2..ac4ee45 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The kit is MIT-licensed and fully generic — install it on a fresh machine and ## Prerequisites - **Rust** (stable toolchain) — the assembler is a small Cargo binary -- **jq** — used by the three shell hooks for JSON parsing (`brew install jq` / `apt install jq`) +- **jq** — used by the four shell hooks for JSON parsing (`brew install jq` / `apt install jq`) - **Claude Code** — the agents, hooks, and skills target Claude Code's agent / skill / hook surface ## Install