Skip to content

Agent asset hierarchy โ€‹

Status: draft, 2026-08-22. Open questions at the bottom need operator rulings. Issue: #950


What problem is this solving? โ€‹

Six layers hold agent guidance. Nothing says which layer a new piece belongs in, so the choice is made by whoever is writing at the time, and the same guidance can end up in two layers or none.

The only written argument on record is in .agents/workflows/README.md: a rule that fails by being skipped belongs in a workflow, a rule that needs judgment at every step stays a skill. That test is correct and it covers one boundary out of five.

What are the six layers? โ€‹

Ordered by how hard they are to ignore, strongest first.

LayerWhat it isHow it failsWhen it loads
HookA script that inspects a tool call and can refuse itCannot be ignored. Fails by being absent, wrong, or unwiredEvery matching tool call
RuleAlways-present guardrail textIgnored by inattention, mid-session drift, or context pressureEvery session, eagerly
WorkflowA script whose steps run in order, every timeSteps cannot be skipped. Fails by never being invokedOn invocation
SkillA procedure the model reads and applies with judgmentFails by not being recalled, or by being read and walked pastWhen the model recalls it
ContextOne person's overlay: voice, people, focus, projectsFails silently when stale or absentEvery session, eagerly
Output styleHow the agent talksFails silently when generated but not selectedEvery session

The ordering is the point. A hook cannot be talked out of, a rule can be forgotten, a skill can be not-recalled. Strength costs reach and flexibility, which is what the routing test trades against.

Which layer does a new piece of guidance belong in? โ€‹

Walk it top to bottom. The first yes wins.

1. Can a machine decide it, and does a violation cost real money or real trust?

  • Then a hook, and also a rule. See the pairing question below.
  • Deterministic and expensive is the hook case: an em dash in shipped copy, a PR aimed at main, a branch switch under a parallel session, a secret inlined into a command, a PR marked ready without her word.

2. Does it bind on every piece of work, whatever the task?

  • Then a rule.
  • Rules are the only layer loaded eagerly for every agent on every tool. That is their whole value and also their cost: every rule added is context spent on every session forever, including the sessions it does not apply to.

3. Is it a fixed sequence, where the failure is skipping a step rather than doing a step badly?

  • Then a workflow.
  • The proof case is on the record: on 2026-08-21 the agenda-creation skill said to rank every candidate against the north star, and the launch plan was never opened, because prose cannot force a read.
  • A step inside a workflow may still be "go think about this". The sequence is guaranteed; the judgment happens inside the steps.

4. Is it a procedure for one kind of task, needing judgment at each step?

  • Then a skill.
  • Most guidance lands here, which is why the skills layer is the one with 33 entries and no internal structure.

5. Is it true for one person and not the team?

  • Then context. Voice, the people she works with, what is in front of her this week.

Nothing routes to the output style directly. It is generated from the voice rule. Treat it as a compile target, not a place to put things.

Why does a rule need a hook, and a hook need a rule? โ€‹

A hook is never the only home for a rule.

Hooks reach Claude Code and nothing else, and they fire at call time, which means an agent can spend a whole session heading somewhere a hook will refuse. The rule is what stops the trip; the hook is what catches the one that got through.

The em dash convention is the worked example, and it is the pattern to copy:

LayerArtifactCatches
Rulekey-conventions.mdThe agent that would otherwise type one, on all four tools
Hookguard-em-dash.shThe Claude write that slipped past the rule, at write time
CIlint:emdash, ratchetedEverything else, including humans and Copilot

Three layers, one convention, each catching what the one before it missed. Rule 17 and rule 16 have the same shape.

A hook with no matching rule is a trap. It refuses an action the agent had no way to know was forbidden, and it refuses it only for Claude.

Which tools actually see each layer? โ€‹

Nowhere else is this written down, and it is the reason the pairing rule exists.

LayerClaudeCopilotGeminiCursor
Rulesyesyesyesyes
Skillsyesyesyesno
Workflowsyesnonono
Hooksyesnonono
Contextyespartial, via context:sync-toolsnopartial

Putting a guardrail in a hook means Copilot and Gemini never see it. That is a fine trade when the hook is a backstop for a rule, and a silent hole when the hook is the only copy.

What are the skill tiers, and why do they matter? โ€‹

Built 2026-08-22. tier: is a required frontmatter field, enforced by the Skill Sync gate. Before it existed, 33 skills presented identically to a model choosing one, and they are not the same kind of thing.

TierWhat it isMembers
OrchestratorSequences other skills, run once per session or dayautopilot, project-manager, agenda-creation
ProcedureDoes one task a specific way, invoked for that taskpr-workbench, session-pr, monitor-ci, test-plan, browser-test, cloud-service, env-vars, script-wiring, planning, design-mockups, distill-agent-log, curate-memory, context-onboard, scenario-matrix, decision-log, frustration-signal, project-creation
DisciplineHow to work, applies inside whatever else you are doingtdd, verified-done, code-review-rigor, code-comments, debug, self-improve, safe-automation, authorization, multi-agent, worktree
ReferenceLookup, no procedure to followrepo-map, design, privacy-architecture, verify

Why it matters:

  • A discipline should be recalled during other work.
  • A reference only when a fact is needed.
  • An orchestrator at most once a session.
  • Before the field existed, all three arrived with the same weight, so a model choosing between repo-map and autopilot had nothing to go on but the description text.

Disciplines are the tier most likely to be walked past, since nothing triggers them. That makes them the strongest candidates for promotion to rules or hooks, which is the routing test running in reverse.

What rule governs the command field? โ€‹

None yet, and that is the finding.

  • 20 skills set command: true.
  • 4 set command: false.
  • 9 omit it.
  • sync-skills.js reads it as if (meta.command), so omitted behaves exactly like false. The nine are not a different choice; they are an unrecorded one.

Proposed rule:

  • command: true when a person would plausibly type it (/agenda-creation, /test-plan, /monitor-ci).
  • command: false when the model should recall it but no human would ever invoke it (code-comments, debug, privacy-architecture).
  • Make the field required, so the sync check fails on omission and the choice is always deliberate.

How do I test and refine an agent asset? โ€‹

The loop already exists. Nothing names it, so no one runs it deliberately.

StageQuestionTool
ObserveHow often did she have to correct an agent, and why?frustration-signal skill
CaptureTurn one correction into a durable changeself-improve skill
RouteWhich layer does it belong in?The routing test above
GraduateMove it from memory to its permanent homecurate-memory skill
Verify behaviorDid the change make the agent pick better?test-rank.js workflow
Verify coverageWill this prompt actually answer the ask?preflight-prompt-check.js workflow
GateDid the generated copies drift from source?Skill Sync, Agents Sync in validate

Two observations about the shape:

  • The gates only check that copies match their source. Nothing checks whether the source is any good. test-rank.js is the only asset that tests behavior rather than bytes, and it covers exactly one step of one workflow. That is the real gap in "testing", and it is not cheap to close, because the only honest test of a skill is whether an agent given a realistic task actually reaches for it.
  • Verify-behavior is the stage that gets skipped, for the same reason every unenforced step gets skipped: it costs a run, and the change looks obviously correct. Naming it in the loop is the cheap half.

Why does the context layer fail differently? โ€‹

Every other layer is committed, so drift shows up as a diff. Context is per-user and per-machine, so it drifts silently and no gate can see it. Two live examples, both found while writing this doc on 2026-08-22.

This laptop's context home was 102 commits behind.

  • The dev VM had been syncing since 08-11; mwrazerblade had not pulled once.
  • npm run context:sync is in no SessionStart hook, so the machine that runs it pushes and the machine that does not simply falls behind.
  • Everything downstream was the 08-11 version: voice, people, projects, and no active/focus.md at all, which was then the first file the agenda-creation skill opened.
  • An agent on this machine would have planned a day against a focus that did not exist and had no way to notice. That is #834.

Memory does not sync at all.

  • The context home's memories entry is a symlink to ~/.claude/projects/<repo>/memory, a machine-local path.
  • This laptop holds 51 notes; the 2026-08-19 graduation ledger counted 60 on the VM.
  • They are separate directories that keep diverging. Filed as #654.

That divergence is the argument for graduation, not a bug to patch. #927 moved the durable half of the corpus into committed skills (authorization, repo-map, safe-automation, frustration-signal, plus additions to verified-done, tdd, debug, multi-agent), where it reaches every tool on every machine.

Read against the routing test, memory is not a seventh layer. It is a staging area: the place a learning lands before anyone knows which layer it belongs in. self-improve writes into it, curate-memory empties it. Anything still sitting there after a graduation sweep is either genuinely personal, or overdue.

Why were workflows pinned to one machine? โ€‹

All three scripts defaulted ROOT to /home/cattreedev/lantern_app, and two also defaulted a context path under that home. On this laptop, /home/mechelle/repos/lantern_app, every one of them read a tree that is not there.

A workflow script has no filesystem or Node API access by design, so it cannot resolve the path itself. The caller has to pass repoRoot through args. The old fallback hid that: on the wrong machine the script did not refuse, it just read nothing and reported on nothing.

Resolved 2026-08-22: repoRoot is required on all three, and contextHome on the two that read the per-user context home.

What has the operator ruled on this design? โ€‹

Six rulings, 2026-08-22, during the PM skill refactor. Execution detail is in implementation.md.

RulingWhat it means
The new-day branch delegates to agenda-creation rather than absorbing itKills the duplication between two orchestrators that both claimed the split
The agenda has no top-level Need-from-you tableAn ask lives on the task block it belongs to. A single collected table becomes a wish list, and the loudest row wins over the current one
active/focus.md is retired; the focus is a line in the agenda header"That is what the agenda is for." One less file to sync, one less thing that can disagree with the board
The status sweep runs on her ask, plus once before the EOD reportNo timer, no unprompted pushes. Sessions that need to tell her something tell her themselves
Sessions may be polled on a status she asked for, not on the pre-EOD runResolved an apparent conflict between the 2026-08-08 "ask first, dig second" rule and the 2026-08-21 "do not poll any session" instruction. Both hold, on different runs
The morning survey restructures to backlog-firstThe launch plan and the tracker become filters, not candidate sources

One of those turned out to be blocked by a transport fact, not a policy one. A workflow subagent can send a message but cannot receive a reply, so the polling had to move to the caller. The ruling survived; only its implementation site changed. See implementation.md.

What is broken right now? โ€‹

Both filed as #951, both fixed on 2026-08-22 per rule 18.

  1. sync-workflows.js had no --check, and validate had no Workflow Sync entry. Edit a workflow, forget to sync, and the stale .claude/workflows/ copy runs. Silently. Skills and rules each have this gate.
  2. .agents/workflows/README.md said the layer was not wired. It is. The wiring shipped in the same PR, so the source of truth told readers to paste scripts in by hand.

What is still open? โ€‹

  1. RESOLVED, 2026-08-22: frontmatter. tier: is required on every skill and validated by lint.sync-skills.js, which rejects a missing tier and a tier outside the four. All 34 skills carry one (3 orchestrator, 17 procedure, 10 discipline, 4 reference). Proven to fail by mutation, both on a removed tier and a misspelled one. Schema in .agents/meta/frontmatter.md.
  2. Should hooks move under .agents/hooks/? They are the only layer outside the source of truth. Moving them makes the pairing rule checkable: a hook with no matching rule could fail the sync. Cost is a real move plus settings rewiring.
  3. Does verify-behavior become a workflow? A skill saying "test your skill change" is a discipline, and disciplines get walked past. A workflow forces it, at the cost of a run per asset change.
  4. Is 33 skills too many? Not asked here, but the tiering will make the answer visible. Four references and ten disciplines suggest some of both belong in rules.
  5. RESOLVED, 2026-08-22: it refuses. repoRoot is required on all three workflows, and contextHome on the two that read the per-user context home. Each throws a message naming what to pass. Proven both directions: no args exits 1 with the message, correct args resolves this machine's path.
  6. Should context:sync run at session start? It would have caught the 102-commit gap on its own. The cost is a network call on every session boot and a write path in a hook, which safe-automation warns about specifically: N sessions boot at once when the fleet starts. A pull-only variant may be the safe half.
  7. Does the PM sequence become a workflow? Now with evidence on both sides. agenda-status.js proves the sequence can be forced and that forcing it surfaces real defects. It also proves a workflow cannot do everything a skill can, since it cannot receive a peer's reply.

Built with VitePress