loopy-loop 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. loopy_loop-0.3.0/.github/workflows/docs-deploy.yml +66 -0
  2. loopy_loop-0.3.0/AGENTS.md +80 -0
  3. loopy_loop-0.3.0/CHANGELOG.md +88 -0
  4. loopy_loop-0.3.0/CLAUDE.md +17 -0
  5. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/Makefile +2 -2
  6. loopy_loop-0.3.0/PKG-INFO +515 -0
  7. loopy_loop-0.3.0/README.md +475 -0
  8. loopy_loop-0.3.0/design/analysis/codex_parallel_analysis.md +665 -0
  9. loopy_loop-0.3.0/design/analysis/loopy-loop-state-and-roadmap.md +445 -0
  10. loopy_loop-0.3.0/design/analysis/synthesis.md +274 -0
  11. loopy_loop-0.3.0/design/decisions.md +205 -0
  12. loopy_loop-0.3.0/design/designs/documentation-site.md +302 -0
  13. loopy_loop-0.3.0/design/designs/improvement-proposals.md +385 -0
  14. loopy_loop-0.3.0/design/designs/success-semantics-and-evaluation.md +189 -0
  15. loopy_loop-0.3.0/docs/http-contract.md +164 -0
  16. loopy_loop-0.3.0/docs/images/logo.png +0 -0
  17. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/docs/session-layout.md +18 -0
  18. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/pyproject.toml +3 -3
  19. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/skills/loopy-loop/SKILL.md +2 -2
  20. loopy_loop-0.3.0/skills-lock.json +16 -0
  21. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/cli.py +13 -2
  22. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/config.py +18 -0
  23. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/coordinator_app.py +221 -27
  24. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/models.py +24 -0
  25. loopy_loop-0.3.0/src/loopy_loop/recovery.py +262 -0
  26. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/worker.py +40 -5
  27. loopy_loop-0.3.0/src/loopy_loop/worker_identity.py +102 -0
  28. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_coordinator_app.py +25 -21
  29. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_idempotent_finished.py +7 -3
  30. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_worker.py +8 -2
  31. loopy_loop-0.3.0/src/tests/test_worker_liveness_recovery.py +728 -0
  32. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/uv.lock +5 -5
  33. loopy_loop-0.3.0/website/.gitignore +25 -0
  34. loopy_loop-0.3.0/website/README.md +71 -0
  35. loopy_loop-0.3.0/website/mdx-components.tsx +36 -0
  36. loopy_loop-0.3.0/website/next.config.ts +26 -0
  37. loopy_loop-0.3.0/website/package-lock.json +4779 -0
  38. loopy_loop-0.3.0/website/package.json +41 -0
  39. loopy_loop-0.3.0/website/postcss.config.mjs +8 -0
  40. loopy_loop-0.3.0/website/public/.nojekyll +0 -0
  41. loopy_loop-0.3.0/website/public/CNAME +1 -0
  42. loopy_loop-0.3.0/website/src/app/docs/child-sessions/page.mdx +135 -0
  43. loopy_loop-0.3.0/website/src/app/docs/cli-reference/page.mdx +104 -0
  44. loopy_loop-0.3.0/website/src/app/docs/concepts/page.mdx +63 -0
  45. loopy_loop-0.3.0/website/src/app/docs/configuration/page.mdx +118 -0
  46. loopy_loop-0.3.0/website/src/app/docs/evaluation/page.mdx +110 -0
  47. loopy_loop-0.3.0/website/src/app/docs/getting-started/page.mdx +122 -0
  48. loopy_loop-0.3.0/website/src/app/docs/http-contract/page.mdx +215 -0
  49. loopy_loop-0.3.0/website/src/app/docs/layout.tsx +46 -0
  50. loopy_loop-0.3.0/website/src/app/docs/page.mdx +37 -0
  51. loopy_loop-0.3.0/website/src/app/docs/session-layout/page.mdx +202 -0
  52. loopy_loop-0.3.0/website/src/app/docs/success-and-control/page.mdx +172 -0
  53. loopy_loop-0.3.0/website/src/app/docs/troubleshooting/page.mdx +186 -0
  54. loopy_loop-0.3.0/website/src/app/docs/workflows/page.mdx +126 -0
  55. loopy_loop-0.3.0/website/src/app/globals.css +166 -0
  56. loopy_loop-0.3.0/website/src/app/layout.tsx +46 -0
  57. loopy_loop-0.3.0/website/src/app/page.tsx +49 -0
  58. loopy_loop-0.3.0/website/src/components/docs/DocsPageNavigation.tsx +42 -0
  59. loopy_loop-0.3.0/website/src/components/docs/DocsSidebar.tsx +62 -0
  60. loopy_loop-0.3.0/website/src/components/docs/DocsTableOfContents.tsx +81 -0
  61. loopy_loop-0.3.0/website/src/components/docs/MobileDocsSidebar.tsx +54 -0
  62. loopy_loop-0.3.0/website/src/components/search/SearchCommand.tsx +181 -0
  63. loopy_loop-0.3.0/website/src/components/site/SiteHeader.tsx +38 -0
  64. loopy_loop-0.3.0/website/src/lib/docs/navigation.ts +64 -0
  65. loopy_loop-0.3.0/website/src/lib/search/pagefind.ts +86 -0
  66. loopy_loop-0.3.0/website/src/lib/utils.ts +7 -0
  67. loopy_loop-0.3.0/website/tsconfig.json +42 -0
  68. loopy_loop-0.2.0/CHANGELOG.md +0 -41
  69. loopy_loop-0.2.0/PKG-INFO +0 -408
  70. loopy_loop-0.2.0/README.md +0 -368
  71. loopy_loop-0.2.0/docs/http-contract.md +0 -106
  72. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.eval-banana/config.toml +0 -0
  73. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.github/workflows/ci.yml +0 -0
  74. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.github/workflows/release.yml +0 -0
  75. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.gitignore +0 -0
  76. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.team-harness/config.toml +0 -0
  77. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.team-harness/coordinator_system_message.md +0 -0
  78. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.team-harness/worker_footer.md +0 -0
  79. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/.team-harness/worker_suffix.md +0 -0
  80. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/LICENSE +0 -0
  81. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/__init__.py +0 -0
  82. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/harness_runner.py +0 -0
  83. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/scheduler.py +0 -0
  84. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/sessions.py +0 -0
  85. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/state_store.py +0 -0
  86. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.gitignore +0 -0
  87. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/eval_reviewer/config.yaml +0 -0
  88. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/eval_reviewer/prompt.txt +0 -0
  89. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/eval_runner/config.yaml +0 -0
  90. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/eval_runner/prompt.txt +0 -0
  91. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/inner/config.yaml +0 -0
  92. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/inner/prompt.txt +0 -0
  93. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/outer/config.yaml +0 -0
  94. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/.loopy_loop/workflow_sets/inner_outer_eval/workflows/outer/prompt.txt +0 -0
  95. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/loopy_loop_config.yaml +0 -0
  96. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/inner_outer_eval/loopy_loop_goal.txt +0 -0
  97. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/.gitignore +0 -0
  98. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/.loopy_loop/workflow_sets/pm_planner_dispatcher/workflows/dispatcher/config.yaml +0 -0
  99. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/.loopy_loop/workflow_sets/pm_planner_dispatcher/workflows/dispatcher/prompt.txt +0 -0
  100. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/.loopy_loop/workflow_sets/pm_planner_dispatcher/workflows/planner/config.yaml +0 -0
  101. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/.loopy_loop/workflow_sets/pm_planner_dispatcher/workflows/planner/prompt.txt +0 -0
  102. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/loopy_loop_config.yaml +0 -0
  103. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/loopy_loop/templates/pm_planner_dispatcher/loopy_loop_goal.txt +0 -0
  104. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/__init__.py +0 -0
  105. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/conftest.py +0 -0
  106. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_api_base_normalization.py +0 -0
  107. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_cli.py +0 -0
  108. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_config.py +0 -0
  109. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_examples.py +0 -0
  110. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_fresh_run_archive.py +0 -0
  111. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_goal_check_gate.py +0 -0
  112. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_goal_hash_derivation.py +0 -0
  113. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_harness_runner.py +0 -0
  114. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_must_follow_success.py +0 -0
  115. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_scheduler.py +0 -0
  116. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_sessions.py +0 -0
  117. {loopy_loop-0.2.0 → loopy_loop-0.3.0}/src/tests/test_state_store.py +0 -0
@@ -0,0 +1,66 @@
1
+ name: Docs Site
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ paths:
7
+ - "website/**"
8
+ - ".github/workflows/docs-deploy.yml"
9
+ pull_request:
10
+ branches: ["main"]
11
+ paths:
12
+ - "website/**"
13
+ - ".github/workflows/docs-deploy.yml"
14
+ workflow_dispatch:
15
+
16
+ # Allow GITHUB_TOKEN to deploy to GitHub Pages.
17
+ permissions:
18
+ contents: read
19
+ pages: write
20
+ id-token: write
21
+
22
+ jobs:
23
+ build:
24
+ runs-on: ubuntu-latest
25
+ defaults:
26
+ run:
27
+ working-directory: website
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+
31
+ - uses: actions/setup-node@v4
32
+ with:
33
+ node-version: "22"
34
+ cache: npm
35
+ cache-dependency-path: website/package-lock.json
36
+
37
+ - name: Install dependencies
38
+ run: npm ci
39
+
40
+ # `next build` type-checks the project and generates .next/types, so a
41
+ # separate pre-build `tsc` step is intentionally omitted (it would run
42
+ # before those generated types exist).
43
+ - name: Build static site (Next.js export + Pagefind index)
44
+ run: npm run build
45
+
46
+ - name: Upload Pages artifact
47
+ uses: actions/upload-pages-artifact@v3
48
+ with:
49
+ path: website/out
50
+
51
+ deploy:
52
+ # Only publish from main; PRs run the build job above as a check.
53
+ if: github.ref == 'refs/heads/main' && github.event_name != 'pull_request'
54
+ needs: build
55
+ runs-on: ubuntu-latest
56
+ # Serialize production deployments only, so PR build-checks stay concurrent.
57
+ concurrency:
58
+ group: "pages-deploy"
59
+ cancel-in-progress: false
60
+ environment:
61
+ name: github-pages
62
+ url: ${{ steps.deployment.outputs.page_url }}
63
+ steps:
64
+ - name: Deploy to GitHub Pages
65
+ id: deployment
66
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,80 @@
1
+ # AGENTS.md — working agreement for this repo
2
+
3
+ `loopy-loop` runs long-running AI agent workflows inside a repository. A FastAPI
4
+ **coordinator** owns durable loop state in files and picks the next workflow; a single
5
+ **worker** runs each assignment through `team-harness`. Continuity lives in files and git,
6
+ not in a chat transcript. Read `README.md` for the user-facing model, and
7
+ `design/decisions.md` for *why the system is the way it is*.
8
+
9
+ This file is the working agreement for any agent (or human) changing this repo. Three
10
+ things are non-negotiable.
11
+
12
+ ## Rule 1 — Respect the deliberate decisions; don't "fix" them
13
+
14
+ `design/decisions.md` is the canonical Architecture Decision Log (D1, D2, …). **Several
15
+ decisions there look like defects if you only skim the code, and are recorded precisely so
16
+ they don't get "fixed" by accident.** Before changing behavior in these areas, read the
17
+ relevant decision (and its companion design doc):
18
+
19
+ - **D3 — iteration success ≠ "work is good."** `IterationResult.success` means only that
20
+ the harness ran without erroring. Do not make it consult worker exit codes / infer
21
+ semantic success. The eval layer (`control.json` + `goal_check.json`) decides quality.
22
+ - **D4 — evaluation is LLM-as-judge; agents don't author deterministic checks.** Do not
23
+ "add deterministic checks" to the stock `inner_outer_eval` eval workflows. (A target
24
+ repo that owns its own test suite is a different case — see D4.)
25
+ - **D2 — single worker is deliberate.** Do not add parallel loopy workers as a scaling
26
+ feature.
27
+ - **D5 — full autonomy with a last-resort escape hatch.** See Rule 2.
28
+
29
+ If you believe a decision is genuinely wrong, propose amending `design/decisions.md`
30
+ (state what changes and why) — do not silently contradict it in code.
31
+
32
+ ## Rule 2 — Autonomy is the goal; the human escape hatch is a LAST resort (D5)
33
+
34
+ This system is meant to run **fully autonomously, with no human in the loop**. Human
35
+ involvement is a last resort, never a normal step.
36
+
37
+ - **The one sanctioned escape hatch already exists.** When a workflow hits a *genuinely
38
+ terminal* blocker — a decision only a human can make, a missing credential, a
39
+ billable/destructive action it isn't permitted to take — it writes the session
40
+ `control.json` with:
41
+ ```json
42
+ {"state": "stopped", "reason": "<specific terminal blocker>", "stop_reason": "unresolvable_error", "schema_version": 1}
43
+ ```
44
+ This stops the loop as terminal, with a recorded reason. That is the entire
45
+ human-in-the-loop mechanism, and it is enough.
46
+ - **Exhaust autonomous options first.** Re-scope, retry with a better child goal, route
47
+ around the blocker. Reach for `unresolvable_error` only when a blocker is genuinely
48
+ unavoidable without a human. It should fire rarely.
49
+ - **Make the give-up legible.** The recorded blocker is the only thing a human sees when a
50
+ run stops — state exactly what was missing and what was tried.
51
+ - **Do NOT build or assume a preferred human gate.** No `paused` / `waiting_for_human`
52
+ state, no `gate_request.json`, no external-action approval flow. That was considered and
53
+ rejected (D5; `design/designs/improvement-proposals.md` P0.2). Do not pause a run to ask
54
+ a question when you could either solve it autonomously or stop cleanly with
55
+ `unresolvable_error`.
56
+
57
+ ## Rule 3 — Design and decision docs must be understandable cold, by future agents AND humans
58
+
59
+ A design or decision doc is read by someone who was **not** in the conversation that
60
+ produced it — a future agent with no memory of this session, or a human who is not a
61
+ specialist. Write for them.
62
+
63
+ - **Explain, don't just name.** Naming a mechanism ("the ping-pong protocol", "cadence
64
+ scheduling", "the double loop") is not explaining it. State, in plain language, *what it
65
+ is, what problem it solves, and why we chose it*, with a concrete example where it helps.
66
+ - **The reasoning lives in the doc, not in your head.** Don't rely on a future reader
67
+ re-deriving the rationale. A decision-log entry may state the conclusion tersely; the
68
+ companion design section must be self-contained.
69
+ - **Anchor claims in the code.** Reference the file/function (e.g. `coordinator_app.py`,
70
+ `harness_runner.py`) so a reader can verify — but lead with the plain-English meaning.
71
+ - **Keep `design/` honest about status.** `design/designs/` is binding; `design/analysis/`
72
+ is working notes (may be superseded); `improvement-proposals.md` is *proposed, not
73
+ decided*. Don't cite a proposal as if it were a decision.
74
+
75
+ When in doubt on any rule, favor the version a stranger could read cold and fully
76
+ understand.
77
+
78
+ ---
79
+
80
+ Note: `CLAUDE.md` points here. Keep this file as the single source; don't fork the two.
@@ -0,0 +1,88 @@
1
+ # Changelog
2
+
3
+ ## 0.3.0 (breaking)
4
+
5
+ **Breaking API change — `/register` requires the worker's process identity.**
6
+ A register without a `worker` object is rejected with HTTP 400. Pre-0.3
7
+ workers cannot register against a 0.3 coordinator; upgrade workers and
8
+ coordinator together (they normally ship in the same install).
9
+
10
+ - **Worker liveness verification (D7).** The worker sends its process
11
+ identity (hostname + pid + a pid-reuse-proof start-time token) with
12
+ `/register` and `/finished`; the coordinator stamps it onto the dispatched
13
+ task. A `/register` while the recorded worker is *verifiably still alive*
14
+ returns HTTP 409 instead of abandoning live work — closing the
15
+ duplicate-work window. Unverifiable identities (remote hosts, or a
16
+ team-harness without process identity) keep the pre-existing
17
+ assume-abandoned recovery behavior. Because every dispatched task now has
18
+ a recorded owner, a stale `/finished` is replayed **only to that owner**
19
+ (anyone else gets HTTP 409) — a task persisted by a pre-identity version
20
+ keeps the legacy replay for that one resume.
21
+ - **Orphaned-agent recovery (P2.5 / TH-D5 consumer side).** When a worker is
22
+ confirmed dead with nothing recoverable, the coordinator applies
23
+ `recovery_policy` (new coordinator-side config, NOT part of the wire
24
+ snapshot; default `drain`, one shared `recovery_drain_timeout_s` deadline,
25
+ default 600s) to agent processes the dead worker's harness run left behind,
26
+ via team-harness's process reaper: drained agents finish and their repo
27
+ edits survive; a `salvage.json` in the interrupted iteration directory
28
+ records what was handled; the history entry is `abandoned_after_<policy>`
29
+ when anything settled. Recovery runs OUTSIDE the state lock (`loopy
30
+ status`/`stop` stay usable while draining), validates that each discovered
31
+ run record actually belongs to the iteration, is same-host-only (a worker
32
+ identity from another hostname skips reaping), and refuses to dispatch
33
+ replacement work (HTTP 409) when any orphan may still be running or when
34
+ team-harness's parent-liveness guard reports the run's owner alive.
35
+ Requires team-harness with the process reaper (> 0.2.10); older versions
36
+ skip orphan recovery gracefully.
37
+ - A stale `/finished` from a **different identified worker** now gets HTTP 409
38
+ instead of a second copy of the live task; unknown identities keep the
39
+ pre-existing stale-retry behavior. State-lock contention surfaces as a clean
40
+ HTTP 503 (and friendly CLI errors) instead of raw tracebacks.
41
+ - The bundled worker uses an unbounded read timeout on `/register` only
42
+ (recovery can legitimately block registration up to the drain deadline),
43
+ keeps the bounded timeout on `/finished`, and exits with code 3 on a 409.
44
+
45
+ ## 0.2.1
46
+
47
+ - Improve README onboarding, install, initialization, configuration, and logging docs.
48
+ - Update package and skill descriptions to avoid unclear repository-scope jargon.
49
+
50
+ ## 0.2.0 (breaking)
51
+
52
+ **Breaking API change — drop leases, polling, and worker identity.**
53
+
54
+ The three-endpoint API (`POST /workers/register`, `POST /workers/{worker_id}/next`,
55
+ `POST /workers/{worker_id}/finished`) is replaced by a two-endpoint ping-pong API:
56
+
57
+ - `POST /register` — returns `TaskResponse` directly (`action: "run"` or `"stop"`).
58
+ - `POST /finished` — returns `TaskResponse` for the next task or stop signal.
59
+
60
+ The `"wait"` action is gone. The worker loop is now a simple `while task.action == "run"`
61
+ loop with no polling.
62
+
63
+ **Removed models and fields:**
64
+ - `WorkerState`, `ActiveAssignment`, `RegisterWorkerResponse`, `NextActionResponse` removed.
65
+ - `assignment_id` removed from `FinishedRequest` and `HistoryEntry`.
66
+ - `worker_id` removed from `HistoryEntry`.
67
+ - `workers` dict and `active_assignment` removed from `LoopState`.
68
+ - Constants `DEFAULT_LEASE_SECONDS`, `DEFAULT_POLL_INTERVAL_SECONDS`,
69
+ `DEFAULT_FINISHED_RETRY_ATTEMPTS`, `DEFAULT_FINISHED_RETRY_BACKOFF_SECONDS`,
70
+ `WAIT_ACTION` removed.
71
+
72
+ **Added:**
73
+ - `CurrentTask` model replaces `ActiveAssignment` (no `worker_id`, no lease).
74
+ - `TaskResponse` model returned by both `/register` and `/finished`.
75
+ - `LoopState.current_task: CurrentTask | None` replaces `active_assignment`.
76
+
77
+ **Crash recovery:** If a worker crashes mid-run, the next `/register` call detects the
78
+ orphaned `current_task`, records it in history as `error="abandoned"`, and dispatches
79
+ fresh work.
80
+
81
+ **Migration note:** Existing `state.json` files containing `active_assignment` or `workers`
82
+ fields will have those fields silently dropped on first read (Pydantic ignores unknown
83
+ fields). Any in-flight run at upgrade time will lose its `active_assignment` record without
84
+ a history entry. Drain all workers before deploying this version.
85
+
86
+ ## 0.1.0
87
+
88
+ - Initial release.
@@ -0,0 +1,17 @@
1
+ # CLAUDE.md
2
+
3
+ The working agreement for this repo lives in **[`AGENTS.md`](./AGENTS.md)** — read it first.
4
+ It is the single source; this file only points to it so the two never diverge.
5
+
6
+ Quick orientation for what most often trips up a change here:
7
+
8
+ - **`design/decisions.md`** is the canonical decision log. Several decisions look like
9
+ defects if you only skim the code and are recorded so they don't get "fixed" by accident
10
+ (notably **D3** iteration-success semantics and **D4** LLM-as-judge evaluation).
11
+ - **Autonomy is the goal; the human escape hatch is a last resort (D5).** The system runs
12
+ unattended. When a workflow hits a genuinely terminal blocker it stops by writing
13
+ `control.json` with `stop_reason: "unresolvable_error"` and a specific recorded reason —
14
+ that is the entire human-in-the-loop mechanism. Do **not** build or assume a preferred
15
+ `paused` / `waiting_for_human` gate; exhaust autonomous options first, then stop cleanly.
16
+
17
+ See `AGENTS.md` Rules 1–3 for the full agreement.
@@ -7,12 +7,12 @@
7
7
  ## Start Claude Code with MCP configuration
8
8
  claude:
9
9
  @test -f .mcp.json || (echo "Error: .mcp.json not found. Please create it first." && exit 1)
10
- PATH="$(HOME)/.bun/bin:$(PATH)" CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 TELEGRAM_STATE_DIR=$(PWD)/.claude/channels/telegram claude --dangerously-skip-permissions --mcp-config .mcp.json --remote-control
10
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 CLAUDE_CODE_ENABLE_AUTO_MODE=1 claude --dangerously-skip-permissions --mcp-config .mcp.json --remote-control
11
11
 
12
12
  ## Continue previous Claude Code session
13
13
  claudecontinue:
14
14
  @test -f .mcp.json || (echo "Error: .mcp.json not found. Please create it first." && exit 1)
15
- PATH="$(HOME)/.bun/bin:$(PATH)" CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 TELEGRAM_STATE_DIR=$(PWD)/.claude/channels/telegram claude --dangerously-skip-permissions --mcp-config .mcp.json --continue --remote-control
15
+ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 CLAUDE_CODE_ENABLE_AUTO_MODE=1 claude --dangerously-skip-permissions --mcp-config .mcp.json --continue --remote-control
16
16
 
17
17
  ## Codex
18
18
  codex: