feat(agents): make skill metadata agent-agnostic

This commit is contained in:
2026-07-29 22:39:02 -04:00
parent 40b37281d5
commit b541251f98
21 changed files with 131 additions and 80 deletions

58
.agents/CONTEXT.md Normal file
View File

@@ -0,0 +1,58 @@
# Skills
A personal collection of agent skills packaged through Nix.
The language below covers the knowledge-mining pipeline — the `consume` (write) and `wiki` (read) pair that move knowledge into and out of the user's Obsidian vault.
## Language
### Places
**Vault**:
The user's personal Obsidian knowledge base, read through `wiki` and written only within one area by `consume`.
_Avoid_: notes folder, Obsidian
**Pull channel**:
The vault area holding reusable knowledge, retrieved on demand by a future agent that goes looking for it.
_Avoid_: wiki proper, retrieval store
**Push channel**:
The target's own always-loaded documentation (`AGENTS.md`), whose value is being in front of an agent unprompted.
_Avoid_: proactive store, always-on docs, `CLAUDE.md`
**Target**:
The single source `consume` ingests in one run — currently a project directory.
_Avoid_: source (reserve for the raw material within the target), input
**Compatibility surface**:
A legacy harness-specific file or directory that points an older agent harness to the canonical agent-neutral surface.
_Avoid_: duplicate source, mirror
### Acceptance axes
**Generalizes**:
A mined fact's property of teaching something true on a *different* target, not only the one it came from.
_Avoid_: reusable, transferable (use only informally)
**Trigger-able**:
A mined fact's property of having a recognizable symptom, error, or task that would send a future agent to retrieve it.
_Avoid_: searchable, useful
### What a source line yields
**General lesson**:
The transferable principle split out of a source line.
_Avoid_: concept, insight
**Specific residue**:
The concrete, target-only answer left after the general lesson is split off.
_Avoid_: leftover, detail
**Proactive rule**:
A mined fact that generalizes but is not trigger-able — a verification-discipline or design-stance rule whose value is firing unprompted.
_Avoid_: habit, guideline
### Planning
**Contribution map**:
The many-to-many record of which consumed file fed which planned note, with the exact contributing sections, including files that fed nothing.
_Avoid_: provenance table, coverage map

View File

@@ -1,8 +1,8 @@
# Consume writes the target's push channel, not only the vault
`consume` was scoped to write only inside the vault's `01 sources/claude/` area.
A real run showed that most mined knowledge is not wiki-shaped — specific residue and proactive rules belong in the target's own always-loaded `CLAUDE.md` — and dropping it lost real signal, while redoing the target-doc edits by hand after each run was toil.
We decided `consume` writes a second channel outside the vault, the target's `CLAUDE.md`, rather than only planning those edits for the user to apply.
A real run showed that most mined knowledge is not wiki-shaped — specific residue and proactive rules belong in the target's own always-loaded `AGENTS.md` — and dropping it lost real signal, while redoing the target-doc edits by hand after each run was toil.
We decided `consume` writes a second channel outside the vault, the target's `AGENTS.md`, rather than only planning those edits for the user to apply.
## Considered Options
@@ -14,4 +14,4 @@ We decided `consume` writes a second channel outside the vault, the target's `CL
`consume`'s blast radius now includes files outside the vault and outside the spec/task scaffolding it deletes.
The plan-approval gate is what keeps that safe: the target write-set is approved separately from the vault write-set, and a declined target write-set degrades to flagged suggestions.
Destructive edits to `CLAUDE.md` are gated on capture — an entry is removed or trimmed only when its general part is present in the wiki.
Destructive edits to `AGENTS.md` are gated on capture — an entry is removed or trimmed only when its general part is present in the wiki.

View File

@@ -0,0 +1,5 @@
# Agent-neutral project surfaces
This repository uses `AGENTS.md` and `.agents/` as the canonical project instruction, context, ADR, spec, task, and project-local skill surfaces.
Claude Code compatibility remains through `CLAUDE.md` and `.claude/` shims because existing harnesses and skills still discover those paths.
The compatibility surfaces are pointers, not duplicate sources of truth, so future agents have one canonical place to read and update.

0
.agents/skills/.gitkeep Normal file
View File

0
.agents/spec/.gitkeep Normal file
View File

0
.agents/tasks/.gitkeep Normal file
View File

View File

@@ -1,54 +0,0 @@
# Skills
A personal collection of Claude Code skills.
The language below covers the knowledge-mining pipeline — the `consume` (write) and `wiki` (read) pair that move knowledge into and out of the user's Obsidian vault.
## Language
### Places
**Vault**:
The user's personal Obsidian knowledge base, read through `wiki` and written only within one area by `consume`.
_Avoid_: notes folder, Obsidian
**Pull channel**:
The vault area holding reusable knowledge, retrieved on demand by a future agent that goes looking for it.
_Avoid_: wiki proper, retrieval store
**Push channel**:
The target's own always-loaded documentation (its `CLAUDE.md`), whose value is being in front of an agent unprompted.
_Avoid_: proactive store, always-on docs
**Target**:
The single source `consume` ingests in one run — currently a project directory.
_Avoid_: source (reserve for the raw material within the target), input
### Acceptance axes
**Generalizes**:
A mined fact's property of teaching something true on a *different* target, not only the one it came from.
_Avoid_: reusable, transferable (use only informally)
**Trigger-able**:
A mined fact's property of having a recognizable symptom, error, or task that would send a future agent to retrieve it.
_Avoid_: searchable, useful
### What a source line yields
**General lesson**:
The transferable principle split out of a source line.
_Avoid_: concept, insight
**Specific residue**:
The concrete, target-only answer left after the general lesson is split off.
_Avoid_: leftover, detail
**Proactive rule**:
A mined fact that generalizes but is not trigger-able — a verification-discipline or design-stance rule whose value is firing unprompted.
_Avoid_: habit, guideline
### Planning
**Contribution map**:
The many-to-many record of which consumed file fed which planned note, with the exact contributing sections, including files that fed nothing.
_Avoid_: provenance table, coverage map

1
.claude/CONTEXT.md Symbolic link
View File

@@ -0,0 +1 @@
../.agents/CONTEXT.md

1
.claude/adr Symbolic link
View File

@@ -0,0 +1 @@
../.agents/adr

1
.claude/skills Symbolic link
View File

@@ -0,0 +1 @@
../.agents/skills

1
.claude/spec Symbolic link
View File

@@ -0,0 +1 @@
../.agents/spec

1
.claude/tasks Symbolic link
View File

@@ -0,0 +1 @@
../.agents/tasks

5
.gitignore vendored
View File

@@ -9,3 +9,8 @@ result-*
# Benchmark run artifacts: reports and local history, keyed by skill name.
tests/.reports/
# BEGIN mkSkillsShellHook
# Generated by mkSkillsShellHook. Nix-delivered skill symlinks, kept out of git.
.agents/skills/benchmark-skill
# END mkSkillsShellHook

20
AGENTS.md Normal file
View File

@@ -0,0 +1,20 @@
# skills
Personal agent skills packaged through Nix.
The domain glossary lives in `.agents/CONTEXT.md`.
## Conventions
- `AGENTS.md` and `.agents/` are canonical for agent-facing project instructions, context, ADRs, specs, tasks, and project-local skill links.
`CLAUDE.md` and `.claude/` exist only as Claude Code compatibility surfaces.
- Skill source lives under `skills/<name>/`.
Do not edit generated links under `.agents/skills/` or `.claude/skills/` as source.
- Run `nix flake check` before considering a repository-wide change complete.
The check builds every packaged skill plus the Home Manager module, shell hook, and benchmark core tests.
- The dev shell may place Nix-delivered skills into `.agents/skills/` and maintain `.claude/skills` as a compatibility symlink.
Generated ignore entries belong in the root `.gitignore`, not inside `.agents/skills/`, because skill scanners honor ignore files inside scanned skill directories.
## Gotchas
- The vault write area remains `01 sources/claude/` for now.
That path is a historical vault taxonomy and is not the canonical project metadata namespace.

5
CLAUDE.md Normal file
View File

@@ -0,0 +1,5 @@
# Claude Code compatibility
You MUST read and follow [`AGENTS.md`](AGENTS.md) before doing any work in this repository.
`AGENTS.md` is the canonical project instruction file.
This file exists only so Claude Code discovers that canonical instruction file.

View File

@@ -1,3 +1,3 @@
# skills
My personal skills packaged through Nix.
Personal agent skills packaged through Nix.

View File

@@ -96,7 +96,7 @@ Failure modes: writing errors to stderr, prompting for confirmation, or exiting
Canonical: install into the agent's session from an explicit setup command, so every conversation starts with relevant state visible, and ship an installable skill for on-demand guidance.
Probe: locate the tool's bundled Agent Skill file, under `~/.claude/skills/<tool>/` or in the installed package or repo, and check the surface for an explicit setup command.
Probe: locate the tool's bundled Agent Skill file, under `~/.pi/agent/skills/<tool>/`, `~/.claude/skills/<tool>/`, or in the installed package or repo, and check the surface for an explicit setup command.
- PASS: the tool ships a discoverable Agent Skill installed by an explicit setup command, optionally alongside a hook that injects a dashboard as initial context.
- PARTIAL: a setup command exists but installs no skill, or a skill exists with no explicit setup path, for example one installed by a postinstall script.

View File

@@ -17,7 +17,7 @@ The card's shape lives in [`REPORT-FORMAT.md`](REPORT-FORMAT.md).
Fix the invocation string first — how this CLI is run (`gitea-axi`, a binary path, `npx -y foo`).
Locate the tool's own Agent Skill file, since it is the authoritative description of the command surface and is itself the evidence for Principle 7.
Look under `~/.claude/skills/<tool>/SKILL.md`, then in the installed package or the repo.
Look under `~/.pi/agent/skills/<tool>/SKILL.md`, then `~/.claude/skills/<tool>/SKILL.md`, then in the installed package or the repo.
A missing skill file is a Principle 7 FAIL that you carry into the judging step.
When it is missing, enumerate the surface from `--help` and no-arg output instead.

View File

@@ -12,20 +12,21 @@ Mine a source for its knowledge, routing each fact to the agent's own wiki or th
It is the write side of a pair with the read-only `/wiki`, which it invokes to read the rest of the vault.
The **pull channel** is the wiki — reusable knowledge a future agent retrieves on demand — and a fact earns a note there only if it both **generalizes** past the target it came from and is **trigger-able**, meaning some symptom, error, or task would send that agent looking for it.
The **push channel** is the target's own always-loaded documentation, its `CLAUDE.md`, which carries what is useful but not wiki-shaped: a concrete repo-specific answer, or a proactive rule whose value is firing unprompted.
The **push channel** is the target's own always-loaded documentation, its `AGENTS.md`, which carries what is useful but not wiki-shaped: a concrete repo-specific answer, or a proactive rule whose value is firing unprompted.
A single fact mined from the source usually splits across both — the transferable general lesson to the pull channel, the specific residue it leaves behind to the push channel.
Nothing is written and nothing is deleted until the user approves the plan.
## The write surfaces
Consume writes to two places and nowhere else.
Consume writes to two channels and nowhere else.
The vault lives at `$(xdg-user-dir DOCUMENTS)/notes`.
Resolve it, and if it does not exist report that the vault is unreachable and stop.
Inside the vault, write only under `01 sources/claude/`, treating every other vault path as off-limits to writes.
Outside the vault, the only sanctioned write is the target's own always-loaded documentation, its `CLAUDE.md` — the push channel of step 6.
Everything else in the target is read-only, save for the scaffolding step 7 deletes.
Outside the vault, the sanctioned content write is the target's own always-loaded documentation, its `AGENTS.md` — the push channel of step 6.
If the target has Claude Code markers such as `.claude/` or `CLAUDE.md`, `consume` may also create or update `CLAUDE.md` as a compatibility shim pointing to `AGENTS.md`.
Everything else in the target is read-only, save for that shim and for the scaffolding step 7 deletes.
The harness does not apply the vault's own permission rules when you run from outside it, so enforcing the vault boundary is the skill's job.
All reading of the wider vault goes through `/wiki` (step 3), which enforces the vault's read boundary itself.
@@ -34,7 +35,7 @@ All reading of the wider vault goes through `/wiki` (step 3), which enforces the
Route the target through this ladder, first match wins:
- A directory containing `.claude/spec/` and/or `.claude/tasks/` → a project: follow [`project.md`](project.md).
- A directory containing `.agents/spec/`, `.agents/tasks/`, `.claude/spec/`, or `.claude/tasks/` → a project: follow [`project.md`](project.md).
- No rung matches → report that the target is not something consume knows how to read, write nothing, and stop.
Done when a branch file is selected, or consume has stopped on an unsupported target.
@@ -67,10 +68,10 @@ The wiki is retrieval-on-demand, so knowledge whose only value is firing *unprom
And the reader is an amnesiac agent, so "the reader will internalize it" is never a reason to keep a note — trigger-ability, not memorability, is the axis.
A fact earns a **pull-channel note** only when it passes *both* axes.
A fact that fails either axis but is still useful to the target goes to the **push channel**, the target's `CLAUDE.md`: a **specific residue** that fails *generalizes* (the concrete repo-specific answer), or a **proactive rule** that generalizes but is not trigger-able (a verification-discipline or design-stance rule whose value is firing unprompted).
A fact that fails either axis but is still useful to the target goes to the **push channel**, the target's `AGENTS.md`: a **specific residue** that fails *generalizes* (the concrete repo-specific answer), or a **proactive rule** that generalizes but is not trigger-able (a verification-discipline or design-stance rule whose value is firing unprompted).
A fact that fails both axes and is useful to no one is dropped.
Most source lines split rather than route whole: the transferable **general lesson** goes to the pull channel, the **specific residue** it leaves behind goes to the push channel — recorded in the target's `CLAUDE.md` when that file does not already hold it.
Most source lines split rather than route whole: the transferable **general lesson** goes to the pull channel, the **specific residue** it leaves behind goes to the push channel — recorded in the target's `AGENTS.md` when that file does not already hold it.
So plan both destinations together, deciding for each pull-channel note whether it is new or an update to an existing note whose knowledge is now stale or thinner than what you have learned.
Keep each pull-channel note atomic — one transferable idea per note.
@@ -89,12 +90,12 @@ The report is a complete ledger of every mined fact's disposition, not only of w
1. **Vault write-set (pull)** — each note to write or update, with its **trigger line**: one sentence naming the symptom, error, or task that would send a reader to retrieve it, and the `[[hub]]` wikilinks it belongs under.
2. **Contribution map** — for every consumed file, the notes it feeds and the exact contributing sections, including any file that fed nothing.
3. **Push write-set (target `CLAUDE.md`)** — each proactive rule and each specific residue to add, each existing entry to trim to its residue, and each pure-general entry to remove, with the exact text and where it lands.
3. **Push write-set (target `AGENTS.md`)** — each proactive rule and each specific residue to add, each existing entry to trim to its residue, and each pure-general entry to remove, with the exact text and where it lands.
4. **Ref-fixes** — each file holding a reference to a spec or task file about to be deleted, and how the reference is fixed or removed. These accompany the scaffolding deletion of step 7, not the target write-set.
5. **Flagged, not authored** — any `[[hub]]` a note links that does not yet exist under `02 tags/` or `03 index/`, and any push knowledge whose home is a hook or checklist rather than `CLAUDE.md` — surfaced for the user to act on by hand.
5. **Flagged, not authored** — any `[[hub]]` a note links that does not yet exist under `02 tags/` or `03 index/`, and any push knowledge whose home is a hook or checklist rather than `AGENTS.md` — surfaced for the user to act on by hand.
6. **Drops** — every mined fact considered and cut, one line of why each.
The vault write-set and the target-`CLAUDE.md` write-set are approved independently: the user may accept one and decline the other.
The vault write-set and the target-`AGENTS.md` write-set are approved independently: the user may accept one and decline the other.
A declined target write-set degrades to flagged suggestions — reported for the user to apply by hand, written nowhere.
The ref-fixes and the scaffolding deletion are not a write-set to accept or decline — they follow from proceeding with the run and execute in step 7, gated only behind the vault writes.
@@ -109,11 +110,12 @@ Write the approved vault write-set first.
Write each new note and update each changed one under the output area the branch declares, using the vault's note template (`99 meta/templates/note.md`): fill its `Tags:` line with the `[[hub]]` wikilinks the note belongs under, and its body with the distilled knowledge.
Link a hub whether or not its note exists yet — a dangling `[[hub]]` is a valid link and still feeds `/wiki` recall.
Then, if the target write-set was approved, reconcile the target's `CLAUDE.md`: add the proactive rules and any specific residue the file does not already hold, trim mixed entries to their specific residue, and remove the pure-general entries.
Then, if the target write-set was approved, reconcile the target's `AGENTS.md`: add the proactive rules and any specific residue the file does not already hold, trim mixed entries to their specific residue, and remove the pure-general entries.
When Claude Code markers are present, create or update `CLAUDE.md` as a compatibility shim to `AGENTS.md` rather than duplicating the push-channel content.
Removal is gated on capture — trim or remove an entry only when its general part is present in the wiki, written just now in this run or confirmed already there via `/wiki`, never on the intention to write a note.
If the target write-set was declined, write nothing to the target and leave its items as the flagged suggestions of step 5.
Done when the approved vault notes are written and, if approved, the target's `CLAUDE.md` is reconciled.
Done when the approved vault notes are written and, if approved, the target's `AGENTS.md` is reconciled.
## 7. Clear the consumed scaffolding
@@ -124,7 +126,7 @@ Done when the branch's cleanup has run.
## 8. Report
Tell the user what you created, updated, and left untouched across both channels — vault notes written or updated, and the target's `CLAUDE.md` reconciliation applied or, if declined, left as flagged suggestions.
Tell the user what you created, updated, and left untouched across both channels — vault notes written or updated, and the target's `AGENTS.md` reconciliation applied or, if declined, left as flagged suggestions.
Repeat the suggested new hubs and any hook-or-checklist items from the report, so the vault's `02 tags/` and `03 index/` and the target's other channels can be filled in by hand.
Done when the summary names every note written or updated, every target edit applied or flagged, and every suggested hub.

View File

@@ -1,7 +1,7 @@
# project branch
How consume reads a project target, and what it clears afterward.
Reached from step 1 of [`SKILL.md`](SKILL.md) when the target is a directory containing `.claude/spec/` and/or `.claude/tasks/`.
Reached from step 1 of [`SKILL.md`](SKILL.md) when the target is a directory containing `.agents/spec/`, `.agents/tasks/`, `.claude/spec/`, or `.claude/tasks/`.
## Read the source, mine the specs
@@ -10,7 +10,8 @@ Read it thoroughly enough to understand its current state and to surface the reu
A gotcha usually carries two separable things — a transferable principle and a concrete repo-specific answer — so surface both.
Step 4 of SKILL.md routes the principle to the pull channel and the residue to the target's push channel.
`.claude/spec/` and `.claude/tasks/` are the record of *why* — the reasoning, trade-offs, and intent behind what the code became.
`.agents/spec/` and `.agents/tasks/` are the canonical record of *why* — the reasoning, trade-offs, and intent behind what the code became.
Claude Code compatibility paths under `.claude/spec/` and `.claude/tasks/` count as the same record only when they resolve to the canonical `.agents/` paths.
They are the richest source of the generalizable lessons, and cleanup destroys them, so mine their reasoning now or lose it.
But they are not current fact: where a spec or task disagrees with the source, the source wins, and where one describes work later abandoned or changed, the source is what actually happened.
@@ -27,9 +28,12 @@ If the user has already grouped some notes into subfolders under `projects/`, wr
## Cleanup
After the notes are written (step 6 of SKILL.md), delete the spec and task files that were present under `.claude/spec/` and `.claude/tasks/` when you read the project in step 2 — the scaffolding this run consumed.
After the notes are written (step 6 of SKILL.md), delete the spec and task files that were present under `.agents/spec/` and `.agents/tasks/` when you read the project in step 2 — the scaffolding this run consumed.
If a target only has legacy `.claude/spec/` or `.claude/tasks/`, consume those paths instead.
If both canonical `.agents/` scaffolding and real distinct legacy `.claude/` scaffolding exist, stop and ask which is authoritative.
A `.claude/` compatibility symlink to `.agents/` is not a distinct tree.
A file added after that read is not swept up.
Leave the now-empty `.claude/spec/` and `.claude/tasks/` directories in place, along with everything else under `.claude/`.
Leave the now-empty `.agents/spec/` and `.agents/tasks/` directories in place, along with any compatibility symlinks under `.claude/`.
Deleting those files can strand references to them.
Scan the target for pointers to each file about to be deleted — in `CLAUDE.md`, `CONTEXT.md`, ADRs, and sibling specs — and fix or remove each one, following the pointer wherever it lands rather than checking `CLAUDE.md` alone.
Scan the target for pointers to each file about to be deleted — in `AGENTS.md`, `CLAUDE.md`, `CONTEXT.md`, ADRs, and sibling specs — and fix or remove each one, following the pointer wherever it lands rather than checking the push channel alone.

View File

@@ -23,7 +23,8 @@ This holds even when another skill invoked grill: grill delivers its summary and
Look for a context file, in order: `.agents/CONTEXT.md`, then `.claude/CONTEXT.md`.
The first that exists wins, and its directory owns the ADRs too (`.agents/adr/` or `.claude/adr/`).
If both files exist, stop and ask which is authoritative rather than guessing.
If both files exist and resolve to different real files, stop and ask which is authoritative rather than guessing.
If `.claude/CONTEXT.md` is a compatibility symlink to `.agents/CONTEXT.md`, use `.agents/CONTEXT.md`.
- **Domain Modeling Mode** — a context file was found.
Run the interview and maintain the project's domain model as terms settle (see [Domain Modeling Mode](#domain-modeling-mode)).

View File

@@ -15,7 +15,7 @@ The caller may be the user directly, a subagent, or another skill such as `/cons
The vault lives at `$(xdg-user-dir DOCUMENTS)/notes`.
If that path does not resolve or does not exist, report that the vault is unreachable and stop.
Read `<vault>/.claude/settings.json` and collect every `permissions.deny` entry of the form `Read(<glob>)`.
Read `<vault>/.agents/settings.json` and `<vault>/.claude/settings.json` when they exist, and collect every `permissions.deny` entry of the form `Read(<glob>)`.
The glob inside each is a path relative to the vault root, so normalize it — drop the leading `./` and trailing `/**` — to get the off-limits path, turning `Read(./05 journal/**)` into `05 journal/`.
Those paths are off-limits: never read or search under one, and never let its contents reach an answer.
The harness does not apply these rules when you run from outside the vault, so enforcing them is this skill's job.