Skip to content

feat(runtime): expose process lifecycle hooks to embedding hosts - #514

Open
MertBasar0 wants to merge 3 commits into
openclaw:mainfrom
MertBasar0:feat/process-lifecycle-hooks
Open

feat(runtime): expose process lifecycle hooks to embedding hosts#514
MertBasar0 wants to merge 3 commits into
openclaw:mainfrom
MertBasar0:feat/process-lifecycle-hooks

Conversation

@MertBasar0

@MertBasar0 MertBasar0 commented Aug 22, 2026

Copy link
Copy Markdown

Related: #499

Context: openclaw/openclaw#128006

What Problem This Solves

Embedding hosts can launch ACP agents through AcpClient or AcpRuntime, but they currently have no supported way to durably record process ownership around the exact spawn boundary. Hosts that need crash recovery or process-lease reconciliation must either wrap ACPX internals or accept a gap between preparing a launch and learning the child PID.

Why This Change Was Made

This adds an optional lifecycle contract with immutable, correlated events for pre-spawn admission, successful spawn, spawn failure, and process exit. Runtime-created clients also receive stable session/probe scopes.

The two admission hooks are deliberately awaited: rejecting before spawn prevents launch, while rejecting after spawn terminates the child before returning the error. Failure and exit observers remain best-effort and cannot mask the underlying process outcome. Exit notification is ordered after spawned admission settles, avoiding a stale-lease race when a child exits quickly.

This is an embedding seam only. It does not add persistence, process-tree cleanup, or host-specific lease policy to ACPX, and therefore does not claim to close #499.

User Impact

Embedding developers can now implement durable host-owned launch tracking without wrapping ACPX spawn internals. Existing clients are unaffected because every lifecycle hook is optional.

Evidence

  • Full pnpm run check passes in a clean Linux checkout: formatting, TypeScript checks, type-aware lint, package and replay-viewer builds, 942 repository tests, and 130 coverage tests.
  • Nine focused lifecycle/runtime regression tests pass, covering event ordering, admission rejection, child cleanup, spawn-failure correlation, a never-settling failure observer, early exit during successful spawned admission, initialization exit, runtime-session scope, and probe scope.
  • The P2 follow-up makes onSpawnFailed nonblocking while preserving synchronous invocation, correlation data, and logging for synchronous throws and asynchronous rejections.
  • The P1 follow-up installs startup-exit observation before awaited spawned admission and checks already-recorded child exit state, preventing startup from hanging when the agent exits while a successful admission hook is still pending.
  • Repository autoreview of the P2 follow-up delta completed cleanly: no accepted/actionable findings; overall result “patch is correct” (0.98 confidence).
  • Repository autoreview of the P1 follow-up delta also completed cleanly: no accepted/actionable findings; overall result “patch is correct” (0.88 confidence).
  • A real embedding-host run on the current PR head with the published @agentclientprotocol/codex-acp 1.6.2 adapter passes; redacted runtime proof is included below.
  • Branch is based on the current openclaw/acpx main at commit time.

Real embedding-host proof

Environment: WSL2 Linux x64, Node v24.15.0, PR head 08a8601, published @agentclientprotocol/codex-acp 1.6.2, existing Codex ChatGPT login. No credential values were logged. The temporary external host imported the built public dist/runtime.js API and used createAcpRuntime, createRuntimeStore, and createAgentRegistry; it was not added to the PR.

The first scenario initialized a real ACP session through codex-acp, then closed it. The second used a real Node child that exited with code 17 while a slow but successful onSpawned admission hook was pending. The third used a real OS spawn failure while onSpawnFailed deliberately returned a Promise that never settles.

environment platform=linux arch=x64 node=v24.15.0 head=08a8601 adapter=@agentclientprotocol/codex-acp@1.6.2
before_spawn launch=launch-1 scope=runtime-session:proof-session command=codex-acp cwd=<workspace>
spawned launch=launch-1 scope=runtime-session:proof-session pid=<ephemeral> startedAt=<timestamp>
session_ready sessionKey=proof-session backend=acpx backendSessionIdPresent=true
exit launch=launch-1 scope=runtime-session:proof-session pid=<same-ephemeral> exitCode=null signal=SIGTERM exitedAt=<timestamp>
assertion_pass scenario=real_adapter_lifecycle_current_head order=before_spawn,spawned,exit correlatedLaunch=launch-1
admission_before_spawn launch=launch-2 scope=runtime-session:admission-proof command=node cwd=<workspace>
admission_spawned_start launch=launch-2 scope=runtime-session:admission-proof pid=<ephemeral>
admission_spawned_end launch=launch-2 pid=<same-ephemeral>
admission_exit launch=launch-2 pid=<same-ephemeral> exitCode=17 signal=null
assertion_pass scenario=exit_during_successful_spawned_admission outcome=rejected errorName=AgentStartupError exitCode=17 stderrCaptured=true elapsedMs=104 deadlineMs=2000 order=before_spawn,spawned_start,spawned_end,exit
failure_before_spawn launch=launch-3 scope=runtime-session:failure-proof command=acpx-proof-agent-that-does-not-exist
spawn_failed_observer_entered launch=launch-3 errorName=AgentSpawnError
assertion_pass scenario=nonblocking_never_settling_spawn_failure_observer outcome=rejected errorName=AgentSpawnError observerCalled=true elapsedMs=104 deadlineMs=2000
proof_pass scenarios=real_adapter_lifecycle_current_head,exit_during_successful_spawned_admission,nonblocking_never_settling_spawn_failure_observer

The successful adapter PID and the admission-test PID were both confirmed exited after the run. No model prompt or inference was needed; this proof exercises the embedding boundary, real adapter process lifecycle, ACP session initialization, correlation, the repaired startup-exit path, and the repaired spawn-failure semantics.

AI assistance

The implementation was AI-assisted. I reviewed the resulting lifecycle contract, failure semantics, tests, generated diff, and real embedding-host trace, and validated it with the checks listed above.

@clawsweeper

clawsweeper Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 22, 2026
@clawsweeper

clawsweeper Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed August 24, 2026, 9:50 AM ET / 13:50 UTC.

ClawSweeper review

What this changes

The PR adds optional lifecycle callbacks to the embedding runtime so hosts can observe or gate ACP agent process spawn, spawn failure, and exit events.

Merge readiness

⚠️ Ready for maintainer review - 2 items remain

Keep open for maintainer review: the implementation is a focused, well-proven embedding feature, but it establishes a durable public lifecycle contract whose names, scopes, ordering, and admission semantics need explicit product sponsorship.

Priority: P2
Reviewed head: 08a86019e73ea140f5eb3e2eebfbc061344eb13e
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) Strong real-boundary proof and focused coverage support a good patch, pending the maintainer’s public-API decision.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR includes redacted live output showing the after-fix embedding boundary with a real adapter, real child exit, and real spawn failure.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR includes redacted live output showing the after-fix embedding boundary with a real adapter, real child exit, and real spawn failure.
Evidence reviewed 7 items Public lifecycle contract: The branch defines four optional lifecycle callbacks and typed immutable event payloads, including explicitly awaited pre-spawn and spawned admission hooks.
Startup and exit ordering: The client invokes pre-spawn admission before spawning, registers exit observation before awaited spawned admission, and releases exit notification only after that admission settles.
Runtime coverage: Runtime session creation, reconnect/control clients, and probes receive the shared observer with stable session or probe scopes; focused tests assert those propagated options.
Findings None None.
Security None None.

Live Verification

Command: pnpm run dev -- --help

Result: PASS (completed)

pnpm run dev -- --help
runner@runnervm76f27:/tmp/clawsweeper-live-proof-514-pbNtAS/target$ pnpm run dev -- --help

› acpx@0.13.1 dev /tmp/clawsweeper-live-proof-514-pbNtAS/target
› tsx src/cli.ts -- --help

pnpm run dev -- --help
Usage: acpx [options] [command] [prompt...]

Headless CLI client for the Agent Client Protocol

Arguments:
  prompt                                  Prompt text

Options:
  -V, --version                           output the version number
  --agent ‹command›                       Raw ACP agent command (escape hatch)
  --cwd ‹dir›                             Working directory (default: "/tmp/clawsweeper-live-proof-514-pbNtAS/target")
  --auth-policy ‹policy›                  Authentication policy: skip or fail when auth is required
  --approve-all                           Auto-approve all permission requests
  --approve-reads                         Auto-approve read/search requests and prompt for writes
  --deny-all                              Deny all permission requests
  --non-interactive-permissions ‹policy›  When prompting is unavailable: deny or fail
  --permission-policy ‹json-or-file›      Permission policy JSON or path (autoApprove, autoDeny, escalate, defaultAction)
  --policy ‹json-or-file›                 Alias for --permission-policy
  --format ‹fmt›                          Output format: text, json, quiet
  --suppress-reads                        Suppress raw read-file contents in output
  --model ‹id›                            Agent model id
  --allowed-tools ‹list›                  Allowed tool names as a comma-separated list (use "" for no tools)
  --max-turns ‹count›                     Maximum turns for the session
  --system-prompt ‹text›                  Replace the agent system prompt (claude-agent-acp via ACP _meta.systemPrompt)
  --append-system-prompt ‹text›           Append text to the agent system prompt (claude-agent-acp via ACP _meta.systemPrompt.append)
  --prompt-retries ‹count›                Retry failed prompt turns on transient errors (default: 0)
  --json-strict                           Strict JSON mode: requires --format json and suppresses non-JSON stderr output
  --no-fs                                 Do not advertise ACP filesystem capabilities
  --no-terminal                           Do not advertise ACP terminal capability
  --timeout ‹seconds›                     Maximum time to wait for agent response
  --ttl ‹seconds›                         Queue owner idle TTL before shutdown (0 = keep alive forever) (default: 300)
  --mcp-config ‹path›                     Load MCP servers from a JSON config file instead of project/global mcpServers
  --verbose                               Enable verbose debug logs
  -h, --help                              display help for command

Commands:
  pi [options] [prompt...]                Use pi agent
  openclaw [options] [prompt...]          Use openclaw agent
  codex [options] [prompt...]             Use codex agent
  claude [options] [prompt...]            Use claude agent
  gemini [options] [prompt...]            Use gemini agent
  cursor [options] [prompt...]            Use cursor agent
  copilot [options] [prompt...]           Use copilot agent
  droid [options] [prompt...]             Use droid agent
  fast-agent [options] [prompt...]        Use fast-agent agent
  grok-build [options] [prompt...]        Use grok-build agent
  iflow [options] [prompt...]             Use iflow agent
  kilocode [options] [prompt...]          Use kilocode agent
  kimi [options] [prompt...]              Use kimi agent
  kiro [options] [prompt...]              Use kiro agent
  mux [options] [prompt...]               Use mux agent
  opencode [options] [prompt...]          Use opencode agent
  pool [options] [prompt...]              Use pool agent
  qoder [options] [prompt...]             Use qoder agent
  qwen [options] [prompt...]              Use qwen agent
  trae [options] [prompt...]              Use trae age
… output truncated …

Assertions:

  • PASS expect_output: Usage:

How this fits together

ACPX’s embedding runtime creates ACP client processes for sessions, controls, and health probes. The new observer flows from runtime options into each client creation path, where it receives correlated child-process lifecycle events.

flowchart LR
  Host[Embedding host] --> Runtime[ACPX runtime]
  Runtime --> Scope[Session or probe scope]
  Scope --> Client[ACP client]
  Client --> Admission[Lifecycle admission]
  Admission --> Process[Agent process]
  Process --> Events[Spawn failure or exit events]
  Events --> Host
Loading

Decision needed

Question Recommendation
Should ACPX adopt these four lifecycle callbacks, scope values, and awaited admission semantics as part of its supported embedding API? Sponsor the lifecycle contract: Accept the narrow observer and admission seam for embedding hosts, with its documented ordering and optional hook behavior.

Why: The patch is technically coherent, but choosing a stable host-facing contract and its blocking semantics is a product boundary that cannot be inferred from tests alone.

Before merge

  • Resolve merge risk (P1) - The callback names, scope taxonomy, event ordering, and intentionally awaited admission hooks become a long-lived embedding API; a host that never settles an admission callback can intentionally block startup.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production versus regression coverage production +242/-18, tests +294/-3 The public runtime surface is accompanied by more regression coverage than implementation growth across client, session, and probe paths.

Merge-risk options

Maintainer options:

  1. Sponsor the lifecycle contract (recommended)
    Merge after maintainers explicitly accept that host admission hooks may delay agent startup and that the callback semantics are supported API.
  2. Pause for a narrower contract
    Keep the PR open or close it without merge until maintainers decide whether these process events belong in the runtime API.

Technical review

Best possible solution:

Sponsor the lifecycle API only if maintainers want ACPX to own this narrow host-observability seam, keeping persistence, lease policy, and process-tree cleanup outside core as the PR describes.

Do we have a high-confidence way to reproduce the issue?

Not applicable as a bug report; the submitted real-host trace demonstrates the proposed runtime behavior on the PR head.

Is this the best way to solve the issue?

Unclear: the implementation is narrow and matches ACPX’s backend-oriented vision, but maintainers must first choose whether this exact public lifecycle contract should exist.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d4c16ab32154.

Labels

Label justifications:

  • P2: This is a bounded embedding-runtime capability with meaningful but non-emergency impact.
  • merge-risk: 🚨 availability: Awaited host admission callbacks participate directly in agent-process startup and can delay or reject that startup by design.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR includes redacted live output showing the after-fix embedding boundary with a real adapter, real child exit, and real spawn failure.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR includes redacted live output showing the after-fix embedding boundary with a real adapter, real child exit, and real spawn failure.

Evidence

What I checked:

  • Public lifecycle contract: The branch defines four optional lifecycle callbacks and typed immutable event payloads, including explicitly awaited pre-spawn and spawned admission hooks. (src/types.ts:234, 08a86019e73e)
  • Startup and exit ordering: The client invokes pre-spawn admission before spawning, registers exit observation before awaited spawned admission, and releases exit notification only after that admission settles. (src/acp/client.ts:953, 08a86019e73e)
  • Runtime coverage: Runtime session creation, reconnect/control clients, and probes receive the shared observer with stable session or probe scopes; focused tests assert those propagated options. (src/runtime/engine/manager.ts:898, 08a86019e73e)
  • Current-main and release check: Current main d4c16ab does not contain this lifecycle API; v0.13.1’s changelog has no process-lifecycle entry, so the requested feature is neither implemented on main nor released. (src/types.ts:234, 08a86019e73e)
  • Feature-history provenance: Runtime embedding work predates this PR, including the original embedding API and prior host callback work; this makes the current runtime contributors the appropriate routing group. (src/runtime.ts:144, be510ba918d4)
  • Real behavior proof: The PR body provides redacted after-fix output from a real external embedding host using the built runtime API, a published ACP adapter, a real child exit during admission, and a real OS spawn failure. (08a86019e73e)

Likely related people:

  • Peter Steinberger: Recent current-main history includes runtime session lifecycle and embedding maintenance, and the current-main commit is authored by this contributor. (role: recent runtime contributor; confidence: medium; commits: d4c16ab32154; files: src/runtime.ts, src/runtime/engine/manager.ts, src/acp/client.ts)
  • Dani Akash: Feature history shows prior runtime metadata and host-driven permission callback additions, which are the closest established public callback pattern. (role: prior embedding API contributor; confidence: medium; commits: 6a609164fc37, f6de6dd18aae; files: src/runtime.ts, src/runtime/public/contract.ts)
  • Onur Solmaz: History identifies the original runtime embedding API and subsequent runtime stabilization work as the foundation for this public surface. (role: introduced embedding runtime; confidence: medium; commits: be510ba918d4, a983e63abfa9; files: src/runtime.ts, src/runtime/engine/manager.ts)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Obtain explicit maintainer sponsorship for the lifecycle contract and its awaited admission semantics.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (5 earlier review cycles)
  • reviewed 2026-08-22T22:28:35.937Z sha 6c6ac17 :: needs real behavior proof before merge. :: [P2] Do not await the best-effort spawn-failure observer
  • reviewed 2026-08-23T00:04:54.938Z sha a05817a :: needs changes before merge. :: [P1] Register startup exit observation before awaiting admission
  • reviewed 2026-08-23T15:08:32.876Z sha 08a8601 :: needs real behavior proof before merge. :: none
  • reviewed 2026-08-23T15:22:11.222Z sha 08a8601 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-23T15:44:03.186Z sha 08a8601 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 23, 2026
@MertBasar0

Copy link
Copy Markdown
Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event exact_review_queue).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. proof: sufficient Contributor real behavior proof is sufficient. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels Aug 23, 2026
@MertBasar0
MertBasar0 marked this pull request as ready for review August 23, 2026 15:41
@MertBasar0
MertBasar0 requested a review from a team as a code owner August 23, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-up on #433: ACP bridge lifeline / process cleanup

1 participant