Commit Graph
59 Commits
Author SHA1 Message Date
kyleandornith-1.5-35b-a3b 45eb16a30a loopd: consult waits one hundred and eighty seconds
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 21:47:20 -07:00
kyleandornith-1.5-35b-a3b 658bc7d1e8 loopd: consult in the M5c registry, not core
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 21:43:39 -07:00
kyleandornith-1.5-35b-a3b 79735b21e4 loopd: scheduler yields to a held subagent
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 20:03:13 -07:00
kyleandornith-1.5-35b-a3b 4491e1b80d loopd: subagent spawn on the background slot
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 19:59:25 -07:00
kyleandornith-1.5-35b-a3b fe145fb83a loopd: dispatch subagent, not the port
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 19:50:13 -07:00
kyleandornith-1.5-35b-a3b bab22bb4c8 loopd: subagent in the M5c registry, not core
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 19:44:25 -07:00
kyleandornith-1.5-35b-a3b 30608995ca loopd: a failed heartbeat still advances last_heartbeat
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 18:24:18 -07:00
kyleandornith-1.5-35b-a3b 57d9aad2d6 loopd: background ToolSummary for opted-in results
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 17:11:40 -07:00
kyleandornith-1.5-35b-a3b 5adb6a2cc0 loopd: cron tick, new session per run
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 17:04:59 -07:00
kyleandornith-1.5-35b-a3b ea0708e305 loopd: heartbeat tick on the background slot
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 16:48:23 -07:00
kyleandornith-1.5-35b-a3b 670b5bbabe loopd: job files, run ledger, jobs-invalid
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 14:20:19 -07:00
kyleandornith-1.5-35b-a3b 587b3924d7 loopd: five-field UTC cron matcher
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 14:07:36 -07:00
kyleandornith-1.5-35b-a3b 6b7912399c loopd: [heartbeat] table and summarise name check
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 14:00:57 -07:00
kyleandornith-1.5-35b-a3b ab4fb65ccc bxcore: ToolSummary log record; messages ignore it
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 13:51:03 -07:00
kyleandornith-1.5-35b-a3b b018b3dc0a loopd: live turns use the session's slot
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 13:47:51 -07:00
kyleandornith-1.5-35b-a3b b274fa7d62 loopd: compact after a full turn and retry SessionFull once
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 00:38:35 -07:00
kyleandornith-1.5-35b-a3b fe8e3e9354 loopd: write the next epoch from a compaction summary
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 00:25:04 -07:00
kyleandornith-1.5-35b-a3b c8b0a01c41 loopd: compact summary on the background slot
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 00:14:03 -07:00
kyleandornith-1.5-35b-a3b 32e81b51fb loopd: compaction threshold and the fallback summary
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-03 00:04:03 -07:00
kyleandornith-1.5-35b-a3b 45984b45be loopd: replay a carried summary as an unlogged user message
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-02 23:46:06 -07:00
kyleandornith-1.5-35b-a3b 18039fa2e4 loopd: open the highest epoch and carry its summary
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-02 23:38:10 -07:00
kyleandornith-1.5-35b-a3b 518d6ec416 loopd: [compact] threshold, summary_chars and summarise
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-10-02 23:25:47 -07:00
kyleandornith-1.5-35b-a3b b33341c53a loopd: ask_memory as a core tool, and a wait of its own on brokerd
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-28 22:41:37 -07:00
kyleandClaude Opus 5.5 e83b53b8b6 review: loopd prints every startup notice before it binds; tests wait for "serving on"
The serve tests waited for the socket file, then killed `loopd` and read its stderr, but the
socket is bound before its mode is set and before "serving on" and the broker notice are printed,
so a kill in between lost those lines (`pointers` failed once under load in M5c-1 task 15). The
broker notice now comes before the bind, so "serving on" is the last startup line, and the tests
wait for it (`tests/support/serving.rs`).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 14:26:37 -07:00
kyleandornith-1.5-35b-a3b 4866353ac9 loopd: a turn's speaker in the log, its number in SessionUpdated
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-28 10:33:36 -07:00
kyleandornith-1.5-35b-a3b c798714af1 bxcore: a turn's speaker, SessionUpdated's turn, the session-state messages
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-28 10:27:28 -07:00
kyleandClaude Opus 5.5 5a2464d81d loopd: the tag check asks /tokenize twice, not once per tag
Found in the M5b device check on straylight: the self-test asked about
each of the 33 tags and each neutralised form, 66 requests, one
connection each, and inferproxy's token bucket (burst 10) refused the
ninth, so loopd would not start. Now it asks about all the tags at once,
one per line, and then all their neutralised forms: the answer to the
first must hold each tag's recorded token in order, the second none of
them. Each tag is a special token, split out before anything else, so
the lines between cannot change it; and a neutralised form is only
dangerous as a tag's own token, so that is what the second answer must
not hold. The errors name a tag by its id, as before.

The fake tokenizer reads text with several tags in it; the tests cover
each tag as ordinary tokens, as another listed or unlisted token, a
duplicated token in the middle and at the end, a form holding each tag,
and both requests failing. Spec section 8 and the runbook entry follow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-27 19:08:42 -07:00
kyleandornith-1.5-35b-a3b fd0437a032 bxcore, loopd, inferproxy: a lock file keeps each to one instance
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-27 19:08:42 -07:00
kyleandornith-1.5-35b-a3b 0d3048c3c4 bxcore, loopd: TurnDone says whether the session has read untrusted content
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-27 19:08:42 -07:00
kyleandornith-1.5-35b-a3b 91992b9743 loopd: the self-test checks the model's tags against the tokenizer
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-27 19:08:42 -07:00
kyleandornith-1.5-35b-a3b b4d631e249 loopd: neutralise user messages, tool results and the memory block
Text from outside the model (the user's message, every tool result, and the
memory block) is neutralised the moment it is first logged, so every later
request replays the same bytes and a tag in that text cannot reach the model as
one of its own control tokens. The model's own output, replay, and the system
prompt are left byte-for-byte.

Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-27 19:08:42 -07:00
kyleandornith-1.5-35b-a3b de60c9e13a bxcore, brokerd, loopd: an invalid-arguments denial says why
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
2026-09-27 19:08:42 -07:00
kyleandClaude Opus 5.5 2b3ae080b4 proto becomes bxcore, the one shared crate (M5b task 00)
Done the way the owner asked and the spike mapped: the crate and the
manifests renamed, then what the build reported fixed. Layers: 138
"proto unresolved" errors across 169 files; cargo fmt reordering
imports; six fixture paths built as strings in brokerd's and bxctl's
tests, which the compiler cannot see, and comments naming
crates/proto/; the crate-dependency check and its self-test. One more
the spike did not reach: a `\nproto =` key inside a printf format in
the self-test, which a word-boundary replacement skips because `n` and
`p` are both word characters.

make gate: gate: ok, 944 tests; no new entry in /tmp.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 01:48:38 -07:00
kyle 15ee4b8e3d loopd: the memory block from memoryd, recall and memory as core tools
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-25 16:41:44 -07:00
kyleandClaude Opus 5.5 70d582acf5 BrokerPort: cap the wait after a pending frame at a day
M3a review finding 8. The wait was expires plus the timeout with no bound,
and the "expiry too far away" guard could not fire, so a far expiry (which
brokerd produces when now + ttl_ms does not fit) parked a turn for ever.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:08:48 -07:00
kyleandClaude Opus 5.5 33994d0dc6 loopd, bxctl, inferproxy: read args_os instead of panicking
M3a review finding 7, for the other three roles. loopd keeps its config path
as a path; bxctl and inferproxy take text arguments and answer one that is
not UTF-8 with their usage.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 21:07:59 -07:00
kyleandClaude Opus 5.5 00a85c124d loopd: read on a socket whose peer closed, instead of failing on macOS
macOS refuses every socket option with EINVAL once the peer has closed
(XNU sosetoptlock, bsd/kern/uipc_socket.c), even with unread data still
buffered. loopd set a read timeout before each read, so on macOS every
frame or response that arrived just before the peer closed was lost:
BrokerPort reported the broker unavailable with "os error 22", and the
llama client failed the same way. Twelve loopd test binaries failed on
macOS; Linux never refuses, so the gate on Talos did not see it.

Both places now go through socket::set_read_timeout, which on Apple
targets takes that one refusal as success: a socket shut in both
directions returns its data or the end at once and cannot block. A
zero timeout is still an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-22 18:27:31 -07:00
kyle 469be2c0a1 Add BrokerPort: loopd asks brokerd for every tool call
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 19:40:35 -07:00
kyle 1ceaa36b9b Give loopd's tool port approvals, its own clock and plain denials
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-20 17:43:05 -07:00
kyle c060c80c7e Fix four review findings: busy release, poison recovery, core.md errors, chat loop
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 21:06:58 -07:00
kyle eb8fc5f920 Add the loopd serve command
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:50:32 -07:00
kyle 8bc835f623 Add the channel server on loop.sock
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:43:12 -07:00
kyle 9063cf958e Add the turn loop with its limits
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 19:14:52 -07:00
kyle 9704a64507 Add the session store: baseline file and append-only log
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:42:00 -07:00
kyle b152ba3cd3 Add the baseline and the log replay function
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:31:33 -07:00
kyle fd7ade9689 Add the tool port, registry, dispatch and the fake tools
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 18:12:45 -07:00
kyle ec5d887daa Add the paths, channel, loop and baseline config tables
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 17:36:20 -07:00
kyle 0f5213a466 Return chunked body data as soon as it is available
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 16:15:22 -07:00
kyle f1d880568f Add the startup self-test and the loopd selftest command
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 15:28:37 -07:00
kyle 59cf89e7ba Add the per-slot gate and chat_with_retry
Implemented SlotGate (one request in flight per server slot, FIFO queue,
bounded) and chat_with_retry (retry only server-gone errors, jittered
backoff within a window and attempt budget). chat acquires the gate and
maps GateFull to Busy; Client gained a gate field.

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
2026-09-18 14:45:45 -07:00