summaryrefslogtreecommitdiff
path: root/AGENTS.md
diff options
context:
space:
mode:
authorbatsumaru <>2026-07-01 18:42:01 +0900
committerbatsumaru <>2026-07-01 18:42:01 +0900
commitd35a7d3b24fa71e13e48fd85e299c12a93e6aab8 (patch)
tree66a824a2c864032f2a1174f6a48239fe6a4e187c /AGENTS.md
parent958dfa35fd030e5b609298b1236692c85b6ffafc (diff)
Add AGENTS.md for cross-session agent context
Covers what a fresh session needs that statuspage/README.md doesn't: the Windows-checkout-vs-FreeBSD-runtime split (nothing here actually executes the check scripts' real commands), the git push/pull deployment loop, the core.fileMode/pre-commit-hook setup, and five gotchas hit and fixed this session (usec/sec substring match, ntpq's "+" prefix, grep -c's exit-1-on-zero, Windows ln -s on directories falling back to a copy, font glyph coverage). CLAUDE.md is a pointer to AGENTS.md rather than a symlink or a duplicate copy - this checkout can't reliably create real symlinks (same root cause noted in AGENTS.md itself), and a stale copy would silently drift out of sync as AGENTS.md changes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Diffstat (limited to 'AGENTS.md')
-rw-r--r--AGENTS.md82
1 files changed, 82 insertions, 0 deletions
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..d88d7ed
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,82 @@
+# AGENTS.md
+
+Guidance for AI coding agents working in this repository.
+
+## What this repo is
+
+`statuspage/` generates a static status console for a FreeBSD homelab
+server (`dandokmang.com`). Modular POSIX `/bin/sh` check scripts each emit
+JSONL rows; an orchestrator (`render.sh`) runs them all, groups the rows by
+section, and writes a static `index.html` (dark/monospace, stoplight-grid
+style) that Caddy serves over WireGuard.
+
+**Start with `statuspage/README.md`** for the full JSONL contract between
+check scripts and the renderer, the jails-are-auto-discovered-not-scripted
+design, failure-isolation behavior, and the current deployment recipe
+(Caddy + DNS-01 cert via Porkbun). This file only covers what that one
+doesn't: workflow and environment gotchas specific to developing here.
+
+## Where code runs vs. where it's edited
+
+This checkout is on Windows. None of the runtime commands the check
+scripts depend on (`sysctl`, `jls`, `jexec`, `pfctl`, `zpool`, `wg`,
+`service`, `ntpq`) exist here - they only exist on the target FreeBSD box.
+
+- **Validate here**: `sh -n path/to/script.sh` for syntax, and dry-run
+ logic by putting small shell stubs for the real commands in a temp dir
+ and prepending it to `PATH` (e.g. a fake `pfctl` that echoes canned
+ output). This is the only way to exercise check-script logic without
+ the real box.
+- **Deploy for real**: this repo's `origin` remote is
+ `ssh://cgit-jail/srv/git/console.git`. The FreeBSD server has its own
+ clone at `~/projects/console`, with `/usr/local/etc/statuspage`
+ symlinked to `~/projects/console/statuspage`. `render.sh` runs there via
+ root cron every minute, writing to `/usr/local/www/status/index.html`.
+ Changes only take effect after: commit here -> push -> `git pull` on the
+ server. There is no way to verify a change actually works against real
+ system state from this machine - say so rather than claiming success.
+
+## Committing shell scripts
+
+`core.fileMode` is `false` on this checkout, because this Windows
+filesystem doesn't reliably preserve the executable bit - `chmod +x`
+followed by a plain `git add` still stages a `.sh` file as `100644`.
+
+`git config core.hooksPath .githooks` (already set in this checkout, but
+**not** carried by a fresh clone - re-run it once after cloning elsewhere)
+activates a pre-commit hook that force-sets `+x` on every staged `*.sh`
+file automatically. A non-`.sh` executable (rare - the hook only globs
+`*.sh`) needs `git update-index --chmod=+x <file>` by hand, and so does
+the hook file itself if it's ever edited (it can't fix its own bit).
+
+## Gotchas already hit once - don't re-discover these
+
+- **`ln -s` on a directory, tested on this Windows box, silently falls
+ back to a real copy instead of a symlink.** Don't trust symlink
+ behavior verified here; it needs confirming on the real FreeBSD box.
+- **Greedy regex substring traps**: `usec` contains `sec`, so
+ `sed 's/.*sec = \(...\).*/.../'` will match the *last* occurrence
+ (`usec`), not the first. Anchor tightly (e.g. match the literal `{ sec
+ = ` prefix) instead of relying on `.*` to stop at the right spot.
+- **`ntpq`'s `rv 0 offset` prefixes non-negative values with a literal
+ `+`.** A sed capture class of `[-0-9.]` silently drops the `+` and
+ matches empty rather than failing loudly - always include `+` alongside
+ `-` in numeric-capture character classes.
+- **`grep -c pattern` exits `1` when the count is `0`**, even though it
+ prints `0`. Guard command substitutions that end in `grep -c` with
+ `|| var=0`, or `set -e` will kill the whole script on a legitimate
+ zero-count case.
+- **Most check commands (`pfctl`, `jls`, `wg`, `jexec`) need root.**
+ `render.sh` runs as root via cron, so this isn't an issue in production,
+ but manual testing on the box needs `doas`/`sudo`.
+
+## Cosmetic conventions (render.sh)
+
+- Status values are `ok` / `warn` / `down` (green/yellow/red) or `info`
+ (gray, for rows that aren't a health signal - e.g. `pf.sh`'s rule
+ listing). Don't repurpose the health colors for non-health rows.
+- The font (`statuspage/fonts/scientifica.ttf`, a bitmap-style font) only
+ ships Arrows, Geometric Shapes, Box Drawings, Mathematical
+ Operators/Symbols-A, Misc Technical/Symbols, and PUA/Powerline glyphs -
+ notably **not** Dingbats (✓/✗). Check glyph coverage against that list
+ before adding new symbols to check-script output.