drops the per-bundle AGENTS.md convention and the rigid template that went with it. each bundle has (or gets) one README.md that serves humans and agents both. bundles/AGENTS.md now has a "Per-bundle README" section pointing at the more substantial existing READMEs (flask, dm-crypt, apt, nextcloud) for orientation, plus loose guidance on what to cover and what to skip. no required structure — match the bundle's actual surface. removes bundles/AGENTS.template.md; the template was prescriptive in a way that wouldn't survive contact with this repo's actual bundles, where READMEs range from one-paragraph balanced docs to operational scratchpads. phase-2 seed-bundle work stays deferred and will land as plain README updates when bundles are materially edited. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.3 KiB
bundles/
Before you start
Read docs/agents/conventions.md first
— it covers vault calls, demagify, the repo.libs.<x> helpers, and the
files agents must not modify. Skipping it leads to subtly broken bundles
(vault calls in the wrong place, dict-in-set TypeError because of
unhashable nesting, etc.).
For bundlewrap-language reference (item types, dep keywords,
metadata_reactor, defaults, item-file template syntax) see the fork's
AGENTS.md
and its docs/content/guide/item_file_templates.md.
What's here
103 bundles. Each is a directory bundles/<name>/ containing some of:
bundles/<name>/
├── items.py # the items this bundle creates (files, services, packages, …)
├── metadata.py # `defaults` + `@metadata_reactor` functions
├── files/ # static or templated file payloads referenced from items.py
└── README.md # one doc per bundle, for humans and agents (see "Per-bundle README" below)
Conventions
- Bundle names are lowercase, hyphen-separated:
backup-server,bind-acme,dm-crypt. No underscores in new bundle names — seeconventions.md#naming-conventions. items.pyis plain Python; it producesfiles = {...},pkg_apt = {...},svc_systemd = {...}, etc. dicts at module scope. Cross-item dependencies useneeds/triggers/triggered_by— see the fork'sAGENTS.mdfor the full keyword cheat sheet.metadata.pyusesdefaults = {...}for static seed values and@metadata_reactor.provides(...)for derived values. Reactors are pure functions of(metadata,)— no side effects, no I/O.- Helpers go in
libs/when they're useful to more than one bundle. Don't duplicate logic across bundles. - Custom item types (e.g.
download:) live initems/, not per-bundle.
How to add a new bundle
mkdir bundles/<name>/(lowercase, hyphenated).- Write
items.pyand (if anything is configurable)metadata.py. Userepo.libs.hashable.hashable(...)when you need to nest a dict or set inside a metadata set; raw dicts/sets aren't hashable. - Drop static payloads into
bundles/<name>/files/. For Mako-templated files, declare'content_type': 'mako'on thefile:item — see the fork's item-file-templates guide. - Wire to nodes. Either add an entry to the relevant
groups/<axis>/<x>.py(preferred for shared bundles) or to the node'sbundleslist directly (nodes/AGENTS.md). - Verify, in this order:
bw test— sanity (loaders + reactors).bw items <node>— confirm new items appear on a node that opts in.bw hash <node>— confirm the change is what you expected. Seedocs/agents/commands.mdand the fork's hash-diff workflow.
- Add a
bundles/<name>/README.md. See "Per-bundle README" below for what to cover.
How to remove a bundle
git grep '<name>'innodes/,groups/, and otherbundles/to find references.- Remove those references.
rm -rf bundles/<name>/.bw testandbw nodesto confirm clean.
Pitfalls
metadata.pyis evaluated at load time for every node, every invocation ofbw. Heavy work or I/O slows the whole repo. Keep reactors pure and fast; pre-compute inlibs/if you must.- Static files vs templates.
bundles/<x>/files/<f>is static unless the matchingfile:item declarescontent_type='mako'(or a templating extension triggers it). To check, read the matchingfile:entry initems.py. - Reactors writing across namespaces. Some bundles' reactors write
into other bundles' metadata namespaces (e.g.
nextcloudwrites intoapt.packages,archive.paths). When you change such a bundle, every consumer's metadata changes too. The bundle'sREADME.mdoften calls these out — but the authoritative source ismetadata.pyitself; grep'<other-bundle>':in the reactors when in doubt. bw hashdoesn't accept selectors. Usebw hash <node>per literal name; see the fork's runbook.
Per-bundle README
Each bundle has (or should have) a README.md. One doc per bundle,
written for humans and agents both. There's no fixed structure —
match the bundle's actual surface, write what helps a future reader
(or future you) avoid trial-and-error.
The existing READMEs vary in quality and shape. For orientation, look at the bigger ones, not the two-line ones:
bundles/flask/README.md— title + one-sentence purpose, a metadata example as a Python dict, then the contract the consuming git repo has to satisfy + a logging pitfall. The closest thing to a "balanced doc" in tree.bundles/dm-crypt/README.md— same shape, shorter: purpose + metadata example + one sentence on effect.bundles/apt/README.md— relevant upstream URLs at the top, then a Python metadata example with rich inline comments (type / optionality / where keys come from).bundles/nextcloud/README.md— operational scratchpad: iPhone-import recipe, preview-generator commands, reset queries. Captures muscle-memory the maintainer would otherwise re-learn each time.
Useful things to include, when relevant:
- A sentence or two on what the bundle does and when you'd attach it.
- A metadata example as a Python dict literal, with
#comments on each key (type, required vs default, units, where it comes from). This is the cleanest way to communicate the schema and matches howmetadata.pyactually looks. - Anything non-obvious about wiring it up — required keys without defaults, group-membership expectations, manual one-time steps.
- Cross-namespace metadata writes, when this bundle's reactors populate another bundle's namespace. Easy to miss, cheap to flag.
- Gotchas, debug recipes, failure modes you've actually hit.
What to skip:
- An exhaustive item list —
items.pyis shorter and more accurate. - Anything that would just rot — version numbers, "TODO" lists, change notes. Use git history.
If a single paragraph is enough to say what's worth saying, write a single paragraph. Verbosity isn't a goal.
Convention going forward is leave-as-you-go: any time you materially edit a bundle, top up its README (or write one if it's missing). Don't burn a session bulk-reformatting the existing ones — uneven quality is part of what we accept in exchange for not blocking other work.
See also
docs/agents/conventions.md— repo idioms (vault, demagify, naming, do-not-touch list).docs/agents/commands.md— repo-specific command deltas.items/AGENTS.md— custom item types (download:); when to write a new one vs usefile:.libs/AGENTS.md— shared helpers.- Fork's
AGENTS.md— bundlewrap-language reference + safety envelope.