Commit graph

265 commits

Author SHA1 Message Date
Parfii-bot
329d7e2a4d feat(agent-substrate/phase-5): migrate 5 kit agents to role+task-spec — substrate v1 FULL
Final phase of agent substrate v1. 5 shipped agents now declare role at
manifest level; assembler expands role's capability text fragments into
the generated .md at a new `# AGENT SUBSTRATE — role <name>` section.
Non-migrated agents byte-identical (golden snapshots green).

Migrated agents:
- kei-code-implementer → edit-local (8 caps: no-git-ops + scope/* +
  quality/* + safety::no-dep-bump + report-format)
- kei-critic → read-only (tools::read-only + output::report-format +
  output::severity-grade)
- kei-architect → read-only
- kei-security-auditor → read-only
- kei-validator → read-only

_assembler/ extensions:
- manifest.rs: substrate_role: Option<String>
- assembler.rs: write_substrate() before blocks (backward-compat; no
  role = no substrate section)
- substrate.rs (new, 102 LOC): loads _roles/<name>.toml, iterates
  capabilities.required, reads _capabilities/<cat>/<slug>/text.md,
  joins with \n\n---\n\n separator
- validator.rs: substrate role existence + cap-text presence check
- tests/substrate_role.rs (4 tests): happy path, unknown role, missing
  capability text, byte-parity on non-migrated
- tests/regenerate_migrated.rs (ignored by default): regeneration gate

_templates/task-examples/ — 5 example task.toml per migrated agent
showing orchestrator the valid invocation shape.

docs/AGENT-SUBSTRATE-SCHEMA.md: Phase 5 row ticked ✓ + Migrated agents
subsection listing 5 agents with roles + pointer to examples.

tests/substrate_integration.sh: +8 Phase-5 assertions
- All 5 migrated .md files contain "# AGENT SUBSTRATE — role"
- kei-code-implementer.md contains "MUST NOT invoke git" (policy::no-git-ops)
- Every _templates/task-examples/*.toml parses as valid TOML
- cargo check --workspace still passes post-migration
- kei-agent-runtime compose works on edit-local-forge.toml example

Tests: assembler 40/40 (was 30, +4 substrate_role + +1 ignored regen),
kei-agent-runtime + kei-capability 37/37 preserved.

Deferred: remaining 7 non-core agents (cost-guardian, modal-runner,
fal-ai-runner, infra/ml-implementer, ml-researcher, researcher) migrate
in v0.24 wave.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 03:07:18 +08:00
Parfii-bot
bd32b48a54 Merge feat/phase-4-hook-wiring — PreToolUse glue for kei-capability 2026-04-23 02:51:11 +08:00
Parfii-bot
aa8333ccda feat(agent-substrate/phase-4): hook wiring — 3-line glue for kei-capability
PreToolUse hooks route through kei-capability check when orchestrator
registers a capability via KEI_CAPABILITY_NAME env var on agent spawn.

hooks/agent-capability-check.sh (22 LOC):
- Pass-through (exit 0) when KEI_CAPABILITY_NAME unset — no-op by default
- Fail-open (exit 0) when kei-capability binary missing — kit convention
- Sources _lib/gate.sh for KEI_DISABLED_HOOKS / KEI_HOOK_PROFILE respect
- exec kei-capability check "$CAP_NAME" when active

hooks/agent-capability-verify.sh (24 LOC):
- Orchestrator-driven, NOT a Claude Code native hook
- Carries env: AGENT_ID, TASK_TOML, WORKTREE_PATH, MAIN_REPO, RUN_MODE
- exec kei-capability verify "$CAP_NAME"

Registered in hooks/hooks.json + settings-snippet.json under both
PreToolUse:Bash and PreToolUse:Edit|Write matchers. Internal NotApplicable
returns exit 0 so non-matching tool calls cost nothing.

install.sh unchanged — hooks/*.sh glob picks up both new files.

tests/hook_wiring_integration.sh (64 LOC) — 3 contract assertions:
  (1) pass-through on unset KEI_CAPABILITY_NAME
  (2) deny+exit 2 on git-op pattern
  (3) allow+exit 0 on cargo-check pattern

Multi-capability routing (for phase 5): KEI_CAPABILITY_NAME currently
holds ONE name. When a role requires N capabilities, orchestrator will
either iterate or kei-capability gains a compose subcommand. Design
note left for phase 5.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:51:10 +08:00
Parfii-bot
d1a1a7d499 Merge github/main — readme rewrite lands alongside agent substrate v1 phases 1/2/3 2026-04-23 02:44:18 +08:00
Parfii-bot
28707a9a4a Merge feat/phase-3-kei-agent-runtime — substrate runtime + kei-capability 2026-04-23 02:36:16 +08:00
Parfii-bot
12e5c27b3c Merge feat/phase-2-role-matrix — 5 roles + AGENT-ROLES.md 2026-04-23 02:36:16 +08:00
Parfii-bot
a7b3e39fa8 Merge feat/phase-1-capability-library — 11 capability bundles 2026-04-23 02:36:16 +08:00
Parfii-bot
b82e3b039e feat(agent-substrate/phase-3): kei-agent-runtime + kei-capability binaries
Two new crates implementing the substrate runtime per locked §Runtime
execution contract + §Capability trait contract (Rust) + §Verify
execution worktree→simulated-merge.

kei-agent-runtime — library + CLI binary:
- src/capability.rs — Capability trait (name/check/verify) + GateContext
  + GateDecision + VerifyContext + VerifyResult + RunMode + TaskSpec
- src/registry.rs — &str → &'static dyn Capability dispatch for 14 impls
- src/gates/ — 6 PreToolUse modules (policy::no-git-ops,
  scope::files-{whitelist,denylist}, safety::no-dep-bump,
  tools::read-only, tools::cargo-only-bash)
- src/verifies/ — 8 on-return modules (quality::constructor-pattern,
  quality::cargo-check-green, quality::tests-green, safety::no-dep-bump,
  scope::files-{whitelist,denylist}, output::{report-format,severity-grade})
- src/compose.rs — task.toml + role + capabilities → prompt.md
- src/spawn.rs — ledger fork + prompt write (actual Agent invocation
  remains orchestrator's tool call)
- src/verify.rs — runs all capability verifies per role; collects
  VerifyReport {passed, failed}
- src/simulated_merge.rs — git worktree add test-merge/<id> + apply diff
  + run verify; cleanup on Drop
- src/main.rs — clap CLI: compose | spawn | verify | run

kei-capability — thin CLI adapter crate:
- Depends on kei-agent-runtime path dep
- Subcommand `check <cap-name>` (PreToolUse gate; stdin JSON, exit 0|2)
- Subcommand `verify <cap-name>` (on-return; env-driven, exit 0 or fail)
- Pattern: shell hook = 3-line `exec kei-capability check "$CAP_NAME"`

Workspace Cargo.toml: both crates registered as members (under agent
substrate v1 marker).

cargo check --workspace: PASS
cargo test -p kei-agent-runtime: 37/37 green
  - 6 capability_trait_smoke (registry lookups, unknown name → None)
  - 3 compose_smoke (fixture role + caps → composed prompt)
  - 12 gate_smoke (each gate: happy + deny + bypass)
  - 4 simulated_merge_smoke (git worktree lifecycle)
  - 12 verify_smoke (each verify: pass + fail + edge cases)
cargo test -p kei-capability: 0/0 (CLI binary, tested via lib)

(Agent completion report cut off by rate-limit at 60 tool-uses; code
itself is green — verified by orchestrator post-commit.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:35:53 +08:00
Parfii-bot
dc83cb2117 feat(agent-substrate/phase-2): role matrix — 5 roles + AGENT-ROLES.md
5 _roles/*.toml per locked §Initial role inventory:

- read-only     → tools::read-only + output::report-format + severity-grade
- explorer      → read-only caps + tools::cargo-only-bash
- edit-local    → no-git-ops + scope::files-{white,deny}list + quality::*
                  + safety::no-dep-bump + output::report-format
- edit-shared   → edit-local caps + relaxed SSoT whitelist (task-time param)
                  + escalation tightened to orchestrator-notify
- git-ops       → spawnable = false, documentation-only

All 11 capability names referenced match phase-1 deliverable path
_capabilities/<cat>/<slug>/ (cross-ref verified before commit).

docs/AGENT-ROLES.md (223 LOC) — human-readable matrix: per-role sections
+ cross-role capability matrix + explicit non-spawnable-git-ops block.

Drift note for orchestrator integration review: edit-local/edit-shared
use inline bash-patterns-allowed = ['^cargo( |$)', '^mkdir( |$)',
'^rm -rf /tmp/'] instead of composing with tools::cargo-only-bash
capability (extra patterns not in that atom). Agent footnoted —
resolution deferred to post-integration (either parameterize the cap
or introduce tools::cargo-plus-basic-bash variant).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:35:52 +08:00
Parfii-bot
c0c3483f02 feat(agent-substrate/phase-1): capability library — 11 declarative bundles
22 files per locked §Initial capability atom inventory:

policy/no-git-ops/               (gate: PreToolUse:Bash, bypass ORCHESTRATOR_META)
scope/files-whitelist/           (gate + verify worktree)
scope/files-denylist/            (gate + verify worktree)
quality/constructor-pattern/     (verify worktree)
quality/cargo-check-green/       (verify both — worktree short-circuit + simulated-merge)
quality/tests-green/             (verify both)
safety/no-dep-bump/              (gate + verify both)
output/report-format/            (verify worktree)
output/severity-grade/           (verify worktree)
tools/read-only/                 (gate: deny Edit/Write)
tools/cargo-only-bash/           (gate: Bash allowlist)

All capability.toml share [capability]/[restricts]/[parameterized]/[text]/
[gate]/[verify] section layout. rust-module paths pre-wired to match
phase-3 file layout. All text.md under 200 words, imperative,
self-contained (composer concatenates with --- separator).

Cross-refs to rule files preserved:
- policy::no-git-ops → RULE 0.13 (orchestrator-branch-first.md)
- quality::constructor-pattern → RULE ZERO (code-style.md)
- output::severity-grade → debugging.md §Security Review
- safety::no-dep-bump → supply-chain rationale

Agent attempted wc -w for word counts — sandbox correctly denied Bash
per RULE 0.13, observable reinforcement of the very policy this
capability encodes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:35:52 +08:00
annaglova
c859df8d37 docs(readme): outcome-oriented rewrite — hero + features + hide complexity under the hood
Refocuses README from defensive ("here's what LLMs do wrong, here's how we fence it")
to welcoming ("here's what you get, install is one line, complexity lives under the
hood"). Same factual content, same feature count, reorganized for new visitors.

Key changes:
- Hero opens with user outcome, not LLM failure modes
- Install moved to 2nd block (was buried mid-README)
- Features rewritten as scenarios ("Your AI sleeps at night") not specs
- "Batteries included" frames counts as confidence signal, not overwhelm
- "Under the hood (only if you care)" explicitly optional section for devs
- "About" confident — 4-8 parallel terminals flex, not self-deprecation

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:23:23 +03:00
Parfii-bot
b8b9c12913 Merge feat/agent-substrate-schema — agent substrate v1 LOCKED 2026-04-23 02:05:21 +08:00
Parfii-bot
a25c282dca feat(agent-substrate): LOCK schema — 8 decisions resolved, 3-phase parallel window opens
Resolved per user review 2026-04-23:

- Layout: declarative (capability.toml + text.md) + Rust modules in
  kei-agent-runtime (not 3 bash files — user pushed for Rust)
- Gate: Rust via kei-capability binary, shell hook = 3-line exec glue
- Verify: Rust same binary, subcommand verify
- Config: TOML (user asked discount between TOML vs YAML — explained
  type-safety + Cargo-native parsing wins)
- Capability ID: :: separator (confirmed)
- Nested path layout
- 200 words/capability text cap
- Verify: worktree short-circuit → simulated-merge (catches
  E1-jsonschema-class integration regressions before main merge)

Phase 3 revised up from 3-4 days to 5-6 due to Rust gate/verify logic
+ simulated-merge executor. Offset by phase 4 dropping from 1 day to
0.5 (shell hooks now thin glue).

3 phases parallelizable immediately after this lock:
- Phase 1: 20 declarative files (capability.toml + text.md × 10)
- Phase 2: 5 role TOML + docs/AGENT-ROLES.md
- Phase 3: kei-agent-runtime + kei-capability binaries + 14 Rust capability modules

Phase 4 + 5 sequential after.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 02:05:21 +08:00
Parfii-bot
372bbc8320 docs(agent-substrate): v1 schema DRAFT — capability triplet + role + task spec + runtime contract
Sibling SSoT to SUBSTRATE-SCHEMA.md (atom substrate). This one decomposes
agent invocations rather than code primitives.

Core contribution — the capability TRIPLET, not just text:
- text.md      — what agent reads (prompt fragment)
- gate.sh      — PreToolUse hook (runtime enforcement)
- verify.sh    — on-return predicate run from main repo (not worktree)

Motivation from substrate v1 orchestration audit:
- 40% prompt boilerplate across 7 spawns (git-ban + constructor-pattern +
  report format etc. copy-pasted each time)
- Self-reported green tests broke at integration (E1 jsonschema
  regression — agent claimed PASS from worktree but main workspace
  failed; caught only by integration test)
- Scope violations (E1 touched invoke.rs when E3 was supposed to own it;
  surfaced only at merge)

Triplet closes all three gaps: capabilities aren't promises agents make
in prose, they're enforced by gate hooks pre-exec and verified by
predicates on return from main branch clean state.

Schema specifies:
- Capability atom layout: _capabilities/<category>/<slug>/
- capability.toml frontmatter shape
- text.md / gate.sh / verify.sh contracts
- Role = bundle of capabilities (5 roles: read-only, explorer, edit-local,
  edit-shared, git-ops)
- task.toml shape (orchestrator-written per spawn; parameterizes roles)
- kei-agent-runtime crate contract: compose + spawn + verify + run
- Initial 10-capability inventory for phase 1
- 6-question decision log with defaults
- 5-phase parallel build plan (phases 1-4 parallel, ~5-7 days wall time)

Open questions flagged at bottom for review before AGENT-SCHEMA-LOCKED.md.

Once locked: sibling SSoTs (atoms + agents) evolve symmetrically — agents
compose atoms, atoms compose agents (ultimate goal).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:39:23 +08:00
Parfii-bot
59fd1a0362 test(substrate): integration now asserts real atom execution via Stream E
Previously expected NotImplemented stub (exit 64). Stream E wired real
subprocess exec to kei-task, so invoke now actually creates tasks.
Updated test:
- Builds kei-task in release + passes KEI_RUNTIME_BIN_DIR + KEI_TASK_DB
- Asserts exit 0 + stdout has 'id' field
- NEW assertion: invoke with empty KEI_RUNTIME_BIN_DIR → exit 127 (BinaryNotFound)
- Bad-input assertion stays (InputInvalid → exit 2)

4 end-to-end assertions now cover the full §Runtime contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:23:05 +08:00
Parfii-bot
07b47dba7e Merge feat/stream-g-sage-rules — atoms+rules unified graph 2026-04-23 01:21:12 +08:00
Parfii-bot
7fb562cfc5 Merge feat/stream-f-forge-pure-rust — eliminate shell-out 2026-04-23 01:21:12 +08:00
Parfii-bot
082b4c09e3 Merge feat/stream-e-invoke-wire — kei-runtime subprocess → real atoms 2026-04-23 01:21:12 +08:00
Parfii-bot
15bf40196b feat(stream-g): kei-sage rules integration — atoms + rules unified graph
Unify atoms and rules in kei-sage's graph. Previously [[rules/...]]
wikilinks were filtered (explicit Stream C scope-deferral). Now they
resolve to rule-node units with rule_ref edges.

kei-atom-discovery extension (non-breaking):
- WikilinkTarget enum: Atom(String) | Rule(String) | Other(String)
- classify_wikilink(inner: &str) -> WikilinkTarget — exposed via lib.rs
- parse_wikilink unchanged for backwards-compat; new callers use
  classify for richer semantics

kei-sage additions:
- rule_index.rs (129 LOC) — RuleRecord + discover_rules walking flat
  *.md + extract_h1 for display name + index_rules (unit_type="rule",
  vault_path="rule:<slug>") + index_rule_edges (walks atom.related,
  emits rule_ref edges atom → rule node)
- atom_cli.rs: cmd_rules_discover + default_rules_root
- main.rs: AtomsRulesDiscover subcommand with --rules-root flag
- tests/rules_smoke.rs: 5 tests (discovery, heading extraction,
  slug fallback for headingless files, empty-dir, atom→rule edge
  persistence)

Tests: 12/12 kei-atom-discovery (+3 classify_wikilink),
28/28 kei-sage (+5 rules_smoke + unit tests now counted).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:21:00 +08:00
Parfii-bot
e84e9fc1fe feat(stream-f): kei-forge pure-Rust templating — eliminate shell-out
Remove std::process::Command invocation of scripts/new-atom.sh from
kei-forge. Templating moves to pure Rust — eliminates the
sed-metacharacter injection class structurally, on top of the
description whitelist that E2 added as defence-in-depth.

src/generate.rs split into 4 Cubes (Constructor Pattern):
- generate/placeholders.rs — 6-token substitution, longer-first ordering
- generate/paths.rs — TargetPaths::resolve + assert_none_exist
- generate/rollback.rs — Drop-based atomic rollback (Rust idiom for
  shell `trap ERR`)
- generate/atom_tests.rs — 5 tempdir integration tests

generate.rs dropped from 295 → 159 LOC as orchestration thin wrapper.

Behavioural parity with scripts/new-atom.sh maintained: same 6 tokens,
same order, refuse-overwrite, atomic rollback, same file-list
ordering. scripts/new-atom.sh untouched on disk (still usable as
standalone CLI).

Cargo.toml: removed mock-generate feature flag (no longer needed —
pure-Rust tests use tempfile::TempDir), added tempfile dev-dep.

Tests: 44/44 (was 29 with mock-generate; +15 new pure-Rust unit tests
across placeholders/paths/rollback/atom_tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:21:00 +08:00
Parfii-bot
8626e23c22 feat(stream-e): invoke wire — kei-runtime subprocess → real atoms
Replace NotImplemented stub with real atom execution per schema
§Runtime invocation contract.

Convention: JSON-in/JSON-out over subprocess. Every refactored crate
exposes `<crate> run-atom <verb>` that reads JSON from stdin (or
--input), dispatches to atoms::<verb>::run, emits Output JSON on
stdout, exits per atom-error class.

Runtime side (kei-runtime):
- InvokeError: +AtomFailed{atom,code,stderr} +SubprocessError
  +OutputParse +BinaryNotFound{crate_name}. NotImplemented kept as
  legacy escape for atoms opting out of run-atom protocol.
- Output: now {atom: String, result: Value} — carries atom's actual
  return value.
- invoke_exit_code: AtomFailed passes through child exit (0..=255),
  Subprocess/OutputParse → 1, BinaryNotFound → 127, NotImplemented → 64.
- Binary resolution: KEI_RUNTIME_BIN_DIR env → PATH fallback.

kei-task side:
- New `pub mod run_atom` in lib.rs
- atoms/mod.rs: VERBS const + DispatchError enum wrapping per-atom errors
- src/run_atom.rs: read_input (stdin/@path/literal), dispatch, exit mapping
- main.rs: Cmd::RunAtom{verb, input} subcommand; collapsed three
  classify_*_error helpers into single classify_dispatch. Legacy
  create/search/add-dependency CLIs preserved.

Tests: 5/5 runtime (+1 invoke_real_atom integration), 9/9 kei-task
(+1 atoms::tests::verbs_list_matches_submodules).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 01:21:00 +08:00
Parfii-bot
9307f8d26e Merge fix/audit-wave-substrate-v1 — security hardening + CLI contract + integration test 2026-04-23 00:56:41 +08:00
Parfii-bot
f7e4725573 fix(substrate): amendment A-1 (input/output required all kinds) + integration test + jsonschema 0.18 relative-$id bug
Three post-E1/E2/E3-merge items:

1. Schema amendment A-1 (architect P0-a, non-breaking clarification):
   input.schema and output.schema are REQUIRED for all atom kinds. The
   shared kei-atom-discovery parses them as Option<PathBuf> only to allow
   tolerant skip-on-missing (stderr warn), not to permit absent schemas.
   Resolves Stream C / Stream D enforcement asymmetry documented in
   critic finding #6.

2. Cross-stream integration test (architect P0-b): tests/substrate_integration.sh
   builds release binaries, scaffolds a test atom corpus, runs
   schema-lint + list-atoms + atoms-discover + invoke; asserts all four
   streams agree on the same atom corpus and exit codes honour the
   locked §Runtime contract. Previously missing — only manual smoke
   checks existed.

3. Fix regression introduced by E1's jsonschema 0.18 upgrade:
   "relative URL without a base" on compile when schema declared a
   relative $id like "kei-task/atoms/schemas/create-input.json".
   validate.rs now synthesises an absolute file:// $id from the
   canonicalised schema path before compile. Internal $refs still
   resolve relative to the schema file; LocalFileResolver still confines
   to the schema's parent dir. Integration test catches this.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:56:27 +08:00
Parfii-bot
ca0635e0fa Merge fix/e3-contract-compliance — exit codes + invoke Err + strict lint
# Conflicts:
#	_primitives/_rust/kei-runtime/src/invoke.rs
2026-04-23 00:52:54 +08:00
Parfii-bot
4e9a7dddfb Merge fix/e2-kei-forge-hardening — DNS/CSRF/injection + headers 2026-04-23 00:49:59 +08:00
Parfii-bot
f1a6098aa9 Merge fix/e1-atom-discovery — shared crate + SSRF/traversal/YAML fixes 2026-04-23 00:49:59 +08:00
Parfii-bot
1bc6fbf4e3 fix(substrate): E3 — CLI contract compliance (exit codes + invoke Err)
Four audit findings on CLI contract violations per locked §Runtime schema:

- crit#7: invoke returned Ok with error payload — now returns
  Err(InvokeError::NotImplemented) → exit 64
- crit#5: typed errors collapsed via anyhow::anyhow!("{e}") in kei-task —
  replaced with CliError { code, msg } + classify_*_error helpers;
  validation errors exit 2, storage errors exit 1 (spec-compliant)
- crit#8: lint.rs wikilink parser accepted [[[foo]] — strict parse_wikilink
  from kei-atom-discovery used; emits finding for malformed entries
- crit#15: draft-07 detection was substring match — is_draft07_uri exact
  match against canonical URIs only

Tests: 4/4 kei-runtime (was 2; +2 invoke exit-code tests) + 8/8 kei-task
(was 7; +1 empty-title exit-2 test) = 12/12 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:49:49 +08:00
Parfii-bot
f7982f0415 fix(substrate): E2 — kei-forge security hardening (DNS rebind + CSRF + injection)
Three HIGH security findings resolved in _primitives/_rust/kei-forge/:

- F-1: DNS rebinding — require_local_host middleware returns 421 on
  non-localhost Host headers
- F-2: CSRF via urlencoded — require_json_content_type middleware
  returns 415 on non-JSON; form HTML now POSTs JSON via fetch()
- crit#1/SA F-7: description sed injection — whitelist validator rejects
  newline/CR/tab/NUL/backtick/$/length>200, blocks the shell-script attack
  at the Rust layer
- crit#11: missing security headers — CSP, X-Frame-Options DENY,
  X-Content-Type-Options nosniff, Referrer-Policy no-referrer on GET /

Zero new deps (axum 0.7 middleware::from_fn + HeaderMap native).
Constructor Pattern compliant — 6 Cube files, largest 231 LOC including tests.

Tests: 29/29 (was 12/12; +17 new). Includes 4 adversarial integration
tests for each defence layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:49:49 +08:00
Parfii-bot
990f5e3711 fix(substrate): E1 — kei-atom-discovery shared crate + 4 critical security fixes
Extracts authoritative atom discovery + frontmatter parsing into new crate
_primitives/_rust/kei-atom-discovery/. kei-sage and kei-runtime now both
consume the same implementation, eliminating Frontmatter drift.

Resolved findings:
- F-3/crit#3: path traversal via md_dir.join() — safe_join helper rejects
  absolute paths + .. components + post-canonicalise escapes (4 sites)
- crit#6/architect P0-a: Frontmatter drift — single AtomMeta struct
- SA supply-chain: serde_yaml archived — migrated to serde_yaml_ng 0.10
- crit#2: JSON Schema $ref SSRF — jsonschema 0.17→0.18 with resolve-file
  feature only, custom LocalFileResolver denies non-file:// schemes
- F-4: symlink traversal — walkdir follow_links(false) explicit everywhere
- F-5: YAML billion-laughs — 64 KiB pre-parse cap

Tests: 9/9 new crate + 23/23 sage + 2/2 runtime + 7/7 kei-task = 41/41 green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:49:49 +08:00
Parfii-bot
42fe08232e Merge feat/stream-d-kei-runtime — invoke/list-atoms/schema-lint MVP
# Conflicts:
#	_primitives/_rust/Cargo.lock
#	_primitives/_rust/Cargo.toml
2026-04-23 00:13:16 +08:00
Parfii-bot
2361a21d15 Merge feat/stream-c-kei-sage-substrate — kei-sage walks atoms/*.md 2026-04-23 00:10:44 +08:00
Parfii-bot
ef48c9993b Merge feat/stream-b-atoms-kei-task — 3 pilot atoms per locked schema 2026-04-23 00:10:44 +08:00
Parfii-bot
9858662b72 Merge feat/stream-a-kei-forge — local web wizard scaffolding atoms 2026-04-23 00:10:44 +08:00
Parfii-bot
d68fddb59a feat(stream-d): kei-runtime — discover + validate + lint (invoke stub)
New crate _primitives/_rust/kei-runtime/ implementing §Runtime invocation
contract from locked substrate schema.

CLI (clap-derive):
- list-atoms [--root] [--crate] [--kind]   → walk + print
- invoke <atom-id> --input <json|@file>    → discover + validate input (stub exec)
- schema-lint [--root] [--crate]           → 6-check validator
- pipe <dag.toml>                          → "not yet implemented" stub

Modules (≤ 200 LOC each, largest lint.rs @ 171):
- src/discover.rs — walk_atoms walks <root>/*/atoms/*.md, parses frontmatter
- src/validate.rs — JSONSchema draft-07 via jsonschema 0.17.1
- src/invoke.rs — MVP stub: discover → parse → validate_input → boundary ack
- src/lint.rs — 6 checks: required fields, kind enum, side_effects shape,
  schema path existence + draft-07 declaration, wikilink resolution
- src/main.rs — clap CLI, exit 0|1|2 per §Runtime contract

Intentional stub boundary: invoke returns structured JSON ack (exit 0),
wire-up to concrete atom impls deferred to integration pass (needs
Stream B atoms landed first).

Registered kei-runtime in workspace members.

Tests: 2/2 integration smoke (lint_smoke, discover_smoke) green.

Stream D of substrate v1 parallel build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:09:58 +08:00
Parfii-bot
57b9475e50 feat(stream-c): kei-sage substrate — walk atoms/*.md + wikilink graph
Extends kei-sage with substrate-atom indexing layer per locked schema
§Graph / discovery contract.

New modules (all ≤ 200 LOC, Constructor Pattern):
- src/atom_parse.rs — frontmatter splitter, wikilink parser, id splitter
- src/atoms.rs — AtomKind + FromStr, AtomRecord, discover_atoms, resolve_wikilinks
- src/atom_index.rs — persists atoms as Units + atom_related edges into existing Store
- src/atom_cli.rs — 4 subcommand handlers

New CLI subcommands (default root ~/.claude/agents/_primitives/_rust):
- atoms-discover — walks atoms/*.md, prints table
- atoms-rank — PageRank over wikilink edges (composes w/ existing vault)
- atoms-related <atom-id> — BFS from atom
- atoms-search <query> — FTS over frontmatter + body

Tolerant scan: invalid frontmatter → stderr warn + continue (never abort).
[[rules/...]] wikilinks filtered at edge resolution per scope (rules
integration deferred to follow-up).

Tests: 9 unit + 6 integration smoke + 8 pre-existing = 23/23 green.
Zero regression. Single new dep: serde_yaml 0.9.

Stream C of substrate v1 parallel build.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:09:57 +08:00
Parfii-bot
ae82bc6242 feat(stream-b): kei-task pilot — 3 atoms (create/search/add-dependency)
Pilot refactor per locked substrate schema. kei-task migrated to atom
layout:

- atoms/<verb>.md — YAML frontmatter + human body for 3 verbs
- atoms/schemas/<verb>-{input,output}.json — JSON Schema draft-07
- src/atoms/<verb>.rs — typed Input/Output/Error + pub fn run()
- src/atoms/mod.rs — module registry
- Cargo.toml [package.metadata.keisei] — crate-level substrate data
- src/main.rs — dispatcher for 3 pilot commands via atoms::

Zero behaviour change: 7/7 integration tests pass before and after
(create_and_get, update_persists, cycle_detected, milestone_linking,
dependency_chain_traversal, task_graph_edges, search_finds_task).

main.rs still has 5 non-migrated subcommands (update, graph,
dependency-chain, milestone, link-milestone) — scope discipline, they
migrate in later passes. main.rs 120 → 132 LOC.

Stream B pilot reference — other crates follow this pattern in v0.24+.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:09:55 +08:00
Parfii-bot
fd25c3af60 feat(stream-a): kei-forge MVP — local web wizard scaffolding atoms
New crate _primitives/_rust/kei-forge/ exposing POST /forge over axum
on 127.0.0.1:8747. Shell-outs to scripts/new-atom.sh for generation.
5-input inline HTML form, no JS required. 9 unit + 3 integration tests
green via `cargo test --features mock-generate`.

Registered kei-forge in workspace members.

Stream A of substrate v1 parallel build — see docs/SUBSTRATE-SCHEMA.md.
Spec pre-locked; schema immutable until 2026-06-03 or revocation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:09:53 +08:00
Parfii-bot
9f6ba0cbfc Merge feat/substrate-schema-v1 — substrate schema v1 locked + template + generator 2026-04-23 00:00:33 +08:00
Parfii-bot
ae4f5b9813 feat(substrate): LOCK schema — 6-week parallel Stream A/B/C/D window opens
Schema at SUBSTRATE-SCHEMA.md (revised 2026-04-22) is immutable until
~2026-06-03 or explicit user revocation. 4 parallel streams may now
proceed independently against this contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:00:33 +08:00
Parfii-bot
559db303e1 feat(substrate): apply user decisions + ship atom template + generator
Schema revisions per user review 2026-04-22 (all 6 open questions resolved
— see §Decision log in SUBSTRATE-SCHEMA.md):

- #3 side_effects: string tags → structured { op, domain } objects (user:
  "лучше сразу с запасом")
- #4 capabilities.toml: DROPPED entirely (user: "почему не мд?"). SSoT is
  atoms/*.md. Crate-level metadata moves to Cargo.toml
  [package.metadata.keisei] — Cargo-native, no drift, no build.rs, no
  generated files to commit. kei-sage + kei-runtime walk atoms/*.md
  directly.
- #5 atom template: shipped in this PR (user: "ui же параллельно! создавай
  все!") so Streams B/C/D can scaffold atoms from day 0 without waiting
  for Stream A (kei-forge UI).
- #1/#2/#6 confirmed as drafted (draft-07, `::` separator, per-atom errors).

New files:

- _templates/atom/ — 5-file template set with placeholder substitution
  (__CRATE__, __VERB__, __KIND__, __DESCRIPTION__ etc). Covers
  atoms/<verb>.md, schemas/<verb>-{input,output}.json, src/atoms/<verb>.rs,
  tests/<verb>_smoke.rs. Each file is a minimal working skeleton.
- scripts/new-atom.sh — POSIX bash generator (bash for $'\n' / readonly /
  trap). Validates verb is lowercase kebab-case, kind is one of
  command|query|stream|transform. Refuses to overwrite existing files.
  Rolls back on any failure (trap ERR deletes all generated files so no
  half-scaffolded state). Tested: produces 5 files, placeholder
  substitution correct on smoke-test crate.

Stream B (atoms refactor) updated to drop the "generates capabilities.toml
via build.rs" wording — now just "writes atoms/*.md + updates Cargo.toml
[package.metadata.keisei]". Stream D reads atoms/*.md + Cargo.toml, not
capabilities.toml.

Schema status: revisions applied, decision log complete. Ready for
SCHEMA-LOCKED.md marker commit once user signs off on revised doc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:53:26 +08:00
Parfii-bot
58944e15bd docs(substrate): v1 atom/capability/graph SSoT schema — DRAFT for review
Substrate thesis requires a single source of truth before parallel work
streams (UI/Atoms/Graph/Runtime) can proceed independently without drift.
This document is that SSoT.

Key decisions baked in (open to revision before lock):

- Atom = one verb on a primitive, not one crate. Target ~150 atoms
  across current 25 crates. Crate = physical container, atom = unit of
  composition.

- File layout: src/atoms/<verb>.rs (code) + atoms/<verb>.md (docs with
  machine-parseable YAML frontmatter) + atoms/schemas/*.json (JSON
  Schema draft-07 for input/output) + capabilities.toml (auto-generated
  aggregator, committed to repo).

- Atom kinds: command / query / stream / transform. Combined with
  side_effects[] and idempotent flag, runtime decides retry safety,
  parallelism, caching.

- Naming: <crate>::<verb> globally unique. Rust :: separator keeps it
  native-feeling.

- Versioning: atoms inherit crate SemVer. Breaking change to an atom =
  new atom (create-v2), old marked deprecated.

- Runtime contract: `kei-runtime invoke <atom-id> --input <json>` with
  schema validation at entry + exit, ledger row per invocation.

- Graph contract: kei-sage auto-walks atoms/*.md, resolves [[atom-id]]
  wikilinks, exposes rank / related / search / graph over atom corpus.

- UI contract: kei-forge web wizard generates .md + .json + .rs + test
  from form input; postcondition cargo check + kei-schema-lint pass.

Document declares 4 stream interfaces explicitly — each stream knows
what it reads from this schema, what it writes, what it does NOT depend
on from other streams. Enables true parallel work.

6 open questions flagged for user review at bottom:
1) JSON Schema draft-07 vs 2020-12
2) Atom ID separator :: vs /
3) side_effects strings vs structured
4) capabilities.toml committed vs gitignored
5) kei-atom-template in this PR or defer to Stream A
6) Error model per-atom vs shared registry

STATUS: DRAFT — awaits user approval + SCHEMA-LOCKED.md marker before
parallel streams start. Once locked, breaking changes require explicit
revocation + all-streams sync.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:39:24 +08:00
Parfii-bot
71cb04525b fix(release): v0.22.3 — native arm64-linux + gh-CLI Publish (no race, no draft)
Two production-readiness fixes motivated by the v0.22.2 post-mortem.

1. aarch64-linux: native ARM runner instead of cross-compile

   v0.22.2 consistently failed `Install aarch64 cross-linker` (apt
   gcc-aarch64-linux-gnu) on the ubuntu-latest x86_64 runner. Was
   carried as `experimental: true` so non-blocking, but meant no
   aarch64-linux Rust tarball ever shipped.

   Fix: move to ubuntu-24.04-arm (native ARM64 runner). Rust builds
   aarch64-unknown-linux-gnu HOST-NATIVELY — no cross-linker, no
   `.cargo/config.toml` linker override. `experimental: false` now —
   native path is reliable.

2. Publish step: softprops/action-gh-release → `gh release create` CLI

   v0.22.2 softprops/action-gh-release v2.6.2 uploaded all 15 assets
   successfully but exited with `failure` due to a metadata-update
   race: asset uploaded to GitHub's blob store, then the subsequent
   PATCH to set the asset's `name` returned 404 because the Releases
   metadata API hadn't caught up yet (eventual consistency). Workflow
   failure → Release left in Draft. We had to promote it manually
   (`gh release edit --draft=false`) and re-upload one missing sha256.

   Fix: replace the action with `gh release create` + `gh release
   upload --clobber` in a bash step.
   - Idempotent: existing release gets updated in place.
   - No metadata PATCH race: CLI never patches, it creates fresh.
   - Retry loop: up to 3 tries per asset on transient network errors.
   - `--clobber` means re-runs replace cleanly.
   - GitHub CLI is pre-installed on every runner, zero new deps.

Verified post-polish on v0.22.2: 16/16 assets present, Release
Published, `kei-mcp-server-darwin-arm64` + `keisei` both execute on
this MacBook (arm64) — adapter list shows Claude Code detected at
project+user scope. SHA256 of `keisei-aarch64-apple-darwin.tar.gz`
verified OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:22:50 +08:00
Parfii-bot
42d964b14f Merge docs/readme-split — 89 KB → 7.8 KB hero + 6 docs/ files + release.yml fix 2026-04-22 22:43:54 +08:00
Parfii-bot
8eadb12d00 Merge docs/readme-missing-sections — About + nightly-cycle + Security 2026-04-22 22:43:54 +08:00
Parfii-bot
f070ada841 fix(release): consolidate bun builds to ubuntu-latest (macos-13 deprecated)
Root cause: macos-13 Intel Mac runners were deprecated by GitHub. The
darwin-x64 bun matrix job was sitting queued for 1.5-2.5 hours on every
tag push (v0.21.1, v0.22.0, v0.22.1) and never picked up a runner. The
release job has `needs: [build-release, build-mcp-binary]` so it waited
forever — NO GitHub Releases were created for any v0.22 tag.

Fix: bun cross-compiles to every target (Linux / macOS / Windows,
x64 / arm64) from any host via `--target=<bun-target>`. Consolidate the
entire build-mcp-binary matrix onto ubuntu-latest. Binaries remain
native per-target (correct Mach-O / ELF / PE format preserved by bun
--target flag).

Side effects:
- Faster: Linux runners provision in seconds vs macOS in minutes
- No macOS quota cost (free tier: 2000 min/month, macOS = 10x multiplier)
- No runner starvation on tag push
- `continue-on-error` arm64-linux carve-out removed (no longer needed —
  all jobs now on the same runner pool with equal reliability)

Verified locally: bun 1.1+ supports all 5 target triples from Linux host.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:42:55 +08:00
Parfii-bot
ce9ba61ee0 docs(readme): split 89 KB monolith into hero-pitch + 6 docs/ files
README down from 89 KB to 7.8 KB (11x reduction, target was 10-15 KB).
Visitor-facing README now loads in one screen — hero + 3 killer features
+ what-it-solves + quick install + docs index.

Extracted 6 new files under docs/:

- INSTALL.md (15 KB) — prerequisites, profiles, interactive install,
  MCP binary, keisei CLI intro, runtime hook controls, what-you-get table
- REFERENCE.md (35 KB) — every one of 25 Rust primitives + 13 shell
  primitives + 10 hooks + 39 skills with actual CLI surface (clap flags,
  exit codes, env vars, state paths), keisei CLI deep-dive, 12 pipelines
- ARCHITECTURE.md (11 KB) — build pipeline, creating-a-new-agent,
  adding custom blocks/manifests, agents overview, cross-tool bridges,
  meta-composer, regen counts, workflow-file editing protocol
- SLEEP-LAYER.md (11 KB) — three-phase nightly cycle diagram,
  session self-audit (RULE 0.14), Cloud REM sync, sleep-on-it incubation,
  deep-sleep NREM consolidation with 4-primitive pipeline + example
- SECURITY.md (7.6 KB) — threat surface table + 8 mitigations in detail
  (memory-repo privacy, secrets-guard patterns, supply-chain SHA pinning,
  S3 SSRF, brain path/name validation, exFAT warning, battle matrix)
- WHY.md (3.6 KB) — full 'From the author' manifesto restored from
  git history (pre-1f3aaca product pivot). Medium/dev.to-friendly for
  virality, separate from the product README

New docs cross-link each other + README has docs index in tail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:20:22 +08:00
Parfii-bot
b55c3d6ef3 docs(readme): restore About section + nightly-cycle overview + security model
Adds 6 missing pieces flagged by readme review:

1. ## About — author attribution + "not a product" positioning + "Why
   Rust, not Python" (was removed in 1f3aaca, but load-bearing context
   for new users). Keeps the product-oriented greeting intact above it.

2. ## Install — plugin vs classic two-path table up front; links to
   PLUGIN.md (v0.16+ Anthropic plugin format was previously un-linked).

3. ## The nightly cycle at a glance — unified ASCII overview of the
   three-phase sleep cycle (A incubation → B REM → C NREM), biological
   analog, phase-interaction rules (marathon owns night, Phase C cadence,
   morning report is human-only).

4. ### Deep-sleep NREM consolidation — 4-primitive pipeline diagram
   (conflict-scan → refactor-engine → graph-check via kei-store) plus a
   concrete example of a detected conflict.

5. ## Security model — 7 bullets covering memory-repo privacy, RULE 0.1,
   secrets-guard, GitHub Actions SHA pinning, S3 SSRF guard, marker
   0o600, exFAT/FAT32 warning. Plus battle-matrix mention.

6. ## Docs — link index to CHANGELOG / PLUGIN / USB-BRAIN guide / battle
   tests (none of those four files were referenced from README before).

README.md: +83 lines (1221 → 1304).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:46:06 +08:00
Parfii-bot
5ec90ca241 fix(tests): repair 2 missing closing braces from v0.22 Track-A↔Track-C merge
Merge of feat/v0.22-keisei-schema-v4 into main (which already had
Track C's fs_type tests) elided '); }' at 2 seams. Tests compiled
once I added them back, but the edit missed the git-add step.

No behaviour change — both tests already passed after the fix;
commit just closes out the working tree.
2026-04-22 21:16:22 +08:00
Parfii-bot
4f6cbfd305 Merge docs/v0.22-reference-section — README Reference section (conflict resolved)
CHANGELOG: Reference entry folded into Track A's block.
README: auto-merged cleanly (agent appended the 670-LOC Reference
section after 'What you get' table, untouched by Track A/B/C).

wc -l README.md: 1233 (was 563 pre-session — 2.2x growth from product
rewrite + USB guide + exobrain CLI docs + Reference section).
2026-04-22 21:11:21 +08:00
Parfii-bot
ca8d980ac6 docs(readme): comprehensive Reference section — every primitive/skill/hook/CLI with real behaviour
+670 LOC to README.md. Source-of-truth extraction from each primitive's
actual src/main.rs (clap subcommands) + hook header comments + skill
SKILL.md frontmatter.

Covers:
  - Rust primitives (25) with real subcommands, flags, state paths,
    exit codes. Extracted from src/main.rs.
  - Shell primitives (13) with usage signature + env-var contract.
  - Hooks (10) tabular + per-hook detail (event/severity/bypass).
  - Skills (39) grouped into 6 collapsible <details> sections.
  - keisei CLI deep-dive — real flag matrix, exit codes, env vars,
    SSoT location, v0.19 hardening invariants.

Agent flagged 4 discrepancies vs prior task-description drafts
(agent refused to fabricate: no --client / --force / --dry-run on
keisei, exit codes 0/1 not 0/1/2, kei-curator --db required).
These were never in the code — docs now describe reality.

bash scripts/regen-counts.sh --check: no drift
wc -l README.md: 1233

Closes user request 'сделай подробное описание каждой функции'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:10:11 +08:00