Skip to content

Commit 0a51a00

Browse files
JonyanDunhclaude
andauthored
feat: key per-session state by parent Claude Code PID, not TERM_SESSION_ID (v1.2.0) (#9)
The v1.1.0 watchdog was unusable in most terminals because it keyed its per-session state file by TERM_SESSION_ID, which only iTerm2, WezTerm, and JetBrains IDE terminals export. Windows Terminal, macOS Terminal.app, GNOME Terminal, Alacritty, tmux, screen, plain Linux ttys, and most other terminals leave it unset, so /watchdog:start would fail at setup. v1.2.0 replaces TERM_SESSION_ID entirely with a process ancestry walk: on startup (both setup-watchdog.js and stop-hook.js), we walk upward from our own process.ppid until we find a process whose name is `claude` and use that PID as the state file key. Every Claude Code session has a distinct PID, so concurrent watchdogs in the same project directory never collide — tested up to 100 concurrent sessions by design. State files are now named `.claude/watchdog.claudepid.<PID>.local.json`. This also ELIMINATES the previous owner_session_id recursion guard. The headless Haiku classifier we spawn is a new Claude Code process with its own distinct PID; its recursive Stop hook walks ancestry to find THAT PID (not the main session's), so the state file lookup naturally misses and the recursive hook exits silently. No explicit ownership bookkeeping needed. ## Architecture New module: lib/claude-pid.js (173 lines). Three OS paths: - Linux: /proc/<pid>/comm + /proc/<pid>/status (fast, no subprocess) - macOS / BSD: ps -o comm=,ppid= -p <pid> via execFileSync - Windows: PowerShell Get-CimInstance Win32_Process via execFileSync Also handles a WATCHDOG_CLAUDE_PID env var override so unit tests can inject a synthetic PID without needing a real Claude Code ancestry. ## Test suite: 59 → 75 Added test/claude-pid.test.js covering isClaudeProcessName heuristic, the env override, and host-platform smoke tests for readProcComm / readProcPpid. Also expanded test/state.test.js with a listAll() test and rewrote test/setup.test.js, test/stop-watchdog.test.js, test/stop-hook.test.js, and test/stop-hook-haiku.test.js to key state files by claudePid instead of termSessionId and include concurrent- session isolation scenarios. Two setup/stop-watchdog tests are now skipped when the test runner itself happens to be inside a Claude Code session (CLAUDECODE=1), since the ancestry walk then correctly finds a real claude PID and those tests were asserting failure. ## Docs All 7 READMEs updated in the same PR. State File section, Requirements table, Plugin Layout tree, and Inspired By comparison table all reflect the new architecture. Cleaned up marketing / changelog-style language throughout: - Dropped "Node.js rewrite" / "cross-platform" qualifiers from the marketplace name, description, plugin description, keywords, and READMEs. The name stays claude-code-watchdog. - Dropped "no WSL2 / Git Bash required" / "runs directly on native Windows" contrast language and the redundant WSL2 row from the Platform support table. - Dropped the entire ## Testing section from READMEs. Test info lives in CONTRIBUTING.md where contributors look. - Dropped the "(no TERM_SESSION_ID required)" Requirements table row and "(new in 1.2.0)" markers from the Plugin Layout tree. - Rewrote the Inspired By "State scoping" row to highlight ralph-loop's hard limit of ONE concurrent loop per project. NOTICE updated with the 1.2.0 modification entry and lib/claude-pid.js in the file list. CONTRIBUTING.md updated with the new test file and concurrent-session scenarios. SECURITY.md attack-surface section updated to drop TERM_SESSION_ID path traversal and owner_session_id recursion guard references. commands/help.md Requirements table and Per-session isolation paragraph rewritten. .gitignore adds .claude/ to prevent state file and user settings leaks. ## Breaking change State file naming changed: previous v1.1.0 files at `.claude/watchdog.<TERM_SESSION_ID>.local.json` will be orphaned after upgrade. Users who had a working v1.1.0 (only iTerm2 / WezTerm / JetBrains) should clean up with `rm -f .claude/watchdog.*.local.json` before running /watchdog:start again. Users who never got v1.1.0 working (most of them) see no migration at all. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 332c3b9 commit 0a51a00

29 files changed

Lines changed: 852 additions & 593 deletions

.claude-plugin/marketplace.json

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3-
"name": "claude-code-watchdog-nodejs",
4-
"description": "Watchdog (Node.js rewrite) — cross-platform self-referential Claude Code loop with zero bash/jq dependencies. Runs natively on Linux, macOS, and Windows. Apache 2.0, derived from ralph-loop.",
3+
"name": "claude-code-watchdog",
4+
"description": "Watchdog — a self-referential Claude Code loop that re-feeds the same prompt until files actually stop changing. Apache 2.0, derived from ralph-loop.",
55
"owner": {
66
"name": "Jonyan Dunh",
77
"email": "jonyandunh@outlook.com"
88
},
99
"plugins": [
1010
{
1111
"name": "watchdog",
12-
"description": "Self-referential loop for Claude Code that re-feeds the user's prompt until the task truly stops producing file edits. Cross-platform Node.js implementation with no bash / jq dependencies. Uses a headless Haiku classifier to judge convergence, requires the agent to actually call tools before exit (no pure-text 'done' claims), and is hidden from the agent so it cannot cheat. Per-session state keyed by TERM_SESSION_ID. Apache 2.0, derived from ralph-loop.",
13-
"version": "1.1.0",
12+
"description": "Self-referential loop for Claude Code that re-feeds the user's prompt until the task truly stops producing file edits. Uses a headless Haiku classifier to judge convergence, requires the agent to actually call tools before exit (no pure-text 'done' claims), and is hidden from the agent so it cannot cheat. Apache 2.0, derived from ralph-loop.",
13+
"version": "1.2.0",
1414
"author": {
1515
"name": "Jonyan Dunh",
1616
"email": "jonyandunh@outlook.com"
@@ -26,11 +26,9 @@
2626
"self-referential",
2727
"iteration",
2828
"convergence",
29-
"ralph-loop",
30-
"nodejs",
31-
"cross-platform"
29+
"ralph-loop"
3230
]
3331
}
3432
],
35-
"version": "1.1.0"
33+
"version": "1.2.0"
3634
}

.claude-plugin/plugin.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "watchdog",
3-
"version": "1.1.0",
4-
"description": "Self-referential loop for Claude Code. Re-feeds the same prompt after every turn until files actually stop changing. Cross-platform Node.js implementation — no bash / jq dependencies, runs natively on Linux, macOS, and Windows.",
3+
"version": "1.2.0",
4+
"description": "Self-referential loop for Claude Code. Re-feeds the same prompt after every turn until files actually stop changing.",
55
"author": {
66
"name": "Jonyan Dunh",
77
"email": "jonyandunh@outlook.com"
@@ -17,8 +17,6 @@
1717
"self-referential",
1818
"iteration",
1919
"convergence",
20-
"ralph-loop",
21-
"nodejs",
22-
"cross-platform"
20+
"ralph-loop"
2321
]
2422
}

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ assignees: JonyanDunh
1818

1919
## Environment
2020

21+
- Watchdog version (from `.claude-plugin/plugin.json`):
2122
- Claude Code version: `claude --version`
23+
- Node.js version: `node --version`
2224
- OS:
23-
- Terminal emulator (iTerm2 / WezTerm / Windows Terminal / ...):
24-
- `TERM_SESSION_ID` is set? (`echo $TERM_SESSION_ID`):
25-
- `jq` version: `jq --version`
25+
- Terminal emulator (Windows Terminal / macOS Terminal.app / GNOME Terminal / iTerm2 / WezTerm / JetBrains / tmux / ...):
2626
- `claude` CLI available for Haiku calls? (`which claude`):
2727

2828
## Relevant logs

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
test/transcript.test.js \
4242
test/state.test.js \
4343
test/judge.test.js \
44+
test/claude-pid.test.js \
4445
test/setup.test.js \
4546
test/stop-watchdog.test.js \
4647
test/stop-hook.test.js \

.gitignore

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
.idea
1+
.idea
2+
3+
# Per-user Claude Code config + per-session watchdog state files. The
4+
# plugin writes state to .claude/watchdog.claudepid.<PID>.local.json and
5+
# users may also drop their own .claude/settings.json here when testing
6+
# the plugin against a local marketplace. None of this should ever land
7+
# in the repo.
8+
.claude/

CONTRIBUTING.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Common types:
8181

8282
## Testing your change
8383

84-
Watchdog ships with 59 automated tests using Node's built-in `node:test` runner — no external test dependencies. Run them from the repo root:
84+
Watchdog ships with 75 automated tests (73 active + 2 skipped-when-inside-Claude-Code) using Node's built-in `node:test` runner — no external test dependencies. Run them from the repo root:
8585

8686
```bash
8787
# Node 22+: glob pattern
@@ -100,12 +100,13 @@ node --test test/transcript.test.js
100100
The suite covers:
101101

102102
- **`test/transcript.test.js`** — JSONL parser, real-vs-tool_result user turn detection, tool_use extraction
103-
- **`test/state.test.js`** — atomic state file writes, merge updates, validation, per-session path keying
103+
- **`test/state.test.js`** — atomic state file writes, merge updates, validation, per-session path keying, concurrent-session enumeration
104104
- **`test/judge.test.js`** — verdict parser (FILE_CHANGES substring trap, ambiguous, empty, multi-token)
105-
- **`test/setup.test.js`** — E2E subprocess tests for `scripts/setup-watchdog.js`
106-
- **`test/stop-watchdog.test.js`** — E2E subprocess tests for `scripts/stop-watchdog.js`
107-
- **`test/stop-hook.test.js`** — E2E subprocess tests for `hooks/stop-hook.js` covering the recursion guard, ownership claim, max iterations cap, missing transcript, and pure-text turn branches (Haiku subprocess not invoked)
108-
- **`test/stop-hook-haiku.test.js`** — E2E integration tests that exercise the **real** `spawnSync('claude', ...)` subprocess path by placing a cross-platform mock Claude CLI (POSIX shell script + Windows `.cmd` wrapper) on the hook's `PATH`. Tests all verdict branches: FILE_CHANGES / NO_FILE_CHANGES / ambiguous (both markers) / ambiguous (neither marker) / CLI failure
105+
- **`test/claude-pid.test.js`** — process ancestry walk (lib/claude-pid.js): isClaudeProcessName heuristic, WATCHDOG_CLAUDE_PID env override, readProcComm / readProcPpid
106+
- **`test/setup.test.js`** — E2E subprocess tests for `scripts/setup-watchdog.js` including concurrent-session independence
107+
- **`test/stop-watchdog.test.js`** — E2E subprocess tests for `scripts/stop-watchdog.js`, including the "only cancels THIS session, leaves concurrent sessions alone" assertion
108+
- **`test/stop-hook.test.js`** — E2E subprocess tests for `hooks/stop-hook.js` covering the natural recursion isolation (different claudePid = different state file), max iterations cap, missing transcript, pure-text turn, and 3-concurrent-sessions scenario (Haiku subprocess not invoked — see next file)
109+
- **`test/stop-hook-haiku.test.js`** — E2E integration tests that exercise the **real** `spawnSync('claude', ...)` subprocess path by placing a mock Claude CLI (POSIX shell script + Windows `.cmd` wrapper) on the hook's `PATH`. Tests all verdict branches: FILE_CHANGES / NO_FILE_CHANGES / ambiguous (both markers) / ambiguous (neither marker) / CLI failure
109110

110111
In addition to the unit/integration suite, you should **also** manually verify your change in a live Claude Code session:
111112

NOTICE

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,23 @@ introduces the following substantive modifications:
7070
logic is extracted into reusable modules under lib/ (constants,
7171
state, transcript, judge, log, stdin), consumed by three thin
7272
entry points (setup-watchdog.js, stop-watchdog.js, stop-hook.js).
73-
The port is covered by 53 tests using Node's built-in node:test
74-
runner (no external test dependencies).
73+
The port is covered by an automated test suite using Node's
74+
built-in node:test runner (no external test dependencies).
75+
76+
- Replaced TERM_SESSION_ID with a process-ancestry walk to find the
77+
parent Claude Code process ID (v1.2.0). Most terminal emulators
78+
(Windows Terminal, macOS Terminal.app, GNOME Terminal, Alacritty,
79+
tmux/screen, plain Linux ttys) do NOT export TERM_SESSION_ID —
80+
only JetBrains IDE terminals, iTerm2, and WezTerm do — so the
81+
v1.1.0 plugin was unusable for the majority of users. v1.2.0
82+
walks the process tree upward from its own ppid until it finds a
83+
process whose name is `claude`, and uses that PID as the
84+
per-session state file key. This also eliminates the need for
85+
the owner_session_id recursion guard: the headless Haiku
86+
classifier subprocess naturally gets its own fresh Claude Code
87+
process with a fresh PID, and its recursive Stop hook walks up
88+
to find THAT PID (not the main session's), so state files are
89+
naturally isolated without any explicit ownership bookkeeping.
7590

7691
Files significantly modified from their ralph-loop originals include:
7792

@@ -87,5 +102,6 @@ Files significantly modified from their ralph-loop originals include:
87102
- lib/judge.js (new in Watchdog 1.1.0)
88103
- lib/log.js (new in Watchdog 1.1.0)
89104
- lib/stdin.js (new in Watchdog 1.1.0)
105+
- lib/claude-pid.js (new in Watchdog 1.2.0)
90106

91107
See each file's header comment for a per-file attribution notice.

README.es.md

Lines changed: 20 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
66
[![Claude Code](https://img.shields.io/badge/Claude%20Code-2.1%2B-7C4DFF.svg)](https://docs.anthropic.com/claude-code)
7-
[![Version](https://img.shields.io/badge/version-1.1.0-green.svg)](./.claude-plugin/plugin.json)
7+
[![Version](https://img.shields.io/badge/version-1.2.0-green.svg)](./.claude-plugin/plugin.json)
88
[![GitHub stars](https://img.shields.io/github/stars/JonyanDunh/claude-code-watchdog?style=flat&color=yellow)](https://github.com/JonyanDunh/claude-code-watchdog/stargazers)
99
[![Inspired by ralph-loop](https://img.shields.io/badge/Inspired%20by-ralph--loop-orange.svg)](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/ralph-loop)
1010

@@ -61,7 +61,7 @@ Todo lo demás es automático. El agent nunca se entera de que hay un bucle corr
6161
- **Cero trampas del agent** — Al agent nunca se le dice que está dentro de un bucle. Sin `systemMessage`, sin contador de iteraciones, sin banner de arranque. No puede atajar emitiendo una señal de completado falsa.
6262
- **Verificación con herramientas obligatoria** — Un turno de puro texto ("Lo he revisado, todo bien") jamás termina el bucle. El agent **tiene que** invocar una herramienta de verdad antes de que siquiera se plantee la salida.
6363
- **Detección de cambios de archivos juzgada por un LLM y consciente del proyecto** — Una llamada headless a `claude -p --model haiku` es el **único** juez de "¿este turno modificó algún archivo del proyecto?". Ve la entrada completa de cada invocación de herramienta y decide semánticamente.
64-
- **Aislamiento por sesión** — El archivo de estado se indexa por `TERM_SESSION_ID`, así que lanzar varios watchdogs en distintas pestañas de terminal nunca choca.
64+
- **Aislamiento por sesión** — El archivo de estado se indexa por el ID del proceso padre de Claude Code, descubierto recorriendo la ascendencia de procesos. 100 watchdogs concurrentes en el mismo directorio de proyecto nunca chocan.
6565
- **Oculto por diseño** — Toda la salida de diagnóstico va a stderr. El transcript JSONL nunca filtra metadatos del bucle al contexto del agent.
6666
- **Apache 2.0** — Derivado de forma limpia del propio plugin `ralph-loop` de Anthropic, con la atribución completa en [NOTICE](./NOTICE).
6767

@@ -121,38 +121,35 @@ Si alguna de las dos falla, el bucle continúa. Rutas de salida adicionales:
121121

122122
## Archivo de estado
123123

124-
El estado por sesión vive en `.claude/watchdog.<TERM_SESSION_ID>.local.json`:
124+
El estado por sesión vive en `.claude/watchdog.claudepid.<PID>.local.json`, donde `<PID>` es el ID del proceso padre de Claude Code descubierto recorriendo la ascendencia de procesos. Ejemplo:
125125

126126
```json
127127
{
128128
"active": true,
129129
"iteration": 3,
130130
"max_iterations": 20,
131-
"term_session_id": "c387e44a-afcd-4c0d-95da-5dc7cd2d8b22",
132-
"started_at": "2026-04-10T12:00:00Z",
131+
"claude_pid": 1119548,
132+
"started_at": "2026-04-11T12:00:00Z",
133133
"prompt": "Fix the flaky auth tests..."
134134
}
135135
```
136136

137-
Cada sesión tiene su propio archivo, indexado por `TERM_SESSION_ID`. Lanzar varios watchdogs en distintas pestañas de terminal funciona sin conflictos.
137+
Cada sesión de Claude Code tiene un PID distinto, así que **100 watchdogs concurrentes en el mismo directorio de proyecto nunca chocan** — cada uno tiene su propio archivo de estado, y `/watchdog:stop` en cualquiera de ellos solo cancela el bucle de esa sesión concreta.
138138

139139
**Monitorizar los watchdogs activos:**
140140

141141
```bash
142142
# Lista todos los archivos de estado por sesión activos en este proyecto
143-
ls .claude/watchdog.*.local.json
143+
ls .claude/watchdog.claudepid.*.local.json
144144

145-
# Iteración actual de una sesión concreta
146-
jq .iteration .claude/watchdog.<SESSION_ID>.local.json
147-
148-
# Estado completo
149-
jq . .claude/watchdog.<SESSION_ID>.local.json
145+
# Inspecciona uno con jq o node
146+
node -e "console.log(JSON.parse(require('fs').readFileSync('.claude/watchdog.claudepid.<PID>.local.json','utf8')))"
150147
```
151148

152149
**Matar manualmente todo lo que haya en este proyecto:**
153150

154151
```bash
155-
rm -f .claude/watchdog.*.local.json
152+
rm -f .claude/watchdog.claudepid.*.local.json
156153
```
157154

158155
---
@@ -292,14 +289,11 @@ El clasificador Haiku no es infalible. Un agent atascado que no para de hacer ed
292289

293290
## Requisitos
294291

295-
Watchdog 1.1.0 es una **reescritura en Node.js**. Nada de bash, nada de jq, nada de POSIX coreutils — solo necesitas `node` y el `claude` CLI. Corre de forma nativa en Linux, macOS y Windows.
296-
297292
| Requisito | Por qué |
298293
| --- | --- |
299294
| **Claude Code 2.1+** | Usa el sistema de `Stop hook` y el formato de plugin del marketplace |
300-
| **`node`** 18+ en el `PATH` | Toda la lógica de los hooks y del setup está escrita en JavaScript. `node:test` (que usa la suite de tests) requiere Node 18+ |
295+
| **`node`** 18+ en el `PATH` | Runtime de los hooks y scripts de setup del plugin |
301296
| **`claude` CLI** en el `PATH` | Se usa para la llamada headless de clasificación con Haiku. Tiene que estar autenticado (OAuth o `ANTHROPIC_API_KEY`) |
302-
| Variable de entorno **`TERM_SESSION_ID`** | Indexa el archivo de estado por sesión. La definen la mayoría de emuladores de terminal (iTerm2, WezTerm, terminales modernas de Linux). Workaround si no está definida: `export TERM_SESSION_ID=$(node -e "console.log(require('crypto').randomUUID())")` antes de lanzar `claude`. |
303297

304298
### Instalar dependencias
305299

@@ -347,16 +341,13 @@ scoop install nodejs-lts
347341
# o bájate el instalador desde https://nodejs.org
348342
```
349343

350-
No hace falta WSL2 ni Git Bash — Watchdog 1.1.0 corre directo en Windows nativo.
351-
352344
### Soporte de plataformas
353345

354346
| Plataforma | Estado |
355347
| --- | --- |
356348
| Linux (Node 18 / 20 / 22) | ✅ Probado en CI |
357349
| macOS (Node 18 / 20 / 22) | ✅ Probado en CI |
358-
| Windows (Node 18 / 20 / 22) | ✅ Probado en CI (PowerShell / cmd nativo, sin WSL2) |
359-
| WSL2 en Windows | ✅ Funciona (es Linux) |
350+
| Windows (Node 18 / 20 / 22) | ✅ Probado en CI |
360351

361352
---
362353

@@ -382,18 +373,21 @@ claude-code-watchdog/
382373
├── lib/ # módulos compartidos (reutilizados por todos los entry points)
383374
│ ├── constants.js # patrón del path del estado, tokens marcadores, plantillas de prompt
384375
│ ├── log.js # diagnósticos por stderr
385-
│ ├── stdin.js # lector síncrono de stdin cross-platform
376+
│ ├── stdin.js # lector síncrono de stdin
386377
│ ├── state.js # ciclo de vida atómico del archivo de estado
387378
│ ├── transcript.js # parser JSONL + extracción de herramientas del turno actual
388-
│ └── judge.js # subproceso headless de Haiku + parser del veredicto
379+
│ ├── judge.js # subproceso headless de Haiku + parser del veredicto
380+
│ └── claude-pid.js # recorrido de la ascendencia de procesos
389381
├── test/ # tests unitarios + de integración con node:test
390382
│ ├── fixtures/ # fixtures JSONL de transcripts
391383
│ ├── transcript.test.js
392384
│ ├── state.test.js
393385
│ ├── judge.test.js
386+
│ ├── claude-pid.test.js
394387
│ ├── setup.test.js
395388
│ ├── stop-watchdog.test.js
396-
│ └── stop-hook.test.js
389+
│ ├── stop-hook.test.js
390+
│ └── stop-hook-haiku.test.js
397391
├── .github/ # workflow de CI (matriz node --test, jsonlint, markdownlint) + plantillas de issue/PR
398392
├── .gitattributes # fuerza los finales de línea LF
399393
├── LICENSE # Apache License 2.0
@@ -402,32 +396,6 @@ claude-code-watchdog/
402396
└── README.{zh,ja,ko,es,vi,pt}.md # traducciones
403397
```
404398

405-
## Tests
406-
407-
Watchdog 1.1.0 viene con 59 tests automatizados usando el runner `node:test` integrado de Node — sin dependencias externas. Lánzalos desde la raíz del repo.
408-
409-
**Node 22+:**
410-
411-
```bash
412-
node --test 'test/*.test.js'
413-
```
414-
415-
**Node 18 / 20** (el soporte de globs se añadió en Node 21, así que o dejas que tu shell expanda el patrón, o listas los archivos a mano):
416-
417-
```bash
418-
node --test test/*.test.js
419-
```
420-
421-
Ejecuta solo un archivo:
422-
423-
```bash
424-
node --test test/transcript.test.js
425-
```
426-
427-
El CI corre la suite completa en `ubuntu-latest`, `macos-latest` y `windows-latest` con Node 18 / 20 / 22 en cada push y pull request.
428-
429-
---
430-
431399
## Inspirado en
432400

433401
Watchdog es un trabajo derivado del plugin [**ralph-loop**](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/ralph-loop) de Anthropic (Apache License 2.0, © Anthropic, PBC). El `ralph-loop` original usaba un protocolo con etiquetas XML `<promise>COMPLETE</promise>` donde el agent declaraba explícitamente haber terminado.
@@ -439,9 +407,9 @@ Watchdog mantiene el mecanismo central — un `Stop hook` que vuelve a inyectar
439407
| **Disparador de salida** | El clasificador headless con Haiku es el **único** juez. Lee la entrada completa de cada invocación de herramienta y decide semánticamente si se modificó directamente algún archivo del proyecto. | El agent tiene que emitir una etiqueta XML `<promise>…</promise>` en su texto final. La frase dentro de las etiquetas es configurable vía `--completion-promise "…"` (por ejemplo `COMPLETE`, `DONE`). Un grep en el `Stop hook` busca la cadena exacta. |
440408
| **Precondición de salida** | Hay que haber llamado a herramientas **Y** que Haiku diga `NO_FILE_CHANGES` | Basta con que coincida el texto del `<promise>`. El agent puede hacer trampa emitiendo la etiqueta antes de tiempo; la única defensa de ralph-loop es un prompt que le pide al agent que no mienta. |
441409
| **Visibilidad para el agent** | Completamente oculto (sin systemMessage, sin banner, diagnósticos solo por stderr) | Al agent se le informa del bucle y del protocolo del promise |
442-
| **Ámbito del estado** | Archivo por sesión, indexado por `TERM_SESSION_ID` | Archivo único de estado a nivel de proyecto |
410+
| **Ámbito del estado** | Un archivo de estado por cada sesión de Claude Code — sin límite de watchdogs concurrentes en el mismo proyecto | Un solo archivo de estado por proyecto — solo UN ralph-loop puede correr por proyecto a la vez |
443411
| **Formato del archivo de estado** | JSON (parseado con `JSON.parse` nativo) | Markdown con frontmatter YAML (parseado con sed/awk/grep) |
444-
| **Runtime** | Node.js 18+ — cross-platform (Linux, macOS, Windows nativo) | Bash + jq + POSIX coreutils — solo Unix |
412+
| **Runtime** | Node.js 18+ | Bash + jq + POSIX coreutils |
445413

446414
Ver [`NOTICE`](./NOTICE) para la atribución completa y el listado detallado de modificaciones.
447415

0 commit comments

Comments
 (0)