- Justfile: pinned shiroa (v0.4.0-rc2, arch-aware) bootstrapped into tools/ by the 'tools' recipe; build-docs/preview-docs use it, so a fresh clone needs only Go and just. Bare 'just' now shows the recipe overview instead of starting a build. - AGENT.md: operating rules for agents (commands, layout, security invariants, shiroa version-pairing trap, testing expectations). - README: prerequisites updated (no global shiroa), bare-just behavior, tools/ in the layout. gitignore tools/ and docs/dist/.
3.8 KiB
3.8 KiB
AGENT.md — operating rules for agents working on Yggdrasil
Personal knowledge base: Typst sources (docs/, a shiroa book) compiled to
a static site, embedded into a Go binary that enforces per-page OIDC group
permissions (Authentik). README.md is the human-facing documentation; this
file is the working rulebook. Follow it; when it conflicts with the user,
the user wins.
Commands
just— shows the command overview (barejustnever builds anything).just build— parse ACL, compile the book, build./server.just run— build everything, then serve on :8080.just check— go vet, go test, gofmt. Run it before every commit.just clean— removesdist/andserver(keepstools/).- The shiroa toolchain is pinned and self-bootstrapped into
tools/by thetoolsrecipe. Never assume a global shiroa/typst install exists; do not install shiroa globally; do not bump the pin casually (see Traps).
Layout
docs/— shiroa book.book.typlists every built page; files not listed there are not part of the site. Categories are=part headers in the summary, pages are# chapter("path.typ")[Title]entries. Final URL = source path with.typreplaced by.html.cmd/parser— build step: scansdocs/for#let access-groups = (..)tags and emitsacl.json. Untagged pages are public.cmd/server+embed.go(repo root) —//go:embedofdist/andacl.jsoninto a single binary.internal/acl— ACL loading and page-key normalization (security critical).internal/oidc— OIDC authorization-code client.internal/middleware— sessions, login/callback/logout, access gate.legacy_docs/— frozen previous site. Never modify or migrate it unless the user asks explicitly.
Security invariants — do not break
- Fail closed: a malformed
acl.jsonaborts startup; protected pages with no configured IdP answer 503, never the content. - Page keys: shiroa pages keep their rendered content in sibling
<page>.<theme>.multi.sir.infiles fetched by client-side JS.acl.PageKeyreduces any URL to a page key so those files inherit the page's protection. If the shiroa output format changes, re-verify this mapping: content in any new sidecar file must be covered or blocked. /searchindex.jsoncontains the text of protected pages: blocked at the router, always.- Session cookies: HttpOnly, SameSite=Lax, Secure unless COOKIE_SECURE=false. OAuth2 states are random and single use; post-login redirect targets are sanitized (open-redirect guard).
Traps
- Shiroa version pairing: the CLI and the
@preview/shiroa:*typst package must match (CLI v0.4.0-rc2 pairs with package 0.4.0; the v0.3.0 release CLI rejects 0.4.0 books). Bump both together and rebuild. - Typst call syntax: no space between
)and the trailing content block —#chapter("x.typ")[Title], not#chapter("x.typ") [Title]. dist/andacl.jsonare embedded at Go build time; there is no runtime reload. After changing docs or ACL, rebuild the binary.go buildneedsdist/andacl.jsonto exist: fresh clones carrydist/.gitkeepand a committedacl.jsonfor exactly this reason. Never gitignore those two.
Testing expectations
- Test what the user runs, not a proxy for it: from a clean state
(
rm -rf tools dist server),just buildandjust runmust succeed with no global shiroa on PATH. Test the barejustoutput too. - Server behavior: curl a public page (200), a protected page (503 without
OIDC env; it must never serve protected content), and
/searchindex.json(404). Extend the unit tests ininternal/aclandinternal/middlewarewhenever touching those paths. - A live OIDC round trip needs a real IdP and is not testable here. Say that explicitly when reporting what was verified.