introduces a balanced set of agent + human docs: - root AGENTS.md (with CLAUDE.md symlink) — 5-rule quickstart, layout map, mental model, use-case keyed example pointers. - docs/agents/conventions.md — vault/demagify, eval-loader constraints, group inheritance, naming, do-not-touch list, suspension idioms, working-style notes. - docs/agents/commands.md — repo-specific deltas to the fork's bw runbook (apt-key offline-verify, *.py_ suspended-node visibility, vault-echo rule). - per-area AGENTS.md for bundles/, nodes/, groups/, libs/, hooks/, data/, items/, bin/ — mechanism-focused, no enumeration. - bundles/AGENTS.template.md — per-bundle doc template with optional `## Writes into` section for cross-namespace reactors. bundlewrap-language reference (item types, dep keywords, reactors, runbook, three-tier safety envelope) is not duplicated here; we link out to the fork's AGENTS.md instead. bw test still green. all internal links resolve. Phase 0 invariants preserved (libs/hooks docstrings, bin/* # purpose: headers). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
2.3 KiB
Markdown
62 lines
2.3 KiB
Markdown
# hooks/
|
|
|
|
## What's here
|
|
|
|
Repo-level lifecycle hooks. Each `*.py` exports one or more functions
|
|
named after the lifecycle event they listen to (`apply_start`,
|
|
`node_apply_start`, `node_run_start`, `test`, `test_node`, …). Bw
|
|
discovers them by importing each module from `hooks/`.
|
|
|
|
Discovery is by `ls hooks/` + the one-line docstring at the top of
|
|
each file:
|
|
|
|
```sh
|
|
head -1 hooks/*.py
|
|
```
|
|
|
|
## Conventions
|
|
|
|
- **One-line module docstring.** Every `hooks/*.py` starts with
|
|
`"""<name>: <one-line purpose>."""`. Add one when introducing a new
|
|
hook; baseline is enforced by `grep -L '"""' hooks/*.py`.
|
|
- **Function name = event name.** Bw calls
|
|
`apply_start(repo, target, nodes, interactive=False, **kwargs)`,
|
|
`node_apply_start(repo, node, interactive, **kwargs)`,
|
|
`test(repo, **kwargs)`, etc. Always accept `**kwargs` so future bw
|
|
arguments don't break the hook.
|
|
- **Test gates use `test` / `test_node`.** Anything that should fail
|
|
`bw test` (and therefore CI / pre-apply sanity) goes here; avoid
|
|
doing test-style assertions in `apply_start`.
|
|
|
|
## How to add a hook
|
|
|
|
1. Pick the lifecycle event (see fork's `AGENTS.md` for the full list).
|
|
2. Create `hooks/<name>.py` with the matching function and a
|
|
docstring.
|
|
3. Run `bw test` once to confirm the hook loads cleanly.
|
|
|
|
## Pitfalls
|
|
|
|
- **A hook that errors at import breaks every `bw` invocation** that
|
|
fires the hook's lifecycle — including `bw test` itself, which
|
|
defeats the obvious diagnostic. Test new hooks in isolation first:
|
|
|
|
```sh
|
|
bw debug -c "import sys; sys.path.insert(0, 'hooks'); import <hookmodule>"
|
|
```
|
|
|
|
Iterate there until the import is clean, then commit.
|
|
- **Hooks have access to the full repo (`repo`, `node`, `nodes`).**
|
|
Don't make them block on network unless that's the explicit purpose
|
|
(e.g. `test_ptr_records.py` does `dig` against `9.9.9.9`).
|
|
- **Order is not guaranteed across hook files.** Two hooks that both
|
|
define `apply_start` will both fire; don't assume which runs first.
|
|
|
|
## See also
|
|
|
|
- [`docs/agents/conventions.md`](../docs/agents/conventions.md) —
|
|
files-not-to-touch, vault rules.
|
|
- [`docs/agents/commands.md`](../docs/agents/commands.md) — test
|
|
workflow.
|
|
- Fork's [`AGENTS.md`](https://github.com/CroneKorkN/bundlewrap/blob/main/AGENTS.md)
|
|
— full hook lifecycle and signatures.
|