CONTRIBUTING.md
raw
· source
Contributing to tdd.md
This file is the on-ramp for new contributors — human or agent. It links to canonical sources rather than restating them. If something here drifts from what the spec or workflow memory says, the canonical artifact wins; please file an issue.
Two URLs, one file:
- Browse:
/GIT/tdd.md/blob/main/CONTRIBUTING.md— via the site's own source viewer - Canonical:
/contributing— the rendered permalink
Before you start
Read in this order:
/sama/v2— the architectural spec (rules, profile, verifier, §5 metrics, §6 evolution policy)/blog/2026-05/sama-v2-on-ramp-gap— why this file exists/blog/2026-05/sama-v2-goal-chain-gap— why/goals are now in git
Then check the live state: /sama/v2/verify must report 7/7 ✓ before and after every merge. This is the load-bearing anti-fudge gate.
How contribution works on this codebase
This is a self-hosted project. The canonical surfaces are all on tdd.md:
- Read the source:
/GIT/tdd.md/tree/main - Issues + discussion: git.tdd.md/syntaxai/tdd.md/issues (the self-hosted Forgejo)
- Clone (read-only):
git clone https://tdd.md/syntaxai/tdd.md.git
Editing the live site is admin-only by design — see src/b51_render_edit.ts. The admin uses the GitHub PR flow internally; external contributors engage through the issue tracker on Forgejo, not via GitHub PRs.
The /goal workflow
The contract for every PR on this site is a /goal slash command. The canonical workflow definition lives at /goals/migrate-historical-goals; a 5-line summary:
- User fires
/goalwithGoal: ... Done when: ... Constraints ... Load-bearing files ...structure - Agent's first action: write the verbatim text to
goals/<slug>.mdwithstatus: pending, branch + commit - Implementation work happens in subsequent commits
- PR body MUST include the verbatim
/goalunder a## /goalheading (defense-in-depth) - Final commit before deploy flips
status: shipped+ fillsmerge_sha
Every shipped /goal is browseable at /goals.
SAMA layer convention
The file prefix encodes the layer. The canonical definition is in /sama/v2 §1.1; the table below shows concrete examples from this repo:
| Prefix | Layer | Means | Example |
|---|---|---|---|
a*_ |
0 — Pure | data + types, no I/O | a31_blog.ts |
b*_ |
1 — Core | pure logic, no I/O | b32_sitemap.ts |
c*_ |
2 — Adapter | parses boundaries; DB, network, fs | c14_git.ts |
d*_ |
3 — Entry | route handlers, app bootstrap | d21_app.ts |
b51_ |
1 — Core (render) | pure HTML rendering | b51_render_layout.ts |
The Law (§1.2): imports flow downward only. The verifier rejects upward or sideways edges mechanically.
How to add a blog post
- Write
content/blog/<slug>.mdwith the body - Add an entry to
ALL_POSTSinsrc/a31_blog.tswith{ slug, title, description, date } - The sitemap, blog index, and
/blog/<slug>route pick it up automatically — registry is the single source of truth - Branch → PR → merge → deploy
Worked example: /blog/2026-05/sama-v2-sitemap-implementation-plan.
How to add a /goal
Type /goal in conversation with the agent. The agent handles the rest per the workflow above.
If you're not the admin: file an issue at git.tdd.md/syntaxai/tdd.md/issues using the Goal: ... Done when: ... Constraints ... Load-bearing files ... shape. The admin (or agent on their behalf) fires it.
How to add an image
- Write
public/images/<name>.svgwith ahttps://tdd.mdwatermark text somewhere on the canvas (typically bottom-right in a muted color) - Render PNG:
rsvg-convert -w 1200 -h 600 public/images/<name>.svg -o public/images/<name>.png - Reference from markdown:

The /images/* wildcard is served by the fallback handler in d21_handlers_fallback.ts — no per-image route registration needed.
How to add a Layer-1 helper
- Write
src/b32_<name>.ts— pure, no I/O, single export per concern - Write the sibling
src/b32_<name>.test.ts— required by§4.3 Modeled-tests - Caller (typically Layer 2 or Layer 3) imports from
./b32_<name>.ts
Worked example: b32_sitemap.ts + b32_sitemap.test.ts.
How to add a top-level directory
⚠ Important: every new top-level directory needs a corresponding COPY <dir> ./<dir> line in Containerfile. Without it, the directory doesn't ship with the runtime image and request-time disk reads return 404. This was discovered in PR #46 when /goals/<slug> returned 404 in production.
Checklist for a new top-level dir:
- Create the directory and any initial files
- Add
COPY <dir> ./<dir>toContainerfile(after the existing COPY lines) - Live-verify a file from the new directory loads after deploy
Anti-fudge defaults
Every PR satisfies these without exception:
- Site language: English only. No Dutch in user-facing strings (blog bodies, banners, error text, page copy)
- Tests stay green:
bun testmust pass; new behaviour gets a sibling test /sama/v2/verifystays 7/7 ✓: structural choices must preserve the verifier verdict- No
--no-verify, no force-push to main: hooks exist for a reason - GitHub flow via
flatpak-spawn: the sandbox doesn't havegh; useflatpak-spawn --host gh ...
Branch / deploy flow (admin path)
The full sequence the agent (or admin) runs end-to-end:
git checkout -b <slug>— branch from main- Implementation work + sibling tests
git push -u origin <slug>+gh pr create(body includes## /goalverbatim per workflow)gh pr merge --merge --delete-branchafter CI greengit checkout main && git pull origin main— sync localgit push p620 main— push to self-hosted bare repoflatpak-spawn --host /var/home/scri/Documents/tdd.md/scripts/p620/deploy-tdd-md.sh— rebuild + redeploy container- Live-verify: curl the changed URLs, confirm
/sama/v2/verifystill 7/7 ✓
When in doubt
- The spec (
/sama/v2) is the single source of truth for architectural rules - The verifier (
/sama/v2/verify) is the single source of truth for whether a commit is conformant - The
/goalsregistry (/goals) is the single source of truth for what every PR was held against - This file links to all three. If it contradicts any of them, the canonical artifact wins; please file an issue at git.tdd.md/syntaxai/tdd.md/issues.