---
name: field-notes
description: Capture hard-won operational knowledge the moment a failure turns into a success, and push it down into config, hooks, or rules so it stops needing to be remembered. Use this whenever a command, build, tool invocation, or API call fails and a later attempt succeeds; whenever you discover an undocumented precondition, required version, required flag, or environment quirk; whenever you catch yourself re-deriving something a previous session must already have worked out; and whenever the user says "write that down", "remember this", "note that for next time", "capture what you learned", or asks to review or promote existing field notes. Trigger this even when the discovery feels small, because small undocumented preconditions are exactly what gets re-derived every session.
---

# Field Notes

Agents burn enormous time rediscovering the same operational facts: the flag that makes the build work, the CLI that has to be used instead of the API, the version that has to be set first. Recording these as memory mostly does not help, because memory is declarative and failures happen at an action. A note saying "this project uses Java 21" does not intercept `mvn`.

This skill exists to do two things: capture confirmed learnings at the moment they are confirmed, and then push each one as far as possible down the enforcement ladder so it stops depending on anyone remembering it.

## The enforcement ladder

Ranked by how reliably the knowledge actually changes behaviour:

1. **A note in a file.** Only works if something loads it at the right moment.
2. **A CLAUDE.md rule.** Always in context, but competes with everything else and gets dropped under load.
3. **A skill.** Loads on phrasing match. Still probabilistic.
4. **Config, a hook, or a check.** Cannot be missed.

Levels 1 to 3 are probabilistic. Level 4 is not. The goal of every capture is to land as low on this list as the knowledge allows. Writing a good note is the fallback, not the objective.

## When to capture

Capture on a **failure to success transition**: something was attempted, it failed or produced the wrong result, a different approach then worked.

The success is what makes this trustworthy. Do not capture a theory at the moment it feels right, because mid-investigation conclusions are frequently the second-to-last theory and get invalidated twenty minutes later. Wait for the thing that actually worked.

Also capture when the user explicitly asks.

The signature to watch for:

- A command exits non-zero, then a modified command succeeds
- An API or tool returns an error that turns out to require a different route entirely
- Something silently produces the wrong output until a precondition is set
- You spend more than a few tool calls establishing something that is written nowhere in the repo

## Step 1: Journal it

Append to `.agent/journal.md`, which is gitignored. This is scratch. No filter, no format, no ceremony, no review cost, and no merge conflicts.

Write the raw pair: what was tried, what it did, what worked instead. One or two lines. Do not stop what you are doing to write prose.

The journal exists because capture has to be cheap enough to happen mid-task, while anything committed has to be filtered. Separating them is what keeps both properties.

## Step 2: Classify

Run this on journal entries when flushing, or immediately if the fix is obvious. Work down the list and stop at the first match.

**Can it be enforced by config or a hook?**

If yes, propose that change instead of writing a note. Prefer mechanisms that hold regardless of which agent or human is driving: a version file, a Makefile target, a git hook, a CI check. Agent-specific hooks are a weaker fallback, because they only fire for the agent that supports them. Use whatever the ecosystem already provides rather than building anything:

| Knowledge | Where it belongs |
|---|---|
| Required language or runtime version | `.tool-versions`, `.sdkmanrc`, `.mise.toml`, `.nvmrc` |
| Required build flags or env vars | Makefile target, wrapper script, `.envrc` |
| Required formatting or lint state | pre-commit hook, CI job |
| A step that must run before another | git pre-commit hook, Makefile dependency, CI job |
| A required file or template shape | issue or PR template, scaffold |

A version requirement recorded as a note is a bug. It has a home in the toolchain and belongs there.

**Is it a precondition on a specific action?**

If yes, write a note keyed to the command, not to the topic. The lookup key must be the thing an agent is about to type.

- Wrong: "The issue tracker needs labels."
- Right: "Before `glab issue create`: run `glab label list` first, the project rejects labels outside its own set."

**Is it a bare fact?**

Facts are the lowest value output here and usually belong in project documentation rather than field notes. Prefer writing them into the README or the relevant doc.

## Step 3: Write the note

One file per note in `docs/agent-notes/`. Never append to a shared file: concurrent branches appending to one file conflict with each other constantly. Individual files follow the same convention as ADRs and stay reviewable in a diff.

Filename: the command or area, then a short slug. `glab-issue-create-labels.md`.

Use this structure:

```markdown
---
trigger: glab issue create, glab issue update
depends_on: .gitlab-ci.yml, project label configuration
recorded: 2026-08-12
---

# Check the project's label set before creating issues

**Symptom:** `glab issue create --label bug` is rejected, or the issue is
created with the label silently dropped.

**Fix:** Run `glab label list` first and use only labels that already exist.
The project does not create labels on demand.

**Why it was not obvious:** The API accepts the request and fails downstream,
so the error does not point at the label.
```

`trigger` is what makes this findable: an agent about to run a command can grep for it. `depends_on` is what makes rot detectable: if those files changed since `recorded`, the note needs re-checking.

## What not to record

- **Snapshots of mutable state.** Record the command that discovers the current labels, never the labels themselves. A note listing today's values is actively misleading in a fortnight.
- **Anything already written in the repo.** Point at it instead.
- **Anything re-derivable in one grep.** The cost of reading the note exceeds the cost of finding out.
- **Narrative about the session.** Nobody reads "I then investigated the build system."
- **Anything you have not actually confirmed working.**

## Flush and review

When the user asks to write up the session, read `.agent/journal.md` and:

1. Discard entries that were invalidated later in the session. This is the main reason the journal is not committed directly.
2. Classify each survivor using Step 2.
3. For anything that belongs in config or a hook, propose the concrete change and show the diff. Do not write it as a note as well.
4. Write the remainder as individual note files.
5. Check `docs/agent-notes/` for existing notes on the same trigger and update them rather than adding a near-duplicate.
6. Clear the journal.

## Promotion

When the user asks to review or promote field notes, read everything in `docs/agent-notes/` and look for:

- **Notes that recur across triggers.** If several notes describe the same underlying constraint, that constraint is a candidate for a CLAUDE.md rule or its own skill.
- **Notes that could now be enforced.** Something that was unenforceable when written may have a hook or config option now. Re-run Step 2 on every note.
- **Stale notes.** If `depends_on` files have changed since `recorded`, verify the note still holds or delete it. A confidently wrong note is worse than no note.

Promotion is a human-reviewed step, run on request. Do not attempt to promote automatically based on how often a note has been used, because that count cannot be tracked reliably.

## The read path

This skill only covers writing. A skill cannot trigger itself at the start of an unrelated task, so notes will not be read unless something else pulls them in.

Add this line to the project's always-on instruction file:

```markdown
Before running an unfamiliar build, deployment, or CLI command in this repo,
grep `docs/agent-notes/` for the command name. Those notes record preconditions
that are not documented anywhere else.
```

It needs to go in every instruction file the repo uses, because no single file is read by every agent:

- **Claude Code**: `CLAUDE.md`
- **GitHub Copilot**: `.github/copilot-instructions.md`
- **Most other agents**: `AGENTS.md`

Copilot reads `AGENTS.md`; Claude Code does not, and reads `CLAUDE.md` only. If you keep an `AGENTS.md`, symlink it (`ln -s AGENTS.md CLAUDE.md`) or import it from the first line of `CLAUDE.md` rather than maintaining two copies that drift.

Without that line, this is a write-only system.

## Installing this skill

Both Claude Code and Copilot read repository skills from `.claude/skills/`, so one location serves both:

```
.claude/skills/field-notes/SKILL.md
```

Copilot also accepts `.github/skills/` and `.agents/skills/`. Pick one and commit it, so the whole team gets the skill without any per-developer setup.

The frontmatter here uses only `name` and `description`, which is the portable subset of the Agent Skills specification. Claude Code supports extra frontmatter fields; other agents ignore them, so avoid them if this skill needs to behave identically in both.