Dependency notes — rules for AI agents
Pacmon keeps a note for each direct dependency in .pacmon/, beside its manifest. People write under the dependency's heading; AI coding agents write under ### Agent notes.
Pacmon: Set Up AI Instructions copies the rules below into the repository as .pacmon/AGENT-RULES.md, and adds a three-line pointer to the instruction files you pick: AGENTS.md, CLAUDE.md, .cursor/rules/dependency-notes.md, .github/copilot-instructions.md. An agent that reads those files finds the rules there. Pacmon does not call any AI service: agents use their own tools, and Pacmon gives them the files and the rules.
The copy in a repository is the one its agents follow. This page shows the rules of the current release, as Pacmon writes them.
Before you touch a dependency
Its notes are beside the manifest you are changing: npm uses .pacmon/DEPENDENCY-NOTES.md, Rust uses .pacmon/cargo/DEPENDENCY-NOTES.md, Maven uses .pacmon/maven/DEPENDENCY-NOTES.md, Gradle uses .pacmon/gradle/DEPENDENCY-NOTES.md, Mix uses .pacmon/mix/DEPENDENCY-NOTES.md, Gleam uses .pacmon/gleam/DEPENDENCY-NOTES.md, Zig uses .pacmon/zig/DEPENDENCY-NOTES.md, Python uses .pacmon/python/DEPENDENCY-NOTES.md, Go uses .pacmon/go/DEPENDENCY-NOTES.md, and .NET/NuGet uses .pacmon/nuget/DEPENDENCY-NOTES.md. In a monorepo, use the nearest file for the same ecosystem, walking up. Read two things first: the free text between # Dependency Notes and the first section (this repository's own rules), then the dependency's ## <name> section.
- Adding a package: open its section in the same commit, with at least
purpose:. Say what you considered and why this one, inalternatives:orlog:. - Upgrading: read its
constraint:andverify:lines, then run whatverify:says. Log the attempt with its outcome even if you reverted it — the next agent must not repeat it. - Removing: keep the section and add
- status: removed <YYYY-MM> — <reason>. Do not delete it. - Trivial packages (
@types/*, tiny helpers):purpose:and, if it applies,bump-with:are enough.
Where you write
## <the dependency's note key>
Text written by people. Do not touch it.
### Agent notes
- key: value
- key: value
- The heading is the dependency's note key, spelled as its manifest spells it:
package.json: the package name with its@scope/—## @types/node- .NET project files and
Directory.Packages.props: the case-insensitive NuGet package ID as written —## Newtonsoft.Json Cargo.toml: the key in the dependency table; for a renamed dependency, the key, not itspackage—## serdepom.xml:groupId:artifactId—## org.slf4j:slf4j-apibuild.gradle(.kts):group:namewithout the version, or the catalog alias as written —## org.slf4j:slf4j-api,## libs.junit.jupitermix.exs: the dependency tuple's first application atom —## phoenix,## ecto_sqlgleam.toml: the key in[dependencies]or[dev_dependencies]—## gleam_stdlib,## gleeunitbuild.zig.zon: the direct field name in the top-level.dependenciesstruct —## known_folderspyproject.tomlor a requirements file: the normalized distribution name, lower-case with.,_, and-treated alike —## requests,## importlib-metadatago.mod: the module path inrequire, including any major-version suffix; atoolbelongs to the module that contains it —## github.com/spf13/cobra,## github.com/jackc/pgx/v5
- The text right under the heading is written by people. Never edit or delete it. Treat it as one of your sources — alongside the code, the git history, the registry and your own reasoning. If your block disagrees with it, the human text wins: fix your block and add a
log:line saying so. ### Agent notesis yours. Lower-case keys, one fact per line, keys may repeat (severalconstraint:orlog:lines are normal). Keys outside the vocabulary below are flagged by Pacmon; if something fits none of them, write it asnote:— never invent a key.- One
## namesection per direct dependency, in alphabetical order.##is reserved for dependencies; inside a section the only heading is### Agent notes. - Never write an empty field or a dash placeholder. If you have nothing true to say, leave the field out.
- Write judgments, not measurements.
- Revise, do not accumulate: correct a line instead of adding a contradicting one.
log:is the exception — it is the history. - Field keys are English. Write the values in the language given by
lang:in the file's frontmatter. - Never remove the frontmatter or the header comment at the top of the file. If you are asked to draft the first human line, keep it short: it shows next to the dependency in its manifest.
Fields
Fill these whenever you can:
| Field | Question it answers | One line of |
|---|---|---|
purpose: |
What job does it do here? | the package's role in this project — what it is and why this repo uses it, one sentence |
usage: |
Where and how is it wired in? | entry points, wrapper module, config; the rule for using it ("always through lib/http.ts") |
constraint: |
What must not change? | a pin, a forbidden upgrade, a coordination requirement — the rule and its reason |
verify: |
How do I check I did not break it? | a command or a flow: vitest src/api, "run the login e2e" |
log: |
What happened, what was decided? | one dated event per line — added (by whom, version, PR), an upgrade attempt, a rejected proposal and why; carry a commit hash, PR or advisory id |
verified: |
Which installed version were these notes checked against? | the resolved version (from the lockfile, where there is one) when you last confirmed the block is still true |
Add these only when they are true and non-obvious:
| Field | Question it answers | One line of |
|---|---|---|
risk: |
What does it cost or endanger? | a judgment — security exposure, native binary, licence obligation, maintenance state — not raw numbers |
runtime: |
Where does it execute? | one of: server, client, build, dev, deploy |
exposure: |
Does it handle untrusted input? | one of: untrusted-input, internal |
bump-with: |
What must move with it? | packages that have to be upgraded together (peer pairs, plugin sets) |
remove-when: |
When should it go? | the exit condition |
alternatives: |
What could replace it? | only real decisions, dated, with a verdict: "fastify (rejected 2023-01: middleware ecosystem)" |
owner: |
Who to ask? | a team, a person, a channel |
status: |
Is it still here? | dead, removal-planned, or removed <YYYY-MM> — <reason>; absent means active |
links: |
Sources? | changelog, docs, upstream issue, registry page — the specific ones, not the obvious |
note: |
Anything else the next agent must know? | free text that fits no other field — one thought per line, never a measurement |
A section whose status: starts with removed is kept on purpose for a package that left its manifest; Pacmon does not flag it as an orphan.
Example
## express
Do not upgrade to v5 — the auth middleware is incompatible (SEC-1301).
Rate-limit settings live in `src/middleware/limits.ts`.
### Agent notes
- purpose: HTTP framework; serves the public REST API and the webhook receiver
- constraint: stay on ^4 — v5 changes router path matching (path-to-regexp v8) and the session API
- verify: `vitest src/api` and the login e2e (`pnpm e2e:auth`)
- log: 2026-03 agent tried 5.0.1, 14 auth tests failed, reverted (PR #402)
- verified: 4.18.2