- New _primitives/ directory, analogous to _blocks/_manifests/_bridges
- tomd.sh: standalone PDF/DOCX/XLSX/PPTX/CSV/code/image → markdown
converter (180 LOC, ported from PROJECT-D bin/keiagent-tomd)
- [tomd] error tag for KeiSeiKit style, KEISEI_TOMD_CACHE env var
- README.md: purpose + invocation + compose-solution discovery
Primitives are first-class building blocks that agents and pipelines
depend on. Installed at $HOME/.claude/agents/_primitives/ by install.sh
in a follow-up commit.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After merging feat/compose-solution, 3 phase files still referenced
patent-scale research / patent block suffix / sensitive IP question. Strip
those generic-kit-incompatible examples:
- phase-2-decompose.md: "patent-scale" → "deep-domain"
- phase-6-block-augment.md: "<slug>-patent" disambiguator → "<slug>-embedded"
- phase-7-assemble.md: drop sensitive IP from fields passed to new-agent wizard
Final grep for "patent" in main tree: zero hits.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Strip all patent-related tooling from the generic kit so it can ship
publicly under MIT without leaking sensitive IP. restricted-scope agents,
blocks, and skill conditionals live in the private PROJECT-E.
Deleted (5 files):
- _manifests/kei-patent-compliance.toml
- _manifests/kei-patent-researcher.toml
- _blocks/domain-sensitive IP-aware.md
- _assembler/tests/fixtures/_manifests/kei-patent-compliance.toml
- _assembler/tests/snapshots/kei-patent-compliance.snap
Cross-reference cleanup:
- 6 manifests: remove kei-patent-* handoffs and "sensitive IP" forbidden lines
- _blocks/deploy-local-only.md: drop sensitive IP rationale, keep ML weights /
offensive / kernel / client-confidential banned-public triggers
- skills/research/SKILL.md: drop patent-angle-scanner + "Patent angles" section
- skills/new-agent/SKILL.md: drop Q5 (patent), renumber Q6→Q5 Q7→Q6
- README.md: drop 2 restricted agents rows, renumber wizard questions 5-7→5-6,
update counts 34→33 blocks / 14→12 agents
- _assembler/tests/golden.rs: remove golden_patent_compliance test
- _assembler/tests/roundtrip.rs: swap kei-patent-compliance fixture to
kei-cost-guardian for double-assembly determinism test
- _assembler/tests/fixtures/_manifests/kei-researcher.toml + snapshot:
remove kei-patent-researcher handoff
Tests: 21 → 20 integration tests, all passing. Grep for "patent" in
main tree returns zero hits outside .claude/worktrees.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a Meta-composer section between Cross-tool bridges and License. The
section explains the one-paragraph intake, links to the 7-phase pipeline,
shows a hook-creation example that routes to /escalate-recurrence, and
emphasizes the Phase 6 block-augmentation feedback loop — the kit gets
smarter with every invocation, with before/after _blocks/ count reported
per session.
Adds a pure-click meta-composer that converts a free-text task description
into the right durable KeiSeiKit artefact — agent, skill, hook, rule, or
block — by composing existing primitives:
- Phase 1 intake (one free-text DESC + target-type click)
- Phase 2 wave-based decomposition (delegates to /research for heavy tasks)
- Phase 3 prior-art grep sweep across _blocks/, _manifests/, skills/,
_bridges/, hooks/ + optional PROJECT-E + external docs
- Phase 4 gap analysis (AskUserQuestion multi-select)
- Phase 5 math-first architecture proposal (derive-first, "what is
unnecessary" pass, Constructor-Pattern check)
- Phase 6 block augmentation — drafts + persists new _blocks/<slug>.md
on user click; kit gets smarter each session
- Phase 7 recipe assembly — branches by type, hands off to /new-agent
(agent) or /escalate-recurrence (hook / rule)
Split into SKILL.md (121-LOC index) + seven phase-*.md files (each <160
LOC) to stay under the 500-LOC/file Constructor-Pattern limit. Minimum 6
AskUserQuestion calls per session enforced by the pipeline; every
referenced block / skill / manifest / bridge path verified to exist on
disk before commit (RULE 0.4 — no fabricated references).
Writes only to _blocks/<slug>.md and skills/<slug>/SKILL.md;
handoffs to /new-agent and /escalate-recurrence own their own files.
- Insert Phase 8 between Phase 6 (Report) and Phase 7 (setup)
- Single AskUserQuestion with 3 options: all 11 / AGENTS.md only / skip
- On accept: invoke ~/.claude/agents/_bridges/emit.sh with the
project path from Phase 2 (optionally --only AGENTS.md)
- On skip: print the exact command the user can run later
- All paths idempotent (emit.sh skips existing files)
- Copy _bridges/ into ~/.claude/agents/_bridges/ so new-agent
skill Phase 8 can invoke the renderer from the user fleet dir
- Add --with-bridges flag: after agents/hooks/skills install,
invoke _bridges/emit.sh "$PWD" to render 11 bridge files
- Guard: if $PWD is the KeiSeiKit source repo itself (detected
via ./install.sh + ./_bridges), warn and skip — avoid
polluting the kit's own working tree
- --help prints usage block; flag parser loop supports future
--activate-hooks coexistence without refactor
- Single-concern renderer (<100 LOC per Constructor Pattern)
- Idempotent — existing files are skipped, not overwritten
- Args: <target> [name] [description]; name defaults to basename,
description defaults to first non-blank line of CLAUDE.md or
README.md, fallback "No description"
- --only <output-path> restricts emission to one file (used by
/new-agent Phase 8 "AGENTS.md only" path)
- Placeholders substituted: PROJECT_NAME, PROJECT_DESCRIPTION,
YEAR, MONTH, DATE
Caught in Phase-2 double-audit pass AFTER commits 1-5 were already
pushed: top-level _blocks/*.md contains prose handoff references to
"cost-guardian" that get composed into generated agent .md files.
These were missed by the skills/manifests sweep because blocks weren't
in the original task spec list (only fixture _blocks/ were mentioned,
and those are separate).
Impact if left unfixed: any project-specialist created via /new-agent
with Q3=Yes (paid APIs) or Q7!=None (scrapers) would compose these
blocks and emit a generated .md referencing the stale `cost-guardian`
handoff target — a dangling reference after the kei-* rename.
Files touched (10 references, all to `cost-guardian`):
- _blocks/api-apify.md (1)
- _blocks/api-elevenlabs.md (2)
- _blocks/api-fal-ai.md (2)
- _blocks/domain-paid-apis.md (2)
- _blocks/scraper-paid-tier.md (3)
Verify: cargo test -> 17/17 still green (fixture _blocks/ isolated
from top-level _blocks/, so no snapshot drift).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wizard's Phase 3 previously computed a deterministic `<slug>-specialist`
name and wrote it directly. Now:
- Phase 3 composition step states the PROPOSED default: `kei-<slug>-specialist`
(matches the KeiSeiKit kit-prefix convention introduced in commit 3039ada).
- NEW Phase 3.5: one AskUserQuestion call with three options:
1. `kei-<slug>-specialist` (default, kit convention)
2. `<slug>-specialist` (user namespace, no kei- prefix)
3. Specify custom name (free-text with strict validation:
regex ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$, length 3-40, no --, no
leading/trailing dash; no auto -specialist suffix)
- Resolved value stored as FINAL_NAME and threaded through Phase 4
(manifest Write path), Phase 5 (--validate + --in-place assemble args),
and Phase 6 (report block + git-commit example).
- Phase 2 prompt updated to reflect the confirmation step.
- Invalid custom-name input re-asks instead of falling through (constructive-
only rule).
Touches only skills/new-agent/SKILL.md. The installed ~/.claude/skills/new-agent/
copy will be refreshed on the next `./install.sh` run.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Agents-overview table: 14 rows renamed to kei-<name>.
- "What you get" table examples: kei-<name> with trailing "...".
- Intro paragraph: note on kei-* namespace motivation (no collision
with user's own same-named agents).
No code/behavior change — this is pure docs alignment with the manifest
rename in commit 3039ada.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename 4 fixture manifests under _assembler/tests/fixtures/_manifests/
({code-implementer,cost-guardian,patent-compliance,researcher}.toml
-> kei-<name>.toml) via git mv. Copy updated top-level manifests into
fixtures so they stay byte-identical (fixtures mirror real manifests).
- Rename 4 snapshot files under _assembler/tests/snapshots/ to match
the new insta snapshot keys.
- Update snapshot bodies to reflect the kei- prefix in:
* frontmatter name field (name: kei-<n>)
* GENERATED comment (_manifests/kei-<n>.toml)
* handoff target lines
* === HEADER === REPORT header (uppercased name in output_format)
- Update test code (golden.rs, roundtrip.rs, validator_negative.rs,
determinism.rs) to use the new manifest filenames + snapshot keys.
Rust function names (e.g. golden_researcher) untouched — they are
internal identifiers, not manifest refs, and the word-boundary rule
(no "_" preceding match) correctly skipped them.
Verify:
cd _assembler && cargo test
-> 17 tests passed (0 + 3 + 4 + 2 + 2 + 6 across 6 test files)
-> Re-run produces no *.snap.new files (snapshots stable)
Regeneration path: because cargo-insta CLI is not installed on the
build host, the .snap.new files produced by the first (failing) test
run were accepted by renaming .snap.new -> .snap. Second cargo test
run passed cleanly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mechanical rename of all 14 kit-agent references in skills/*/SKILL.md.
Pattern: word-boundary match that excludes "-" on both sides, applied
longest-first so "ml-researcher" rewrites before "researcher" (avoids
the "kei-ml-kei-researcher" double-prefix trap).
skills/new-agent/SKILL.md (14 refs):
- Phase 3.3 handoff list (code-implementer/critic/validator mandatory,
cost-guardian/ml-implementer/ml-researcher/infra-implementer/
security-auditor conditional)
- Phase 3.5 role-template example (Hand off ... to code-implementer ...)
- Phase 4 manifest-template example (target = "code-implementer" etc.)
- Phase 6 report-block example ("Handoffs: code-implementer, critic, ...")
- Description-string ref on Phase 1b (cost-guardian mandatory)
skills/research/SKILL.md (5 refs):
- `critic` renamed to `kei-critic` inside backticks and bold
- Teammate-role mentions that happen to share the name
- NOTE: hyphenated compound labels like `web-researcher`, `code-explorer`,
`{component}-critic`, `meta-critic` are left untouched — they are
ad-hoc teammate-role labels, not kit-agent handoffs. The boundary rule
(no "-" immediately before the name) preserves them correctly.
Other 4 skills (debug-deep, pr-review, refactor, test-gen) have zero
kit-agent references — untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename _manifests/{architect,code-implementer,cost-guardian,critic,
fal-ai-runner,infra-implementer,ml-implementer,ml-researcher,modal-runner,
patent-compliance,patent-researcher,researcher,security-auditor,validator}.toml
to kei-<name>.toml (git mv — history preserved).
- Update every `name = "..."` field to the new kei- name.
- Update every handoff `target = "..."` cross-reference (62 occurrences across
14 manifests) to point at the kei-prefixed counterpart.
- Update backticked prose cross-refs in role/forbidden_domain/description
strings: `code-implementer` -> `kei-code-implementer`, etc.
- Update SSoT header comments: "SSoT for <name>." -> "SSoT for kei-<name>.".
- Fix 3 bare-word prose refs missed by quoted/backticked patterns:
kei-code-implementer.toml (validator enforces), kei-security-auditor.toml
(description Hands fixes off to ..., forbidden_domain separate critic pass).
Noun-phrase mentions left intact (not agent refs): "senior software
architect", "ruthless code critic", "patent prior-art researcher",
"architectural claim", "critical findings", etc.
Verify:
cd _assembler && cargo build --release
AGENT_ROOT=$(pwd)/.. target/release/assemble --validate
-> 14 OK
Namespace motivation: kit-shipped agents live in a reserved "kei-*"
namespace so downstream installs can drop in custom, same-name agents
without collision (e.g. user's own `validator` or `critic`).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Regression test for the fix in 30cd08b (replaced
`root.parent().unwrap()` with `.unwrap_or(root.as_path())` at
main.rs:45). Two cases:
- `agent_root_slash_does_not_panic` — `AGENT_ROOT=/ assemble /dev/null`
must reach the "parse failed" error path without panicking. Guards
against the `relative_to()` call site specifically.
- `agent_root_slash_full_run_no_panic` — same env with a valid stub
manifest supplied explicitly. Even though the run fails at
`mkdir /_generated` (unprivileged), it must fail GRACEFULLY, not
with SIGABRT from an `.unwrap()` on a None parent.
Both assertions: no "panicked at" in stderr, and `status.code()` is
Some (signal-kill would return None on Unix).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tests/determinism.rs (3 cases):
- same input across 2 isolated tempdirs → byte-identical output
- same input across 10 isolated tempdirs → all byte-identical
(catches HashMap iteration nondeterminism a 2-run check can miss)
- reordering blocks in the manifest changes output, but only in the
block region — frontmatter + role + trailing sections are stable
tests/roundtrip.rs (2 cases):
- every manifest string (name, model, tools list, all domain_in /
forbidden_domain / handoff.target / handoff.trigger entries)
appears verbatim in the generated output; no field silently dropped
- two consecutive runs in the SAME tempdir produce identical bytes
(defence against caching / mutable-global drift)
tests/validator_negative.rs (6 cases):
- unknown block ref → error mentions the bad name
- missing obligatory block (memory-protocol removed) → error names it
- empty handoff array → error mentions "handoff"
- whitespace-only role → error mentions "role"
- empty domain_in → error mentions "domain_in"
- --validate flag on a valid manifest: exit 0, no file written
Not covered: unsubstituted `{{placeholder}}` check — that validator
rule is being added in a parallel PR (fix/remaining-findings) and is
not yet on this base branch. Add a case for it when the check lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add tests/golden.rs with insta-backed snapshot assertions for:
- researcher (minimal — 3 obligatory blocks only)
- cost-guardian (minimal + output_extra_fields)
- patent-compliance (minimal + references.extra)
- code-implementer (obligatory + 4 implementer-specific blocks)
Coverage: all four frontmatter fields (name/description/tools/model),
role body, block concatenation order, domain_in / forbidden_domain /
handoffs / output format (including extra fields) / references (both
optional memory_project + project_claudemd and references.extra).
The snapshots in tests/snapshots/*.snap are the signed contract —
any change to assembler.rs output must be reviewed via
`cargo insta review` and committed alongside the code change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add insta + tempfile to _assembler/Cargo.toml [dev-dependencies].
- Create tests/common/mod.rs with helpers: seed_tempdir (copies
fixtures into an isolated AGENT_ROOT), run_assemble (invokes the
built binary via std::process::Command), and assemble_one
(end-to-end single-manifest helper).
- Seed tests/fixtures/ with the 4 manifests covered by the golden
snapshots (code-implementer, researcher, cost-guardian,
patent-compliance) and the 7 blocks they reference (baseline,
evidence-grading, memory-protocol, rule-pre-dev-gate,
rule-test-first, rule-error-budget, rule-double-audit).
Binary-only crate (no lib target), so integration tests invoke the
assemble binary in-process instead of calling internal functions.
This exercises the full main.rs I/O + validator + assembler pipeline
end-to-end, which is exactly what the determinism claim covers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
$HOOKS_DIR ($HOME/.claude/hooks) is shared with other kits. Backing up
the whole directory cumulatively bloats foreign hooks across re-runs.
Switch to backup_file per KeiSeiKit-owned hook so only the 3 files we
actually overwrite get a .bak-TIMESTAMP sibling. backup_dir remains for
KeiSeiKit-owned directories (_blocks, _templates, _assembler, skills).
say/warn/err now detect isatty(1) and the NO_COLOR env convention. When
stdout is redirected to a log file or NO_COLOR is set, ANSI escape codes
are suppressed. Interactive activation prompt also gated.
Previous block-rebuild path piped through head -40, so a FAIL on line 50
was invisible. Now FAIL/ERROR lines are always printed first; OK lines
are still truncated. Written in POSIX sh per Fix 4.
Walks every string-valued manifest field after load and rejects values
containing `{{...}}` (conservative: requires both `{{` and `}}`). Catches
wizard bugs that would emit literal `{{MEMORY_PROJECT}}` into the
generated agent .md. Four unit tests cover role/memory_project/single-brace
accept/empty-accept cases.
Offline build is attempted first so a fresh clone with a warm registry
cache can install without network. On failure, fall back to a regular
cargo build --release which will fetch from crates.io.
All three hooks changed shebang from bash to sh. No bashisms were in use
(no [[, no local, no arrays) so only the interpreter line moved. Verified
with sh -n, and dash smoke-run with a sample tool_input JSON.
Explains that 8 of 34 blocks are used by shipped manifests; the other 26
feed the /new-agent wizard. Adds a v0.1.1 disclaimer that re-running
install.sh backs up kit-owned directories and hook files to .bak-TIMESTAMP.
Adds --activate-hooks flag for non-interactive hook activation, plus a
TTY prompt at end-of-install. Merge is jq-based, groups by matcher, and
de-dupes hook entries by command — idempotent across re-runs. Existing
user hooks on the same matcher are preserved. Non-TTY without the flag
keeps the manual instructions.
If cargo build or any later step fails, the ERR trap walks the list of
backups created during this run and atomically swaps each .bak-TIMESTAMP
back onto its original. Idempotent via ROLLED_BACK guard. On success
nothing is rolled back — backups remain as the user's recovery copy.
_blocks/memory-protocol.md references ~/.claude/memory/MEMORY.md, but the
installer previously only scaffolded agents/ hooks/ skills/ — so the first
agent that followed the block would fail reading a non-existent index.
Now mkdir -p ~/.claude/memory and, only when MEMORY.md is absent, write a
minimal placeholder (frontmatter + pointer to the block). User-edited
MEMORY.md is never overwritten.
root.parent().unwrap() at main.rs:45 panicked if AGENT_ROOT pointed at a
filesystem root (e.g. AGENT_ROOT=/). Now falls back to root itself via
.unwrap_or(root.as_path()) so the 'OK <manifest> → <path>' line just
prints the absolute path in that edge case instead of aborting.
All three hooks used `set -eu` + `cat | jq …`. Without jq installed, jq
would fail and `-e` would abort the hook → non-zero exit → Claude Code
refuses Edit/Write/Bash system-wide. Now each hook probes for jq BEFORE
`set -eu` and exits 0 silently if absent. Also dropped the useless `cat |`
pipe — `jq -r` reads stdin directly.
Companion: install.sh jq check upgraded from warn to hard `exit 1` because
without jq the hooks are dead weight; message states jq is required on
any machine that will activate the hooks.
Previously cp -f clobbered user-edited _blocks/, _templates/, _assembler/,
hooks/, and skills/ silently — violating the README's "idempotent" claim
on re-run. Now each of those targets is snapshotted to a timestamped
<target>.bak-$(date +%s)/ sibling before overwrite, but only when the
target actually contains regular files (freshly-mkdir'd scaffolds are
skipped). _manifests/ unchanged — already uses per-file skip-if-exists.
Kit source ($KIT_DIR) is never backed up.