Commit graph

47 commits

Author SHA1 Message Date
Parfii-bot
26e74cfa15 Merge SP1 — kei-spawn automation envelope 2026-04-23 10:22:38 +08:00
Parfii-bot
948f07bfa8 Merge E2 — kei-capability fork subcommand 2026-04-23 10:22:38 +08:00
Parfii-bot
02451f5f49 feat(sp1): NEW kei-spawn crate — automation envelope
spawn <task.toml> internally calls prepare + ledger fork, emits
JSON ready for Agent tool invocation. verify wraps post-return
check+ledger update. list-pending shows running forks.

kei-ledger invoked via subprocess (no lib.rs in kei-ledger).
KEI_SPAWN_LEDGER_NOOP=1 test escape hatch for CI without binary.

spec_sha = SHA-256 of task.toml bytes (workspace sha2 dep).

Tests: 6/6 integration (happy, explicit-id, unknown-role, non-spawnable,
verify-missing, end-to-end roundtrip).

Step 3 (Anthropic API) stays with orchestrator — next iteration adds
kei-spawn drive <task.toml> for HTTP automation.

Workspace Cargo.toml: +kei-spawn member.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
6e7e517f83 feat(e2): kei-capability fork subcommand + lineage stamping
New 'fork' subcommand copies capability dir + rewrites capability.toml
with [lineage].fork_from + parents + creator + created. Refuses
clobber, validates slug regex.

Tests: 4 integration + 2 unit (epoch_to_iso, split_cap_name) = 6/6.

Doc update in AGENT-SUBSTRATE-SCHEMA.md §Orchestrator ergonomics.

Zero-chrono ISO-8601 via Hinnant's algorithm (single-file).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
5a34c35311 feat(tx2): kei-sage facet query + lineage traversal
3 new subcommands:
- facet-query <key=value> [<k2=v2>...] — AND-filter walks primitives
- lineage <primitive-id> [--depth N] — BFS ancestors/descendants/forks
- author <creator-id> [--limit N] — all primitives by creator

facet_query.rs walks _capabilities/*/*/capability.toml + _manifests/*.toml
via toml parser. Handles missing sections correctly (None != specific).

lineage.rs BFS over parents[] wikilinks + fork-from + created-by edges.

Tests: 34/34 (was 28, +6: 3 facet_smoke + 3 lineage_smoke).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:21:45 +08:00
Parfii-bot
010def05ad Merge R2 — kei-cache
# Conflicts:
#	_primitives/_rust/Cargo.toml
2026-04-23 05:56:12 +08:00
Parfii-bot
b823a99812 Merge R1 — kei-pipe DAG runtime 2026-04-23 05:55:35 +08:00
Parfii-bot
41eec8d5b1 Merge M5 — kei-sage migration 2026-04-23 05:55:35 +08:00
Parfii-bot
91f9f050e1 Merge M4 — kei-crossdomain migration 2026-04-23 05:55:35 +08:00
Parfii-bot
af16066793 Merge M3 — kei-social-store migration 2026-04-23 05:55:35 +08:00
Parfii-bot
a28ce2b36c Merge M2 — kei-content-store migration 2026-04-23 05:55:35 +08:00
Parfii-bot
76dcdc5c87 feat(r2): new kei-cache crate — deterministic result cache
Wraps pure (query/transform) atom invocations with SHA-256 keyed
cache. Refuses Command/Stream kind atoms as unsafe.

22/22 tests (14 unit + 8 integration). Canonical JSON keying
(formatting-drift safe). TTL expiry. AtomExecutor trait decouples
subprocess from test mocks.

Default DB ~/.claude/cache/cache.sqlite, overridable via --db or
$KEI_CACHE_DB.

Workspace Cargo.toml: +kei-cache member.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
0b948ca07c feat(r1): new kei-pipe crate — atom DAG runtime
The critical missing substrate composition layer.

kei-pipe run <dag.toml> — reads DAG spec, topo-sorts atoms, executes
sequentially, pipes JSON between steps via $step.path.to.field
resolver. 6 Constructor-Pattern cubes: dag/resolve/exec/report/lib/main.

5/5 smoke tests: happy path + cycle detection + unknown dep +
nested path resolver + unreadable file.

Resolver envelope matches kei-runtime Output — atoms round-trip
identically through either runtime.

Workspace Cargo.toml: +kei-pipe member.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
5f72f6a0a8 feat(m5): migrate kei-sage to kei-entity-store engine (largest migration)
28/28 tests preserved — most complex migration.

Primary entity = unit via engine; edges + FTS stay sage-local in
custom_migrations (engine TextPair minimal: lacks id/weight/created_at/
UNIQUE constraint that sage's graph operations require).

pagerank.rs + bfs.rs preserved as sage-local (graph semantics tied to
typed edge_type + weight, not generic).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
59c30603f3 feat(m4): migrate kei-crossdomain to kei-entity-store engine (edges-only)
5/5 tests preserved. Synthetic nodes PK table via engine; cross_edges
stays in custom_migrations because engine's TextPair is too minimal
(id/weight/evidence/metadata columns needed).

Flag for engine follow-up: TextPair DDL needs optional edge metadata
columns — same gap flagged by M5 independently.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
0b645db646 feat(m3): migrate kei-social-store to kei-entity-store engine
5/5 tests preserved. Primary entity = person; orgs + interactions +
relationship_graph stay custom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
6ad8fd81ed feat(m2): migrate kei-content-store to kei-entity-store engine
4/4 tests preserved. Primary entity = content_units; prompts +
campaigns + campaign_assets in custom_migrations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:13 +08:00
Parfii-bot
519600d1bf feat(m1-dogfood): migrate kei-chat-store to kei-entity-store engine
Primary entity = chat_messages (integer-PK; sessions stay bespoke —
TEXT UUID PK incompatible with engine's IntegerPk).

Secondary tables (chat_sessions, indexes, FTS rename fts_chat →
fts_chat_messages) moved into custom_migrations. FTS shadow column
session_id dropped (never used as MATCH filter).

Archive verb NOT enabled: chat_sessions.status is TEXT enum not INTEGER
flag — engine archive verb incompatible. archive_session stays bespoke.

cost REAL column dropped — engine has no Real FieldKind. per-message
cost struct field kept (=0.0) for API compat; session total_cost
aggregate still maintained bespoke in save_message.

5/5 tests preserved + 1 new engine migration-parity smoke test.

DOGFOOD prompt feedback (M1 via kei-agent-runtime prepare):
6 engine limitations surfaced for follow-up — FieldKind::TextPk,
FieldKind::Real, archive-TEXT-enum variant, FTS UNINDEXED shadow cols,
atom dir assumption, rusqlite drop logic. See M1 task report.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 05:55:12 +08:00
Parfii-bot
30a07e22ca Merge feat/convergence-p3-role-dna — role expression + DNA identity 2026-04-23 04:47:30 +08:00
Parfii-bot
84319efcb6 feat(convergence/p3): Role expression (extends/relaxes) + DNA identity
Layer E + G. Role TOML gains extends/relaxes for parent-role
composition; agent spawn gets self-describing DNA identity alongside
UUID.

Role expression:
- _roles/*.toml gain optional `extends = "<parent>"` + `relaxes = [...]`
- compose.rs + verify.rs delegate to new role::resolve_role() with
  recursive extends-chain resolution + cycle detection
- explorer.toml: 28→18 LOC (extends read-only)
- edit-shared.toml: 31→23 LOC (extends edit-local, relaxes
  scope::files-whitelist for task-param override)

DNA identity:
- new dna.rs (159 LOC) — compose/render/parse round-trip
- AgentInvocation carries dna field (prepare.rs)
- Format: <role>::<caps-bitmap>::<sha4-scope>::<sha4-body>-<hex4-nonce>
- ≤ 80 chars total, greppable, parseable
- 11 capability codes in CAP_CODES table: NG, FW, FD, CP, CG, TG, ND,
  RF, SG, DT, BA

kei-ledger schema v2:
- ADD COLUMN dna TEXT + prefix index
- `kei-ledger fork --dna <string>` optional flag
- AgentRow.dna: Option<String>
- Backward compat: schema migration detects + applies on open

Docs: AGENT-SUBSTRATE-SCHEMA.md Layer E + Layer G sections + CAP_CODES table.

New deps: sha2 (workspace), rand 0.8.

Tests: kei-agent-runtime 50 (was 41, +9: 4 role + 5 DNA), kei-ledger
10 (was 9, +1 DNA roundtrip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:46:48 +08:00
Parfii-bot
793b91bc43 feat(convergence/p1): kei-entity-store engine + schema fragments + kei-task pilot
Layer A + B of convergence wave. Extract common SQLite-CRUD + graph
logic into kei-entity-store engine; introduce JSON Schema fragments;
pilot-migrate kei-task to verify parity.

New crate _primitives/_rust/kei-entity-store/ (1151 LOC):
- src/schema.rs — EntitySchema + FieldDef + enabled_verbs + fts_columns
  + edge_table + custom_migrations
- src/engine.rs — Store::open with WAL pragma + migration runner
- src/verbs/ — 8 data-driven verb modules (create/get/list/search/
  update/delete/link/rank) uniform JSON-in/JSON-out signature
- src/error.rs — typed VerbError enum
- tests/verb_smoke.rs — 10/10 green

New _schemas/fragments/ (83 LOC JSON):
- entity-base.json, titled.json, titled-content.json, edge.json

kei-task pilot migration:
- TASK_SCHEMA: EntitySchema static (67 LOC, was 58)
- store.rs becomes thin shim over engine::Store
- atoms/create.rs + atoms/search.rs delegate to engine verbs
- atoms/schemas/*.json use $ref to _schemas/fragments/ (DRY)
- Task-specific secondary tables (milestones, task_deps) stay via
  schema.custom_migrations; cycle-detection in deps.rs stays
  hand-rolled (domain logic, not generic CRUD)
- 9/9 tests green — full behavioural parity

Convergence delta:
- kei-task touched files: 342 → 389 LOC (+47 for JSON marshalling
  boundary; net wash on pilot)
- BUT each remaining 5 sibling crate can shrink ~400-500 LOC on migration
- Expected total reduction when all 6 migrated: ~2500 LOC across the cluster

Follow-ups declared:
- Migrate kei-chat-store, kei-content-store, kei-social-store to engine
- Migrate kei-sage (needs string-id edge variant; currently generic
  link/rank assume int ids)
- Migrate kei-crossdomain
- Expose list/delete atoms in kei-task (engine supports, atoms not yet)
- Fold kei-curator as engine::hygiene module (per P4 audit)
- Fold kei-search-core entities, keep workflow as thin kei-search-pipeline

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 04:46:47 +08:00
Parfii-bot
64ffe39e01 feat(convergence/u3): kei-provision Rust crate — unify hetzner+vultr provisioners
Pre-unlock wave U3 (highest-ROI). Task 7 from CONVERGENCE-PLAN —
consolidate 2 provision-*.sh scripts into Rust via Backend trait.

Old shells (provision-hetzner.sh, provision-vultr.sh) had identical
6-subcommand surface (create|status|destroy|list), log/die/check_deps
helpers, idempotency contract. Sole delta: hcloud vs vultr-cli. RULE 0.2
says Rust-first when >50 LOC + growth expected.

New crate _primitives/_rust/kei-provision/:
- src/backend.rs (58 LOC) — Backend trait: create/status/destroy/list;
  CreateOpts and ServerInfo structs
- src/backends/hetzner.rs (143 LOC) — shells to `hcloud server ...`
  --output=json, parses JSON response, honors HCLOUD_TOKEN env (RULE 0.8)
- src/backends/vultr.rs (189 LOC) — same pattern, `vultr-cli instance`,
  honors VULTR_API_KEY env
- src/exec.rs (100 LOC) — Command runner + PATH-aware env preservation
- src/b64.rs (49 LOC) — minimal user-data base64 encoder; zero
  transitive deps
- src/main.rs (141 LOC) — clap CLI `kei-provision <backend> <cmd>`
- tests/backend_smoke.rs (184 LOC) — tempdir PATH-inject fake hcloud +
  fake vultr-cli, no real cloud. Mutex-serialized (Rust test parallelism).

Tests: 11/11 (3 b64 unit + 8 backend_smoke integration). Coverage:
hetzner status present/absent/list, vultr status found/absent/destroy
idempotent, unknown-backend error, CreateOpts default.

Old shells kept with superseded-v0.17 header — install.sh still copies
them, legacy scripts still work. New users get kei-provision binary.
harden-base.sh untouched (different lifecycle — runs on target VPS).

Backend trait factored to accept aws/doctl/linode follow-ups without
re-architecture.

Workspace Cargo.toml: +kei-provision member (1 line).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 03:43:40 +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
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
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
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
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
4ccb1548a2 Merge refactor/v0.22-kei-store-async-backend — AsyncBackend trait + shared runtime 2026-04-22 21:06:50 +08:00
Parfii-bot
bc7e099697 refactor(v0.22): kei-store AsyncBackend trait + shared tokio runtime (Track B)
Extracts an AsyncBackend trait in kei-store so future GCS/Azure/Bunny
backends implement 5 async fns, not re-invent the sync-over-tokio
bridge. Closes architect P1 + P2 findings.

NEW src/async_backend.rs (189 LOC):
  - trait AsyncBackend with get/put/list/list_recursive/delete/exists
  - AsyncBackendStore<B: AsyncBackend> — generic MemoryStore impl
    (sync-over-async via shared runtime)
  - shared_runtime() -> &'static Runtime via OnceLock
    (multi-thread, 2 workers, enable_io+enable_time)
  - path helpers (validate_rel, short_hash, is_manifest_key) moved
    here as single source of truth

NEW src/s3_cloud/backend.rs (120 LOC):
  - S3AsyncBackend impl of AsyncBackend — 5 async fns using the
    existing aws-sdk-s3::Client

MODIFIED src/s3_cloud/mod.rs (200 → 43 LOC):
  pub type S3CloudStore = AsyncBackendStore<S3AsyncBackend>;
  Thin re-export + inherent new(cfg) constructor.
  Doc-header documents the extension seam: 'adding GCS = impl 5 async fns'.

MODIFIED src/s3_cloud/keys.rs (66 → 40 LOC): compat shim — re-exports
  validate_rel / short_hash / is_manifest_key from async_backend.
  Old call-sites + 4 unit tests unchanged.

Deps: async-trait = 0.1 added under s3 feature; tokio now has
  rt-multi-thread feature too.

FIXES N=2 Store footgun: prior impl created a current_thread Runtime
  per instance — 2 instances in one process = 2 runtimes, block_on
  panic if caller is on another runtime. Shared multi-thread runtime
  via OnceLock means N instances all share 2 workers.

REAL VERIFICATION (agent-pasted):
  cargo check -p kei-store: clean
  cargo check -p kei-store --features s3: clean
  cargo test -p kei-store --release: 10+9+0 = 19 passed
  cargo test -p kei-store --features s3 --release: 38+9+6 = 53 passed
    (+7 vs baseline 46)

Tests added (7):
  async_backend::tests::shared_runtime_is_singleton
  async_backend::tests::validate_rel_rejects_absolute
  async_backend::tests::validate_rel_rejects_parent
  async_backend::tests::short_hash_deterministic
  async_backend::tests::is_manifest_key_matches_format
  s3_cloud::tests::async_backend_shared_runtime_handles_two_store_instances
  s3_cloud::tests::async_backend_runtime_is_multi_thread

Public API preserved: S3CloudStore::new / .branch / .current_branch /
  .key / .backend_name. Factory + integration tests untouched.

Pre-existing: list_inner 38 LOC (moved verbatim from mod.rs, not
  refactored per Core Rule 3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:06:50 +08:00
Parfii-bot
5993f32146 feat(v0.22): FS warn + battle-test matrix + USB docs platform split (Track C)
1. Filesystem type detection (architect P2 finding)
   _primitives/_rust/keisei/src/fs_type.rs (NEW, 103 LOC)
     - statfs(2)-based detection on unix (libc = '0.2' under
       [target.'cfg(unix)'.dependencies])
     - Recognizes exfat / msdos (FAT32) via f_fstypename on macOS,
       via f_type magic numbers on Linux (0x4d44, 0x2011bab0)
     - Windows stub returns Unknown (GetVolumeInformationW TBD)
     - warn_on_unsafe_fs(root) emits stderr warning on ExFat/Fat32
   brain.rs::load calls warn_on_unsafe_fs after canonicalize+symlink
     checks. Warning NOT fatal — user can opt into single-client use.

2. Battle-test matrix (architect P3 finding)
   tests/battle/Dockerfile.install-test-alpine (NEW)
     - alpine:3.19 + apk rust/cargo/pandoc
     - Exposes musl-vs-glibc issues in aws-sdk-s3, rusqlite, git2
   tests/battle/Dockerfile.install-test-debian (NEW)
     - debian:12 + rustup stable + pandoc
     - Default server distro, different apt structure from Ubuntu
   tests/battle/README.md rewritten — 3-distro matrix with run script

3. USB-BRAIN-GUIDE platform split
   docs/USB-BRAIN-GUIDE.md — restructured as TOC + platform-agnostic
     preamble + exFAT warning + cross-platform troubleshooting
   docs/USB-BRAIN-GUIDE-macos.md (NEW, 97 LOC) — Gatekeeper, diskutil,
     /Volumes, xattr -d com.apple.quarantine
   docs/USB-BRAIN-GUIDE-linux.md (NEW, 98 LOC) — /media/$USER,
     umount, ext4 recommended, systemd-udev auto-mount note
   docs/USB-BRAIN-GUIDE-windows.md (NEW, 115 LOC) — PowerShell
     Dismount-Volume, NTFS, FS-advisory Unknown caveat

REAL VERIFICATION (paste from agent):
  cargo check -p keisei: Finished (clean)
  cargo test -p keisei --release: 32 passed 0 failed (30 existing + 2 new)
  docker buildx outline: both new Dockerfiles parse

Constructor Pattern:
  fs_type.rs 103 LOC, brain.rs 198 LOC (at limit 200, held the line)
  All fns <30 LOC. Each USB guide sub-doc 97-115 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:56:42 +08:00
Parfii-bot
e5cd0d6790 feat(v0.21): kei-store real S3 backend behind opt-in 's3' feature flag
Promotes S3 from MVP stub to functional via aws-sdk-s3. Default builds
unchanged (zero new deps). Feature flag ensures users who don't need
S3 don't pay the ~5MB binary / C-toolchain cost.

Cargo.toml: new [features] s3 = [...] gating 4 optional deps:
  aws-sdk-s3 = 1.130.0
  aws-config = 1.8.16 (with behavior-version-latest)
  tokio = 1.52.1 (current-thread runtime, no multi-threaded bloat)
  bytes = 1 (S3 body passthrough)

s3_cloud/ module (4 files, Constructor Pattern):
  mod.rs (190 LOC) — S3CloudStore + MemoryStore trait impl
  client.rs (81 LOC) — aws-config builder, KEI_STORE_S3_ENDPOINT
    override for R2 / Wasabi / MinIO / any S3-compat
  keys.rs (60 LOC) — path-traversal guard + DJB2 hash helper
  tests.rs (63 LOC) — builder + prefix + key-guard unit tests

Factory routing (factory.rs):
  with 's3' feature + bucket URL → S3CloudStore (real network)
  without 's3' feature → S3Store stub (existing MVP, preserved)

Security posture:
  - Branch-prefix isolation rejects  traversal at keys.rs layer
  - aws-config default credential chain (env → ~/.aws → IMDS);
    no bespoke credential handling
  - rustls, not OpenSSL (matches existing crate tree)

Tests: 22 existing + 11 new (4 keys + 3 client + 5 mod + 5 smoke)
  cargo test -p kei-store (default features): 9 passed
  cargo test -p kei-store --features s3: 22 + 9 + 5 = 36 passed
  cargo clippy -p kei-store --features s3: clean

Real stdout verified for all verify criteria. No fabrication.

MANIFEST.toml [primitive.kei-store] deps updated to reflect feature
opt-in model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:59:11 +08:00
Parfii-bot
d32ca0bc28 fix(v0.19): audit hardening — 3 security HIGH + 3 critic HIGH + 2 critic MEDIUM
Closes consolidated findings from wave-audit (critic + security + architect):

SECURITY HIGH:
  H1 path escape — Brain::load rejects absolute mcp_server paths +
    any containing '..'; canonicalize + starts_with(root) assertion;
    new Error::PathEscape variant.
  H2 brain name validation + clobber refuse — regex ^[a-z][a-z0-9_-]{0,63}$
    enforced at Brain::load; adapters refuse to overwrite existing
    mcpServers[name] with NameConflict (unless same content).
  H3 symlink reject at canonicalize — std::fs::symlink_metadata()
    called before canonicalize; Error::BrainIsSymlink with resolved
    target path; prevents USB → $HOME pivot.

CRITIC HIGH:
  #1 rusqlite dep deleted (zero uses in src/, pulls C toolchain).
  #3 BrainPaths memory/artifacts/manifests now Option<String>
    (only mcp_server required; schema no longer lies about contract).

CRITIC MEDIUM:
  #1 _primitives/_rust/keisei/src/paths.rs (new, 23 LOC) — SSoT for
    $KEISEI_HOME/$HOME resolver; config.rs and claude_code.rs
    delegate instead of duplicating 7-line block.
  #2 canonicalize error preserves io::Error via new Error::BrainLoad
    { path, source } with #[source] attribute.
  #5 fsx::write_atomic_json rewrite via tempfile::NamedTempFile
    + persist — Windows-safe, cross-fs-fallback handling.

New module split (Constructor Pattern): brain.rs (104 → 122) now a
thin orchestrator over brain_validate.rs (108 LOC) which owns
symlink-reject / canonicalize-root / read-manifest / validate-schema
/ validate-name / check-relative-in-root / canonicalize-in-root.

Deps: regex = { workspace = true }, tempfile = "3" (runtime).
Workspace-level regex = "1.10" added.
MANIFEST.toml [primitive.keisei] deps updated.

Tests: 11 pre-existing + 5 adversarial:
  - manifest_with_absolute_mcp_server_rejected — proves /usr/bin/python3
    CANNOT land in settings.json (PathEscape + marker absent asserts)
  - manifest_with_parent_traversal_rejected — ../../etc/passwd rejected
  - manifest_with_invalid_name_rejected — 'claude-ide!' rejected
  - brain_path_is_symlink_rejected — USB → $HOME pivot blocked
  - attach_refuses_to_clobber_existing_mcp_entry — NameConflict on diff

All 16 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:36:11 +08:00
Parfii-bot
e6cab72587 feat(v0.19): multi-client adapters + detach/mount/list-adapters + schema v2
Extends keisei CLI from single-client (v0.18) to multi-client exobrain:
new subcommands detach/mount/list-adapters, 3 new adapters (Cursor,
Continue, Zed), schema v2 for ~/.claude/keisei-attached.toml with
[[attachments]] array (v1 backward-compat via untagged serde).

New subcommands:
  detach — iterate marker attachments, call adapter.detach() on each,
    then delete marker. Real strip of mcpServers entry per adapter.
  mount <brain> — auto-attach to ALL detected clients in one call.
  list-adapters — tabular status (name / detected / config path).

New adapters (each <130 LOC mirrors claude_code.rs pattern):
  adapters/cursor.rs — .cursor/mcp.json project-local, fallback
    ~/.cursor/mcp.json global.
  adapters/continue_adapter.rs — ~/.continue/config.json with
    experimental.modelContextProtocolServers key.
  adapters/zed.rs — ~/.config/zed/settings.json (Linux) or
    ~/Library/Application Support/Zed/settings.json (macOS) with
    context_servers key. Zed schema marked [UNVERIFIED] pending docs.

Schema v2 (~/.claude/keisei-attached.toml):
  [[attachments]]
  client_type = "claude-code"
  config_path = "/Users/.../.claude/settings.json"
  [[attachments]]
  client_type = "cursor"
  config_path = "/Users/.../proj/.cursor/mcp.json"

v1 marker migration: untagged serde accepts legacy client_type=string,
upgrades to single-entry attachments[] on next write.

Tests: 5 (v0.18) + 6 new = 11 integration tests, all pass:
  - attach_then_status_happy_path
  - attach_missing_manifest_errors
  - attach_unsupported_schema_errors
  - status_without_attach_is_clean
  - attach_writes_marker_with_expected_fields
  - mount_with_claude_code_only_detected (new)
  - mount_with_no_client_detected (new)
  - detach_round_trip (new)
  - detach_preserves_other_mcp_servers (new)
  - list_adapters_prints_expected_rows (new)
  - schema_v1_to_v2_migration (new)

Known issues (defer to follow-up commit):
  - CRITIC HIGH#1: rusqlite declared but unused
  - CRITIC HIGH#3: BrainPaths fields required but only mcp_server used
  - SECURITY H1/H2/H3: brain path/name not validated before writing
    into client config — will be addressed before tagging v0.19.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:04:45 +08:00
Parfii-bot
59725ae021 Merge branch 'feat/v0.15-artifact-handoff' — kei-artifact typed handoff pipeline
# Conflicts:
#	_primitives/MANIFEST.toml
2026-04-22 14:15:17 +08:00
Parfii-bot
24c584ee50 fix: remove genesis-scan from public kit (internal tool, Bundle-only)
Per user decision: publishing the sensitive IP pattern blocklist via public
scanner is leak of the blocklist itself (attack surface). genesis-scan
remains in PROJECT-E (private); user-global
~/.claude/hooks/genesis-leak-guard.sh (runtime hook) separate.

Deleted:
- _primitives/_rust/genesis-scan/ (whole crate, 5 files)
- hooks/git-pre-commit-genesis.sh (scanner companion)

Modified:
- workspace Cargo.toml -1 member (24→23)
- MANIFEST.toml — removed [primitive.genesis-scan] + core/full profile refs
- .github/workflows/ci.yml — removed genesis-scan job
- README.md — 7 count/description edits (24→23 rust, 10→9 hooks, 37→36 full)
- install.sh — 5 edits (--help + menus)
- mcp-server tool-registry.ts + test — scanner removed from MCP surface
- kei-sleep-queue.sh — removed scan_prompt() pre-submit hook
- 2 sleep-on-it skill phases — removed genesis-scan references

Tests: 160 Rust (was 167, -7 genesis-scan tests as expected), 24 assembler unchanged.
2026-04-22 14:11:22 +08:00
Parfii-bot
537589e6a7 feat(primitives): kei-artifact typed handoff pipeline (BMAD-style doc passthrough)
- kei-artifact Rust crate (25th): schema registry + artifact store + SHA-256 id + chain walker
- 5 schemas (JSON Schema 2020-12 strict): spec / plan / patch / review / research
- Manifest extension: optional produces_artifact + expects_artifact per handoff (non-breaking)
- Validator extension: KNOWN_ARTIFACT_SCHEMAS whitelist check + 4 new tests
- 3 kei-* manifests updated with typed handoff (architect→code-implementer→critic chain)
- compose-solution phase-5 cross-ref to kei-artifact

Tests: 189 Rust workspace (was 167, +22 artifact tests) + 24 assembler (was 20, +4 validator tests)
2026-04-22 14:10:08 +08:00
Parfii-bot
adc007b7b0 feat(primitives): 10 Rust crates extracted from LBM (Genesis-scrubbed)
- kei-router — keyword-dispatch meta-tool (CfC ML fallback removed)
- kei-sage — Obsidian-style knowledge graph, FTS5 + BFS + PageRank
- kei-task — task DAG with deps, milestones, dependency-chain queries
- kei-chat-store — Claude conversation session persistence + FTS search
- kei-crossdomain — typed-edge store + BFS cross-domain glue
- kei-search-core — 3-wave deep research with microcent budget cap
- kei-content-store — asset + prompt + campaign registry
- kei-social-store — people + interactions CRM (lite)
- kei-curator — edge-decay graph hygiene utility
- kei-auth — multi-tenant session tokens (replaces single-bearer)

Genesis-scan pre-import pass: skipped pkg/mxl1/*, pkg/inference/*, pkg/trainer/*,
pkg/nc01/*, internal/ml/* (all Genesis/CfC adjacent, sensitive IP).
Security: skipped tools_threat/radio/protocol/med/mlreg (offensive/banned).
Domain verticals skipped: hr/legal/infra/ops/api/osint/edu/geo/hw/finance.

New 'mcp' profile in MANIFEST.toml bundles all 10 for MCP server deployment.

Workspace now 24 crates, cargo check --workspace clean, 94 workspace tests pass.
2026-04-22 12:48:56 +08:00
Parfii-bot
19ee220e0a feat(primitives): 4 Rust crates for deep-sleep — conflict-scan, refactor-engine, graph-check, store
- kei-conflict-scan: rules/hooks/blocks/orphans/CP detection (6 tests)
- kei-refactor-engine: plan-mode + advisory patch format, zero-conflict guarantee (5 tests)
- kei-graph-check: wikilinks/handoffs/block-refs validator (4 tests)
- kei-store: trait + 5 backends (filesystem/github/forgejo/gitea prod, s3 stub) (8 tests)

1916 LOC Rust total; all files <200 LOC; 23/23 tests pass.
2026-04-22 08:28:22 +08:00
Parfii-bot
48b1a8cdcf Merge branch 'feat/v0.10-genesis-scan' — kei-memory + genesis-scan v0.10.0 reconciled 2026-04-22 01:04:32 +08:00
Parfii-bot
10bc799d26 feat(primitives): genesis-scan Rust — sensitive IP leak detector (CI/pre-commit)
26 forbidden patterns synced with ~/.claude/hooks/genesis-leak-guard.sh.
7 exempt scopes (KeiLab/theory/ml-keilab chatlogs/keinet-cfc-eigen/keinet-gpu-wgpu).
CLI: --path, --staged, --stdin, --format=human|json|github-actions, --exit-on-hit.
Self-reference resolved via EXEMPT_SUBSTRINGS + tempfile fixtures with runtime-assembled strings.
7/7 tests pass.
2026-04-22 01:01:56 +08:00
Parfii-bot
040e189b80 feat(primitives): kei-memory Rust crate — offline session analyzer (Genesis-clean) 2026-04-22 00:50:04 +08:00
Parfii-bot
c89352c87c Merge branch 'feat/frontend-v040' — 4 stacks + 3 Rust + 5 shell + 17 skills + /site-create (partial)
Cargo.lock regenerated after 8-crate workspace merge.
2026-04-21 21:17:19 +08:00
Parfii-bot
ebf841c7d9 feat(primitives): 3 Rust cubes — mock-render, visual-diff, tokens-sync 2026-04-21 21:07:45 +08:00
Parfii-bot
521659bbfb feat(primitives): 2 Rust verification cubes
- ssh-check — parse sshd_config + drop-ins, merge last-wins, lint against
  hardened baseline (pw-auth=no, root=prohibit-password, maxauthtries≤3,
  AllowUsers whitelist, no CBC ciphers, ETM MACs, no ssh-rsa host key).
  4 modules: main (clap CLI) + parse + rules + check. Tests: 9 pass
  (hardened baseline, password-auth-yes-fails, cbc-cipher-fails,
  allow-users-not-in-whitelist-fails, missing-required-fails, etc.).

- firewall-diff — diff intent YAML against `ufw status numbered` output.
  Defensive-only (never runs ufw). Stdin or --status-file input. Parses
  (v6) families, normalises "Anywhere"→"any". Exit 2 on any missing/
  extra rule. 4 modules: main + intent + ufw + diff. Tests: 8 pass
  (load-minimal-intent, exact-match-clean, missing-rule-surfaced,
  extra-live-rule-surfaced, inactive-ufw-fails, integration).

Workspace: clap 4 + serde + serde_yaml + serde_json. release opt-level=z,
LTO, strip. Constructor Pattern: largest file check.rs 213 LOC (93 non-
test); every function under 30 LOC.

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