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>
146 lines
5.9 KiB
Markdown
146 lines
5.9 KiB
Markdown
# Conventions
|
|
|
|
Repo-specific idioms an agent has to know before editing this BundleWrap
|
|
config. For bundlewrap-the-language reference (item types, dep keywords,
|
|
metadata-reactor semantics, after-change runbook), see the fork's
|
|
[`AGENTS.md`](https://github.com/CroneKorkN/bundlewrap/blob/main/AGENTS.md).
|
|
|
|
## Secrets
|
|
|
|
Secrets live in `.secrets.cfg` and are referenced from node files by
|
|
"demagify" magic strings. The loader (`nodes.py`) walks node dicts and
|
|
resolves any leaf string of the form `!<verb>:<arg>`.
|
|
|
|
| Magic string | Resolves to |
|
|
|---|---|
|
|
| `!password_for:<id>` | `repo.vault.password_for(id)` |
|
|
| `!decrypt:<ciphertext>` | `repo.vault.decrypt(ciphertext)` |
|
|
| `!decrypt_file:<path>` | `repo.vault.decrypt_file(path)` |
|
|
| `!32_random_bytes_as_base64_for:<id>` | `repo.vault.random_bytes_as_base64_for(id, length=32)` |
|
|
|
|
Magic strings are only resolved inside **node files** (everything under
|
|
`nodes/`). They are *not* resolved in group files, bundle metadata
|
|
defaults, or item attributes — call `repo.vault.<verb>(...)` directly
|
|
there.
|
|
|
|
**Never echo decrypted values.** Don't print, log, or paste them, even
|
|
in `bw debug` exploration. If you need a sanity check, hash or
|
|
fingerprint instead. This applies to AI agents and humans equally.
|
|
|
|
## Bundlewrap version
|
|
|
|
The venv runs **editable** from the maintainer's fork:
|
|
|
|
```
|
|
-e git+https://github.com/CroneKorkN/bundlewrap.git@main#egg=bundlewrap
|
|
```
|
|
|
|
Pinned in `requirements.txt`. The fork's `main` tracks upstream
|
|
`bundlewrap/bundlewrap` master; the fork's [`AGENTS.md`](https://github.com/CroneKorkN/bundlewrap/blob/main/AGENTS.md)
|
|
is the canonical agent-oriented bundlewrap-language reference.
|
|
|
|
To pull upstream changes into the venv:
|
|
|
|
```sh
|
|
(cd .venv/src/bundlewrap && git pull)
|
|
```
|
|
|
|
## Eval-loaded node and group files
|
|
|
|
`nodes/*.py` and `groups/*.py` are loaded by `eval()` in `nodes.py` /
|
|
`groups.py` (top of the repo). Each file must be a single Python
|
|
expression — typically a dict literal.
|
|
|
|
Consequences:
|
|
|
|
- **No top-level imports.** No `from foo import bar`, no `import os`.
|
|
Helpers go in `libs/` and are reached via `repo.libs.<x>` from
|
|
bundle code, not from node files.
|
|
- **No statements.** No `if`/`for`/`def` at the top level. Use
|
|
expressions (ternaries, comprehensions) instead.
|
|
- **Silent drop on parse error.** Vanilla bundlewrap silently omits a
|
|
node/group whose file fails to eval. The maintainer patched
|
|
`groups.py` (commit `dc40295`) to print the error instead — but it
|
|
still skips the file. Symptom: `bw nodes` lists fewer nodes than you
|
|
expect. Cure: re-read the file and check for accidental imports or
|
|
syntax errors.
|
|
|
|
## Group inheritance order
|
|
|
|
Metadata merges along this chain (from the fork's docs):
|
|
|
|
```
|
|
all → location → os → machine → applications → node
|
|
```
|
|
|
|
`groups/all.py` is the universal base; `groups/{locations,os,machine,applications}/`
|
|
hold the per-axis groups; the node's own metadata wins last.
|
|
|
|
## Naming conventions
|
|
|
|
| Where | Convention | Example |
|
|
|---|---|---|
|
|
| `nodes/*.py` | `<location>.<role>.py` | `home.server.py`, `htz.mails.py` |
|
|
| `groups/*.py` | one file per group; subdir = purpose | `groups/applications/nextcloud.py`, `groups/os/debian-13.py` |
|
|
| `bundles/<name>` | lowercase, hyphen-separated | `backup-server`, `bind-acme`, `routeros-monitoring` |
|
|
| Custom items | `items/<type>.py` | `items/download.py` |
|
|
|
|
Underscores in bundle names appear only in `_old`-suffixed leftovers
|
|
(see below); don't introduce new ones.
|
|
|
|
## Suspension and soft-delete idioms
|
|
|
|
These conventions look like dead code; they aren't. Don't clean them up.
|
|
|
|
- **`*.py_` parked node.** A node file whose name ends in `.py_` is
|
|
silently excluded from `bw nodes` (the loader only matches `*.py`).
|
|
Used to keep decommissioned-but-not-deleted node configs in tree.
|
|
Example: `nodes/htz.l4d2.py_`.
|
|
- **"for now / disable / dummy / offline" markers.** Commits or comments
|
|
containing these phrases mark deliberate suspensions, not bugs. Check
|
|
`git log -- <file>` before re-enabling — the maintainer reverses
|
|
these manually when the underlying condition resolves.
|
|
- **`_old` / `_old2` directories.** Recovery buffers during big
|
|
refactors. Don't delete them without asking, even if they look
|
|
orphaned.
|
|
|
|
## Files agents must not modify
|
|
|
|
| Path | Why |
|
|
|---|---|
|
|
| `.secrets.cfg*` | vault key material |
|
|
| `.venv/` | local Python environment |
|
|
| `.cache/` | bw runtime cache |
|
|
| `.bw_debug_history` | shell history for `bw debug` |
|
|
| `.envrc` | direnv local-environment config |
|
|
| `/.cocoindex_code/` | local code index, not in git |
|
|
| `README.md` (root) | maintainer's personal TODO scratchpad — not project docs |
|
|
|
|
Treat `hooks/` and `items/` (custom item types) with extra care: they
|
|
affect `bw`'s behavior for the whole repo, not a single bundle.
|
|
|
|
## Working style
|
|
|
|
- **Iterative commits are normal.** The maintainer commits in small
|
|
checkpoints (`+`, `fix`, `whitespace`, terse one-liners). Don't
|
|
rebase WIP branches without asking. As an agent, prefer
|
|
complete-feeling commits over mimicking the iterative style.
|
|
- **Burst-state awareness.** Before writing into a subsystem, run
|
|
`git log --since='1 month ago' bundles/<x>` (or `nodes/<x>.py`).
|
|
≥10 recent commits means the subsystem is in flux; read the most
|
|
recent diffs first — your assumptions about its metadata shape may
|
|
already be stale.
|
|
- **Branch names.** PRs go through self-hosted Gitea/Forgejo. Branch
|
|
names are lowercase snake_case, descriptive
|
|
(`debian-13`, `htz.mails_debian_13_squash`, `l4d2_the_next`).
|
|
|
|
## Bundlewrap-version migration recipe
|
|
|
|
When the next bw major lands:
|
|
|
|
1. Read the upstream migration guide.
|
|
2. `git grep` for affected reactor / item patterns.
|
|
3. Rewrite each (one commit per pattern is fine — see Working style).
|
|
4. Bump `requirements.txt` last.
|
|
|
|
Pattern from commit `186d503` (bw 4 → 5).
|