iksir nestles at hum, drops the agent runtime - #4
Merged
Merged
Conversation
- types.ts: Add Rasul (full messenger), RisalaDakhila (inbound events), KhiyarTafauli (interactive options). Rename telegramMessageId → huwiyyatRisalaMuqaddim for provider-agnosticism. - messenger.ts: TelegramMessenger now implements full Rasul interface with baddaa()/awqaf()/indaRisala() lifecycle. Inbound Telegram routing moved here from main.ts — emits normalized RisalaDakhila events. arsalaSualBiKhiyarat() renders KhiyarTafauli[] as inline keyboards. - saail.ts: banaMafatihSatriyya() → banaKhiyarat() returns abstract KhiyarTafauli[] instead of Telegram-specific keyboard markup. - main.ts: SiyaqKhadim.telegram removed, only rasul: Rasul remains. addaMualijatTelegram() deleted — replaced by rabatRisalaDakhila() which routes RisalaDakhila events to business logic. All ctx.telegram calls converted to ctx.rasul.send/arsalaSualBiKhiyarat.
Iksir no longer drives OpenCode. It connects to a humd as a forager bee
over the thrum socket and prompts whichever hive al-Kimyawi has kindled.
The choice of what burns in the furnace was never Iksir's to make.
Substrate, replaced:
src/hum/thrum.ts NDJSON unix-socket client, hello + reconnect
src/hum/identity.ts stable fbee_<hex> hid from a persisted ed25519 seed
src/hum/client.ts AmilHum — the same surface the khuddam always used
khalaqaJalsa -> mint a sid locally (jalasat were always ours)
sendPrompt -> chi:"prompt" -> chunk* -> finish
abortSession -> chi:"cancel"
mahaqaJalsa -> chi:"cleanup"
summarizeSession -> chi:"curate" (no provider, no hardcoded model)
replyToQuestion -> chi:"release-permit"
question.asked <- chi:"permission-ask"
Two laws taken from humd's source, both load-bearing:
I. Manifests are volatile — humd clears them on restart and prunes on
disconnect. The hello therefore rides every connection, not just the
first, or Iksir stays nestled but unrouteable.
II. Iksir must never declare bee:["worker"]. humd re-broadcasts worker
output onto the sid sigil, and Iksir is the bee that claimed it.
Tool calls come off the wire now instead of a poll. humd routes chi:"tool-call"
by name to whichever manifest declares it; the 24 mun_* bodies are unchanged
and still inscribe their hadath into the sijill, so Munaffidh keeps draining a
durable table. The journal stays the record; the thrum is only the road.
Deleted: src/opencode/client.ts, plugins/iksir.ts, the @opencode-ai/sdk
dependency, the iksir-agent systemd unit, and the sync of prompts and plugins
into OpenCode's config dirs. The ruqan are Iksir's own — read from prompts/
and sent as systemPrompt, since nothing attaches "agents" by name any more.
config: opencode.server -> hum.{miqbas,namudhaj}, both optional. The socket is
discovered (HUM_THRUM_SOCK -> HUM_SOCKET -> humd's runtime.json -> state dir),
and the model is chosen by kindling a hive, not by configuring Iksir.
Note: two test files carried uncommitted edits from before this work and are
folded in here, since the rename had to reach them for the build to pass.
143 tests pass. Adds Orchfile so `hum hive <path> install` can supervise Iksir.
src/mcp/iksir-mcp.ts -> src/alat/alat-al-iksir.ts There was an MCP server there because OpenCode needed to be told what Iksir could do. Nothing needs telling any more: the adawat ride in the hello, humd merges every forager's tools into the foragerTools it hands each worker, and a nida comes back by name. What was left was a JSON-RPC costume over a tool registry, so the costume comes off. MunadiMunMcpServer -> AlatAlIksir aalijTalab(tools/call) -> naffidh(name, args): Promise<string> TaarifAlatMcp -> TaarifAla MuaallijAlatMcp -> MuaallijAla Deleted: the JSON-RPC envelope types, the tahyia/tools-list/tools-call dispatch, src/mcp/http-transport.ts, src/mcp/serve.ts, the iksir-mcp systemd unit and the Requires= that chained the daemon behind it, and IKSIR_MCP_PORT. The instruments themselves — all 24 of them — are untouched, and each still inscribes its hadath into the ahdath table for Munaffidh to drain. Also collapses the CLI's three-service machinery to one. The MCP server and the agent runtime were both Iksir's to supervise once; the nest is al-Kimyawi's concern now, and the instruments ride the daemon's own process. `iksir start mcp` and `iksir start agent` are gone with the services. Net -303 lines. 143 tests pass.
A deletion leaves no trace, so a comment explaining an absence only puzzles
whoever reads next. Git holds the why.
Rewrites the headers in alat-al-iksir.ts, hum/client.ts, cli.ts and main.ts
to state the mechanism rather than narrate the change away from it.
Two comments in katib.ts were not merely stale but wrong, and the second
describes a real gap rather than a wording one:
- aalajaDamj was documented as belt-and-suspenders behind a compaction
plugin that injected diary entries into the summary itself. With no
plugin, the follow-up message is the only thing carrying a murshid's
decisions across a curation.
- It claimed to catch nest-triggered compactions too. It does not. A
worker that curates itself on token overflow raises no tone Iksir
hears, so only curations Raqib asks for are caught.
143 tests pass.
The tree showed only the Khuddām, then dropped to the Buwtaqa, so Iksīr read as servants with nothing being guided. The Murshidun appeared in the prose but never in the diagram. They are not Khuddām. The split is lifetime: the Khuddām are eternal, one of each, and are Iksīr itself; the Murshidun are summoned per wasfa, are many, and perish when the work is done. A Sani hangs below each. The distinction matters more now that a Murshid is a cell burning in someone else's nest rather than a session Iksīr owns. Also updates ARABICIZED_TYPES.md for the renamed types.
Restoring state asked the amil whether each persisted jalsa still existed.
That check made sense against OpenCode, which owned the sessions. It does
not now: AmilHum answers from an in-memory map that is empty at boot, so
every row was skipped as "no longer exists" and katib restored nothing on
any restart. The rows survived, orphaned and unreachable, and the next
mention of a ticket minted a fresh vessel on a fresh branch.
The source of truth moved and the permission check stayed behind. This
removes it — hammalaHala restores every row unconditionally, and hands
each back to the amil via istaadaJalsa, which until now had no caller.
nestId rides in the existing hala_mufassala JSON beside activePRs, so a
resumed murshid carries its resume token and wakes remembering its work.
No schema migration needed.
Two more checks of the same kind go with it:
- wajadaAwKhalaqa asked the amil to confirm a session katib itself
tracked, and deleted its own entry when the amil said no.
- the title-search recovery path scanned the amil's map for sessions
katib had already registered, and rebuilt the branch name from scratch
rather than the persisted one. Dead, and wrong if it ever fired.
Raqib no longer claims a compaction it cannot confirm. summarizeSession
is fire-and-forget over the wire and always returns true, so "Auto-
compacted session X" was announced whether or not anything happened.
It now records the count when it asks, checks on a later heartbeat
whether the vessel actually shrank, and tells al-Kimyawi once when it
did not — which is also the honest outcome when a curation legitimately
trims nothing.
Adds a restart regression test: a vessel lit under one amil is restored,
with its nestId, by a second amil that has never heard of it. Verified to
fail with the old existence check in place.
144 tests pass.
Verified against a live humd (0.31.18, thrum 0.7.0): the hello is accepted, `bee.hid.registered` rather than `bee.hid.invalid`, and it counts forager.tools.registered count=23 Twenty-three, not twenty-four. The extra name in the old MCP file was the server's own, and that server is gone. Also withdraws an unfair note about WIRE.md. It documents an XDG_RUNTIME_DIR socket and I called it stale against the 0.32 source — but the running 0.31 daemon binds exactly where WIRE.md says. The default moved in 0.32; both are right for their version, which is precisely why the client asks runtime.json before falling back.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Iksīr no longer drives OpenCode. It connects to a
humdas a forager bee over the thrum socket and prompts whichever hive al-Kimyawi has kindled. The choice of what burns in the furnace was never Iksīr's to make.The ~70% that is genuinely Iksīr — Linear, GitHub,
istihalbranch surgery,mumayyiztriage, quiet hours, code-intel — never moved.The substrate
New
src/hum/:thrum.tsidentity.tsfbee_<hex>hid from a persisted ed25519 seedclient.tsAmilHum— the same surface the khuddām always calledthrum.test.tsThe tongue, translated once and nowhere else:
Two laws, taken from humd's source
Both load-bearing, both tested:
bee:["worker"]. humd re-broadcasts the output tones of any bee whose manifest carries"worker"onto the sid sigil — and Iksīr is the bee that claimed that sigil. It would hear its own voice returned.Instruments
src/mcp/becamesrc/alat/— Ālāt al-Iksīr (آلات الإكسير). There was an MCP server there because OpenCode needed telling what Iksīr could do; nothing needs telling now. The 23 instruments ride in the hello, humd merges every forager's into theforagerToolsit hands each worker, and a nida returns by name.Gone with it: the JSON-RPC dispatch,
http-transport.ts,serve.ts, theiksir-mcpsystemd unit and theRequires=chaining the daemon behind it. The instrument bodies are unchanged and each still inscribes its hadath into theahdathtable, so Munaffidh keeps draining a durable journal. The sijill is the record; the thrum is the road.Persistence
Restoring state asked the amil whether each persisted jalsa still existed — sensible against OpenCode, which owned sessions. Not now:
AmilHumanswers from a map that is empty at boot, so every row was skipped and katib restored nothing on any restart. The source of truth moved and the permission check stayed behind.hammalaHalanow restores unconditionally and hands each vessel back viaistaadaJalsa.nestIdrides in the existinghala_mufassalaJSON, so a resumed murshid carries its resume token — no schema migration. Two sibling checks went with it, including a title-search recovery path that rebuilt branch names from scratch rather than the persisted ones.Raqib no longer announces a compaction it cannot confirm. It records the count when it asks, checks later whether the vessel actually shrank, and says so once when it did not.
Verified against a live humd
0.31.18, thrum 0.7.0:
bee.hid.registeredrather thanbee.hid.invalidis the one thing a fake socket cannot tell you — a malformed hid breaks reconnect dedup silently and leaks a manifest every time.144 tests pass.
Known gaps
chi:"curate"is a no-op in humd today — it sits in thethrum.recv.todoarm. Raqib's compaction request is accepted and dropped, which is why raqib now measures instead of trusting. Upstream: feat(curate): wire chi:"curate" end to end hum#54.chi:"release-permit"likewise, and nothing emitspermission-ask, so Saail is unreachable — itspermission-askbody shape is inferred from the chi contract rather than observed.cli.tsJalsaSijilltype errors, untouched — they predate this branch.Config:
opencode.server→hum.{miqbas,namudhaj}, both optional. The socket is discovered (HUM_THRUM_SOCK→HUM_SOCKET→ humd'sruntime.json→ state dir) and the model is chosen by kindling a hive.What Iksīr asks of al-Kimyawi is one line, and it belongs in the README as a prerequisite: a nestled worker, plus something in the nest providing
fs. A murshid withoutfscan contemplate the runūz but never inscribe them.