Skip to content

Feat/3.0.0 vocabulary - #7

Merged
tacoda merged 22 commits into
mainfrom
feat/3.0.0-vocabulary
Jun 29, 2026
Merged

tacoda merged 22 commits into
mainfrom
feat/3.0.0-vocabulary

Conversation

@tacoda

@tacoda tacoda commented Jun 29, 2026

Copy link
Copy Markdown
Owner

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 eval

  • Symmetric guide/sensor — each mode: computational | inferential.
  • rule is a projection-target name, not a kind (author a guide).
  • source dropped — external access is a tool (transport: cli | mcp | plugin).
  • New: hook, pattern (Diátaxis docs), posture (→ settings.json), tool.

Framework hooks

  • Unified HookFire: a hook, computational guide (LSP), or computational
    sensor (gate check) all fire on event: + run:; inferential guide → rule
    shim, inferential sensor → agent dispatch.
  • keystone hook fire <event> dispatcher · auto-fire from verify/document promote · single host→keystone settings.json bridge (no per-hook mapping).

Frontmatter

mode event run agent returns tier transport allow/ask/deny.
Projection lowers to host-native keys; projected artifacts are kebab-case,
keystone--prefixed (/keystone-<name>).

Migration + removals

  • v3_0 migrate: .keystone/→.harness/, corrected vocab, mode inference,
    traces:→corpus:. Idempotent; lint-clean.
  • Removed the source subsystem (web/mcp/config); tools register on the MCP
    server; scaffold templates + docs (README, MCP instructions, CLAUDE.md) on 3.0.

Verification

go test ./... (15 pkgs) + go vet green · dogfood migrated + lint-clean ·
CodeScene gate clean on every commit.

tacoda added 22 commits June 25, 2026 14:30
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.
@tacoda tacoda self-assigned this Jun 29, 2026
@tacoda
tacoda merged commit 6c33bb2 into main Jun 29, 2026
1 check passed
@tacoda
tacoda deleted the feat/3.0.0-vocabulary branch June 29, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant