gitoriaLog in with ident

antcolony

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit3a4d03243a4d0324antcolony#37: a too-long report gets up to 3 fix tries, finished work is never thrown away for lengthmre3a4d0324/STATUS.md

54.3 KB

  1. # STATUS
  2. ## 2026-09-27 — a report refused only on length keeps its work (antcolony#37) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  3. Cause: the fix step (mission 027) resumed a refused report's Claude session ONCE; a report still refused after that one fix
  4. threw the whole finished session away and restarted the ticket from nothing (seen 3× on 2026-09-27: tracker#1 twice, tracker#3
  5. — each ~10 min / ~$1, only a `decided` line 5 characters too long). Fix: `lib/work.hl` — the fix step now gets up to
  6. `MAX_FIX_TRIES` (3) tries (`meta.fixTries`, persisted in `session.json`), each one resending the exact problems (field,
  7. length, limit) again; only after 3 refused tries does the ticket go back to `open`. `fixPrompt` and the FINALIZE log line now
  8. say "(try N of 3)". `tests/fake-claude.mjs`: `FAKE_FINALIZE_MODE` may be a comma list, one mode per successive fix call, to
  9. simulate "refused, refused, fixed".
  10. Tested: `COLONY_E2E_PORT_BASE=8710 node tests/e2e.mjs` → 352 passed, 0 failed. 2 new checks (antcolony#37): a worker whose
  11. first two reports are too long, fixed on the third try — ONE lease, no second work session, posted; a worker whose report
  12. stays too long for all 3 fix tries → back to open, no controller run. The 3 existing mission-027 fix-step checks updated for
  13. the new "(try 1 of 3)" wording.
  14. ## 2026-09-26 — a ticket waiting for a creator question is not restarted (antcolony#30) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  15. Cause: a half-done ticket goes back to `open`; its creator question is a child, and children that are questions never blocked. Fix: `lib/relations.hl` `blockReason` —
  16. a question child that is neither confirmed nor rejected → "waiting for the creator's answer on X (state)" (`next`, `run`, `work` refuse it); a rejection newer than the last session still outranks a pending question.
  17. Safety net (`lib/next.hl`): a ticket with `COLONY_MAX_STARTS_PER_HOUR` (default 4, 0 = off) session starts in the last hour is not eligible ("restart limit").
  18. Tested: `COLONY_E2E_PORT_BASE=8730 node tests/e2e.mjs` → 351 passed, 0 failed (new checks: half done + open question waits and `work` refuses; confirmed question → continues; edited the m023 check). The restart limit itself has no own e2e check.
  19. ## 2026-09-26 — sealed workers get the sibling projects their gates start (antcolony#33) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  20. Cause: the box already binds every `dependsOn` project's dev folder read-only (`lib/sandbox.hl`), but the registry listed only `hybriel` for tickets and gitoria,
  21. so ident (started by their browser gates from `../ident.worldapi.org`) was not in the box. Fix: `projects/tickets.worldapi.org.json` → dependsOn hybriel + ident;
  22. `projects/gitoria.worldapi.org.json` → hybriel + ident + tickets. Read-only, `.env` masked, no code change. Checked: `./colony box tickets.worldapi.org` now binds ident ro.
  23. Now run: inside `./colony box tickets.worldapi.org --folder <copy>` (bwrap), `node tests/browser.mjs` → 233 passed, 0 failed (ports 8712/8713); the box showed ident read-only (touch fails).
  24. Not run: gitoria's box (its folder is not on this machine).
  25. ## 2026-09-26 — a worker killed for parking is parked, not failed (antcolony#28) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  26. Cause: `running` entries are copies (a Hybriel push copies), so the park reason set at the second SIGTERM never reached the hook the end handler reads;
  27. the killed worker (exit 143) was recorded as WORK FAILED. Fix: process, phase and park reason live in `live[session]` — `lib/daemon.hl` (taken over from
  28. session s-20260926T1538-a97668) and the same fix in `lib/agent.hl`. e2e: `tests/e2e.mjs` has the antcolony#28 park/resume checks (from the earlier session).
  29. Not run: the e2e suites (they break on tickets' new projects, antcolony#31); `lib/agent.hl` only load-checked (`./colony agent` reaches its argument check).
  30. ## 2026-09-26 — only real questions reach the creator (antcolony#24) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  31. Done (README "Only real questions reach the creator"): no question limit; the controller's verdict rules on every question
  32. (ask / decided / trivial / internal / packed); dropped ones become a "Decided" line with the answer, packed ones fail the check.
  33. Files: `lib/controller.hl`, `lib/report.hl`, `templates/controller.md`, `verdict.schema.json`, `report.md`, `tests/fake-claude.mjs`, `tests/e2e.mjs`.
  34. Tested: `bin/hybriel tests/questions-test.hl` (validate / decide / filter); `COLONY_E2E_PORT_BASE=8710 node tests/e2e.mjs` → 351 passed, 0 failed (2026-09-26).
  35. Not run: a real Claude controller (only the fake one rules in tests).
  36. ## 2026-09-26 — short titles for question tickets (antcolony#23) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  37. Done: a report's `questions` entry is now `{ title, text }` — the worker writes the short title (one line, ≤ 80 characters) and it becomes the
  38. subject `Question (<ticket>): <title>`; `text` keeps the old limits (≤ 3 lines, ≤ 300 characters). An old plain string is still accepted (first line = title).
  39. Files: `lib/report.hl` (validate, `questionSubject`, `questionText`), `templates/report.schema.json`, `templates/report.md`, README, `tests/e2e.mjs`.
  40. Tested: `tests/e2e.mjs` on the stable copies (ports 8704/8705): report refusals for a title over 80 characters / a missing title, `report --post` files
  41. "Question (alpha#3): Is it small enough?" — ok. The run stopped later at m026 (EADDRINUSE: other workers' servers on 8706–8712), unrelated to this change;
  42. those and the later suites were not re-run.
  43. ## 2026-09-26 — answers of questions in the brief (antcolony#22) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  44. Done: in "Tickets of <project>" every answered / confirmed creator question is followed by the creator's own comments on it
  45. (quoted, last 3, 600 characters each) — `lib/brief.hl` (`answerLines`). Checked read only: `./colony brief antcolony 22` shows
  46. "Answer of the creator: …" under #5, #10, #11, #12 …. Not run: the big e2e suites; no new test (needs a tickets copy with an answered question).
  47. The creator setting a question to confirmed is the creator's own step (or `/confirm`).
  48. ## 2026-09-26 — small local models for routine decisions (antcolony#20) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  49. Done (README "Small local models"): librarian model `local` / `local:<alias>` → OpenAI-compatible llama-server (`COLONY_LOCAL_URL`), schema enforced by
  50. the server, same `checkAnswer`; unreachable / cut off / refused → Claude fallback (`COLONY_LIBRARIAN_FALLBACK`, default sonnet). Default model unchanged (sonnet).
  51. Files: `lib/librarian.hl` (`localAnswer`, `classify`), `local-test.hl`, `.env.example`, `docker-compose.yml`. Tested: canned text through `classify` with a real
  52. llama-server (granite-4.0-h-micro Q8) → answered; dead port + fallback off → "did not answer"; dead port + fallback → goes to Claude.
  53. Measured (CPU only, no GPU visible in the box; ~55 s per call): granite micro agreed with Claude on only 4 of 8 real prompts (run cut short by the usage limit). Gemma E4B thinks too long (~95 s/call).
  54. Second run (antcolony#20, session s-20260926T1451): Qwen3.5-9B Q4_K_M on CPU (16 threads, thinking off): ~55 tok/s prompt, 3–4 tok/s output; a call ran to the 700-token cap and took 210–270 s — unusable for the librarian on this box; no accuracy number came out. Only a GPU (not visible to the worker box) or a smaller model can work.
  55. Not done / open: no model proven good enough; a bigger model and the GPU were not tested; keep `sonnet` until a measured run (`.scratch/loc/eval.py URL N`) agrees well; the
  56. controller stays on Claude; the e2e suites were not re-run.
  57. ## 2026-09-26 — status and daily summary from tickets (antcolony#19) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  58. Done (README "Status and daily summary"): `lib/status.hl` — `./colony status [--write]` (per-project state table → `status/STATUS.md`),
  59. `./colony digest [--post]` (what waits for the creator, filed once a day as one inbox ticket, source `colony:digest:<day>`);
  60. `run` files it once a day after `COLONY_DIGEST_HOUR` (UTC, default 7, `off` = never). Tested: `node tests/e2e-status.mjs` 12/12;
  61. `tests/e2e-keywords.mjs` 15/15; a dry run against the live tickets (read only) lists 138 waiting.
  62. Not done / open: no mail/push delivery (ident#7 on hold) — the inbox ticket is the delivery; the live container runs the old code until restarted.
  63. ## 2026-09-26 — each worker in its own sealed box (antcolony#18) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  64. Done (README "Sandbox"): every Claude session (worker, finalize, resume, controller) runs in a bubblewrap box built from an
  65. allowlist — system read-only, empty home with only the claude login + toolchain, the project's own folder rw (`.env` masked),
  66. its dependencies' folders + docs read-only, nothing else of the disk; no tokens in the environment; own process namespace.
  67. Deploy rights (live folder rw + `~/.ssh` ro) only for a ticket with the line `colony-deploy: yes` (opening text or creator
  68. comment). Files: `lib/sandbox.hl`, `claude.hl` (`sandbox` option), `work.hl` (`boxOf`, `runBox`, refusal before the lease),
  69. `controller.hl`, `brief.hl` (+ events), `docker-compose.yml` (`COLONY_SANDBOX`, `COLONY_SANDBOX_RO`), `colony box`.
  70. Tested: `node tests/e2e-sandbox.mjs` 19/19; `tests/e2e.mjs` 345/345 (incl. a `work` with the box ON, fake claude), `tests/e2e-agent.mjs` 46/46; a REAL `claude -p` inside the box answers (Chrome headless, node, git too);
  71. bwrap works as uid 1000 inside the live container (`docker exec --user 1000`). The other suites run with `COLONY_SANDBOX=off`.
  72. Not done / open: the network is not restricted (Claude API, tickets, dev servers need it); the Claude login folder is
  73. writable inside (it holds the account's history of ALL colony sessions); nothing marks a ticket for deploy yet (the architect
  74. writes `colony-deploy: yes`); the box takes effect when the architect restarts the container.
  75. ## 2026-09-26 — the end-to-end suites run on tickets' projects and roles (antcolony#31)
  76. Done: `tests/e2e.mjs` (348/348) and `tests/e2e-agent.mjs` (46/46) run against the current tickets + ident folders. The creator logs in
  77. first (admin) and opens each test project right before its first ticket (`openProject`), with Colony as member `edit`; `antcolony`
  78. is opened up front (the scheduler files questions there). Reads are translated back to the scheduler's own state names
  79. (progress / review / pending / done / reopened → in progress / awaiting creator / on hold / confirmed / rejected; a pending
  80. "Question…" = awaiting creator) and the server's extra `assign` events are left out. The librarian is off in the suite unless its own
  81. section turns it on (the creator is a project admin now, so its comments would start a real librarian call). The old "Colony may not
  82. reject" check is now "Colony (edit) may not change members (403)".
  83. Not done: none. The tickets copy must be in a starting state (another worker's half-written edit once stopped it at boot).
  84. ## 2026-09-26 — new ticket states and roles (antcolony#27) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  85. Done (README "New ticket states and roles"): `lib/tickets.hl` reads the new states (review / pending / done / reopened / progress)
  86. as the old names the logic knows and writes the names the server speaks (asks `GET /api/projects` once); a built ticket → `review`,
  87. a creator question → `pending`, `/hold` → `pending`, `/confirm` → `done`, `/reject` → `reopened`, the lease → `progress`; a reopened
  88. ticket is picked up like a rejected one. The creator = the project's admin (members API), used by librarian + keywords instead of a
  89. name list (the names list stays as the fallback for the old tickets). New `tests/e2e-states.mjs` (own tickets#20 copy): 14/14.
  90. Old suites on the old tickets copy unchanged (see the run files in `.scratch/`).
  91. Not done / open:
  92. - The tickets API never shows the ident short id, and events carry only the author's display name: the admin is matched by name
  93. (by user id as soon as tickets adds `userId` to an event — the code already takes it). Filed as a tickets issue.
  94. - tools/t.py and tools/watch.py on Byrodin are the architect's (read-only for workers).
  95. - The scheduler's and the architect's tokens must be members with role `edit` of every project (admin adds them) — day-of-switch step.
  96. - The big e2e suites still run on the OLD tickets copy (`.scratch/stable`); only `e2e-states.mjs` uses the #20 copy.
  97. ## 2026-09-26 — keywords in comments (antcolony#17)
  98. Done: `lib/keywords.hl` — `/hold`, `/prio`, `/confirm`, `/reject <why>` from the creator's comments (README "Keywords"); `run`
  99. handles them every iteration, `./colony keywords [--post]` by hand; `next` / `run` order eligible tickets by `/prio` then age.
  100. Tested: `tests/e2e-keywords.mjs` 15/15 against own tickets + ident.
  101. Next: tickets' new state `answered` is counted with `awaiting creator` (creator's inbox) in next/run.
  102. Not done / open:
  103. - `/confirm` / `/reject` need the creator's token (`COLONY_CREATOR_TOKEN_FILE`) — tickets lets only the creator do them; until the
  104. creator provides one the scheduler answers "use the button". A tickets feature "act on behalf of the creator" would be cleaner.
  105. - Tickets' new `answered` state (creator's comment on an `awaiting creator` ticket) is not known to `next` / `relations` yet.
  106. - The live container runs the old code until restarted.
  107. ## 2026-09-26 — Claude quota per account, shared across computers (antcolony#16) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  108. Done (README "Claude quota per account"): `agent --account NAME` (`COLONY_CLAUDE_ACCOUNT`, default host name) → sync carries account +
  109. last reading + limit pause; the scheduler (`run --serve`) pools per account: freshest reading, a limit on any host holds all, one
  110. start per account until a newer reading (`--account-settle`, 60 s). Files: `lib/agent.hl`, `lib/daemon.hl` (accountBlock), `scheduler.hl`
  111. usage, `tests/e2e-agent.mjs` §5b. Open: the single-host `run` is unchanged (one host = one account); no account auto-detection.
  112. ## 2026-09-26 — agents announce capabilities (antcolony#15) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  113. Done (README "Capabilities"): `agent --capabilities LIST` (`COLONY_CAPABILITIES`) → sent in every sync; registry `"needs": [..]` per
  114. project; `daemon.hl` starts a new ticket only where the host offers all needs, else `P#n waits — H does not offer: x`. Helpers in
  115. `util.hl`, `needs` parsed in `registry.hl`. Test: `tests/e2e-agent.mjs` extended (+1 check). No project file has `needs` yet
  116. (nothing changes until the architect adds one).
  117. ## 2026-09-26 — scheduler on its own host + an agent per host (mission 035, antcolony#14) — awaiting the architect's check; LIVE CONTAINER UNCHANGED
  118. Done (README "Scheduler + agents per host"): `./colony run --serve PORT` = the scheduler (starts no worker, state in tickets only),
  119. `./colony agent --scheduler URL` = the agent of a host (runs `work` for the commands it gets, owns quota + ports, buffers events while
  120. disconnected). Transport: HTTPS request/answer (`POST /agent/sync`, shared agent token) — Hybriel has no WebSocket client
  121. (hybriel#109, already filed), so the concept's "one WebSocket" is replaced, not faked; same effects. New files: `lib/agent.hl`,
  122. `lib/AgentServer.hl` (hl:http1 server, `plugins/http1` copied from hybriel master), `tests/e2e-agent.mjs`; changed: `daemon.hl`
  123. (serve mode), `work.hl` (`--brief-file`), `brief.hl` (port marker), `tickets.hl` (agent token), `scheduler.hl`, `colony`.
  124. Tested (fake claude only, own tickets+ident, ports 8710-8719): `COLONY_E2E_PORT_BASE=8710 node tests/e2e-agent.mjs` — see the run
  125. 39/39 (`.scratch/t/run3.txt`); the old suite `tests/e2e.mjs`: 343/343 unchanged (`.scratch/t/full1.txt`). Note: the e2e needs a tickets/ident copy that logs in today — the current
  126. ident (ident#23 in progress) breaks the login step of BOTH suites; the runs used yesterday's copies (`COLONY_E2E_TICKETS_DIR` /
  127. `COLONY_E2E_IDENT_DIR`, `.scratch/stable/`).
  128. Not done / open: the Byrodin container files + deploy (architect); the librarian still needs Claude on the scheduler host; the live
  129. Loreana container keeps running the all-in-one `run` (unchanged behaviour, the new code only adds `--serve` / `agent`).
  130. ## 2026-09-26 — antcolony#13 (react to tickets events instead of polling) — BLOCKED on a Hybriel gap, nothing built
  131. Finding: tickets pushes its events only over the hl:web page socket (`/__hl/socket`, frames `ticketCreated` / `ticketEvent`,
  132. sent only to a tab that has said `hello` and mounted a component listening for them). The scheduler would have to be a
  133. WebSocket CLIENT. Hybriel has none: `hl:http1`'s `ws_client.hl` is the SERVER-side peer (natives `http1.ws_send/ws_close/...`
  134. only), `hl:fetch` cannot upgrade (only `stream = true` for chunked/NDJSON bodies), `hl:proc` has no stdin (hybriel#91), and
  135. tickets has no SSE / streaming endpoint to feed `fetch` stream mode. A JS/other-language bridge is forbidden. No code changed.
  136. Filed as a Hybriel gap (report `issues`). Alternative if the architect prefers: tickets gets a streaming endpoint (SSE/NDJSON)
  137. and the scheduler consumes it with `fetch(stream = true)`.
  138. Plan once a source exists: `daemon.hl` — an event (new ticket / comment / state change) triggers `tick()` at once (debounced,
  139. never overlapping the `busy` guard); the `every(interval)` loop stays only as a slow safety net (lease expiry, quota reset,
  140. reconnect gap), default raised from 60 s.
  141. ## 2026-09-25 — the librarian respects the Claude usage limit (mission 034, antcolony#25) — awaiting the architect's check; LIVE CONTAINER NEEDS A RESTART
  142. Why: live 19:58 the 5 h limit was reached, yet every iteration called the librarian's model (answer: subtype `success`,
  143. is_error, 429, empty) → text unfiled → no start, every minute until the reset. Live answer kept: `.scratch/m034/livecheck/`.
  144. Done (README "Usage limit" under `run`, + notes in "Librarian → ORDER", run steps 3/4, "Quota + parking"):
  145. - `daemon.hl`: with the librarian on, `claude -p /usage` FIRST in every iteration; at/above the start threshold (reserve /
  146. week limit; 100 % = reached, also with the checks off) → no librarian call, no start, ITER line `librarian not run: …`.
  147. Reading reused for the start check (re-read if the pass made model calls).
  148. - `claude.hl` rateLimitOf: also the synthetic `error: "rate_limit"` message, 429 without is_error, "session/weekly limit".
  149. Checked on the LIVE result file: limited=true, reset 18:50:00Z.
  150. - `librarian.hl`: a limited call → `→ USAGE LIMIT …`, pass stops, no try counted; summary `limited`, `resetMs`.
  151. - `work.hl` parkRun(…, resetKnown, done) → `limited`/`resetMs` in the result; `run` pauses: `LIMIT: usage limit reached —
  152. librarian and starts paused until <ISO> · <who>` (one line), silent iterations (no librarian / probe / start), `LIMIT:
  153. resumed …` (one line); unknown reset → 15 min. The pause is in-process only (a restart re-probes).
  154. Tested (fake claude only, own tickets+ident 8751/8752, pools 8770-8799): `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs`
  155. - dev copy WITHOUT `.env` (`.scratch/m034/dev/`): 343/343 → `.scratch/m034/e2e-new-noenv-2.txt` (baseline pre-034: 330/330 `e2e-baseline-noenv.txt`)
  156. - THIS folder with the LIVE `.env` present (not read, not changed; mtime still 14:03:28), container running (not touched):
  157. 343/343 → `.scratch/m034/e2e-live-env.txt`; `claude-guard.log` absent = no real claude call
  158. - pre-034 code + new tests (`.scratch/m034/origtest/`): 13 FAILED → `.scratch/m034/e2e-origcode-newtests.txt`
  159. - 3 old checks changed on purpose (README "Tests of mission 034"). Pre-034 code: `.scratch/m034/orig/`.
  160. Not done / open:
  161. - Live container still runs the pre-034 code until `docker compose up -d` (architect). After the restart, check
  162. `logs/colony.log` for `librarian not run: …` / `LIMIT:` lines while the limit is reached.
  163. - Every iteration now spawns the `/usage` probe (1–4 s, $0) also when nothing is to start (needed to guard the librarian).
  164. - The 15-min fallback and the reset times are not verified against a REAL limit hit after the change (fake only).
  165. ## 2026-09-24 — lease expiry must never touch finished tickets (mission 031, antcolony#1) — awaiting the architect's check; LIVE CONTAINER NEEDS A RESTART
  166. Why: ITER 45 (21:05Z) expired ident#19 1.9 s after `./colony deployed` had moved it to awaiting creator (stale survey +
  167. the `colony-deployed:` marker voided "ready" so `leaseOf` fell back to the old dead lease) → 2nd worker ran on it.
  168. Done (README "Mission 031" under Leases; code `lib/lease.hl` endOf / stillLeased / expireLease, `lib/daemon.hl`):
  169. - A lease ENDS (kind `ended`, never expired) on any state change after it, a `colony-deployed:` line, or the session's own
  170. report (not "ready to deploy") / verdict / run / lease-expired marker. `run` + `leases` list it with the reason.
  171. - `run` expiry, `leases --expire` and `run`'s resume of a parked session RE-READ the ticket right before writing; not STILL
  172. `in progress` with the same lease → nothing written, `NOT expired|NOT resumed <ref> …: re-read right before — <why>`.
  173. - Test hook `COLONY_TEST_HOOK_URL` (tests only) → e2e reproduces the race deterministically.
  174. Tested (fake claude only, own tickets+ident 8751/8752, hook server 8758, pools 8770-8799): `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs`
  175. - dev copy WITHOUT `.env` (`.scratch/m031/dev/`): 330/330 → `.scratch/m031/e2e-new-noenv-2.txt` (run 1 had 4 test bugs, fixed)
  176. - THIS folder with the LIVE `.env` present (not read, not changed; mtime still 21:58:49), container running: 330/330 →
  177. `.scratch/m031/e2e-live-env.txt`; `claude-guard.log` absent = no real claude call
  178. - pre-031 code + only the hook (`.scratch/m031/orighook/`): 322/8 FAILED → `.scratch/m031/e2e-orighook.txt` — the new
  179. checks catch the bug (B: `expired lr#2 … → open` after the move to awaiting creator; A: expired + a 2nd worker started)
  180. - live, GET only: `./colony leases` from the dev copy → `.scratch/m031/live-leases-get-only.txt`
  181. Pre-031 code: `.scratch/m031/orig/`.
  182. Not done / open:
  183. - Live container still runs the pre-031 code until `docker compose up -d` (architect).
  184. - Remaining gap: re-read → write are two requests (ms apart); closing it needs a conditional state change in tickets
  185. (e.g. `expect: "in progress"` on POST …/state) — not built (other project).
  186. - The heartbeat of a RUNNING session still renews a lease on a ticket someone moved away (not in scope; the renewal is a
  187. comment only, and `leaseOf` now ignores it because the state change ended the lease).
  188. ## 2026-09-24 — scheduler fixes after the librarian (mission 030, antcolony#1) — awaiting the architect's check; container NOT started
  189. Done (README "Relations, questions, rejections" last bullet, "Librarian → Where the files go", "Test → Test isolation"):
  190. - **A question ticket is never work, in no state**: `next`/`cycle`/`run` list it "a question for the creator — the
  191. librarian takes its answer (<state>) — never work" (checked before the rework-on-rejection logic); `brief`/`work`/`salvage`
  192. refuse it; `run` never resumes a session parked on one. Code: `lib/relations.hl` `questionWhy`, `next.hl` survey,
  193. `brief.hl` buildBrief, `work.hl` salvage, `daemon.hl` resume.
  194. - **Test isolation**: Hybriel loads the `.env` beside `scheduler.hl` (proved: `.scratch/m030/envprobe/`), so the e2e now
  195. runs the scheduler from a copy WITHOUT `.env` (`.scratch/e2e/app/`), drops inherited COLONY_*/FAKE_*, and puts a
  196. refusing `claude` guard on PATH (fake only).
  197. - **DECISIONS never into a `"workers": false` project**: `librarian.hl` projectFile → `librarian/projects/<p>/`. Hybriel's
  198. file re-rendered to `librarian/projects/hybriel/DECISIONS.md` (`./colony librarian --render`), the untracked
  199. `/media/STORAGE/projects/hybriel/DECISIONS.md` deleted (nothing else touched there).
  200. - What the wrongly started sessions changed: `.scratch/m030/wrong-sessions.txt` (run folders + transcripts),
  201. `.scratch/m030/wrong-sessions-tickets.txt` (live ticket events, GET only). Nothing there was changed.
  202. Tested (fake claude only, own tickets+ident 8751/8752, pools 8770-8799): `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs`
  203. - dev copy WITHOUT `.env`: 320/320 → `.scratch/m030/e2e-new-noenv-1.txt` (baseline pre-030 code: 310/310 `e2e-baseline-noenv.txt`)
  204. - a synthetic hostile `.env` (`.scratch/m030/synthetic.env`: max turns 120, week limit 100, bogus token + CLAUDE_CONFIG_DIR, …):
  205. OLD code 294 passed / 16 failed (`e2e-orig-synthetic-env.txt` — the problem reproduced), NEW code 320/320 (`e2e-new-synthetic-env.txt`)
  206. - THIS folder with the LIVE `.env` present (not read, not changed; mtime still 21:58:49): 320/320 → `.scratch/m030/e2e-live-env.txt`
  207. ("this folder HAS a .env … — ignored"; `claude-guard.log` absent = no real claude call)
  208. Pre-030 code: `.scratch/m030/orig/`, dev copy `.scratch/m030/dev/`.
  209. Not done / open:
  210. - Live container not started (architect). No real Claude run in this mission.
  211. - Hybriel note: the interpreter reads `.env` beside the entry script only (not the cwd) and an empty shell variable beats it;
  212. SPEC only documents `--native` ("beside the binary, then in the cwd") — not filed.
  213. - `ready` / `deployed` do not check for questions: ident#17 (a question) is still "in progress · ready to deploy" from the
  214. pre-030 session s-20260924T1857-dc5328 → `./colony ready` lists it; do NOT run `deployed ident.worldapi.org 17`.
  215. - gitoria#3 / #4 are `awaiting creator` with "Ready for you to test" comments of the wrong sessions; gitoria's
  216. `docs/differ-from-custom-ide.md` + `STATUS.md` were edited by them (list in `.scratch/m030/wrong-sessions.txt`) — the
  217. architect decides; nothing reverted.
  218. - The antcolony-docs README still says the librarian writes DECISIONS.md "per project (dev folder)" — Byrodin file, not edited.
  219. ## 2026-09-24 — the librarian (mission 029, antcolony#21) — awaiting the architect's check; LIVE CONTAINER NEEDS A RESTART
  220. Done (README "Librarian"): `./colony librarian` reads the CREATOR's texts in tickets (comments, state texts incl. answers on
  221. question tickets, tickets he opened, edits; READ only) + once the architect's chat seed; one model step per new text
  222. (sonnet, `--tools ""`, schema `templates/librarian.schema.json`); the code keeps the creator's exact words (a model excerpt
  223. only if verbatim), marks the reading as the librarian's (seed: the architect's), assigns project / `all` + topic; writes
  224. `DECISIONS.md` per project (dev folder, else code folder, else `librarian/projects/<p>/`) and `templates/decisions-global.md`
  225. — current only, by topic, contents on top; corrections → `*-archive.md`. Store `librarian/decisions.json`, state
  226. `librarian/state.json`, calls `librarian/calls/`. Every brief: section "Decisions of the creator — a decision here overrides
  227. anything else; ask only if it is not decided here" (paths + whole file ≤ 150 lines, else the matching topics) after the
  228. conventions; UI projects (registry `"ui": true`: tickets, ident, gitoria) name `antcolony-docs/docs/layouts-conventions.md`.
  229. ORDER: `run` awaits a librarian pass at the start of every iteration and starts nothing while a creator text is unfiled;
  230. `brief`/`work`/`cycle` by hand await a pass first. Chat transcripts as a source were built and then DROPPED (creator: "the
  231. librarian should be enough. i have to adopt to the workflow"): code removed, the 16 chat entries removed from the live store
  232. (backup `.scratch/m029/librarian-before-drop-chat/`).
  233. Installed in this folder (pre-029 code `.scratch/m029/orig/`, dev copy `.scratch/m029/dev/`). **The running container still
  234. runs the old code** (Hybriel loads it at start): `docker compose up -d` (or `docker restart antcolony-scheduler`) is needed for
  235. `run` to call the librarian; the new compose env lines (COLONY_LIBRARIAN*, COLONY_CREATOR_NAMES) need `up -d`.
  236. Tested: `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 310/310 (266 old — one check changed: the Hybriel block path the
  237. architect changed after 027; baseline was 265/266 — + 44 librarian, fake model) → `.scratch/m029/e2e-fake-final.txt`; m012
  238. tickets → `.scratch/m029/e2e-fake-m012.txt`. Live brief (GETs only, `--librarian off`): `.scratch/m029/briefs/live-tickets-12.md`.
  239. FIRST LIVE PASS (real sonnet, colony subscription `CLAUDE_CONFIG_DIR=/home/mre/.claude-colony`, READ only on tickets):
  240. seed 19 entries (`.scratch/m029/live-seed.txt`); pass `--since 2026-09-23` (`live-pass-probe.txt` 1 call $0.0289,
  241. `live-pass.txt` 155 calls $4.627 — 130 of them chat messages, dropped afterwards); `--redo` of 4 wrongly read answers + 3 new
  242. creator texts (`live-redo.txt`, 7 calls $0.2211). **Total $4.88** (ticket texts alone ≈ $1). Result: global 19 (seed),
  243. antcolony 8, tickets 7, ident 4, gitoria 3, hybriel 1 current entries, nothing superseded.
  244. ```bash
  245. cd /media/STORAGE/projects/antcolony-scheduler
  246. ./colony librarian # what is new (no model call)
  247. CLAUDE_CONFIG_DIR=/home/mre/.claude-colony ./colony librarian --post-files # by hand until the container is restarted
  248. cat templates/decisions-global.md DECISIONS.md ../tickets.worldapi.org/DECISIONS.md ../ident.worldapi.org/DECISIONS.md
  249. ```
  250. Not done / open:
  251. - The tickets API shows DISPLAY NAMES only (no user id, no "is creator" flag): the creator is recognised by name
  252. (`COLONY_CREATOR_NAMES=Caramboleyo,creator`); a user who picks the name "Caramboleyo" would count. Proper: tickets marks
  253. events by the configured creator (e.g. `byCreator: true`, computed from TICKETS_CREATOR_IDENTITY) — needs a tickets change
  254. + deploy (not done here).
  255. - Readings can be wrong (the quote is always there): the first pass read "yes" on ident#13 as the summary's suggestion
  256. (fixed by a prompt rule + `--redo`); antcolony#6's reading says "workers run in bypass" (they run `auto`) — left as is.
  257. - Cost per call ~$0.03 (the input with every current entry is re-written to the cache each call); fine for a few texts per
  258. iteration, costly for a big backlog.
  259. - `librarian/lock` of a pass killed mid-way blocks `run` starts for up to 15 min (stale time).
  260. - A text written while a pass runs reaches the next iteration's briefs (seconds).
  261. - `templates/conventions.md` (hand copy of the antcolony README conventions) overlaps `decisions-global.md` (seed): both are
  262. in every brief; which stays is the architect's call.
  263. - `projects/-media-STORAGE-projects-antcolony-scheduler/` (a Claude Code project folder with a session .jsonl, created 20:32,
  264. not by this mission) sits in the registry folder; the registry ignores it (no .json).
  265. ## 2026-09-24 — permanent operation as the Docker container `antcolony-scheduler` (mission 028, antcolony#1) — awaiting the architect's check
  266. Done (README "Operations"): `docker-compose.yml` (busybox, `restart: unless-stopped`, host network + PID namespace, cap
  267. SYS_ADMIN + seccomp unconfined, `stop_grace_period: 75s`, json-file 3×10 MB), `docker/pivot.sh` (root: private mounts,
  268. `pivot_root` into the host's `/`, drop to uid 1000 with mre's groups), `docker/entrypoint.sh` (uid 1000: mre's env,
  269. `./colony run [--live]`, docker's one SIGTERM → finish, park after `COLONY_STOP_FINISH_SECONDS`=20, `logs/colony.log`
  270. rotating), `.env.example` (reserve 100 / week limit 100 = the creator's setting; everything else commented defaults).
  271. Default `COLONY_LIVE=1`. **Container NOT created** (removed after a `up --no-start` check): start = `cp .env.example .env`
  272. (check it) → `docker compose up -d`.
  273. Tested (own tickets 8752 + ident 8751, fake claude, pool 8770-8779, test container `antcolony-scheduler-m028` via
  274. `.scratch/m028/dc.sh`; outputs `.scratch/m028/test-*.txt`): run picks/works/posts tiny#1..6 (ITER lines in `docker logs`);
  275. docker stop during a session → finish → park after 20 s (stop took 21 s, no process left) → docker start → resumed →
  276. posted; stop during a short session → finished + posted (9 s); idle stop 1 s; docker kill → no process left; kill -9 of the
  277. scheduler → docker restarted the container; docker exec as uid 1000: REAL `claude --version` 2.1.280 + `claude -p /usage`
  278. (cost 0, 0 turns, session 28 %, week 44 %), headless Chrome WITH sandbox ok, `./colony leases`. Processes: uid 1000, CapEff 0.
  279. Not done / open:
  280. - No reboot tested (not allowed on a shared host): restart after boot + park at shutdown rely on docker's
  281. `unless-stopped` + stop timeout (75 s < systemd's 90 s for docker.service) — check at the first reboot.
  282. - `/media/STORAGE` is a separate fstab mount: if docker ever starts before it, the entrypoint is missing → the container
  283. exits and restarts until it is there (not observed).
  284. - The pool 8700-8799 overlaps ports used on Loreana (8765, 8766, 8787, 8795).
  285. - Workers keep mre's docker group + sudo (wheel) as on the host — no isolation beyond the host's.
  286. ## 2026-09-24 — after the first live batch: readable test steps, deploy gate, fewer questions (mission 027, antcolony#1) — awaiting the architect's check
  287. Done (README "Mission 027"): `result` ≤ 120, `test` 2–4 steps ≤ 90 (numbered Markdown list in every comment), no `.scratch`
  288. step, no local address on a project with `live`; ≤ 3 questions of ≤ 3 lines / 300 chars; new report key `decided` (optional
  289. in the validation, required in the schema) → one "Decided: …" bullet. **Deploy gate**: complete + passed report on a project
  290. with `live` → "Built — goes live with the next deploy." (`· ready to deploy` marker), ticket stays `in progress`, never expires,
  291. not in `next`; `./colony ready` lists them, `./colony deployed <project> <n>` posts "Now live on <site> — <result>" + numbered
  292. steps + details and sets `awaiting creator` (needs `runs/<S>/report.json` on this host). Projects without `live` → awaiting
  293. creator as before. Brief: "Conventions for all apps" as text (`templates/conventions.md`, a copy), the project's own tickets
  294. (newest first, ≤ 40), where the creator tests (live URL). A refused report gets ONE fix step (same session resumed, like
  295. finalize). Controller told that live-site steps are checked against the code.
  296. Tested (fake claude only, own tickets+ident 8751/8752, work ports 8753-8759, run 8780-8799):
  297. `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 266/266 (234 − 3 moved + 35 new) → `.scratch/m027/e2e-fake-3.txt`; m012 tickets 254/254 → `e2e-fake-m012.txt`; baseline
  298. before the change 234/234 (`e2e-baseline.txt`). Live brief (GET only) `.scratch/m027/briefs/live-tickets-12.md`.
  299. Not done / open:
  300. - No real Claude run: whether Sonnet keeps 120/90 is untested; a miss now costs one cheap fix step instead of the session.
  301. `maxLength`/`maxItems` still not in the schema (unknown whether `claude --json-schema` accepts them).
  302. - The deploy itself stays manual: the architect runs `./colony ready` → deploys → `./colony deployed <p> <n>` (on Loreana,
  303. where the run folders are). No `--live` guard on `deployed` (it posts to COLONY_TICKETS_URL like `report --post`).
  304. - `templates/conventions.md` and `templates/hybriel-block.md` are hand copies of Byrodin files. The Hybriel block still tells
  305. workers to read `/CONTAINERS/projects/antcolony/docs/hybriel-for-app-workers.md` — that path does not exist on Loreana.
  306. - The ≤ 5 line limit is counted without the numbered step lines (creator/architect to confirm).
  307. - A 2nd session's report on a live ticket that is already `awaiting creator` posts the "Built — goes live…" line, state left.
  308. ## 2026-09-24 — continue unfinished work, clean up after sessions, cheaper finalize, salvage lease (mission 026, antcolony#1) — awaiting the architect's check
  309. Done (README "Mission 026"): report key `complete` (bool, validated; controller checks it); a passed `complete: false`
  310. report → ONE comment "Half done: <result>; the next worker continues." + still open, ticket `in progress → open` (never
  311. awaiting creator; a half-done report does not answer a rejection). Brief section "Previous attempt" (`lib/previous.hl`:
  312. last colony session, how it ended, result, open, work copy from `.scratch/…` paths, report path). After every worker /
  313. finalize / controller part: `lib/cleanup.sh` stops processes listening on the session's ports that started during that
  314. part (never others: before the part, other user, the scheduler, another `COLONY_SESSION`), logged + `session.json.cleanup`.
  315. Finalize resume without `--disallowedTools`. `salvage` leases the ticket (token always, ticket must be `open`).
  316. Tested: `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 234/234 (215 old — 3 m025 checks changed on purpose: finalize argv,
  317. salvage lease — + 19 new, fake claude), m012 tickets 222/222 — `.scratch/m026/e2e-fake-5.txt`, `e2e-fake-m012.txt`.
  318. ONE real tiny run (`.scratch/m026/real.sh`, own tickets 8753/8754, stopped): Sonnet worker --max-turns 2 → out of steps
  319. $0.1866 → finalize resume **$0.0301, cache read 83 909 / write 1 259** (m025's with the flag: $1.0528, cache read 0), no
  320. file changed; FAKE controller (its fail verdict is meaningless: it only understands `cat X`). The real salvaged report of
  321. ident.worldapi.org#2 (a COPY + `"complete": false`) posted to own tickets as half done: `.scratch/m026/halfdone-real.txt`.
  322. Pre-026 code: `.scratch/m026/orig/`.
  323. Not done / open:
  324. - Live post of ident.worldapi.org#2 = architect: add `"complete": false` to its `runs/…/report.json`, then `./colony check
  325. runs/s-20260924T1527-525807 --post` (README "Mission 026", last bullet).
  326. - No limit on half-done rounds (a ticket could go half done → open forever); not counted as controller fails.
  327. - Cleanup stops only LISTENING processes of the range: non-listening leftovers (a `--watch` parent, a headless Chrome
  328. without a port in the range) survive; a worker that ignores its range is not covered.
  329. - A half-done comment can still show "Still running: …" from the report although the cleanup stopped it.
  330. - "Previous attempt" reads the run folder only on the host that ran it; old sessions without `complete` show no "(not complete)".
  331. - The real controller never saw a `complete` field yet (the real run used the fake controller).
  332. ## 2026-09-24 — finalize step, budget in the brief, `salvage` (mission 025, antcolony#1) — awaiting the architect's check
  333. Done (README "Finalize step + salvage"): a worker ending with `error_max_turns` or killed by `--timeout` gets its SAME Claude
  334. session resumed once (`claude -p --resume`, same schema/model/permission mode, `--max-turns 8`, Edit/Write/NotebookEdit off,
  335. `runs/<S>/finalize.md` "STOP WORKING — write your report now") → valid report → controller → post as usual; none → back to
  336. open once (unchanged texts). Brief section `## Budget` (steps, "report before step N−min(10,N/3)", time). `./colony salvage
  337. <runs/S> [--post]` = the same for a finished run (no lease; controller told to re-run nothing that writes). Resumed sessions:
  338. Claude reports CUMULATIVE cost → the scheduler now counts `total − claudeCostSeen` per part (also fixes mission 020's
  339. parked-resume double count). Controller transcript keeps start + end of long sessions. `run` passes `--finalize-*`.
  340. Tested: `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 215/215 (187 old unchanged + 28 new, fake claude only), m012
  341. tickets 203/203 — `.scratch/m025/e2e-fake-4.txt`, `e2e-fake-m012.txt`. Pre-025 code: `.scratch/m025/orig/`.
  342. **Real salvage of the first live run** (the only real Claude run; Sonnet): `runs/s-20260924T1527-525807` (original copy
  343. `.scratch/m025/run-orig/`) against OWN tickets+ident (`.scratch/m025/own-tickets.mjs`, 8753/8754, stopped afterwards):
  344. `COLONY_TICKETS_URL=http://127.0.0.1:8754 COLONY_TOKEN_FILE=.scratch/m025/own/colony-token ./colony salvage
  345. runs/s-20260924T1527-525807 --post --ports 8770-8779` → output `.scratch/m025/salvage-real.txt`: finalize 4 turns, 113 s,
  346. one read-only Bash call, REPORT OK (8 done, 5 verified, 6 open, 3 questions) → controller PASS (15 findings ok, 7 turns) →
  347. posted on the own copy of ident.worldapi.org#2 (3 question tickets, → awaiting creator). Cost: finalize **$1.0528** (Claude
  348. printed $5.7198 = the whole session — session.json corrected by `.scratch/m025/costfix.py`, backup
  349. `session.before-costfix.json`), controller $0.5453 → whole session $6.2651. The ident folder was unchanged (find
  350. size+mtime of 14 064 entries before/after identical: `.scratch/m025/ident-{before,after}.txt`).
  351. **Live post = architect's decision**: `COLONY_TOKEN_FILE=… ./colony check runs/s-20260924T1527-525807 --post` (reuses
  352. verdict.json, no new Claude session; session.json `outcome: posted` refers to the OWN instance).
  353. Not done / open:
  354. - The finalize resume missed the prompt cache: its first call wrote the whole 207 k context anew (cache read 0) although the
  355. worker's 1 h cache was 18 min old — probably because `--disallowedTools` changes the tool list (= the cached prefix). A
  356. finalize WITHOUT that flag might cost ~$0.1 instead of ~$1 — unproven (would need another real run).
  357. - A salvaged report of unfinished work still sets `awaiting creator` ("Ready for you to test") although its result says
  358. "not copied in, not testable" — question for the creator/architect.
  359. - Leftover ident dev servers of the live worker still run (pids 1396754/1396755, ports 8700/8701, from
  360. ident `.scratch/dev-m022`) — not ours, not killed.
  361. - A `run` could pick the (open) ticket while a salvage of it runs (salvage takes no lease).
  362. - A park (2nd SIGTERM) during the finalize step resumes with the normal resume prompt, not the finalize one.
  363. ## 2026-09-24 — readable ticket texts, weekly limit, hand-filed questions (mission 023, antcolony#1) — awaiting the architect's check
  364. Done (README "Ticket texts", "report", "run", "Leases", "Relations"): every text the scheduler writes into tickets follows
  365. antcolony README "Ticket texts are written for the creator" — ≤ 5 short plain lines + ONE short machine line last (lease,
  366. heartbeat, park, resume, give-back, lease expiry, report comment + state, controller fail comment + state, all creator
  367. questions, issue tickets). Report schema + `result` (one sentence) + `test` (1–4 steps), validated (one line, ≤ 200
  368. characters); the comment = result · **Test:** · ≤ 3 detail bullets · `colony-report: S · sha256 <12 hex>[ · controller
  369. pass]` — the full report + verdict stay in `runs/<S>/`. Markers shortened (no ISO times, no Claude id; old markers still
  370. parse). Heartbeats: lease ttl 7200 s, heartbeat ttl/2 (a session < 1 h writes none). `run --week-limit P` /
  371. `COLONY_WEEK_LIMIT` (default 84): no start while the weekly usage is above it or unknown; `--reserve 100` / `--week-limit
  372. 100` switch the checks off (architect update: first live runs up to 100 %). Haiku allowed (never refused; default stays
  373. Sonnet + auto). Hand-filed children whose subject starts with the word `Question` are creator questions, not work.
  374. Tested (own tickets + ident on 8751/8752, `run` workers 8780-8799, fake claude only):
  375. `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 187/187 (169 old, old-text checks rewritten to the new texts, + 18 new);
  376. with the m012 tickets 175/175. Logs `.scratch/m023/e2e-fake-2.txt`, `e2e-fake-m012.txt`; every scheduler text of the run
  377. `.scratch/m023/texts-2.md`; run outputs `.scratch/m023/run-logs-2/`. Pre-023 code: `.scratch/m023/orig/`.
  378. Not done / open:
  379. - No real Claude run: whether Sonnet keeps `result`/`test` within the limits is untested (the schema only says it in the
  380. descriptions — `maxLength`/`pattern`/`maxItems` were left out because it is unknown whether `claude --json-schema`
  381. accepts them; `report.hl` refuses a too-long result → the ticket goes back to open, which costs a whole session).
  382. - Worker free text quoted in tickets (questions, issue repro/observed/expected) is only clipped where it becomes a single
  383. line (subjects, bullets); a long question or repro stays long.
  384. - Haiku + the default mode `auto` still falls back to `default` (Haiku has no auto mode) → with prompts off it can
  385. edit nothing; `bypassPermissions` stays refused (question for the creator).
  386. - Old tickets keep their old long texts (nothing rewritten).
  387. ## 2026-09-24 — blocked-by, questions as tickets, rejections as work (mission 022, antcolony#1) — awaiting the architect's check
  388. Done (README "Relations, questions, rejections", `lib/relations.hl`): `next`/`cycle`/`run`/`work` treat a ticket with
  389. a blocker that is not `confirmed` ("blocked by X#n (state)") or with children ("a parent …") as not eligible — the
  390. scheduler's own creator-question children don't count; a `rejected` ticket whose last rejection is newer than the last
  391. colony session start is eligible again (`work` leases it `rejected → in progress`), its brief STARTS with `REJECTED by
  392. the creator: <text>` + the creator's comments since the last session + the "build what was described" rule (kept until
  393. a colony report answers it); `report --post` files every `questions` entry as its own ticket in the ticket's project
  394. (`awaiting creator`, parent = the ticket, source `colony-report:<S>:questions:<i>`, idempotent), links it in the comment,
  395. and turns `issues[].blocks = true` into a `blocked-by` link; unknown-project and Nth-fail creator questions get the
  396. ticket as parent. Every brief has a "Relations" section. `templates/report.md`: one self-contained question per entry,
  397. `[]` when none. Fake claude: `questions` default `[]` (was `['fake worker: none']`), `FAKE_QUESTIONS`.
  398. Tested (own tickets + ident on 8751/8752, fake claude only, tickets now started WITH a creator identity):
  399. `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 169/169 (144 old — 4 report checks adapted to the new link event /
  400. question ticket — + 25 new); with the m012 tickets (no relations, no read view) 159/159. Logs `.scratch/m022/e2e-fake-1.txt`,
  401. `e2e-fake-m012.txt`, briefs + the `run` output `.scratch/m022/briefs/`. Pre-022 code: `.scratch/m022/orig/`.
  402. Not done / open:
  403. - `next --post`'s project-level questions stay in `antcolony` without parent; `cycle` / `run` still never file them.
  404. - A rejected ticket "not newer than the last session" can hardly happen (every rejection is a new event after the lease);
  405. that branch (`work: REFUSED — … no rejection is newer`) is not exercised by the e2e.
  406. - Question children of a ticket are never checked by the scheduler (an unanswered question does not hold the ticket).
  407. - Rejected tickets are ordered like open ones (oldest first), not first.
  408. - No real Claude run in this mission.
  409. ## 2026-09-24 — `run` daemon: loop, expiring leases, quota reserve, parking + resume, ports per session (mission 020, antcolony#1/#2 build order 4 part 2) — awaiting the architect's check
  410. Done (README "run", "Leases", "Quota + parking"): `./colony run [--once] [--interval S] [--parallel K] [--reserve P]
  411. [--port-pool A-B] [--ports-per-session N] [--lease-ttl S] [--heartbeat S] [--live]` (`lib/daemon.hl`): per iteration
  412. expire dead leases → resume due parked sessions → start eligible tickets of this host (one per dev folder) while slots
  413. are free and the `/usage` quota is below the reserve; one `ITER` line per iteration, `SESSION END` per session.
  414. Leases carry an expiry marker + heartbeat comments (`lib/lease.hl`, also for `work`/`cycle`); a restarted run skips
  415. live leases. Usage-limit evictions and the 2nd SIGTERM park the session (`colony-parked` marker, ticket stays leased),
  416. resumed with `claude -p --resume` (worker) or a new controller. Port range per session → brief + env `COLONY_PORTS*`.
  417. Wrapper `colony`: setsid + SIGTERM/SIGINT → stop file (1st finish, 2nd park). Refuses live tickets without `--live`.
  418. `./colony leases [--expire]`. `on Error` in scheduler.hl: a fetch failure no longer aborts (status 0).
  419. Quota reading (proved, $0): `claude -p /usage … --verbose` is a local command (0 turns, cost 0, ~1–4 s);
  420. `usage_report.rate_limits.limits[kind=session].percent` + `resets_at` (`.scratch/m020/usage-probe/`: the first probe
  421. by hand and one through `lib/quota.hl` → `{"percent":5,"resetsMs":1790274000279,"weekly":41,"cost":0}`).
  422. Tested (own tickets + ident on 8761/8762, workers 8780-8799): `COLONY_E2E_PORT_BASE=8760 node tests/e2e.mjs` 144/144
  423. twice (119 old + 25 `run`, fake claude only), with the m012 tickets 143/143. Logs `.scratch/m020/e2e-fake-{1,2}.txt`,
  424. `e2e-fake-m012.txt`, run outputs `.scratch/m020/run-logs-2/`. Pre-020 code: `.scratch/m020/orig/`. No real worker run.
  425. Not done / open:
  426. - Real Claude never hit the limit here: the rate-limit detection (rejected `rate_limit_event`, 429, "hit your limit")
  427. is from the verbose output format seen in normal runs + guesses at the error result; verify on the first real eviction.
  428. - No tickets live events (polling only; `--interval`); no WebSocket / agent split; quota per host = per logged-in account.
  429. - Heartbeat = a comment every ttl/3 (tickets has no editable lease field) → noise in the history; expiry puts the
  430. ticket back to `open` (concept says "host offline, never failed").
  431. - A crashed / SIGKILLed run kills its Claude sessions (hl:proc PDEATHSIG) — work is lost, the lease expires, a new
  432. session starts from the history (no `--resume` after a crash).
  433. - Parked sessions resume only on the host that parked them; if it never comes back the lease expires (resume + ttl).
  434. - "no verdict" (controller crashed) still leaves the ticket leased → with leases it goes back to `open` after the ttl.
  435. - `run` is not a container / service yet; weekly limit only printed, not enforced.
  436. ## 2026-09-24 — controller step + `cycle` built (mission 019, ticket antcolony#1 build order 4 part 1) — awaiting the architect's check
  437. Done (README "The controller", "check", "cycle"): after a schema-valid report `work` starts a second
  438. one-shot Claude session (same safety settings, Edit/Write/NotebookEdit disallowed, same dev folder;
  439. input = templates/controller.md + report + compact transcript of the worker's session + brief) →
  440. `verdict.json` `{verdict pass|fail, findings[], summary}` (`--json-schema templates/verdict.schema.json`;
  441. code validates, a pass with a `false`/`no evidence` finding becomes a fail). `--post` follows the verdict:
  442. pass → report comment + controller section + `awaiting creator`; fail → findings comment → `open`; Nth
  443. fail (`--max-fails`, default 2) → creator question + `on hold`. `./colony check <run dir> [--post]` (reuses
  444. verdict.json), `./colony cycle [--post] [--dry-run]` (next on THIS host → work → controller → post, summed
  445. cost), `work --dry-run`. Refactor: `lib/claude.hl` (session runner shared by worker + controller).
  446. Tested (own tickets + ident on 8761/8762): `COLONY_E2E_PORT_BASE=8760 node tests/e2e.mjs` 119/119 (fake
  447. worker + fake controller), with the m012 tickets 118/118; `COLONY_E2E_REAL=1 …` 124/124 with REAL Sonnet:
  448. cycle → worker made hello.txt ($0.087, 4 turns), controller re-ran the cat → PASS ($0.175, 3 turns),
  449. posted; fake worker claiming `missing.txt` + REAL controller → FAIL, both findings `false` ($0.104, 4
  450. turns), back to open. No permission denials. Logs: `.scratch/m019/e2e-fake-2.txt`, `e2e-fake-m012.txt`,
  451. `e2e-real.txt`; real run folders `.scratch/m019/real-runs/`. Pre-019 code: `.scratch/m019/orig/`.
  452. Not done / open:
  453. - Controller runs with host access like the worker (auto-mode classifier + instructions + no Edit/Write);
  454. a malicious report could name a harmful command to "re-run" — only the classifier and the prompt stop it.
  455. - No verdict → the ticket stays `in progress` (no lease expiry yet); retry by hand with `check`.
  456. - A failed report's `issues` are not filed (listed in the fail comment); the fail count lives only in the
  457. ticket's comments (markers).
  458. - `cycle` does one ticket per call, no loop / daemon; picks only tickets whose dev folder is on this host.
  459. - Everything from mission 016 below still open (daemon, quota, ports per session, isolation).
  460. ## 2026-09-24 — agent v0 `work` built (mission 016, ticket antcolony#2)
  461. Done: `./colony work <project> <n> [--post] …` (README "work"): brief → lease (`in progress`, "session
  462. <id> started on <host>") → `claude -p` headless in the dev folder (`--json-schema`
  463. templates/report.schema.json, `--permission-mode auto`, `--permission-prompts none`,
  464. `--strict-mcp-config`, model/max turns/timeout/budget configurable) → `runs/<session>/` (brief, raw
  465. result, stderr, report, session.json with cost/usage) → `report` validation → `--post`; no valid report
  466. → back to `open` with the reason. Scheduler fixes: `"workers": false` → never eligible ("takes no
  467. workers", no creator question), `work` refuses it; registry `projects/` here is the single source
  468. (`COLONY_PROJECTS_DIR`, default `./projects` beside scheduler.hl). `brief.hl`/`report.hl` refactored
  469. into `buildBrief` / `reportFile` (same output).
  470. Tested (own tickets + ident on 8751/8752): `COLONY_E2E_PORT_BASE=8750 node tests/e2e.mjs` 101/101 (fake
  471. claude), with the m012 tickets 100/100; `COLONY_E2E_REAL=1 …` 106/106 with the REAL claude: Sonnet
  472. created `hello.txt`, report posted, `awaiting creator` ($0.18, 4 turns); Haiku `--max-turns 1` →
  473. `error_max_turns` → back to `open` ($0.06). Logs: `.scratch/m016/e2e-real.txt`, `e2e-fake.txt`,
  474. `e2e-fake-m012.txt`. Claude flag probes: `.scratch/m016/probe/`.
  475. Not done / open:
  476. - No daemon / WebSocket / heartbeat / lease expiry, no quota reserve or parking (`--resume` with the
  477. recorded Claude session id is possible later), no port-range assignment per session (briefs keep
  478. `--ports` / `COLONY_PORTS`), no controller step, no isolation (worker = host user `mre`).
  479. - Auto mode is unavailable for Haiku (falls back to `default` → with prompts off nothing can be
  480. edited); `work` only WARNS after the fact. Could refuse up front or use `stream-json` and kill early.
  481. - Lease + give-back are one state event with text each (not a separate comment).
  482. - Never run against live tickets (rule); first live `work` = architect with the Colony token.
  483. - Exit status always 0 (Hybriel) — read the last line (`WORK DONE/OK/FAILED`).
  484. Hybriel findings (not yet filed): (020) inside an object literal a field defined EARLIER shadows an outer
  485. variable of the same name (`let ref = {project='p'}; { ref = 'x#1' project = ref.project }` → unlocated
  486. `error.NotAnInstance`); no signal handlers (the wrapper does SIGTERM); hl:proc children get PDEATHSIG=SIGTERM
  487. (undocumented in server.hl); options after the script need `--`; no process exit status; hl:proc
  488. `spawn`/`spawnArgs` have no cwd/env options (work uses `sh -c`); hl:proc/hl:fs offer no call for the script's own
  489. absolute directory (the `colony` wrapper exports `COLONY_HOME`); (019) no `Math` (`round4` uses `%`); an
  490. object stored in another object's field is a COPY — later changes to the original are not seen
  491. (`meta.controller = cm` must be re-assigned before each write).
  492. ## 2026-09-26 (3rd session) — antcolony#20 local models: CPU still too slow
  493. Tried the already-running Nemotron-3.5-Lightning-30B-A3B (MoE, CPU, container on :8821) with `.scratch/loc/eval.py`: 4 librarian prompts (~3k tokens each) did not finish in 900 s (killed). Same wall as Qwen3.5-9B: prompt processing on CPU is the bottleneck. Still needed: GPU visible to the worker box (Vulkan lists no device; /dev/dri exists) or a much shorter librarian prompt. Local option stays opt-in; default stays `sonnet`.

Branches

Latest commits

  • 3a4d0324antcolony#37: a too-long report gets up to 3 fix tries, finished work is never thrown away for lengthmre
  • a6af7883tracker: worker box sees calendar.worldapi.org (login to copy)mre
  • c613d26btemplates: bridges to external components (login.js for ident's selector) are allowed (creator 2026-09-27)mre
  • 9062978ctracker: worker box sees /media/STORAGE/projects/old-tracker read-only (tracker#2 source data)mre
  • 7f9660eeState of 2026-09-27, before the move to gitoriamre