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 29, 2026, 3:48 AM ET / 07:48 UTC.

ClawSweeper review

What this changes

Adds optional public lifecycle hooks that let embedding hosts observe and admit ACP agent process launches, failures, and exits with session or probe scope metadata.

Merge readiness

⚠️ Ready for maintainer review - 3 items remain

Keep open for a maintainer product/API decision. The implementation and real embedding-host evidence are strong, but the new public admission hooks deliberately permit an embedding host to hold agent startup indefinitely, so that availability contract needs explicit acceptance.

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

Review scores

Measure Result What it means
Overall readiness 🦞 diamond lobster (5/6) A well-tested, real-proof-backed public API implementation awaiting a narrow maintainer contract decision.
Proof confidence 🦀 challenger crab (6/6) Sufficient (terminal): The supplied PR-body terminal trace runs the built public runtime API in a real WSL2 embedding host with a published codex-acp adapter, observes ordered lifecycle events through session initialization and close, and separately proves early-exit recovery plus a non-settling failure observer without altering the underlying spawn outcome.
Patch quality 🦞 diamond lobster (5/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The supplied PR-body terminal trace runs the built public runtime API in a real WSL2 embedding host with a published codex-acp adapter, observes ordered lifecycle events through session initialization and close, and separately proves early-exit recovery plus a non-settling failure observer without altering the underlying spawn outcome.
Evidence reviewed 6 items Public lifecycle contract: The branch defines immutable launch, started, failure, and exit event shapes, with awaited pre-spawn and post-spawn admission hooks and best-effort failure/exit observers.
Startup ordering and cleanup: Startup installs failure observation before awaiting post-spawn admission; rejected post-spawn admission terminates the child, and exit notification waits for admission settlement.
Runtime propagation: All inspected runtime client construction paths forward the host hook and assign runtime-session scope; the probe path uses runtime-probe scope.
Findings None None.
Security None None.

How this fits together

The runtime API creates ACP clients for embedded sessions and health probes, which spawn adapter processes and then establish ACP connections. This change exposes that spawn boundary to an embedding host before session initialization and when the child later exits.

flowchart LR
  A[Embedding host] --> B[Runtime options]
  B --> C[ACP client process launch]
  C --> D{Lifecycle admission hook}
  D --> E[ACP session initialization]
  C --> F[Spawn failure or process exit]
  F --> G[Host lifecycle observer]
Loading

Decision needed

Question Recommendation
Should ACPX make unbounded, embedding-host-owned awaited admission hooks a stable public runtime contract? Adopt host-owned admission policy: Accept the opt-in contract as implemented, with embedding hosts responsible for their own timeout and recovery behavior.

Why: The implementation intentionally makes hook completion part of the process-start boundary, so choosing a timeout or recovery policy changes the public availability contract rather than repairing a coding defect.

Before merge

  • Resolve merge risk (P2) - Awaited onBeforeSpawn and onSpawned callbacks have no timeout or cancellation boundary, so an embedding host can indefinitely delay startup; after a child has spawned, its exit observer is intentionally held until onSpawned settles.
  • Complete next step (P2) - A maintainer must choose the public availability semantics; there is no discrete mechanical repair to route automatically.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production versus test delta production +242/-18, tests +294/-3, changelog +2 The public runtime feature has more focused regression coverage than production growth, including propagation and lifecycle-race cases.

Merge-risk options

Maintainer options:

  1. Accept host-owned admission policy (recommended)
    Merge with the documented opt-in availability tradeoff: an embedding host must bound or recover its own awaited admission hook.
  2. Bound admission before merge
    Add a deliberate timeout or cancellation contract and focused recovery proof for a non-settling admission callback.
  3. Pause the public API
    Do not land the lifecycle seam until maintainers want to support its long-term availability semantics.

Technical review

Best possible solution:

Adopt the public hook only if maintainers explicitly accept host-owned timeout and recovery policy; otherwise define a bounded admission/cancellation contract before releasing it.

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

Not applicable as a feature request; the supplied real embedding-host terminal trace nevertheless exercises the changed public runtime boundary and its failure cases.

Is this the best way to solve the issue?

Unclear pending product direction: the implementation handles the tested process races, but maintainers must choose whether unbounded host-owned admission is the desired stable API policy.

AGENTS.md: found and applied where relevant.

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

Labels

Label justifications:

  • P2: This is a useful but non-urgent public runtime API addition requiring a bounded maintainer decision.
  • merge-risk: 🚨 availability: The introduced awaited admission callbacks can intentionally stall process startup until the embedding host settles them.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦀 challenger crab and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The supplied PR-body terminal trace runs the built public runtime API in a real WSL2 embedding host with a published codex-acp adapter, observes ordered lifecycle events through session initialization and close, and separately proves early-exit recovery plus a non-settling failure observer without altering the underlying spawn outcome.
  • proof: sufficient: Contributor real behavior proof is sufficient. The supplied PR-body terminal trace runs the built public runtime API in a real WSL2 embedding host with a published codex-acp adapter, observes ordered lifecycle events through session initialization and close, and separately proves early-exit recovery plus a non-settling failure observer without altering the underlying spawn outcome.

Evidence

What I checked:

  • Public lifecycle contract: The branch defines immutable launch, started, failure, and exit event shapes, with awaited pre-spawn and post-spawn admission hooks and best-effort failure/exit observers. (src/types.ts:234, 08a86019e73e)
  • Startup ordering and cleanup: Startup installs failure observation before awaiting post-spawn admission; rejected post-spawn admission terminates the child, and exit notification waits for admission settlement. (src/acp/client.ts:849, 08a86019e73e)
  • Runtime propagation: All inspected runtime client construction paths forward the host hook and assign runtime-session scope; the probe path uses runtime-probe scope. (src/runtime/engine/manager.ts:898, 08a86019e73e)
  • Focused regression coverage and real proof: Added tests cover event ordering, rejected admission cleanup, nonblocking failure observers, early exit during admission, and runtime scope forwarding. The supplied full PR body also contains a redacted terminal trace of the built public runtime API with a real codex-acp adapter, an early-exit scenario, and an OS spawn failure. (test/client.test.ts:1421, 08a86019e73e)
  • Current-main and release check: The current fetched main snapshot contains no occurrences of the new lifecycle API names under src, the PR head is not contained by a release tag, and v0.13.2 predates the current main commit. This feature is neither merged nor shipped. (ef6b81e71756)
  • Feature-history routing: Recent public runtime embedding seams include permission-policy and prompt-readiness work by xenaocx-dev, Vincent Koc, and Peter Steinberger; the current client/runtime history is shared rather than owned by the PR author alone. (src/runtime/public/contract.ts:351, 3cd61f404818)

Likely related people:

  • steipete: Peter Steinberger authored recent runtime lifecycle and embedding-adjacent changes, released the current main snapshot, and was explicitly asked for the API decision in the discussion. (role: recent runtime-area contributor and likely API decision owner; confidence: high; commits: 1ee1e82c2357, 5ef9b5849e13, ef6b81e71756; files: src/runtime/public/contract.ts, src/acp/client.ts)
  • xenaocx-dev: Introduced the existing public runtime permission-policy seam, a close precedent for reviewing a new host callback contract. (role: introduced adjacent public embedding behavior; confidence: medium; commits: 3cd61f404818; files: src/runtime/public/contract.ts)
  • Vincent Koc: Has substantial recent history in the ACP client and public runtime surface, including the existing prompt-readiness embedding API. (role: recent ACP client and runtime contributor; confidence: medium; commits: 5f8960a949a0, f29a0e5ae133; files: src/acp/client.ts, src/runtime/public/contract.ts)

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 (10 earlier review cycles; latest 8 shown)
  • 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
  • reviewed 2026-08-24T13:50:48.211Z sha 08a8601 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-24T22:07:28.039Z sha 08a8601 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-25T10:07:02.087Z sha 08a8601 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-28T23:35:47.430Z sha 08a8601 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-29T03:47:53.153Z 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
@MertBasar0

Copy link
Copy Markdown
Author

@steipete This is ready for a maintainer product/API decision. The current head includes real embedding-host proof, all repository checks pass, and ClawSweeper reports no actionable findings.

Could you confirm whether ACPX should adopt the opt-in awaited onBeforeSpawn / onSpawned admission hooks as a public runtime contract, with timeout and recovery policy owned by embedding hosts?

If so, the PR is ready as-is. If you prefer bounded timeout/cancellation or nonblocking semantics, I’m happy to adjust.

@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Aug 29, 2026
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: 🦞 diamond lobster Very strong PR readiness with only minor 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