Repository navigation
Feat/3.0.0 vocabulary - #7
Merged
Merged
Conversation
BREAKING. Collapse the two-layer (framework-wraps-host) taxonomy into one canonical set using the names the agent community already uses. - kinds: guide→rule, sensor→hook, action→command, playbook→skill, persona/subagent→agent; new `document` kind; corpus/concern kept. Old kinds removed outright (no redirect/deprecation). - convention over configuration: `kind:` inferred from the canonical directory; an explicit `kind:` overrides. - frontmatter associations: `traces:`→`corpus:`; add produces/consumes/ stop/gates/type/produced_by/supersedes + instance `gate:`; drop `deps:` from the authoring surface. - scaffold/new/MCP: new verbs (rule/hook/command/skill/agent/document/...), `keystone_new_document`, dead generators removed. - projection: merged kinds → host surfaces; cursor/continue/claude adapters remapped to rule/hook. - new `keystone document` subcommand: list + gate-validated promote. Framework code only; dogfood migration + the v3_0 migration step follow.
BREAKING. One agent-neutral root that feeds every host. - config: DefaultHarnessRoot = ".harness" (single source of truth for the location). KeystoneDir returns the root — INDEX, lockfile, work/, and primitives all live under .harness/. keystone.json stays at repo root. - v2.x migrations pinned to legacy .keystone (legacyHarnessRoot / legacyKeystoneDir); rebuildIndex/rebuildIndexComposed take an explicit index dir so each era writes to its own layout. - v3_0 migration: relocate .keystone/ -> .harness/, rename kinds to the 3.0 vocabulary, split sensors (host_triggers -> hook, else agent), playbook -> skills/<id>/SKILL.md, traces -> corpus, inject required tools:/triggers: when converting, seed .harness/work/, rebuild index. - Walk skips .harness/work/ — document instances are tracked by `keystone document`, not indexed as primitives. - document workDir + cmd paths routed through config. Code Health: extracted planV3Move/applyV3Moves/isWorkspaceDir; residual string-arg/primitive smells on the path-migration module + pre-existing Walk complexity accepted. Embedded scaffold templates + dogfood .keystone/ still on 2.x vocab — migrated next (slice 7).
- keystone init creates the target dir if absent (mkdir -p) instead of erroring; extracted ensureProjectDir (runInit complexity down 33->31). - v3_0 migration splits sensors by nature: review-* / *-debt / spec-adherence are inferential (-> agent), the rest computational (-> hook), replacing the host_triggers heuristic which misclassified trigger-less computational sensors. Forward-compatible with the frozen 3.0 domain (keystone-3.0.0-domain.md).
Restore the keystone authoring vocabulary that the earlier 3.0 work wrongly collapsed into community names. The 1-to-many mapping (one keystone kind → host mechanism by mode) is the framework's value, not a 1:1 rename. Taxonomy (KnownKinds, 15): guide, sensor, hook, agent, command, skill, playbook, pattern, corpus, document, concern, posture, tool, eval, source. - rule dropped as a kind — it is a projection-target name; author a guide. Lint rejects kind: rule with a guide-pointing hint. - hook kept as a first-class framework hook layer; agent absorbs persona+subagent; pattern/posture/tool added. - canonicalDirKind remapped to guides/ sensors/ hooks/ ... tools/ (no rules/). Frontmatter: add mode, event, run, agent, returns; validate the sensor/hook action contract (computational -> run:, inferential -> agent: + returns:, mutually exclusive). Add guide tier (iron-law | golden-rule | preference, default preference). Projection: KindRule -> KindGuide for the rule-shim path (project.go, cursor + continueide adapters) — a glob-scoped inferential guide projects to the .claude/rules/ shim. The v3_0 migration still emits collapse vocab; its rewrite (corrected mapping + mode inference) is a later slice, and TestV3_Up_PostMigrationLintClean is skipped until then.
ProjectionRelPath is now keyed on (kind, mode): - playbook projects like skill -> .claude/skills/<name>/SKILL.md - inferential sensor -> .claude/agents/<name>.md (the subagent a review hook dispatches); computational sensor -> no host file (runs via the hook layer) - inferential guide + globs -> .claude/rules/ shim; computational guide -> no shim (a hook carries it) Every projected host artifact is kebab-case and keystone-prefixed (command review -> /keystone-review; skills/agents/rule-shims likewise), applied in project.go + the cursor/continueide rule adapters. Ids already in the keystone namespace are not double-prefixed. Inferential guides and sensors are framework-fired (slice 5 wires the hook layer); these projections are the artifacts it dispatches. host_triggers / ProjectHooks are untouched here and retired in slice 5. Refactors to hold Code Health: ProjectionRelPath split into guide/sensor helpers; projection tests share seedFiles/assert* helpers.
A posture primitive declares allow/ask/deny tool-permission lists; ProjectPosture (claudecode adapter) merges them into settings.json permissions — additive, deduped, sorted, idempotent, preserving user-authored entries. Wired into keystone project + watch. Add Allow/Ask/Deny frontmatter fields (parse + struct). Extract projectClaudeCode / watchClaudeCode helpers so the hooks+posture projection lives in one place (also pulls runProject/runWatchAdapters back under their prior complexity).
…ook layer Record the decision: playbooks spawn subagents via prose in their projected SKILL.md (no declarative field — keystone has no runtime to enforce it). Deterministic parallel fan-out of inferential sensors/agents lives in the framework hook dispatcher (slice 5), which keystone actually runs.
keystone new pattern|posture|tool (+ MCP keystone_new_pattern|posture|tool): - pattern: prose documentation pattern (Diataxis modes — tutorial, how-to, reference, explanation); generates a doc skeleton, no projection - posture: allow/ask/deny permission lists (project to settings.json, slice 3) - tool: author-defined callable; transport cli | mcp | plugin (keystones generic sense of "tool"), run: handler + args schema Add transport frontmatter field. Refactor to hold Code Health: runNew -> map dispatch; registerWriteTools -> writeGenerators + registerHarnessTools.
source is no longer authorable: external-system access (Jira, an API curled for context) is a tool — transport cli=curl or mcp. Remove KindSource from KnownKinds + canonicalDirKind, keystone new source, MCP keystone_new_source, and runNewSource. Tests updated (sources/ now off-convention). The read-side subsystem (mcp/source.go keystone_source_*, web sources pages, context.json) is decoupled (reads context.json, not kind:source primitives) and stays transitionally — its removal is slice 5c.
Add the framework-event registry (primitive.FrameworkEvents: pre-command, post-command, pre-playbook, post-playbook, on-gate, pre-verify, post-verify, on-phase-enter, on-phase-exit) and keystone hook fire <event>: - selects kind:hook bound to the event - computational (run:) hooks execute in parallel; any non-zero exit blocks - inferential (agent:) hooks emit a dispatch manifest for the host to spawn (keystone cannot invoke an LLM itself) - fire context (--phase/--command/--type) passed to run: scripts as env Fix a latent bug: scanRoots was a stale hardcoded dir list (still had actions/personas/sources/rules, missing hooks/patterns/posture/tools/ documents) so those primitives were invisible to Walk/INDEX. Derive scanRoots from canonicalDirKind so the walker and taxonomy cannot drift. walk_test fixtures updated to 3.0 vocab. Host bridge + auto-fire wiring (document promote -> on-gate, verify -> pre/post-verify) are the next increment.
keystone verify now fires pre-verify (blocking gate) before the policy check and post-verify after; keystone document promote fires on-gate after a gate advances (non-fatal — the transition is already committed). pre-verify gates, post-verify/on-gate react. The verify wrapper (verifyWithHooks) lives in verify_hooks.go so verify.go stays untouched (its runVerify is a pre-existing god-function; wrapping avoids piling onto it). --sensor mode skips the lifecycle hooks.
Rewrite claudecode.ProjectHooks: instead of mapping each sensor host_trigger into settings.json, install ONE generic bridge entry per host phase any kind:hook binds to (via event:) -> "keystone hook fire <phase>". keystone dispatches the matching hooks itself; the adapter writes no per-hook entries. Framework events are keystone-fired, never bridged. Drops the per-sensor host_triggers projection + severity-wrapping (the dispatcher owns blocking now). stripManagedHooks decomposed into helpers. hooks_test + v2_3 migration test rewritten to the bridge model. host_triggers frontmatter field is now vestigial — the v3_0 migration will set event: on migrated hooks (slice 6).
A tool declares transport: cli | mcp | plugin + a run: handler. lint enforces the contract (run: required, transport in the allowed set). transport: mcp tools are registered on keystone's own MCP server at startup: registerToolPrimitives reads kind:tool/transport:mcp from the index and registers each as an MCP tool whose handler shells out to run:, passing declared args as KEYSTONE_ARG_<NAME>. cli/plugin tools reach the agent through their own transports.
source is gone end to end. Delete the read-side subsystem that backed the former kind: the mcp/source.go tools+resources, mcp/adapter.go (folder/url adapters + context.json loader), web/sources_actions.go + 5 source templates, the /sources + /api/sources routes, the sources KPI, the source health cache, and the no-sources insight. Drop context.json from the v3_0 relocate list and the SSE sources topic. External-system access is a tool (transport cli=curl / mcp). primitiveCache kept (it lived in cache.go alongside the deleted healthCache). Live-verified: dashboard renders, /sources 404s, kpi widgets 200.
Sensor model (symmetric): guide and sensor each keep mode. The deterministic firing layer is unified — a hook, a computational guide (LSP), and a computational sensor (gate check) all fire via event:+run: through primitive.HookFire; an inferential guide is a glob-activated rule shim, an inferential sensor is a review dispatched as an agent with a returns: verdict. Closes the "computational sensor fires nowhere" gap. - lint: guide computational->run; sensor computational->run | inferential->returns; hook contract unchanged - projection: inferential sensor->agents, computational sensor/guide->no adapter file (bridged) - claudecode bridge + keystone hook fire: select via HookFire (hook + computational guide/sensor) - migration: guide->guide, playbook->playbook (collapse fixes), action->command, persona/subagent->agent, computational sensor (host_triggers)->hook (event/run/mode), review sensor->agent, traces->corpus. Lint-clean test un-skipped + green.
The fresh-install seed harness now scaffolds 3.0 primitives. actions→commands, personas→agents (kind rewrites), guides traces:→corpus:, dropped sources/ and the rules/ source dir (source + rule are not authorable kinds). Sensors split by the symmetric model: computational dev-checks (build, test, lint, coverage, type-check, sast, secret-scan, vuln-scan, stack-drift, commit-message) → hooks/ (mode:computational + event + placeholder run); inferential reviews/snapshots → sensors/ (mode:inferential + returns). keystone-new-action skill → keystone-new-command. Fresh keystone init produces a lint-clean harness; golden test updated.
Ran keystone migrate up on this repo: relocate .keystone/ -> .harness/, rename every primitive to 3.0 vocab (actions->commands, personas->agents, computational sensors->hooks, traces->corpus, ...), seed the document workspace, rebuild INDEX. Hand-converted three computational guides (gofmt/gopls/go-vet) from the stray kind: computational to kind: guide + mode: computational + event/run. Reprojected .claude/. lint clean (0 errors). go install of the 3.0 binary (repointing the live hooks) is deferred to a separate step.
readAppliedTolerant looked for .harness/keystone.lock.json (wrong name — it is lockfile.json) and writeApplied always wrote to the legacy .keystone/lockfile.json (gone post-3.0). So the dogfood migrate up recorded "3.0" into a stale husk and migrate status reported "applied: none". Resolve the lockfile at its current location (<root>/.harness/lockfile.json, legacy .keystone fallback) for both read and write. migrate status now shows 3.0 applied; re-running migrate up is a clean no-op. Includes the recorded lockfile + reprojected surfaces from the dogfood re-run.
The migrated gofmt/gopls/go-vet computational guides fire on PostToolUse via the hook bridge. gopls is not always installed -> exit 127 noise on every edit. Guard each run: with `command -v <tool>` so an absent tool is a clean no-op instead of a failure.
Bring the authoritative docs to 3.0 vocab. MCP server instructions: .keystone -> .harness, traces -> corpus, drop the removed external-source stage + tools + resources, correct the kind list. README: 14-kind table (single set, no two-layer split), rules->corpus->ask flow (no external stage), drop source MCP tools / resources / dashboard page. CLAUDE.md (project + claude-code menu template): .keystone -> .harness, actions->commands, personas->agents, the hook bridge note, and a 3.0 activation table.
Projection no longer copies primitive bodies verbatim — it lowers the frontmatter to the host-native subset Claude Code expects and strips the keystone-only fields (kind, id, corpus, includes, mode, event, returns, gates, tier, …). Skills/agents emit name + description (agents add tools/model); commands emit description + argument-hint/allowed-tools/model. Body preserved. Replaces the verbatim copyOne with writeLowered (also kills a duplication smell). Rule shims keep their synthesized format.
Regenerate the host surface after the lowering change: .claude/ skills, agents, and commands now carry only host-native frontmatter (name/description/tools/ model), no keystone-only keys.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Title:
feat(3.0)!: keystone 3.0 — symmetric primitive vocabulary + framework hooks
Body:
Keystone 3.0. Reshapes the primitive taxonomy and adds a deterministic
framework-hook layer. Breaking: every install migrates via
keystone migrate up.Taxonomy (14 kinds)
guide sensor hook agent command skill playbook pattern corpus document concern posture tool evalmode: computational | inferential.ruleis a projection-target name, not a kind (author aguide).sourcedropped — external access is atool(transport: cli | mcp | plugin).hook,pattern(Diátaxis docs),posture(→ settings.json),tool.Framework hooks
HookFire: ahook, computationalguide(LSP), or computationalsensor(gate check) all fire onevent:+run:; inferential guide → ruleshim, inferential sensor → agent dispatch.
keystone hook fire <event>dispatcher · auto-fire fromverify/document promote· single host→keystone settings.json bridge (no per-hook mapping).Frontmatter
modeeventrunagentreturnstiertransportallow/ask/deny.Projection lowers to host-native keys; projected artifacts are kebab-case,
keystone--prefixed (/keystone-<name>).Migration + removals
v3_0migrate:.keystone/→.harness/, corrected vocab, mode inference,traces:→corpus:. Idempotent; lint-clean.sourcesubsystem (web/mcp/config);tools register on the MCPserver; scaffold templates + docs (README, MCP instructions, CLAUDE.md) on 3.0.
Verification
go test ./...(15 pkgs) +go vetgreen · dogfood migrated + lint-clean ·CodeScene gate clean on every commit.