Add whole-program background execution for embedders - #445
Open
tobert wants to merge 3 commits into
Open
Conversation
Kaijutsu needs asynchronous execution without bypassing kaish or losing custom tools and execution options. Add an API that validates a detached execution snapshot before returning its shared JobManager receipt. Publish statement output once, retain terminal cancellation and timeout diagnostics, and propagate embedder cancellation. Shell ampersand jobs keep their existing external-output streaming behavior. Validation: six focused async tests; cargo test --all; cargo clippy --all --all-targets; rustdoc with warnings denied. DeepSeek V4 Flash reviewed the whole kernel and job manager; snapshot and terminal-diagnostic findings were fixed and retested. Co-Authored-By: GPT-5.6 Terra <noreply@openai.com> Co-Authored-By: GPT-6 <noreply@openai.com> Co-Authored-By: DeepSeek V4 Flash <noreply@deepseek.com>
tobert
added a commit
to tobert/kaijutsu
that referenced
this pull request
Sep 12, 2026
Amy chose asynchronous shell submission as the default and removed the background flag and host-shell escape path. foreground=true explicitly waits. Both modes use kaish and the same gate; pending approvals return stable operation/ask receipts and complete into separate output blocks. Reuse a context-owned kaish JobManager for native operations and RPC jobs. Add operation inspection/cancellation and extend kj wait to operations, ask decisions, and jobs without making timeout cancel the work. Persist results and keep read-only shells from mutating shared jobs. Pin the reviewed whole-program Kaish API from tobert/kaish#445. A continuation window lasts 30 minutes after the last inference request; yield does not refresh it. Explicit handoff signoff closes the window. Capture epochs on asks and operations, claim eligible automatic wakeups once, and preserve results after window closure. Capture separately supplied stdin for reviewer inspection and approval replay. Update coder instructions, schemas, client receipts, and ACP/TUI interface checks. Validation: kernel 2874 tests (6 ignored), server 244, MCP 95, types 336; client 164, TUI 331, ACP 103; wire approval identity 1, lifecycle 18, gate execution 13, MCP shell end-to-end 6; final hook-stdin regression failed before its fix and the hook suite passed afterward. Isolation fixtures compile; container execution was not run. Emitted wait/signoff help and shell schemas inspected; generated prompt comparison checked. DS4 reviewed the Kaish API and async operation code; completion deduplication and lock lifetime fixes were checked. Remaining recovery/output work is recorded in docs/issues.md. Co-Authored-By: GPT-5.6 Terra <noreply@openai.com> Co-Authored-By: GPT-6 <noreply@openai.com> Co-Authored-By: DeepSeek V4 Flash <noreply@deepseek.com>
The result a background program settles with could lose data. A
runtime fault replaced it with the error's outer line, so
`echo out; x=$((1/0))` settled with empty stdout and no cause.
Timeout and cancellation diagnostics were picked from exit codes 124
and 130, so `exit 124` reported a timeout, and a cancelled external
child, which exits 143, reported nothing.
The job now accumulates the statement results it streams. A fault
keeps that output and appends the `{:#}` cause chain.
`run_under_watchdog` returns its diagnostic when the deadline actually
elapsed, and cancellation is read from the job's token; a failed
result under a tripped token reports 130. Each terminal diagnostic
lands in the result and, through the same output channel, after the
statement stderr in the stream.
Validation runs on the one fork that executes rather than on a second
snapshot, and skips AST mode the way foreground execution does. Parse
and validation are shared helpers; `validate_parsed` avoids the name
`validator::validate_program` already carries on main. A failed job's
result carries the embedder's egress baggage.
Co-Authored-By: DeepSeek V4 Flash <noreply@deepseek.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
This was referenced Sep 12, 2026
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.
Kaijutsu's asynchronous shell returns an operation receipt and later reads the job's result, so it needs kaish to start a whole program as a job without rewriting the source into
cmd &.Kernel::execute_background_with_optionsparses and validates the source on the fork that will run it, registers a job only when that passes, and returns theJobId. The job keeps the call's variables, cwd, tools, timeout, and cancel token;JobManager::cancelreaches builtins and child process groups.Output reaches the job's streams after each top-level statement finishes. External children in this job do not tee into the streams, so no byte is written twice. Shell
&jobs keep teeing external output as it arrives.A timeout, a runtime fault, and a cancellation are not statements, so no statement callback carries their diagnostic. The job appends it to both the result and the stderr stream, after the statement stderr that came before it. A fault keeps the output that ran before it and names its cause; a result built from the error alone had lost both:
Timeout and cancellation are read from the watchdog deadline and the job's token, not from the exit code, so
exit 124andexit 130add no diagnostic, and a cancelled external child reports 130 rather than its signal's 143.run_under_watchdognow returns its diagnostic when the deadline elapsed. Parsing and validation moved intoKernel::parse_programandKernel::validate_program, which foreground execution and the background preflight share.Co-Authored-By: GPT-5.6 Terra noreply@openai.com
Co-Authored-By: GPT-6 noreply@openai.com
Co-Authored-By: DeepSeek V4 Flash noreply@deepseek.com
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
🤖 Generated with Claude Code