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>
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 withnft -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 housecarland 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.mdunder## [Unreleased], and the matchingdocs/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 testrunsgo vetand agofmt -lcheck.goimportsisn't installed, so fix imports by hand.
The logo and wordmark
- The masters are
artwork/logo.svg(the carved doorway) andartwork/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, andassets/logo.svg, the favicon, from the small one) and runsscripts/banner.py, which rebuildsartwork/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.pyreads them from there.
Testing
make test # vet + gofmt check + unit tests
Web UI rules
As in Jarl and Steward:
- Build DOM only with
h()fromui.js, neverinnerHTML. - The CSP is
selfonly: no inline styles or scripts. Use a class, or setel.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 isvXwith message "Housecarl X".
Shell hygiene
- Never kill processes by pattern (
pkill -f). The pattern matches the shell running it. Find the PID withpsand 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.