docs: add plans and recommendations

- docs/plans/Local github setup.md
- docs/plans/lees-de-readme-md-validated-book.md
- docs/plans/zustand-store-rearchitecture.md
- docs/recommendations/beelink-ubuntu-scrum4me-server-caveman-plan.md
- docs/recommendations/claude-vm-job-flow-git-strategy.md
- docs/INDEX.md updated

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-09 22:54:14 +02:00
parent d292e445d9
commit 0d126695db
6 changed files with 1990 additions and 0 deletions

View file

@ -0,0 +1,458 @@
---
title: "Caveman plan — Beelink naar Ubuntu Scrum4Me server"
status: draft
audience: [maintainer, operator]
language: nl
last_updated: 2026-05-09
---
# Caveman plan — Beelink naar Ubuntu Scrum4Me server
## Doel
Zet de Beelink mini-PC om naar een dual-boot machine waarop **Ubuntu Server 24.04 LTS** de standaard server-boot is. Windows blijft bestaan als fallback, maar Scrum4Me draait op Ubuntu.
Doelopstelling:
```text
Beelink mini-PC
├─ Windows fallback
└─ Ubuntu Server 24.04 LTS default
├─ Docker Engine
├─ Postgres
├─ Scrum4Me webserver
├─ worker-idea
├─ worker-implementation
└─ worker-orchestrator
```
## Hardware
Bekende specs:
| Onderdeel | Waarde |
|---|---|
| Merk | Beelink |
| CPU | Intel Core i5-12450H |
| CPU boost | Tot 4,4 GHz |
| RAM | 32 GB DDR4 |
| Opslag | 1 TB |
| GPU | Intel integrated graphics |
| Vorm | Mini-PC |
Conclusie: geschikt voor Scrum4Me als single-user/small-team server, mits implementation-concurrency op 1 blijft en resource limits strak staan.
## Caveman Regels
- Geen Ubuntu Desktop installeren.
- Geen GPU-driver installeren tenzij beeld echt kapot is.
- Geen Docker Desktop.
- Geen Postgres-poort naar internet.
- Geen Docker socket mounten in workercontainers.
- Geen repos, caches of worktrees op de Windows-partitie.
- Alles onder `/srv/scrum4me`.
- Eerst één worker werkend krijgen, daarna pas drie.
- Eerst via lokaal IP testen, daarna pas domein/TLS.
- Ubuntu wordt default boot; Windows is fallback.
## Waarom Geen Drivergedoe Verwacht Wordt
De CPU heeft Intel integrated graphics. Ubuntu Server heeft geen desktop nodig. Intel geeft aan dat de meeste Linux-distributies Intel graphics drivers al meeleveren. Voor deze machine verwacht je de kernel-driver `i915`.
Na installatie alleen checken:
```bash
lspci -k | grep -EA3 'VGA|3D|Display'
lsmod | grep i915
```
Als `i915` zichtbaar is: klaar. Niet verder aan sleutelen.
## Fase 0 — Voorbereiding In Windows
1. Maak backup van belangrijke Windows-data.
2. Sla BitLocker recovery key op als BitLocker aan staat.
3. Zet Windows Fast Startup uit:
- Control Panel
- Power Options
- Choose what the power buttons do
- Turn off fast startup
4. Maak vrije ruimte:
- Open Disk Management.
- Shrink `C:`.
- Laat ongeveer `600 GB` unallocated voor Ubuntu.
Aanbevolen diskverdeling:
```text
Windows: 250-300 GB
Ubuntu /: 120 GB
/srv/scrum4me: rest van vrije ruimte
swapfile: 16 GB
EFI: bestaande EFI behouden
```
## Fase 1 — Ubuntu USB Maken
1. Download Ubuntu Server 24.04 LTS amd64.
2. Maak USB-stick met Rufus of Balena Etcher.
3. Sluit ethernet aan op de Beelink.
4. Boot van USB.
Veelvoorkomende Beelink toetsen:
```text
Boot menu: F7
BIOS: Del
```
BIOS-checks:
```text
UEFI boot: aan
Secure Boot: mag aan blijven, maar uitzetten als install gedoe geeft
Power on after power loss: aan
Ubuntu later als eerste boot entry
```
## Fase 2 — Ubuntu Installeren
Kies tijdens installatie:
```text
Install Ubuntu Server
OpenSSH server: YES
Desktop: NO
Storage: Custom layout
```
Storage:
```text
Bestaande EFI partition:
mount: /boot/efi
formatteren: NEE
Nieuwe ext4 partition 120 GB:
mount: /
Nieuwe ext4 partition rest:
mount: /srv/scrum4me
```
Niet kiezen:
```text
Use entire disk
```
Dat zou Windows verwijderen.
## Fase 3 — Eerste Boot
Login op Ubuntu.
```bash
sudo apt update
sudo apt upgrade -y
sudo reboot
```
Na reboot:
```bash
sudo hostnamectl set-hostname scrum4me-server
ip a
```
Zet in je router een DHCP reservation voor het IP-adres. Dat is simpeler dan handmatige netwerkconfiguratie.
## Fase 4 — Server Niet Laten Slapen
```bash
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
```
In BIOS:
```text
Power on after power loss: ON
Sleep: OFF als optie bestaat
Boot order: Ubuntu eerst
```
## Fase 5 — Basis Tools
```bash
sudo apt install -y git curl ca-certificates gnupg htop iotop ufw fail2ban unzip jq
```
Firewall:
```bash
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw enable
sudo ufw status
```
Let op: Docker kan gepubliceerde containerpoorten buiten gewone `ufw`-verwachtingen om bereikbaar maken. Publiceer straks alleen reverse proxy poorten naar buiten.
## Fase 6 — Docker Engine Installeren
Gebruik Docker Engine native op Ubuntu. Geen Docker Desktop.
```bash
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
```
```bash
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
```bash
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
sudo reboot
```
Na reboot:
```bash
docker run hello-world
docker compose version
```
## Fase 7 — Scrum4Me Directories
```bash
sudo mkdir -p /srv/scrum4me/{postgres,repos,worker-cache,worker-logs,worker-state,backups,compose,caddy}
sudo chown -R $USER:$USER /srv/scrum4me
```
Doelstructuur:
```text
/srv/scrum4me/postgres database data
/srv/scrum4me/repos cloned GitHub repos / mirrors
/srv/scrum4me/worker-cache npm/git/cache
/srv/scrum4me/worker-logs worker logs
/srv/scrum4me/worker-state worker state
/srv/scrum4me/backups local backup staging
/srv/scrum4me/compose docker compose files
/srv/scrum4me/caddy reverse proxy config
```
## Fase 8 — Services
Einddoel:
```text
postgres
scrum4me-web
worker-idea
worker-implementation
worker-orchestrator
caddy
```
Aanbevolen resource limits voor 32 GB RAM:
| Service | CPU limit | Memory limit | Opmerking |
|---|---:|---:|---|
| `postgres` | 2 CPU | 3-4 GB | Lokale DB |
| `scrum4me-web` | 2 CPU | 2-3 GB | Next.js runtime |
| `worker-idea` | 2 CPU | 4 GB | Grill, plan, chat |
| `worker-implementation` | 4-5 CPU | 10-12 GB | Zwaarste worker |
| `worker-orchestrator` | 2-3 CPU | 5-6 GB | PR review, CI triage, conflicts |
| `caddy` of `nginx` | 0.25 CPU | 256 MB | Reverse proxy |
Laat 5-7 GB vrij voor Ubuntu, Docker overhead, filesystem cache en pieken.
## Fase 9 — Tokens en Secrets
Maak aparte tokens per rol:
```text
SCRUM4ME_TOKEN_IDEA
SCRUM4ME_TOKEN_IMPLEMENTATION
SCRUM4ME_TOKEN_ORCHESTRATOR
GH_TOKEN_IDEA
GH_TOKEN_IMPLEMENTATION
GH_TOKEN_ORCHESTRATOR
CLAUDE_CODE_OAUTH_TOKEN_IDEA
CLAUDE_CODE_OAUTH_TOKEN_IMPLEMENTATION
CLAUDE_CODE_OAUTH_TOKEN_ORCHESTRATOR
```
Tokenbeleid:
| Token | Rechten |
|---|---|
| Idea | Read-only waar mogelijk, markdown/status updates via Scrum4Me |
| Implementation | GitHub contents RW + pull requests RW |
| Orchestrator | PR RW, contents RW alleen voor conflict/repair |
Bestandsrechten:
```bash
chmod 600 /srv/scrum4me/compose/*.env
```
Geen secrets in git.
## Fase 10 — Backups
Minimum:
```text
Elke nacht pg_dump
Elke nacht backup van /srv/scrum4me/compose
Offsite kopie naar cloud, NAS of externe disk
Backup restore maandelijks testen
```
Lokale backup alleen is onvoldoende. Als de SSD stuk gaat, is alles weg.
## Fase 11 — Monitoring
Simpel beginnen:
```bash
docker ps
docker stats
htop
iotop
df -h
du -sh /srv/scrum4me/*
journalctl -u docker --no-pager -n 100
```
Dagelijkse health checklist:
```text
Docker containers up?
Disk < 80% vol?
Backups gelukt?
Workers online?
Postgres bereikbaar?
Webserver bereikbaar via HTTPS?
Geen runaway logs?
```
## Fase 12 — Uitrolvolgorde
Niet alles tegelijk.
1. Ubuntu werkt.
2. SSH werkt.
3. Docker werkt.
4. Caddy/nginx testpagina werkt.
5. Postgres container werkt.
6. Scrum4Me webserver werkt lokaal.
7. Scrum4Me webserver werkt via HTTPS.
8. Eén worker werkt: `worker-idea`.
9. Tweede worker werkt: `worker-implementation`.
10. Derde worker werkt: `worker-orchestrator`.
11. Role-aware queue claiming aanzetten.
12. Backups testen.
## Eerste Smoke Test
Na installatie:
```bash
hostnamectl
free -h
df -h
lscpu
docker version
docker compose version
docker run hello-world
lspci -k | grep -EA3 'VGA|3D|Display'
lsmod | grep i915
```
Verwacht:
```text
Ubuntu 24.04 LTS
~32 GB RAM zichtbaar
Docker werkt
1 TB disk verdeeld zoals gepland
i915 zichtbaar voor Intel integrated graphics
```
## Foutscenario's
### Geen beeld na Ubuntu install
Eerst:
```text
Gebruik HDMI-poort 1
Gebruik andere kabel
Boot recovery mode
Probeer tijdelijk Secure Boot uit
```
Niet meteen drivers installeren.
### Windows start direct, geen Ubuntu menu
BIOS boot order aanpassen:
```text
Ubuntu boven Windows Boot Manager
```
### Docker permission denied
```bash
groups
```
Als `docker` ontbreekt:
```bash
sudo usermod -aG docker $USER
sudo reboot
```
### Server wordt traag
Check:
```bash
docker stats
free -h
htop
iotop
```
Eerste maatregel:
```text
implementation-worker alleen laten draaien
orchestrator zware builds verbieden
worker memory limits verlagen
```
## Bronnen
- Ubuntu Server requirements: <https://ubuntu.com/server/docs/reference/installation/system-requirements/>
- Ubuntu Server install docs: <https://ubuntu.com/server/docs/how-to/installation/>
- Intel Linux graphics guidance: <https://www.intel.com/content/www/us/en/support/articles/000005520/graphics.html>
- Docker Engine on Ubuntu: <https://docs.docker.com/installation/ubuntulinux/>
- Next.js self-hosting: <https://nextjs.org/docs/app/guides/self-hosting>

View file

@ -0,0 +1,213 @@
---
title: "Aanbeveling — Claude VM jobflow en gitstrategie"
status: draft
audience: [product-owner, maintainer, ai-agent]
language: nl
last_updated: 2026-05-09
---
# Aanbeveling — Claude VM jobflow en gitstrategie
## Managementsamenvatting
Scrum4Me heeft inmiddels een duidelijke jobarchitectuur: de app maakt jobs aan, de Docker-runner claimt jobs en start Claude op een VM, en `scrum4me-mcp` bewaakt de lifecycle, worktrees, branches, pushes en PR's. De huidige implementatie is daarmee sterker en veiliger dan een prompt-gestuurde agent die zelf jobs ophaalt, pusht of PR's maakt.
De belangrijkste aanbeveling is om deze servergestuurde lijn expliciet leidend te maken:
- Claude implementeert en commit lokaal, maar bepaalt niet de branch-, push- of PR-strategie.
- `scrum4me-mcp` blijft de enige partij die jobs claimt, worktrees koppelt, branches pusht, PR's maakt en auto-merge activeert.
- Productinstellingen bepalen bewust de PR-strategie: `SPRINT` als veilige default, `STORY` voor kleine auto-mergebare changes, `SPRINT_BATCH` alleen voor goed afgebakende single-repo sprints.
- De documentatie en prompts moeten worden bijgewerkt, omdat sommige oudere docs nog een handmatige "niet pushen tot user-test"-flow beschrijven terwijl de actuele VM-flow al automatisch pusht na een succesvolle job.
## Huidige Flow
```mermaid
flowchart TD
U["Gebruiker start sprint, idee of plan"] --> A["Scrum4Me app voert preflight uit"]
A --> Q["ClaudeJob wordt QUEUED"]
Q --> S{"Product.pr_strategy"}
S -->|STORY| J1["TASK_IMPLEMENTATION jobs<br/>branch per story"]
S -->|SPRINT| J2["TASK_IMPLEMENTATION jobs<br/>branch per sprint"]
S -->|SPRINT_BATCH| J3["1 SPRINT_IMPLEMENTATION job<br/>hele sprint"]
Q --> J4["IDEA_GRILL / IDEA_MAKE_PLAN / PLAN_CHAT<br/>geen git PR-flow"]
J1 --> R["scrum4me-docker runner<br/>quota, claim, payload, claude -p"]
J2 --> R
J3 --> R
J4 --> R
R --> C["Claude op VM<br/>wijzigt code, commit lokaal, logt, verifieert"]
C --> M["scrum4me-mcp update_job_status<br/>verify gate, push, PR, statuspropagatie, cleanup"]
M --> P{"PR-strategie"}
P -->|STORY| PS["PR per story<br/>auto-merge na groene checks"]
P -->|SPRINT| PP["draft PR per sprint<br/>ready bij sprint DONE"]
P -->|SPRINT_BATCH| PB["draft PR per sprint<br/>ready na batch DONE"]
```
## Rollen en Verantwoordelijkheden
| Actor | Verantwoordelijkheid | Mag niet doen |
|---|---|---|
| Gebruiker / product owner | Productinstellingen kiezen, sprint starten, review/merge bij sprint-PR's | Impliciete gitregels in prompts laten zweven |
| Scrum4Me app | Preflight, jobcreatie, strategie snapshotten op SprintRun | Zelf VM-werk orkestreren |
| scrum4me-docker | Job claimen, Claude starten, lease vernieuwen bij batchjobs | Zelf branch/PR-beleid bepalen |
| Claude op VM | Implementeren, lokaal committen, logs schrijven, verificatie draaien | Pushen, PR's maken, jobs ophalen |
| scrum4me-mcp | Claimprotocol, worktrees, branchnaam, push, PR, auto-merge, cleanup | Beslissingen overlaten aan losse prompttekst |
| GitHub | Branch protection, status checks, auto-merge, merge queue | Onbeschermde main-merge toestaan |
## Beslissingspunten
| Moment | Beslissing | Eigenaar | Advies |
|---|---|---|---|
| Productconfiguratie | `pr_strategy` en `auto_pr` | Gebruiker / product owner | Maak dit expliciet zichtbaar als operationele keuze |
| Sprint-start | Welke jobs worden aangemaakt | Scrum4Me app | Blijf blokkeren op ontbrekende plannen, open vragen en cross-repo batchrisico |
| Jobclaim | Welke job mag draaien | scrum4me-mcp | Houd atomic claim met lease en stale reset centraal |
| Runtime | Model, thinking budget, permissions | Job-config resolver | Snapshot bij enqueue en log de gekozen configuratie |
| Implementatie | Welke codewijziging en commits | Claude | Commit lokaal per logische laag, geen push |
| Verify gate | `EMPTY`, `PARTIAL`, `DIVERGENT` acceptabel? | scrum4me-mcp | Maak gate-regels testbaar en documenteer per jobkind |
| Push | Branch pushen of no-changes | scrum4me-mcp | Push alleen na succesvolle terminale status en geldige verify gate |
| PR | Geen PR, draft PR, ready PR, auto-merge | scrum4me-mcp + GitHub | Gebruik branch protection en required checks als harde randvoorwaarde |
| Failure | Retry, fail, skip, pause, cascade | scrum4me-mcp | Houd foutafhandeling server-side, niet prompt-side |
## Git- en PR-strategie
| Strategie | Jobs | Branch | PR | Mergebeleid | Aanbevolen gebruik |
|---|---:|---|---|---|---|
| `STORY` | Een job per taak | `feat/story-<story-id>` | PR per story | Auto-merge na groene checks | Kleine, onafhankelijke stories met betrouwbare CI |
| `SPRINT` | Een job per taak | `feat/sprint-<sprint-run-id>` | Een draft PR per sprint | Ready bij sprint DONE, menselijke merge | Veilige default voor productwerk |
| `SPRINT_BATCH` | Een job voor hele sprint | `feat/sprint-<sprint-run-id>` | Een draft PR per sprint | Ready na batch DONE, menselijke merge | Single-repo sprint met stabiele scope en contextvoordeel |
| Idee/plan jobs | Een job | Geen normale featurebranch | Geen PR | Alleen status/docs/logs | Ideevorming en planvorming |
Belangrijk: in de huidige implementatie betekent `auto_pr=false` niet automatisch "niet pushen". MCP pusht nog steeds branches wanneer een job succesvol afrondt en er commits zijn. `auto_pr` bepaalt vooral of daarna automatisch een PR wordt gemaakt.
## Aanbevolen Default
Gebruik `SPRINT` als standaardstrategie voor Scrum4Me-productwerk.
Redenen:
- Er is maar één PR per sprint, dus review en deployment blijven overzichtelijk.
- Claude kan per taak draaien en falen zonder dat de hele sprintcontext in één lange sessie hoeft te blijven leven.
- De PR blijft draft totdat de sprint klaar is, wat goed past bij menselijke review.
- Het voorkomt dat veel kleine story-PR's automatisch deployments of reviewprocessen starten.
Gebruik `STORY` alleen wanneer:
- De repository sterke branch protection heeft.
- Required checks verplicht zijn.
- De story klein genoeg is om automatisch te mergen.
- Auto-merge gewenst is en deploymentkosten acceptabel zijn.
Gebruik `SPRINT_BATCH` alleen wanneer:
- Alle taken in dezelfde repository zitten.
- De sprintscope stabiel is.
- Er weinig kans is op tussentijdse gebruikersvragen.
- Contextbehoud belangrijker is dan kleine herstelbare stappen.
## Concrete Acties
### 1. Maak MCP de formele orchestrator
Leg in de docs vast dat `scrum4me-mcp` de enige eigenaar is van:
- jobclaim en lease;
- worktree-aanmaak;
- branchnamen;
- push;
- PR-creatie;
- auto-merge;
- statuspropagatie;
- cleanup.
Claude mag alleen lokaal committen en via MCP-tools status/logs/verificatie doorgeven.
### 2. Trek documentatie gelijk
Werk minimaal deze stukken bij:
- `CLAUDE.md`: onderscheid maken tussen handmatige lokale agentflow en VM-jobflow.
- `docs/runbooks/branch-and-commit.md`: verouderde "push pas na user-test"-regel beperken tot handmatige runs.
- `docs/runbooks/auto-pr-flow.md`: expliciet maken dat MCP na `done` pusht en daarna optioneel PR maakt.
- `scrum4me-docker/README.md`: beschrijven dat de runner één job per `claude -p` uitvoert.
- `scrum4me-mcp/README.md`: branchnamen actualiseren naar `feat/story-*` en `feat/sprint-*`.
### 3. Fix prompt/tool-contracten
Los deze inconsistenties op:
- Task prompt: `update_job_status(skipped)` vereist een `error`, niet alleen een `summary`.
- Sprint prompt: `verify_required` wordt gebruikt als enum/gate, niet als boolean.
- Sprint prompt: verduidelijk wanneer een task binnen een batch echt `SKIPPED` mag worden.
- Docker docs: verwijder de oude instructie dat Claude zelf `wait_for_job` blijft aanroepen.
### 4. Maak de state machine expliciet
Documenteer en test de lifecycle als state machine:
```text
QUEUED -> CLAIMED -> RUNNING -> DONE
|-> FAILED
|-> SKIPPED
|-> CANCELLED
```
Aanbevolen start: een pure TypeScript transition table met tests. XState is pas nodig als visualisatie, model-based testing of complexere parallelle staten belangrijk worden.
### 5. Versterk GitHub-randvoorwaarden
Voor repositories waar `STORY` auto-merge gebruikt:
- Require status checks before merging.
- Require pull request reviews of CODEOWNERS voor risicovolle paden.
- Disable force pushes op beschermde branches.
- Gebruik `gh pr merge --auto --squash --match-head-commit` of equivalent met head-SHA guard.
- Overweeg merge queue zodra meerdere workers tegelijk PR's kunnen laten landen.
### 6. Beperk VM-risico
De VM-runner moet blijven werken met:
- least-privilege tokens;
- expliciete allowed tools;
- worktrees per job;
- geen secrets in logs;
- geïsoleerde runtime;
- duidelijke retry- en stale-claimregels;
- optioneel netwerkbeleid per repository of jobtype.
## Governance-Regel
De centrale regel voor Scrum4Me zou moeten zijn:
> Claude mag code veranderen en lokaal committen. Alleen Scrum4Me MCP mag bepalen wanneer werk klaar is, welke branch wordt gepusht, of er een PR komt, en of die PR automatisch mag mergen.
Deze regel voorkomt dat prompts, docs en runtimegedrag uit elkaar gaan lopen.
## Bronnen en Lokale Referenties
Lokale referenties:
- `actions/sprint-runs.ts` — sprint-start, preflight en jobcreatie.
- `components/products/pr-strategy-select.tsx` — productkeuze voor `STORY`, `SPRINT`, `SPRINT_BATCH`.
- `scrum4me-docker/bin/run-one-job.ts` — runner claimt één job en start Claude.
- `scrum4me-mcp/src/tools/wait-for-job.ts` — claimprotocol, worktree en branchresolutie.
- `scrum4me-mcp/src/tools/update-job-status.ts` — verify gate, push, PR, auto-merge, statuspropagatie.
- `scrum4me-mcp/src/git/push.ts` — branch push.
- `scrum4me-mcp/src/git/pr.ts` — GitHub PR-create, PR-ready en auto-merge.
Externe bronnen:
- GitHub Docs — Protected branches: <https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches>
- GitHub Docs — Required status checks: <https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging>
- GitHub Docs — Auto-merge: <https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-auto-merge>
- GitHub CLI — `gh pr merge`: <https://cli.github.com/manual/gh_pr_merge>
- GitHub Docs — Merge queue: <https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue>
- Trunk Based Development — Short-lived branches: <https://trunkbaseddevelopment.com/short-lived-feature-branches/>
- DORA — Trunk-based development capability: <https://dora.dev/capabilities/trunk-based-development/>
- Temporal Docs — Durable workflows: <https://docs.temporal.io/>
- XState Docs — State machines: <https://stately.ai/docs/state-machines>
- Anthropic Docs — Claude Code headless mode: <https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-headless>
- Anthropic Docs — Secure deployment guidance: <https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-secure-deployment>