Files
housecarl/AGENTS.md
T
abrown38andClaude Opus 5.5 54beb0bba3 Start Housecarl: the logo, the wordmark and the skeleton
Housecarl will be a firewall manager for nftables, built the way Jarl and
Steward are: housecarld (a daemon with a REST API and web UI), hc (the
CLI) and SQLite.

- The logo: a carved Nordic doorway in Jarl's blue (artwork/logo.svg),
  with a small version without the carvings, lighter on dark
  backgrounds. scripts/logo.py builds the web UI's copies and
  scripts/banner.py the README banner.
- The HOUSECARL wordmark in Jarl's and Steward's angular letters, with
  new H, O, U and C (assets/brand.js), and the UI's color tokens.
- housecarld and hc print their version; the Makefile, version package,
  AGENTS.md, CHANGELOG and the design sketch (docs/design.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:20:05 +01:00

3.9 KiB

Working on Housecarl

Notes for coding agents (and people) changing this repository. Read this first, then docs/design.md, the plan and its open questions.

Housecarl is a firewall manager for Linux: housecarld keeps the machine's nftables ruleset and serves a REST API and a web UI; hc is the CLI; SQLite holds everything. It is the third of a set with Jarl (the BIND manager, ../jarl) and Steward (the DHCP server, ../steward) and copies their ways: the same auth, socket and web UI helpers, the same release process, the same look. When in doubt, do it the way Jarl and Steward do. Go module housecarl, CGO_ENABLED=0, Linux only for housecarld.

Housecarl is at its start: only the version commands, the build and the brand exist. Most rules below are for what is coming.

Ground rules

  • The database is the source of truth. The ruleset is rendered from it; never read nftables' state back as configuration (an importer would be the only exception).
  • Every change goes through one engine: edit a copy of the configuration, validate the whole result, render, check with nft -c -f, apply with nft -f, and save the objects, the history entry and the audit record together. Never write to the store from a handler.
  • Housecarl's own table only. Write inet housecarl and nothing else; never flush the whole ruleset (Docker, libvirt and others keep theirs).
  • Don't lock the user out. Changes to the rules for the machine itself are applied on probation and rolled back unless confirmed (docs/design.md).
  • Every user-visible change updates CHANGELOG.md under ## [Unreleased], and the matching docs/ page in the same change.
  • Errors say what is wrong and how to fix it, naming the object.
  • Schema changes append a migration; never edit a shipped one.
  • make test runs go vet and a gofmt -l check. goimports isn't installed, so fix imports by hand.

The logo and wordmark

  • The masters are artwork/logo.svg (the carved doorway) and artwork/logo-small.svg (without its carvings, for under about 64 px). Each is one evenodd path in a shared viewBox; their color comes from CSS (--logo, lighter in the dark theme).
  • make logo (scripts/logo.py) copies them into the web UI (assets/logo.js, and assets/logo.svg, the favicon, from the small one) and runs scripts/banner.py, which rebuilds artwork/banner.svg. Never edit those outputs by hand.
  • The wordmark's letters are paths in assets/brand.js, in the angular style of Jarl's and Steward's (A, R and L are Jarl's, S and E Steward's). banner.py reads them from there.

Testing

make test      # vet + gofmt check + unit tests

Web UI rules

As in Jarl and Steward:

  • Build DOM only with h() from ui.js, never innerHTML.
  • The CSP is self only: no inline styles or scripts. Use a class, or set el.style.prop.
  • Colors are the CSS custom properties in style.css, with light and dark values; reuse them.
  • Rebuild housecarld after editing, since the files are embedded.
  • Function over polish. Leave pick-list checkboxes unticked by default.

Git and releases

The maintainer's rules:

  • Commit only when asked. Never push. The maintainer pushes, to Gitea at gitea.adbraun.lol.
  • Branches are dev-X.Y.Z, never named like a tag.
  • A release is a commit "Release X": it sets VERSION, updates the README status line, and (for a final release) moves [Unreleased] to ## [X] - YYYY-MM-DD. The annotated tag is vX with message "Housecarl X".

Shell hygiene

  • Never kill processes by pattern (pkill -f). The pattern matches the shell running it. Find the PID with ps and kill that.
  • Run long-lived test servers in the background mode of your tool, not with & in a shell that exits.
  • Never apply a test ruleset to this machine's own nftables. Test in a network namespace or a container.