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>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-18 21:20:05 +01:00
commit 54beb0bba3
24 files changed
+949

No files matched your search

+92
View File
@@ -0,0 +1,92 @@
# Working on Housecarl
Notes for coding agents (and people) changing this repository. Read this
first, then [docs/design.md](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
```sh
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.