Tähän mennessä olet käyttänyt yksittäisiä rooleja yksittäisiin tehtäviin. Spec-loop yhdistää ne autonomiseksi silmukaksi, joka ajaa, kunnes valmis tai pysähtymisehto täyttyy.
Loop-malli
┌─────────────────────────────────────────────────┐
│ │
│ Read Spec │
│ ↓ │
│ Implement (Builder agent) │
│ ↓ │
│ Run Checks (deterministic local commands) │
│ ↓ │
│ Review (Reviewer agent) │
│ ↓ │
│ Approved? ──No──→ Adjust + iterate ──┐ │
│ │ │ │
│ Yes ↑ │
│ ↓ │ │
│ Ship + log decision trace ←──────────┘ │
│ │
│ max_iterations exceeded? ──→ Halt + escalate │
│ │
└─────────────────────────────────────────────────┘
Spec-driven loop
Spec-driven loop on factory-pattern, jossa agentti(t) ajavat saman silmukan toistuvasti — implement → check → review — kunnes spec on täytetty tai max-iteraatiot ylittyy. Avain: spec on ainoa source of truth, eivät arvaukset siitä, mitä halutaan. Loop pysähtyy itsestään hallitusti.
Spec-rakenne
Spec-loopin spec on JSON tai YAML, jolla on tarkat kentät:
{
"goal": "Add 120-second timeout to all outbound HTTP calls in src/api/",
"max_iterations": 5,
"checks": [
{
"name": "syntax",
"command": "python -m py_compile src/api/*.py",
"must_pass": true
},
{
"name": "tests",
"command": "pytest tests/api/ -x",
"must_pass": true
},
{
"name": "timeout-exists",
"command": "grep -q 'timeout=120' src/api/*.py",
"must_pass": true
}
],
"implement_instructions": "Use the requests library timeout parameter. Don't change behaviour for non-HTTP calls.",
"review_instructions": "Verify timeout is exactly 120s, not approximated. Verify no test was disabled.",
"allowed_tools": ["Read", "Glob", "Grep", "Edit", "Bash"]
}| Kenttä | Mitä se tekee |
|---|---|
goal | Mitä halutaan saada aikaan — yhdellä lauseella |
max_iterations | Pysähtymisehto — älä koskaan loop ikuisesti |
checks | Deterministiset lokaalit komennot, jotka ajetaan jokaisen iteraation jälkeen |
implement_instructions | (Optional) miten rakennetaan |
review_instructions | (Optional) miten arvioidaan |
allowed_tools | Tool-whitelist — turvallisuus |
Pro-vinkki
Avain: checks ovat deterministisiä komentoja, ei LLM:n arvauksia. pytest, grep, npm test, eslint — nämä antavat oikean vastauksen joka kerta. LLM-reviewer voi sanoa "näyttää hyvältä", mutta vain test-suite tietää, toimiiko se.
Hands-on: Aja 04_spec_loop_factory.py
Pro-vinkki
Hands-on -tiedostot (04_spec_loop_factory.py, spec.example.json,
backend-runner) jaetaan Sessio 4:n live-koulutuksessa Wed Jun 17 —
facilitator antaa zip-paketin tai jakaa repo-linkin sessiossa.
Itseopiskelussa lue tämä lesson ohjeena spec-loopin rakenteesta,
mutta odota tiedostot live-sessiosta tai pyydä niitä
tuki@modernpath.ai.
Valmistautuminen:
cd content/basematerials/session-4-agentic/claude-factory-rehearsal/
# Valitse joku CLI-backend, jolla on aktiivinen subscription
# (claude / codex / opencode)
uv run python -VAja perus-spec:
uv run python 04_spec_loop_factory.py \
--backend claude \
--spec spec.example.jsonTee oma spec:
{
"goal": "Add 120s timeout",
"max_iterations": 3,
"checks": [
{
"name": "syntax",
"command": "{python} -m py_compile {target_file}"
},
{
"name": "timeout-exists",
"command": "grep -q 'wait_for' {target_file}"
}
]
}uv run python 04_spec_loop_factory.py \
--backend claude \
--spec spec.add-timeout.jsonPohdittavaa harjoituksen aikana
Miten loop päättää milloin pysähtyä?
Mitä tapahtuu, kun yksi checks epäonnistuu?
Mihin ihmisen review sopii spec-loopissa?
Spec quality = output quality
Huono spec = huono output, riippumatta agentin älykkyydestä.
| Anti-pattern | Esimerkki | Korjaus |
|---|---|---|
| Vague goal | "Make it better" | "Reduce p95 latency from 300ms to under 100ms for /api/users" |
| Ei checksejä | (puuttuu) | Vähintään: syntax, tests, custom check |
| Korkea max_iterations | 50 | Aloita 3–5; nosta vain jos perusteltu |
| Whitelist puuttuu | (puuttuu) | Lisää allowed_tools — esim. älä anna bash jos ei tarvita |
| Liian iso scope | "Refactor entire auth module" | Pilko: "Add timeout to auth.py", "Split auth.py into oauth + session" |
Harjoitus: Kirjoita spec omasta tehtävästäsi
Ota oma to-do (tiimisi backlogista) ja kirjoita siitä spec spec.example.json -muodossa. Mitä on goal? Mitkä ovat 3 determinististä checkiä? Mikä on järkevä max_iterations?
Mitä loop NÄYTTÄÄ ajossa?
Tyypillinen onnistunut ajo:
[iteration 1/5] Builder
→ Reading src/api/users.py
→ Reading specs/add-timeout.json
→ Edit: Added timeout=120 to 3 fetch() calls
→ Tokens: 1842 in / 421 out / $0.012
[iteration 1/5] Checks
✓ syntax — passed (0.4s)
✗ tests — FAILED (test_long_response timed out)
✓ timeout-exists — passed
[iteration 1/5] Reviewer
→ Verdict: REQUEST_CHANGES
→ Reason: test_long_response uses 180s mock — needs adjustment
[iteration 2/5] Builder
→ Edit: Updated test mock from 180s to 100s
→ Tokens: 612 in / 89 out / $0.004
[iteration 2/5] Checks
✓ syntax — passed
✓ tests — passed (12s)
✓ timeout-exists — passed
[iteration 2/5] Reviewer
→ Verdict: APPROVED
→ Total cost: $0.016, total time: 47s
[FINAL] Status: SUCCESS iterations: 2/5 cost: $0.016Mitä tämä kertoo:
- Iteraatio 1 epäonnistui deterministisesti (test failure), ei LLM:n arvauksena
- Builder näki virheen ja korjasi sekä koodin että testin
- Reviewer hyväksyi vasta kun checks olivat vihreät
- Lokitettu hinta + aika → seuraava run on vertailukohta
Yhteenveto
- 🔁 Spec-loop = Read Spec → Implement → Run Checks → Review → iterate
- 🎯 Spec on single source of truth — ei arvauksia
- ✅ Checks ovat deterministisiä komentoja, eivät LLM-arvauksia
- 🛑 Pysähdys: kaikki checks läpi TAI max_iterations ylittyy
- 👤 Ihmisen rooli: kirjoita hyvä spec + hyväksy valmis tuotos
Seuraavassa oppitunnissa: Antipatternit — mitä menee pieleen ja miten suojautua siltä, että factorysta tulee vastuuvelka.