bundlewrap/AGENTS.md
CroneKorkN 852a65a6f6
AGENTS.md: 6th rule — try ccc search before grep for concept queries
The repo is indexed with cocoindex-code; semantic search beats grep for
"where is X / which bundle does Y" questions where you don't know the
exact identifier. Without `--path '**'` ccc scopes to the current
working directory, which is rarely what you want when navigating
ckn-bw — call it out so agents don't get confusing empty results.
2026-05-10 21:32:08 +02:00

6.5 KiB

ckn-bw — agent & contributor guide

What this repo is

A BundleWrap configuration-management repo for ~22 personal/family-infra nodes. Nodes, groups, and bundles are defined in plain Python; bw apply deploys the resulting state to real machines.

Note: the root README.md is the maintainer's personal scratchpad, not project documentation. Onboarding lives here, in AGENTS.md.

Quickstart for agents

Six rules; follow these and you won't break things:

  1. Read-only by default. Never run bw apply, bw run, or bw lock without explicit user request — even with -i. Stick to bw test, bw nodes, bw groups, bw items, bw metadata, bw hash, bw verify, bw debug. See docs/agents/commands.md and the fork's safety envelope.
  2. Never echo decrypted secrets. Don't print, paste, or log the value behind a !password_for:, !decrypt:, or !32_random_bytes_as_base64_for: magic string — not even from bw debug exploration. See conventions.md#secrets.
  3. Don't touch the do-not-modify list. .secrets.cfg*, .venv, .cache, .bw_debug_history, .envrc, root README.md. Treat hooks/ and items/ (custom item types) with extra care: a broken hook or item type breaks every bw command repo-wide.
  4. Use the fork. The venv runs editable from github.com/CroneKorkN/bundlewrap (branch main). Behavior tracks upstream main; the fork's AGENTS.md is the canonical bundlewrap-language reference. See conventions.md#bundlewrap-version.
  5. Prefer adding helpers to libs/ over duplicating logic across bundles. Repo-wide helpers go in libs/, reachable as repo.libs.<x>.
  6. Search semantically. This repo is indexed with ccc — try ccc search '<concept>' --path '**' before grep for "where is X / which bundle does Y" questions. Without --path '**', results are filtered to the current working directory's subtree.

Layout

Dir What's there
bundles/ 103 bundles. One subdir per bundle (items.py, metadata.py, files/).
nodes/ One file per node (~22). eval()-loaded; demagified through repo.vault.
groups/ Group definitions, organized by axis (applications/, locations/, machine/, os/).
libs/ Shared Python helpers reachable as repo.libs.<modulename>.
hooks/ bw lifecycle hooks (apply_start, test, node_apply_start, …).
data/ Out-of-bundle data assets (apt keys, grafana dashboards, …).
items/ Custom item types (currently download:).
bin/ Operator scripts; not invoked by bundlewrap.
docs/agents/ Repo conventions and command deltas.

How nodes, groups, and bundles fit together

  • A node (nodes/<location>.<role>.py) declares the groups it belongs to and any node-local bundles + metadata overrides.
  • A group (groups/<axis>/<x>.py) attaches bundles and shared metadata to its members. Groups inherit via supergroups.
  • A bundle (bundles/<x>/) is one chunk of configuration: items.py produces the items (files, services, packages), metadata.py declares defaults and @metadata_reactor functions that derive metadata from other metadata.
  • The repo-root loaders (nodes.py, groups.py) walk these dirs and eval() each file. nodes.py additionally demagifies the result, resolving !password_for: etc. through repo.vault. See conventions.md#eval-loaded-node-and-group-files for the constraints this places on editors.
  • Metadata merges along: all → location → os → machine → applications → node.

Conventions you must know

Topic Where
Bundlewrap-language reference (item types, dep keywords, reactors) Fork's AGENTS.md — read first if new to bundlewrap
Vault / demagify magic strings conventions.md#secrets
Bundlewrap install (editable from the fork) conventions.md#bundlewrap-version
Group inheritance order, naming patterns conventions.md#group-inheritance-order, #naming-conventions
Repo-specific bw command deltas (apt keys, suspended nodes, vault echo) commands.md
Lib helpers top-of-file docstrings in libs/*.py (head -1 libs/*.py)
Suspension idioms (*.py_, _old/, "for now") conventions.md#suspension-and-soft-delete-idioms

Where to look for examples

When writing a new bundle, copy patterns from one that already does the thing you need:

Pattern Look at
Vault calls inside metadata reactors bundles/dm-crypt/metadata.py (compact, focused)
Mako-templated files bundles/bind/items.py (DNS zonefile rendering)
Cross-bundle reactor writing bundles/nextcloud/metadata.py (writes into apt.packages, archive.paths)
Custom download: items bundles/minecraft/items.py
Node file (single-purpose) nodes/home.server.py
Group with supergroups chain groups/os/debian-13.py

Where this doc lives

  • This file: AGENTS.md at the repo root.
  • CLAUDE.md is a symlink to this file — both names point to the same content so different tools can find it.
  • The personal TODO scratchpad (README.md) is separate and not project documentation.