scrum4me-docker/README.md

147 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# scrum4me-agent-runner
Headless Claude Code worker die de Scrum4Me job-queue (M13) leegtrekt vanaf
een QNAP NAS via Container Station. Geen Vercel, geen browser, geen
toetsenbord — Claude Code draait als daemon, claimt jobs uit
`mcp__scrum4me__wait_for_job`, voert ze uit in een per-job clone, en pusht
nooit zelf.
## Architectuur in één plaatje
```
┌─ QNAP TS-664 (Container Station) ─────────────────────────────┐
│ │
│ ┌─ container: agent-runner ────────────────────────────────┐ │
│ │ PID 1: tini → run-agent.sh (daemon-loop) │ │
│ │ ├─ health-server.js (8080 → host) │ │
│ │ └─ claude -p (per-batch, met MCP via stdio) │ │
│ │ └─ scrum4me-mcp → Neon Postgres │ │
│ │ │ │
│ │ /tmp/job-<id> ephemeral working trees │ │
│ │ /var/cache/repos bare git mirrors (volume) │ │
│ │ /var/cache/npm npm cache (volume) │ │
│ │ /var/log/agent run + job logs (volume) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ /share/Agent/cache /share/Agent/logs /share/Agent/state │
└────────────────────────────────────────────────────────────────┘
▼ HTTPS
Neon Postgres (Scrum4Me DB)
Vercel ─── Scrum4Me UI (gebruikers enqueueen jobs)
```
Eén `claude -p`-invocation roept intern `wait_for_job` aan totdat de
queue leeg is (≈600 s lege block-time → afsluiten). De wrapper start
`claude -p` opnieuw zodra hij eindigt, met exponentiële backoff bij
fouten.
## Wat zit waar
| Bestand | Doel |
|--------------------------|-----------------------------------------------------------------|
| `Dockerfile` | Ubuntu 22.04 + Node 22 + Claude Code + scrum4me-mcp + scripts |
| `docker-compose.yml` | Service-definitie, volumes, env-file, restart-policy, limits |
| `package.json` | Npm-dependencies van de runner zelf (alleen `scrum4me-mcp` pin) |
| `mcp-config.json` | Claude Code MCP-config (verwijst stdio naar scrum4me-mcp) |
| `CLAUDE.md` | Agent-rol-instructies, auto-geladen door `claude -p` |
| `bin/entrypoint.sh` | Container-startup: dirs, health-server, daemon-loop |
| `bin/run-agent.sh` | Daemon-loop met backoff, exit-code-routing en state-writes |
| `bin/check-tokens.sh` | Pre-flight: API-token, OAuth-token, DB-bereikbaarheid |
| `bin/job-prepare.sh` | Per-job: bare-fetch + clone-via-reference naar `/tmp/job-<id>` |
| `bin/job-cleanup.sh` | Per-job: logs naar `/var/log`, working tree weg |
| `bin/health-server.js` | HTTP-endpoint op 8080 dat state.json en marker-files leest |
| `bin/rotate-logs.sh` | Compress/cleanup van oude `.log`-bestanden |
| `.env.example` | Alle env-vars met uitleg |
## Vereisten op de NAS
- Container Station 2+ (Docker compose v2)
- Drie shares aangemaakt: `/share/Agent/cache`, `/share/Agent/logs`, `/share/Agent/state`
- Of één share `/share/Agent` waaronder de drie subdirs vallen
- Internet-uitgang naar `api.anthropic.com`, `github.com`, je Neon-host, `registry.npmjs.org`
## Deploy
```bash
# 1. Op je werkstation: token's regelen
# a. CLAUDE_CODE_OAUTH_TOKEN → draai `claude setup-token` (browser-flow)
# b. SCRUM4ME_TOKEN → log in als de dedicated agent-user in
# Scrum4Me, /settings/tokens, label "NAS-runner"
# c. DATABASE_URL/DIRECT_URL → Neon dashboard
# 2. Repo op de NAS plaatsen
ssh admin@nas
cd /share/Agent
git clone https://github.com/<jij>/scrum4me-agent-runner.git
cd scrum4me-agent-runner
# 3. Env aanmaken
cp .env.example .env
chmod 600 .env
vi .env # vul alle waarden in
# 4. Build + start
docker compose build
docker compose up -d
# 5. Verifiëren
curl http://nas.local:8080/health
docker compose logs -f
```
## Updaten (handmatig, bewust)
`SCRUM4ME_TOKEN` of `CLAUDE_CODE_OAUTH_TOKEN` rouleer je via een rebuild:
```bash
cd /share/Agent/scrum4me-agent-runner
git pull
vi .env # nieuwe waarden
docker compose build # nieuwe scrum4me-mcp-versie als dat veranderd is
docker compose up -d
```
Dezelfde flow voor schema-drift in scrum4me-mcp: pin een nieuwe
`MCP_GIT_REF` in `.env` of in `docker-compose.yml`, rebuild.
## Health-endpoint
`GET http://<nas>:8080/health` retourneert:
```json
{
"status": "running", // running | idle | unhealthy | token-expired
"lastBatchAt": "2026-05-01T12:34:56Z",
"lastBatchExit": 0,
"consecutiveFailures": 0,
"tokenStatus": { "anthropic": "ok", "scrum4me": "ok", "db": "ok" }
}
```
HTTP-status: `200` als running/idle, `503` bij token-expired of als de
laatste heartbeat ouder is dan 5 minuten.
## Filesystem-grenzen
De agent-user heeft geen SSH-keys, geen `~/.gitconfig` met push-credentials,
en geen toegang tot andere shares dan `/share/Agent/*`. Commits worden
lokaal in de per-job clone gemaakt; pushen gebeurt door jou op je
werkstation na review (CLAUDE.md regel: *"`git push` is altijd expliciet"*).
## Bekende grenzen
- **Eén actieve job tegelijk.** De wrapper-loop is sequentieel. Voor
parallellisme zou je meerdere containers met dezelfde `SCRUM4ME_TOKEN`
kunnen draaien — `wait_for_job` gebruikt `FOR UPDATE SKIP LOCKED` dus
dat is veilig op DB-niveau, maar dan moet je je `node_modules`-cache
per container scheiden.
- **OAuth-token: 1 jaar geldig.** Bij verloop schrijft de wrapper een
`TOKEN_EXPIRED`-marker en wordt de container `unhealthy`. Geen
auto-rotatie.
- **`npm install` per job** kost op een N5095 ~3060 s per Next.js-clone,
óók met de pnpm-store. Voor zeer kleine fixes is dat de dominante
factor. Kan later vervangen worden door een persistente warm-`node_modules`
per repo als dat een knelpunt wordt.