663b1c046c
Files changed: - CHANGES.md - VERSION - instructions/CONTRACT.md - instructions/wiki-ingest/SKILL.md
277 lines
17 KiB
Markdown
277 lines
17 KiB
Markdown
# instructions/ - Instruction Layer Contract
|
|
|
|
Agent-directed procedure. Everything an agent is *told to do* lives here, and nowhere else.
|
|
|
|
**Quality goal:** executability + precision - every step actionable, every decision point
|
|
explicit, ambiguity eliminated. A vague prescription spends bounded context on interpretation
|
|
instead of action.
|
|
|
|
`instructions/` is not a pipeline stage and not a collection. It is part of the control plane,
|
|
alongside [AGENTS.md](../AGENTS.md).
|
|
|
|
## Two forms, three reference tiers
|
|
|
|
| Form | File | Loaded by |
|
|
|------|------|-----------|
|
|
| **Instruction** | `instructions/<name>.md` | A link from a skill, a contract, AGENTS.md, or CLAUDE.md - or run explicitly on request |
|
|
| **Skill** | `instructions/<name>/SKILL.md` | The agent harness, automatically, once published |
|
|
|
|
The Instruction/Skill split is **structural, not editorial**: a subdirectory containing a
|
|
`SKILL.md` is published; a flat `.md` file never is. Nothing else decides it, and no
|
|
frontmatter flag controls it.
|
|
|
|
The split exists because publication is not free. Every published skill's description sits in
|
|
the agent's context for the whole session, whether or not it is used. A procedure that runs
|
|
once a quarter earns a link, not a permanent slot.
|
|
|
|
Within the flat `instructions/<name>.md` form, `tools/wikitool instructions verify`'s
|
|
reference rule (below) has two further tiers, told apart by frontmatter `manual: true`:
|
|
|
|
| Tier | `manual:` | Referenced from AGENTS.md/CLAUDE.md/a contract/a skill/... | Linked from AGENTS.md, CLAUDE.md, or a skill | When |
|
|
|------|-----------|------------------------------------------------------|-----------------------------------|------|
|
|
| **Linked** | absent (default) | Required - `verify` reports it as dead otherwise | Allowed | The normal case: every instruction most agents will run |
|
|
| **Manual** | `true` | Not required, and a CONTRACT.md/COLLECTION.md/other-instruction mention is fine | Forbidden - `verify` reports it if it IS linked there | Rare, deliberate, or still experimental - must never be picked up implicitly. Named directly by the user, or mentioned as documentation, never followed as an automatic step |
|
|
|
|
AGENTS.md and CLAUDE.md are both "automatically loaded" for this purpose, but for disjoint
|
|
harnesses: AGENTS.md is read natively by every harness except Claude Code, and CLAUDE.md exists
|
|
because Claude Code does not read AGENTS.md on its own (see AGENTS.md's file-naming table). A
|
|
Claude-Code-only instruction is therefore reached from CLAUDE.md, not AGENTS.md - a link from
|
|
AGENTS.md would load it into every other harness's session too, where it may not even apply.
|
|
|
|
CLAUDE.md can reach it two ways, and the choice is about *when the decision is made*:
|
|
|
|
| From CLAUDE.md | Effect | Use for |
|
|
|---|---|---|
|
|
| `@instructions/<name>.md` | The whole file is in context for every session on this harness | A decision made in passing - while spawning a subagent, while picking a review level - where nobody would stop to open a document |
|
|
| A markdown link | Only the link line is in context; the body is read on demand | A procedure looked up deliberately, when its trigger is recognisable from the link alone |
|
|
|
|
An import is the strongest load in this layer - stronger than a skill, which puts only its
|
|
`description` in context - so it is also the most expensive. It is charged to every session on
|
|
that harness whether or not the session ever makes the decision, which is the bar each further
|
|
import has to clear. `tools/wikitool instructions verify` counts either form as a reference: both
|
|
put the filename in CLAUDE.md.
|
|
|
|
**A mention in README.md or CHANGES.md is not a reference.** Both describe the stack to a human
|
|
- the file-naming table makes README.md "never by an agent as instruction" - so a mention there
|
|
documents an instruction without deploying it to anyone. `verify` scans neither when asking
|
|
whether an instruction is still reachable, which is exactly why the answer means something. The
|
|
`instructions/dev/` boundary check below asks the opposite question - what would *dangle* in a
|
|
distributed instance - and does scan README.md, because `dist export` ships it verbatim.
|
|
|
|
Three kinds of file use the Manual tier today: [german-terminology.md](german-terminology.md), a
|
|
vocabulary consulted on demand rather than a procedure; [kb-profiles.md](kb-profiles.md), the
|
|
catalogue of authoring profiles an instance may adopt into its own `kb/CONVENTIONS.md` and
|
|
`COLLECTION.md` files; and every migration document (below).
|
|
|
|
## `instructions/migrations/`
|
|
|
|
A content migration is a Manual instruction with three extra frontmatter fields
|
|
(`types/instruction.schema.yaml`): `migrates_to:`, the stack version whose content shape it
|
|
produces; `migration_kind:` (`mechanical` | `assisted`); and `obligation:`
|
|
(`required` | `offered`, default `required`). It lives at
|
|
`instructions/migrations/<version>-<slug>.md`.
|
|
|
|
`migration_kind:` and `obligation:` are **two axes, not one**. The first says how the work is
|
|
carried out, the second whether it has to happen at all:
|
|
|
|
| `obligation:` | Means | `migrate status` |
|
|
|---|---|---|
|
|
| `required` | The content must reach the new shape or it no longer fits the machinery | Counted as outstanding; `migrate done` advances `kb_version` through it, in chain order |
|
|
| `offered` | A file the instance owns still works as it is, and the stack proposes a better default | Listed separately, never blocks, no ordering rule. `migrate done` records it in the applied ledger and leaves `kb_version` where it is |
|
|
|
|
Keeping them apart is what stops `migrate status` crying wolf: an instance nagged about an
|
|
improvement it declined stops reading the nag that means its content no longer fits its
|
|
machinery. And because taking an offer deliberately does not move the version, the **applied
|
|
ledger** - not `kb_version` - is what makes an offer stop being offered; without that record
|
|
there is no way to tell a taken offer from an ignored one.
|
|
|
|
An `offered` migration is what makes an instance-owned file upgradeable at all. `dist export`
|
|
records a sha256 per shipped file in `.wikitool-release.json`, so `migrate status` can say which
|
|
of those files the instance edited and which it merely received - the first have to be
|
|
reconciled by a person, the second can simply be copied over.
|
|
|
|
The tier fits exactly: a migration must never be picked up implicitly - it rewrites the corpus -
|
|
and it is referenced by nothing, because `tools/wikitool migrate status` finds it by reading the
|
|
directory and comparing `migrates_to:` against this instance's `kb_version`. That is also why
|
|
these files are ordinary instructions rather than a new stage: `dist export` already ships
|
|
`instructions/`, so a migration reaches every distributed instance without a second export path.
|
|
|
|
Writing one is [migrate-corpus.md](migrate-corpus.md), which also holds the procedure for
|
|
carrying a migration out. The baseline is `1.0.0` - nothing older has a document.
|
|
|
|
## `instructions/dev/`
|
|
|
|
A fourth, orthogonal split: material relevant only to developing the tool stack - procedures for extending
|
|
`tools/wikitool`, the type schema, or this layer itself, rather than operating on wiki content -
|
|
lives under `instructions/dev/`, one level in. `tools/wikitool dist export` prunes that whole
|
|
directory, unconditionally and one-way: there is no command that adds it back to a distributed
|
|
instance. This is a whole-directory exclusion, distinct from the
|
|
`<!-- dist:strip-start/end -->` marker convention ([tools/CONTRACT.md](../tools/CONTRACT.md)),
|
|
which removes marked *content* from an otherwise-shipped file rather than excluding a file
|
|
outright.
|
|
|
|
This is orthogonal to the Linked/Manual split above, not a third value of the same field: a
|
|
`instructions/dev/*.md` file still carries `manual:` or not, exactly like any other instruction,
|
|
and still needs a reference from somewhere for `verify`'s ordinary orphan check. What
|
|
`instructions/dev/` adds on top is a hard boundary in the other direction - `tools/wikitool
|
|
instructions verify` also reports anything under it that is referenced from **outside** it,
|
|
because such a reference would dangle the moment `dist export` runs. A skill switching a session
|
|
into this mode is nested under `instructions/dev/` too, for the same reason: it must never reach
|
|
a distributed instance either.
|
|
|
|
The one sanctioned crossing is a routing line from AGENTS.md into `instructions/dev/`, and it
|
|
uses the marker convention to stay honest: wrapped in `<!-- dist:strip-start/end -->`, so `dist
|
|
export` removes the line and the directory it points at together, and `verify`'s boundary check
|
|
skips marker-block content before scanning, exempting exactly that line and nothing else.
|
|
|
|
## Publishing
|
|
|
|
`tools/wikitool instructions sync` **copies** each skill directory into `.agents/skills/` (read
|
|
natively by GitHub Copilot, Codex CLI and Mistral Vibe) and `.claude/skills/` (Claude Code reads
|
|
nothing else).
|
|
|
|
Both targets are generated and gitignored. A fresh clone therefore has no skills until
|
|
`sync` runs - see [bootstrap.md](bootstrap.md).
|
|
|
|
Copies, not symlinks: a symlink cannot go stale but is unreliable on Windows checkouts and
|
|
does not survive being archived or copied. The price of a copy is drift, and drift is what
|
|
`tools/wikitool instructions verify` checks - byte for byte against the source.
|
|
|
|
## Writing an instruction
|
|
|
|
Scaffold with `tools/wikitool new instruction --name "<name>"`; the contract is
|
|
`tools/wikitool types describe instruction`.
|
|
|
|
- **Imperative title.** It answers "what does this tell me to do?". This binds the flat
|
|
`instructions/<name>.md` form only - a skill's H1 is a different case, below.
|
|
- **`description` is the retrieval wire.** Write it to match the question an agent would ask
|
|
when it needs this procedure, not as a label for the file.
|
|
- **Frontload.** Self-contained enough for an agent with no prior context: define terms
|
|
inline, do not assume other documents are loaded. What this does and does not say about
|
|
linking a shared contract: below.
|
|
- **Reasoning earns its place by deciding something.** Keep what an agent needs in order to get
|
|
*this* decision right, at the step where it falls; cut the explanation of why the step exists
|
|
at all. If that is worth preserving, it is a concept page under `kb/concepts/`, linked from
|
|
here. Where the line runs, and how to test a passage against it: below.
|
|
- **State scope boundaries.** When does this *not* apply, and what to do instead.
|
|
|
|
### A skill's H1 is a name, not an imperative
|
|
|
|
`instructions/<name>/SKILL.md` takes a name-shaped H1 matching its `name:` frontmatter -
|
|
`# Wiki Ingest`, not `# Ingest a source file into the wiki`. The imperative-title rule is
|
|
written for the flat form and stops there.
|
|
|
|
The heading lies on no retrieval path. What decides whether a skill is picked up is
|
|
`description`, which sits in the agent's context from session start; the body is read only once
|
|
the skill is already open, and by then the title has nothing left to decide. Anthropic's
|
|
skill-authoring guidance agrees by omission and by example: it normalises `name` and
|
|
`description` and says nothing about the body's heading, and its own worked examples are noun
|
|
phrases (`# PDF Processing`, `# BigQuery Data Analysis`). So does the vendored `commonplace`
|
|
corpus, which arrived at the imperative-title rule independently and carves out the same
|
|
exception in the same breath - "for promoted skills, the skill name is the title".
|
|
|
|
That is the whole exception. Everything else in this section binds a `SKILL.md` exactly as it
|
|
binds an instruction.
|
|
|
|
### Reference depth: bundled files, not repo-wide contracts
|
|
|
|
Anthropic's skill-authoring guidance asks that reference files stay **one level deep from
|
|
`SKILL.md`**, because a file reached at the second hop may be previewed rather than read -
|
|
`head -100` instead of the whole file - leaving the step to run on incomplete information.
|
|
|
|
That rule governs **skill-bundled** material: files sitting in `instructions/<name>/` beside the
|
|
`SKILL.md`. The guidance's own worked example is a bundle (`SKILL.md` → `REDLINING.md`,
|
|
`OOXML.md`), and it says nothing about files outside the skill directory. No skill in this repo
|
|
has a bundled file today, so as written the rule currently binds nothing here.
|
|
|
|
A link from a skill to a repo-wide contract - [kb/CONTRACT.md](../kb/CONTRACT.md),
|
|
[tools/CONTRACT.md](../tools/CONTRACT.md), [gates.md](gates.md) - is a different category, and
|
|
the two halves of the question have different answers:
|
|
|
|
- **The mechanic is real and directory-independent.** A contract reached at the second hop can
|
|
be read partially exactly as a bundled file would be. Nothing about the path makes it safe.
|
|
- **The rule is not.** Reading its scope wider than it states would attribute a rule to a source
|
|
that does not carry it - the same move invariant 3 forbids about facts.
|
|
|
|
So the shared contracts stay shared and stay linked once. AGENTS.md invariant 8 is what put them
|
|
there: copying `kb/CONTRACT.md` into five `SKILL.md` files is precisely the second copy that
|
|
drifts. § Frontload does not ask for that either - it asks that a **step** be decidable without
|
|
prior context, not that every rule the step obeys be restated at it.
|
|
|
|
What the mechanic does oblige is cheaper than either: **a link says what the step needs from the
|
|
file it points at.** A bare "read X first" leaves a partial read undetectable; naming what is to
|
|
be taken from it - the field, the section, the decision - keeps the step decidable even when the
|
|
read came up short, and tells the next author which reference is actually load-bearing.
|
|
`wiki-ingest` step 7 is the shape: three contracts linked, each with the clause that says why
|
|
this step needs it.
|
|
|
|
This is a narrower posture than the vendored `commonplace` corpus takes, which makes outbound
|
|
links exceptional in its instruction collection and frontloads the rest. That works for a corpus
|
|
whose procedures do not share a contract; here they do, and invariant 8 outranks the preview
|
|
risk.
|
|
|
|
**All of the above is a judgment, not a measurement**, and it is worth knowing why it cannot be
|
|
the second. Whether the mechanic bites here is not something this repo can currently observe:
|
|
the L2 trajectory scorers read `wikitool` calls, gates and publishes, never an agent's file
|
|
reads, and no tool hook is wired on the primary harness at all - so a `head -100` leaves nothing
|
|
to score. The other half of the claim, what ended up in the context window, produces no event
|
|
anywhere by construction. Gitea #72 records what a test would cost and why it was not bought.
|
|
|
|
### How much reasoning a step may carry
|
|
|
|
"Cut the reasoning" and "keep enough to decide an edge case" are one sentence pulling two ways,
|
|
and the largest instruction in this repo lives in the gap. The line runs here:
|
|
|
|
| Keep | Cut |
|
|
|---|---|
|
|
| What an agent must know to get this decision right, at the step where it falls | Why the step exists at all |
|
|
| The consequence of the wrong choice, when nothing later catches it | The consequence, when a validator, a gate or a later step catches it |
|
|
| Why a plausible-looking default is the wrong answer | Background about the design that produced the field |
|
|
|
|
Two tests, both cheap:
|
|
|
|
- **Substitution.** Delete the passage and read the step again. Does an agent with no prior
|
|
context still make the same call? If yes, it was background. If it now guesses, it was a
|
|
decision aid, and it stays - however long it runs.
|
|
- **Once.** A decision aid belongs at the step where the decision falls, and at exactly one such
|
|
step (AGENTS.md invariant 8). Where the same decision falls at two steps - `wiki-ingest` asks
|
|
for `fidelity`/`authority` in step 1 and again in step 6 - the reasoning is written at the
|
|
first and the second carries the instruction plus a pointer, never a second telling.
|
|
|
|
A passage that survives both is not an exception to the rule. Deciding an edge case is the part
|
|
the rule keeps; the length it takes to do that is not the measure.
|
|
|
|
## Instruction duality
|
|
|
|
These files are both content and running system. Changing one changes agent behaviour
|
|
immediately: the edit is live for the next agent that loads the text, with no release step.
|
|
Treat edits as deployments, not documentation updates.
|
|
|
|
The same duality runs the other way. An instruction nothing loads is inert - it deploys to no
|
|
one. `tools/wikitool instructions verify` reports a file here that nothing references, because
|
|
otherwise nothing would - unless it is `manual: true` (see "Two forms, three reference tiers"
|
|
above), where the same duality flips the check: being loadable from somewhere IS the fault.
|
|
|
|
## Single source
|
|
|
|
A rule belongs in exactly one place; everywhere else links to it. This is an authoring rule,
|
|
not a checked one - prose duplication is a judgment call, so it is reviewed during a
|
|
`wiki-lint` pass rather than enforced by a validator.
|
|
|
|
What lives where:
|
|
|
|
| Layer | Owns |
|
|
|-------|------|
|
|
| [AGENTS.md](../AGENTS.md) | Invariants and routing - what must always hold |
|
|
| `instructions/` | How the tooling is *operated* |
|
|
| [kb/CONTRACT.md](../kb/CONTRACT.md) | What the stack enforces about a page, in every instance |
|
|
| `kb/CONVENTIONS.md` + each `COLLECTION.md` | What *this* instance decided about authoring - owned by the instance, shipped only as a `.template` |
|
|
| [types/](../types/type-spec.md) | What a page structurally *is* |
|
|
| [tools/CONTRACT.md](../tools/CONTRACT.md) | What each command does and how it fails |
|
|
|
|
## What does not belong here
|
|
|
|
- Knowledge. A fact about a system is a page under `kb/`.
|
|
- The reasoning behind a procedure - that is a concept page, linked from the instruction.
|
|
- Anything under `.agents/skills/` or `.claude/skills/`: those are generated copies.
|