[draft] fix(agent_subrun): launch a wasm engine through moonrun - #1292
Open
bobzhang wants to merge 1 commit into
Open
[draft] fix(agent_subrun): launch a wasm engine through moonrun#1292bobzhang wants to merge 1 commit into
bobzhang wants to merge 1 commit into
Conversation
Every sub-run under `moonx` died at spawn:
explore produced no report (Failed("subrun spawn failed:
OSError(\"@process.spawn(): Permission denied\")"))
`self_executable()` resolves the child from argv[0], which on a wasm build is
the `.wasm` module itself. No OS will `exec` that, so the `explore`, `review`,
and `subtask` tools and the `--review-gate` audit all failed while the parent
turn worked fine — the failure only shows up on a backend CI never spawned
children on. (`--concurrency` best-of-N is unaffected: its attempts are
in-process tasks, not child engines.)
The module needs its runtime in front of it, `moonrun <module> -- <args...>`,
which is the shape `moonx` used to start the parent. Doing that rewrite in
`run_subrun`, once, just after the argv is fully assembled, fixes every caller
without touching a signature: `self_exe` stays a `String` and `agent_explore`'s
public `definition` is unchanged, so nothing downstream (`openseek_tui`) breaks.
There is no .mbti drift.
The runtime is named rather than discovered. Hosts normally hand a program a
way back to themselves — `process.execPath`, `sys.executable`, `RbConfig.ruby`
— and self-respawn goes through that; wasm has no equivalent, and `moonrun` is
the only host supplying the FFI this binary needs, so there is nothing to
choose between. The suffix test reads the child path rather than the parent's
own backend, which keeps a native parent pointed at a wasm engine working and
leaves the scripted test children alone.
Verified on the wasm build: explore now reports
`subrun_finished status="captured"` with citations, where it previously failed
three times.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xp3xk2xvGLmknC4eCFW3yX
bobzhang
force-pushed
the
fix/subrun-wasm-launcher
branch
from
September 5, 2026 08:22
49f5ab5 to
dde5e82
Compare
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.
Follow-up to #1290. With openseek 0.3.1 on mooncakes,
moonx bobzhang/openseek/cmd/openseek run '...'works — but only for flat runs. Anything that spawns a child engine died at spawn:Cause
self_executable()(cmd/openseek/subrun.mbt) resolves the child fromargv[0]. On a wasm build that is the.wasmmodule itself, which no OS willexec.Affected: the model-callable
explore,review, andsubtasktools, and the--review-gateaudit — every path that reaches@agent_subrun.run_subrun. The parent turn itself worked fine, which is why it was invisible to CI: the wasm row never spawned a child.Not affected:
--concurrencybest-of-N (its attempts are in-process tasks on the same task group, not child engines) and theopenseek reviewsubcommand (in-process, no spawn).Fix
The module needs its runtime in front of it —
moonrun <module> -- <args...>, the same shapemoonxused to start the parent. The rewrite goes inrun_subrun, once, right after the argv is fully assembled (after the--sessionappend, so the fence lands in the right place).Doing it at that choke point fixes all four callers without touching a signature.
self_exestays aString,agent_explore's publicdefinitionis unchanged, and there is no.mbtidrift — soopenseek_tuiand any other consumer of the just-published 0.3.1 are unaffected.On naming the runtime rather than discovering it
Worth being explicit, since sniffing a file extension is not usually the right instinct.
A host normally hands a program a way back to itself —
process.execPath(Node),sys.executable(Python),RbConfig.ruby(Ruby) — and self-respawn is supposed to go through that API. wasm has no equivalent: a module cannot ask who is hosting it. There is also nothing to choose between here, becausemoonrunis the only host that supplies the FFI this binary needs (process spawn, sockets, filesystem) — a bare WASI runtime could not have run the parent either, so it can never be the answer.The suffix test reads the child path, not the parent's own backend. That keeps a native parent pointed at a wasm engine working, and leaves the scripted test children (
sh, absolute paths, bare names) untouched.Verification
Before, on the wasm build — three failed delegations. After:
launch_argvcover the rewrite, the empty-argv fence, native passthrough, scripted/PATH children, and.wasmas suffix-only (/build/wasm/openseekandopenseek.wasm.bakmust not trigger).moon test -p bobzhang/openseek/agent_subrun— 33/33 on both native and wasm.moon check,moon check --target wasm,moon fmt --checkall clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01Xp3xk2xvGLmknC4eCFW3yX