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

- 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.
This commit is contained in:
Parfii-bot 2026-04-21 20:09:24 +08:00
parent a23cde32a8
commit d155afc554
6 changed files with 40 additions and 8 deletions

View file

@ -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.

View file

@ -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 <file>` |
`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

View file

@ -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 `<!-- GENERATED by _assembler -->` 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

View file

@ -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

View file

@ -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"

View file

@ -4,6 +4,13 @@ description: Deep research on any topic using parallel agents, web search, and c
argument-hint: <topic or question>
---
> **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