@kodax-ai/kodax 0.7.96 → 0.7.97-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +85 -62
  3. package/README_CN.md +57 -67
  4. package/config-templates/config.example.jsonc +0 -14
  5. package/dist/chunks/{agent-7N427EVB.js → agent-J7SHFM5N.js} +1 -1
  6. package/dist/chunks/argument-completer-ZJQOWTIS.js +2 -0
  7. package/dist/chunks/{chunk-ABZDFK2X.js → chunk-2GV6MQ4T.js} +14 -14
  8. package/dist/chunks/{chunk-6QI3GOYG.js → chunk-3PS3YEDS.js} +1 -1
  9. package/dist/chunks/chunk-4VJMQDTH.js +417 -0
  10. package/dist/chunks/{chunk-NI7PBPUR.js → chunk-5DSUVP46.js} +1 -1
  11. package/dist/chunks/chunk-5P7RTSZT.js +21 -0
  12. package/dist/chunks/{chunk-XXNR6S4Q.js → chunk-6ZAQKFIM.js} +1 -1
  13. package/dist/chunks/chunk-7V2QBZ73.js +137 -0
  14. package/dist/chunks/{chunk-C7U542KM.js → chunk-F7DHZH6T.js} +1 -1
  15. package/dist/chunks/{chunk-7IMWOR34.js → chunk-HSRYDDPF.js} +1 -1
  16. package/dist/chunks/chunk-K3DQGSQU.js +372 -0
  17. package/dist/chunks/chunk-NO23K2CB.js +2 -0
  18. package/dist/chunks/{chunk-NKT3B3DR.js → chunk-OT5WHAX4.js} +1 -1
  19. package/dist/chunks/{chunk-YEAUDI6U.js → chunk-QGWHJIO4.js} +1 -1
  20. package/dist/chunks/chunk-QOFFAY5C.js +261 -0
  21. package/dist/chunks/{chunk-4PFZ7BEE.js → chunk-QVDTORL3.js} +11 -11
  22. package/dist/chunks/chunk-QZ4B4AWG.js +473 -0
  23. package/dist/chunks/chunk-RXDS6CNA.js +355 -0
  24. package/dist/chunks/{chunk-WV3DJVW4.js → chunk-VDGPJQL7.js} +135 -135
  25. package/dist/chunks/chunk-VEZ4WHPN.js +641 -0
  26. package/dist/chunks/chunk-ZPPAT25E.js +5 -0
  27. package/dist/chunks/chunk-ZQYWDI4O.js +1 -0
  28. package/dist/chunks/chunk-ZS2GUADU.js +498 -0
  29. package/dist/chunks/{chunk-GN2IY5YE.js → chunk-ZTYZYXGV.js} +1 -1
  30. package/dist/chunks/{chunk-EM4XJBTK.js → chunk-ZZQ4GDVU.js} +1 -1
  31. package/dist/chunks/{client-6WZZTTSV.js → client-MXOJ5XUN.js} +1 -1
  32. package/dist/chunks/{compaction-config-ZMEJU4U7.js → compaction-config-5VZSGKBQ.js} +1 -1
  33. package/dist/chunks/{construction-bootstrap-RX4DMHI7.js → construction-bootstrap-U2ZU2WAT.js} +1 -1
  34. package/dist/chunks/dist-CSLNWLOE.js +2 -0
  35. package/dist/chunks/dist-XXMJMJDU.js +2 -0
  36. package/dist/chunks/host-RUXYZFYN.js +2 -0
  37. package/dist/chunks/readline-helpers-JCVULR4C.js +2 -0
  38. package/dist/chunks/run-manager-DRIM5VNE.js +2 -0
  39. package/dist/chunks/utils-MQEBGKIX.js +2 -0
  40. package/dist/index.d.ts +63 -30
  41. package/dist/index.js +10 -6
  42. package/dist/kodax_bootstrap.js +1 -1
  43. package/dist/kodax_cli.js +1745 -1734
  44. package/dist/kodax_resume.js +32 -35
  45. package/dist/native/win32-x64/kodax-windows-sandbox.exe +0 -0
  46. package/dist/native/win32-x64/kodax-windows-text-transaction.node +0 -0
  47. package/dist/native/win32-x64/manifest.json +2 -2
  48. package/dist/sandbox-network-broker.js +77 -77
  49. package/dist/sdk-a2a.d.ts +33 -18
  50. package/dist/sdk-a2a.js +8 -9
  51. package/dist/sdk-agent.d.ts +33 -26
  52. package/dist/sdk-agent.js +1 -1
  53. package/dist/sdk-client.d.ts +40 -0
  54. package/dist/sdk-client.js +2 -0
  55. package/dist/sdk-coding.d.ts +87 -499
  56. package/dist/sdk-coding.js +1 -1
  57. package/dist/sdk-experimental-memory.d.ts +3 -4
  58. package/dist/sdk-experimental-memory.js +1 -1
  59. package/dist/sdk-llm.d.ts +11 -9
  60. package/dist/sdk-llm.js +1 -1
  61. package/dist/sdk-mcp.d.ts +3 -3
  62. package/dist/sdk-mcp.js +1 -1
  63. package/dist/sdk-media.d.ts +3 -1
  64. package/dist/sdk-media.js +1 -1
  65. package/dist/sdk-repl.d.ts +317 -70
  66. package/dist/sdk-repl.js +2 -2
  67. package/dist/sdk-runtime.d.ts +580 -452
  68. package/dist/sdk-runtime.js +1 -1
  69. package/dist/sdk-sandbox.js +1 -1
  70. package/dist/sdk-session.d.ts +13 -9
  71. package/dist/sdk-session.js +1 -1
  72. package/dist/sdk-skills.js +1 -1
  73. package/dist/semantic-worker.js +57 -57
  74. package/dist/types-chunks/{base.d-Bt9lhwSV.d.ts → base.d-ZBOdjDUT.d.ts} +2 -1
  75. package/dist/types-chunks/{bash-prefix-extractor.d-DWFIMg0v.d.ts → bash-prefix-extractor.d-DvswAXKS.d.ts} +136 -66
  76. package/dist/types-chunks/{capability-learning.d-gRtO03f6.d.ts → capability-learning.d-B4pxKwP4.d.ts} +1 -1
  77. package/dist/types-chunks/{capability.d-Ch5Vos33.d.ts → capability.d-DOF3r0fJ.d.ts} +1 -1
  78. package/dist/types-chunks/{capsule.d-Dj1n6s0Y.d.ts → capsule.d-B4atvlxE.d.ts} +7 -19
  79. package/dist/types-chunks/client-contract-A1jdk6xz.d.ts +1993 -0
  80. package/dist/types-chunks/{controller.d-C0IM1Tud.d.ts → controller.d-BkUJ_3sl.d.ts} +1 -1
  81. package/dist/types-chunks/{controller.d-J2t1q8Ly.d.ts → controller.d-yyKajPTi.d.ts} +140 -1380
  82. package/dist/types-chunks/{cost-tracker.d-BWI4lFWn.d.ts → cost-tracker.d-BeaenODW.d.ts} +2 -47
  83. package/dist/types-chunks/{history-retrieval.d-CPN5PMBV.d.ts → history-retrieval.d-JdFfkeF3.d.ts} +2 -2
  84. package/dist/types-chunks/{manager.d-rtmywU9M.d.ts → manager.d-C_20XqCV.d.ts} +8 -1
  85. package/dist/types-chunks/manifest.d-Bw2i-zQi.d.ts +18 -0
  86. package/dist/types-chunks/provider-credential-context.d-BH2OaB1b.d.ts +47 -0
  87. package/dist/types-chunks/provider-request-observation.d-jL8T6wVO.d.ts +34 -0
  88. package/dist/types-chunks/{public-api.d-amBop8Nk.d.ts → public-api.d-Cq8ILMte.d.ts} +52 -13
  89. package/dist/types-chunks/{resolver.d-BrwLoWNr.d.ts → resolver.d-DLY01RHx.d.ts} +4 -2
  90. package/dist/types-chunks/{types.d-CSv0_cZC.d.ts → review-inbox.d-BeaLRNHx.d.ts} +251 -3
  91. package/dist/types-chunks/{shell-command-sets.d-oejwpP_7.d.ts → review-packet.d-D4bbTbq3.d.ts} +46 -3
  92. package/dist/types-chunks/{exec-policy.d-BPESl90L.d.ts → run-manager.d-C7Q71rin.d.ts} +385 -62
  93. package/dist/types-chunks/runtime-client-info-CxnlZlW5.d.ts +175 -0
  94. package/dist/types-chunks/{sdk-session-B6XjHNU1.d.ts → sdk-session-BDFjCpDn.d.ts} +12 -4
  95. package/dist/types-chunks/{side-query.d-DHWG1JZg.d.ts → side-query.d-DTrhVd_r.d.ts} +4 -3
  96. package/dist/types-chunks/trusted-repl-entry-vbUM8R6P.d.ts +445 -0
  97. package/dist/types-chunks/{types.d-CtO8mR1s.d.ts → types.d-BJTN-RZr.d.ts} +5 -5
  98. package/dist/types-chunks/{types.d-BrQMB-hy.d.ts → types.d-BjOq57-z.d.ts} +6 -0
  99. package/dist/types-chunks/types.d-o7t9dds4.d.ts +1484 -0
  100. package/dist/types-chunks/{utils.d-DcznBeQ3.d.ts → utils.d-CWiMhFfu.d.ts} +202 -36
  101. package/docs/CLIENT_CONTRACT.md +441 -0
  102. package/docs/SDK_MIGRATION.md +123 -0
  103. package/docs/SPACE_SDK_SEAMS.md +139 -0
  104. package/package.json +10 -5
  105. package/public_docs/README.md +12 -133
  106. package/public_docs/configuration/config-files.md +8 -14
  107. package/public_docs/sdk/embedder-guide.md +494 -420
  108. package/dist/chunks/argument-completer-FAIHW7HZ.js +0 -2
  109. package/dist/chunks/chunk-66XN5AFU.js +0 -417
  110. package/dist/chunks/chunk-7O2AIFNE.js +0 -373
  111. package/dist/chunks/chunk-DSXUXUZG.js +0 -5
  112. package/dist/chunks/chunk-GYO73UYQ.js +0 -275
  113. package/dist/chunks/chunk-HPCS3LZ5.js +0 -324
  114. package/dist/chunks/chunk-HZYRLIOC.js +0 -137
  115. package/dist/chunks/chunk-SC2ELSUS.js +0 -675
  116. package/dist/chunks/chunk-TEUD5VPJ.js +0 -471
  117. package/dist/chunks/chunk-TYZ2ZAYL.js +0 -487
  118. package/dist/chunks/dist-3UCCMCYR.js +0 -2
  119. package/dist/chunks/dist-F5IWZSAY.js +0 -2
  120. package/dist/chunks/host-W2JJ3V3Q.js +0 -2
  121. package/dist/chunks/run-manager-RBWU3EVE.js +0 -2
  122. package/dist/chunks/utils-DJ4ZFJGL.js +0 -2
  123. package/dist/runtime-worker.js +0 -5381
  124. package/dist/types-chunks/review-inbox.d-CTeUIKda.d.ts +0 -225
  125. package/dist/types-chunks/run-manager.d-hm1XgEou.d.ts +0 -94
  126. package/dist/types-chunks/trusted-repl-entry-D0w5M0UZ.d.ts +0 -323
  127. package/dist/types-chunks/types.d-B1l9pWyX.d.ts +0 -146
@@ -1,48 +1,129 @@
1
- # KodaX SDK — Embedder Integration Guide
2
-
3
- Beta.3 repairs Windows WFP probe allocation in KodaX doctor and the bundled ASRT 0.0.65 dependency. SDK installs with `--ignore-scripts` receive the repair. Authenticated credential/Host Tool bridge takeover retires the old RPC connection so clients can reconnect and resume live scoped leases without replaying dispatched tools. Production and source-test TypeScript checks are separate; public SDK entry points remain unchanged.
4
-
5
- > Audience: host applications embedding `@kodax-ai/kodax` (and its
6
- > subpaths) as a substrate — e.g. KodaX Space's desktop wrapper, IDE
7
- > extensions, custom CLIs. If you are an end-user running the `kodax`
8
- > command-line tool, see the root [README.md](../../README.md) instead.
9
-
10
- This guide tracks the `v0.7.96` release; npm publication remains a
11
- separate manual maintainer step. The SDK
12
- advertises Windows `sandboxRuntime:11`, `runtimeAutoModeGuardrail:6`,
13
- `sharedSessionSettings:2`, `runtimeExitSettlement:2`, and
14
- `crashOutcomeModel:2`;
15
- trusted text transactions are split from platform shell containment
16
- (cross-Runtime per-file kernel locking, revision CAS, flushed atomic
17
- replacement, and a native restricted-token Windows shell runner behind
18
- native shell protocol version 10/setup generation 10 with no command-lifetime
19
- global admission lock), and local tool-result capacity overflow
20
- records bounded `capacityDebt` and commits through a bounded recovery ladder
21
- instead of aborting the Run. On top of v0.7.95: per-command Windows sandbox
22
- runner/pipe/Job lifecycles, setup-only machine migration and recovery, rolling
23
- failed-broker replacement without an ordinary command lock or queue, stale learning-lock
24
- reclamation with fullscreen terminal teardown, exact-input Explicit Skill
25
- execution, and coding-result finalization before the public completion
26
- signal, on top of concurrent sandboxed text mutations,
27
- Session-persisted and Git-backlink-validated KodaX worktree roots (including
28
- strict `core.worktree` identity for a real submodule Session root),
29
- authorized-root git trust (`gitSafeDirectory: authorized-repo-roots`),
30
- scheduled shutdown failure reporting, missing-workspace Run start,
31
- `conversationHistory:2`, independent explicit Skill invocation, diagnosed
32
- invalid `allowed-tools` / malformed hook JSON, observed text-helper stdin
33
- failures, byte-bounded git-metadata reads, observed
34
- Run-finalization and process-cleanup rejections, typed disconnect facts,
35
- structured credential-safe Runtime failure details, and exact-`runId` recovery
36
- after reconnect
37
- on top of v0.7.93 failed-exit fast settlement, previous-boot ACL recovery, and
38
- isolated Anthropic/OpenAI abort classification, plus the v0.7.92
39
- filesystem-effect operation-token coordinator, recorded-release owners,
40
- managed Session-before-completion ordering, and canonical-first resume
41
- reconstruction. v0.7.91 still supplies bounded owner-scoped interactions,
42
- stale prepared-Session recovery, crash-resumable Runtime exit settlement,
43
- effective live output segments, and standalone lazy provider dependency
44
- bundling.
1
+ # KodaX SDK — Product Client and Host Integration
2
+
3
+ This page describes the current FEATURE_298/299 development tree, whose package
4
+ baseline is `0.7.97-alpha.1`. Some seam additions are newer than that baseline; this does not
5
+ claim that this contract is already published to npm. Check the installed
6
+ package exports and the connected Host's capabilities when migrating.
7
+
8
+ For applications sharing KodaX sessions, use `KodaXProductClient` from
9
+ `@kodax-ai/kodax/client`. The Host owns execution, configuration and persistence;
10
+ clients submit intent, answer interactions and render Host facts. The old
11
+ `KodaXClient` / `Client` classes and low-level Runtime facade are different
12
+ objects, not alternate names for this contract.
13
+
14
+ - [Product integration](#product-client-integration): connection and lifecycle.
15
+ - [Migration guide](../../docs/SDK_MIGRATION.md): old-to-new calls, ownership,
16
+ errors, history, cancellation and acceptance checklist (Chinese).
17
+ - [Complete Client contract](../../docs/CLIENT_CONTRACT.md): normative behavior
18
+ and method inventory; [types](../../packages/coding/src/client-contract.ts).
19
+ - [Removed surfaces](#migrating-to-v0797): breaking changes and replacements.
20
+ - [Space Host seams](../../docs/SPACE_SDK_SEAMS.md): trusted Main authorization,
21
+ canonical Fork/Retry/Rewind, Host configuration, attachments, statistics and lifecycle limits.
22
+ - Numbered sections below retain low-level library/Host guidance and historical
23
+ release context. They are not instructions for a product UI to create its own
24
+ execution owner or write the shared Host's files.
25
+
26
+ ## Product Client integration
27
+
28
+ ### Choose the connection entry
29
+
30
+ | Need | Entry | Ownership |
31
+ | --- | --- | --- |
32
+ | Start or attach a local compatible Host | `ensureKodaXClient(options)` | Uses the shared launcher; updates only an eligible idle Host |
33
+ | Attach without starting or replacing a Host | `connectKodaXClient(options)` | Passive Node connection |
34
+ | Browser/UI contract types | `import type` from `/client` or `@kodax-ai/coding/client-contract` | No running Host or browser transport is provided by types |
35
+ | Trusted Host bootstrap, scoped credentials, Host Tools, explicit embedding | `/runtime` | Separate low-level authority; never a fallback after product connection failure |
36
+ | Independent Agent/LLM/coding library | `/agent`, `/llm`, `/coding` | Independently usable; not a shared-Session product client |
37
+
38
+ Both product constructors return `Promise<KodaXProductClient>`. The `/client`
39
+ subpath is ESM; CommonJS hosts use `await import('@kodax-ai/kodax/client')`.
40
+ It is not a root-entry re-export. `endpoint` is a local named pipe/Unix socket,
41
+ not an HTTP/WebSocket address. A browser application needs its own supported
42
+ bridge; do not import the Node connector into browser code.
43
+
44
+ `homeDir` is the base directory containing `.kodax`, not `.kodax` itself.
45
+ `connect` additionally accepts `endpoint` and `token`; `ensure` accepts
46
+ `daemonStartupTimeoutMs`. Both accept `profile` and `clientInfo`. Presentation
47
+ metadata such as `clientInfo.name` grants no authority. Configure provider
48
+ credentials at the Host, rather than passing API keys in input submissions.
49
+
50
+ ### Observe, submit, and settle
51
+
52
+ The following helper uses an existing Client and Session. The application owns
53
+ connection/session selection and supplies renderers that replace the displayed
54
+ view and answer `view.interactions` through `client.interactions.respond`.
55
+ Without an interaction UI, a Run can legitimately wait for an answer. This
56
+ example neither auto-approves requests nor infers completion from rendering.
45
57
 
58
+ ```ts
59
+ import type {
60
+ KodaXProductClient, ClientSessionView, ClientObservationStatus,
61
+ } from '@kodax-ai/kodax/client';
62
+
63
+ export async function submitImmediate(
64
+ client: KodaXProductClient,
65
+ sessionId: string,
66
+ inputId: string,
67
+ text: string,
68
+ render: (view: ClientSessionView) => void,
69
+ showConnection: (status: ClientObservationStatus) => void,
70
+ ) {
71
+ const observation = await client.sessions.observe(sessionId, render, {
72
+ onStatus: showConnection,
73
+ });
74
+ try {
75
+ const accepted = await client.inputs.submit({
76
+ sessionId, inputId, text, delivery: 'immediate',
77
+ });
78
+ if (accepted.state !== 'submitted' || !accepted.runId) {
79
+ throw new Error(`Input ${inputId} is ${accepted.state}; inspect its receipt before continuing.`);
80
+ }
81
+ return await client.runs.await(accepted.runId);
82
+ } finally {
83
+ observation.close(); // Detaches this observer; does not stop the Run.
84
+ }
85
+ }
86
+ ```
87
+
88
+ Keep `inputId`, original text and artifacts before calling this helper. After a
89
+ lost response query `inputs.read(sessionId, inputId)` on the same Host; never
90
+ silently create a new ID and resubmit. This helper handles only immediate
91
+ submission; queued, steer and redirect flows must follow their acceptance state.
92
+
93
+ Create/select sessions using `client.sessions.create({projectPath})` or
94
+ `list/read`. Use `client.sessions.updateSettings` for execution choices, then
95
+ submit input. On application disposal call `client.disconnect()`; use
96
+ `runs.stop` or `sessions.cancel` for explicit Stop, and `host.shutdown()` only
97
+ for an explicit request to close an idle Host. `phase: 'unknown'` from
98
+ `runs.await` is an uncertain outcome, not success, even on a healthy connection.
99
+
100
+ ### Replace the consumption model
101
+
102
+ | Concern | Product surface | Consumer responsibility |
103
+ | --- | --- | --- |
104
+ | Current UI | `sessions.observe` | Replace each view; bounded items are not a complete transcript |
105
+ | Full display item | `sessions.readItem` | Keep the observed ID; validate paginated original text/input |
106
+ | History/search | `readHistory`, `readHistoryEntry`, `searchHistory` | Keep page revision and distinct history IDs; no cross-revision splicing |
107
+ | Settings and discovery | `sessions.*Settings`, `config.*`, `catalog.*` | Distinguish saved overrides/defaults from effective settings |
108
+ | User questions and permissions | `interactions.list/respond`, `view.interactions` | Reply to the exact request; use only Host-provided grant suggestions |
109
+ | Commands/Skills/review | `commands.*`, `inputs.submit`, `review.start` | Host prepares trusted execution; returned Run IDs are followed, not resubmitted |
110
+ | Command feedback | `sessions.appendNotice` | Durable client-only notices; report failures without re-running commands |
111
+ | MCP/Agents/Memory/Learning/Workflow | `mcp`, `registrations`, `agents`, `memory`, `learning`, `workflows` | Use domain operations; keep executable modules and local owners out of UI code |
112
+
113
+ Observation connection errors, pending interactions and Run terminal outcomes
114
+ are separate facts. Workflow/Learning subscription `ready` confirms registration,
115
+ not snapshot synchronization; rebuild a failed subscription and read its current
116
+ snapshot. Reconnect does not authorize replaying mutations. See the complete
117
+ Client contract for nullable reads, revision conflicts, lifecycle error handling,
118
+ and feature-specific Host compatibility checks.
119
+
120
+ ## Low-level reference and release history
121
+
122
+ The sections below describe independent libraries, trusted Host capabilities and
123
+ past release decisions. Their examples are scoped to those layers. Product UI
124
+ migrations follow the entry and lifecycle above; retained low-level exports do
125
+ not mean every low-level capability has a Product Client equivalent. Historical
126
+ capability versions and removed APIs must be read with the migration table.
46
127
  This guide documents the SDK surfaces a host integrator needs that
47
128
  are NOT obvious from inspecting the type definitions alone:
48
129
 
@@ -62,7 +143,7 @@ are NOT obvious from inspecting the type definitions alone:
62
143
  14. [Media input artifacts — `@kodax-ai/kodax/media`](#14-media-input-artifacts--kodax-aikodaxmedia-feature_239-v0756)
63
144
  15. [Space v0.7.57 follow-up ledger](#15-space-v0757-follow-up-ledger)
64
145
  16. [SDK agent-profile surface — `KodaXAgentProfile`](#16-sdk-agent-profile-surface--kodaxagentprofile-feature_247-v0758)
65
- 17. [Runtime SDK, Worker isolation, and local daemon](#17-runtime-sdk-worker-isolation-and-local-daemon-feature_253-feature_257)
146
+ 17. [Runtime SDK and local daemon](#17-runtime-sdk-and-local-daemon-feature_253-feature_257)
66
147
  18. [External-agent executor plane](#18-external-agent-executor-plane-feature_258-v0767)
67
148
  19. [Session surface filtering and cursor pagination](#19-session-surface-filtering-and-cursor-pagination-feature_261-v0767)
68
149
  20. [Cost-disciplined workflow routing and telemetry](#20-cost-disciplined-workflow-routing-and-telemetry-feature_259-v0767)
@@ -77,6 +158,7 @@ are NOT obvious from inspecting the type definitions alone:
77
158
  29. [Evidence-gated background Skill learning](#29-evidence-gated-background-skill-learning-feature_263-v0778)
78
159
  30. [Standalone sandbox SDK](#30-standalone-sandbox-sdk-v0778)
79
160
  - [Learned Skill promotion reference](#learned-skill-promotion-reference-v0778)
161
+ - [Migrating to v0.7.97](#migrating-to-v0797)
80
162
 
81
163
  §1–§3 (and the Phase-7/8 MCP-popout surface in §1) land in v0.7.42
82
164
  under FEATURE_186 (see [ADR-032](../../docs/ADR.md#adr-032-sdk-embedder-surface-closure-feature_186-v0742)).
@@ -95,6 +177,9 @@ under FEATURE_186 (see [ADR-032](../../docs/ADR.md#adr-032-sdk-embedder-surface-
95
177
 
96
178
  ## 1. MCP server management — `McpManager` runtime API
97
179
 
180
+ > Independent MCP library reference. Product clients use `client.mcp` and
181
+ > `client.catalog`; they do not instantiate a manager or edit the Host's JSON.
182
+
98
183
  ### Why this exists
99
184
 
100
185
  `@kodax-ai/kodax/mcp` re-exports `McpCapabilityProvider`, which is the
@@ -723,6 +808,9 @@ subpaths in a follow-up release.
723
808
 
724
809
  ## 6. Session persistence — wiring `runKodaX` to disk
725
810
 
811
+ > Independent in-process library ownership only. Product clients use
812
+ > `client.sessions` and never attach a `SessionStorage` to a shared Host.
813
+
726
814
  ### The trap
727
815
 
728
816
  ```ts
@@ -1028,14 +1116,13 @@ lineage tail, or concurrent durable write fails with
1028
1116
  `SessionReadError.code === 'data_changed'`. Reload, obtain a fresh boundary,
1029
1117
  and rebuild the tail before retrying.
1030
1118
 
1031
- Host-owned Ink sessions follow the same rule: their prepared-tail persistence helper
1119
+ Standalone Session owners follow the same rule: the prepared-tail persistence helper
1032
1120
  falls back to `appendSessionDelta(id, data)` after `data_changed`, so the
1033
1121
  authoritative full snapshot merges the newest UI/session state. Background
1034
1122
  write failures are emitted as structured diagnostics; they are not swallowed
1035
1123
  and a stale tail is never retried unchanged.
1036
- Runtime-owned Ink sessions instead save host display/settings state and adopt
1037
- the Runtime's durable lineage, as described in
1038
- [transcript ownership](#unreleased-interrupted-run-recovery-and-transcript-ownership).
1124
+ Product Ink sessions use the Host Client API and never save a competing local
1125
+ transcript or lineage; see [transcript ownership](#unreleased-interrupted-run-recovery-and-transcript-ownership).
1039
1126
 
1040
1127
  A non-null fulfilled append result is the reusable successor boundary. A
1041
1128
  fulfilled `null` means the tail did commit exactly once, but the successor
@@ -1580,6 +1667,9 @@ and your Node / OS / SDK version.
1580
1667
 
1581
1668
  ## 10. Model capabilities — context window, reasoning, descriptors
1582
1669
 
1670
+ > Product consumers query `client.catalog` and effective Host settings. Direct
1671
+ > provider construction and credential access below belong to library/Host code.
1672
+
1583
1673
  ### Why this exists
1584
1674
 
1585
1675
  A popout-style UI typically wants to list every provider/model KodaX
@@ -1828,6 +1918,9 @@ metadata, we can promote the snapshot to derive from it.
1828
1918
 
1829
1919
  ## 11. Workflow process events and lifecycle controls (FEATURE_229, v0.7.50)
1830
1920
 
1921
+ > Product consumers use `client.workflows` with declarative inputs. The lower
1922
+ > level runner/module interfaces below remain Host integration mechanisms.
1923
+
1831
1924
  FEATURE_229 makes dynamic workflow progress a reusable SDK process surface
1832
1925
  instead of terminal-only text. Hosts can observe and control workflows without
1833
1926
  parsing `/workflow` output, replaying slash commands, or depending on Ink view
@@ -2559,9 +2652,9 @@ ambiguous call instead of risking cross-session delivery. Low-level child-Actor
2559
2652
  producers may continue to pass an explicit `agentId`.
2560
2653
 
2561
2654
  `enqueueWithArtifacts()` is an in-process queue helper for direct/inline runs.
2562
- Runtime Worker and daemon clients must use `runtime.runs.submitInput(...)` (with
2655
+ Daemon clients must use `runtime.runs.submitInput(...)` (with
2563
2656
  the same `sessionId` and `afterRunId`) because a process-local MessageQueue
2564
- cannot cross those transport boundaries. Use `delivery:'after_turn'` to create
2657
+ cannot cross the transport boundary. Use `delivery:'after_turn'` to create
2565
2658
  a continuation Run after the current Run ends, or `delivery:'interrupt'` to
2566
2659
  inject into the current active Actor Run at its next safe Runner boundary.
2567
2660
 
@@ -2682,18 +2775,25 @@ runKodaX({
2682
2775
 
2683
2776
  ---
2684
2777
 
2685
- ## 17. Runtime SDK, Worker isolation, and local daemon (FEATURE_253-FEATURE_257)
2778
+ ## 17. Runtime SDK and local daemon (FEATURE_253-FEATURE_257)
2686
2779
 
2687
2780
  `@kodax-ai/kodax/runtime` is the stable host-facing runtime facade for
2688
2781
  applications that want KodaX as a substrate instead of only as a terminal CLI.
2689
2782
  It wraps the same coding/session engine used by the REPL and exposes it through
2690
- one interface in three deployment shapes:
2783
+ one interface in two deployment shapes:
2691
2784
 
2692
2785
  - **embedded / inline**: in-process runtime owned by the caller;
2693
- - **embedded / worker**: private caller-owned runtime in a disposable V8 Worker;
2694
2786
  - **daemon**: local-only runtime owner reached through a named pipe on Windows or
2695
2787
  a Unix domain socket on Linux/macOS.
2696
2788
 
2789
+ The v0.7.96 Worker-hosted embedded runtime (`isolation: 'worker'`, the
2790
+ `dist/runtime-worker.js` sidecar, and the `requirements.hardDispose` gate) was
2791
+ removed in v0.7.97. Loading the configured A2A plane is owner wiring, not
2792
+ Runtime magic: call `createConfiguredA2ARuntimeIntegration({ configHome })`
2793
+ (exported from `@kodax-ai/kodax/a2a`) and pass its `runtimeOptions` as
2794
+ `externalAgents` — exactly what the CLI does for both its embedded sessions
2795
+ and the daemon Host it launches.
2796
+
2697
2797
  The daemon is not a separate product engine. It hosts the embedded runtime behind
2698
2798
  a process boundary, so REPL, Space, IDE adapters, ACP, and custom SDK clients can
2699
2799
  share the same profile runtime without reimplementing sessions, permissions,
@@ -2701,13 +2801,16 @@ events, config, MCP, catalogs, artifacts, or diagnostics.
2701
2801
 
2702
2802
  ### Which shape to use
2703
2803
 
2804
+ Product UI and shared-Session automation should use `/client` as described at
2805
+ the top of this guide. This table also identifies explicit low-level ownership.
2806
+
2704
2807
  | Host scenario | Recommended shape | Why |
2705
2808
  |---|---|---|
2706
2809
  | Unit tests, one-off scripts, short-lived SDK tools | `createKodaXRuntime()` | No daemon lifecycle; easiest cleanup. |
2707
2810
  | A single app owns all KodaX state in one process | `createKodaXRuntime({ mode: 'embedded' })` | Direct in-process calls and no IPC. |
2708
- | A single app needs private state plus hard V8 disposal | `createKodaXRuntime({ mode: 'embedded', isolation: 'worker' })` | Same services over MessagePort; `close()` escalates to Worker termination. |
2709
- | REPL + Space + IDE should share sessions/status/permissions | `createKodaXRuntime({ mode: 'daemon' })` | Starts or reuses the local profile daemon. |
2710
- | Attach to an already-started daemon only | `connectKodaXRuntime({ profile, homeDir })` | Attach-only by default; fails if no daemon is ready. |
2811
+ | REPL + Space + IDE product clients | `ensureKodaXClient({ profile, homeDir })` | Starts or reuses the Host and returns the Product contract. |
2812
+ | Product attach-only client | `connectKodaXClient({ profile, homeDir })` | Passive; fails if no compatible Host is ready. |
2813
+ | Trusted low-level daemon integration | `ensureKodaXRuntime` / `connectKodaXRuntime` | Runtime services rather than Product business methods. |
2711
2814
  | Test/CI isolated daemon namespace | pass `homeDir` and `profile` | Keeps state/config/sessions out of the user's home daemon. |
2712
2815
 
2713
2816
  ### Public construction contract
@@ -2728,26 +2831,21 @@ The important creation options are:
2728
2831
  | Option | Default | Contract |
2729
2832
  |---|---|---|
2730
2833
  | `mode` | `'embedded'` | Chooses private ownership or a shared daemon process. |
2731
- | `isolation` | `'inline'` | Embedded-only. `'worker'` creates a private Runtime Worker; daemon rejects any explicit isolation because it is already process-isolated. |
2732
- | `worker.resourceLimits` | unset | Optional V8 heap/stack limits; requires `isolation: 'worker'`. |
2733
- | `worker.shutdownTimeoutMs` | `2000` | Grace before the parent terminates the Runtime Worker. |
2734
- | `worker.configuredA2A` | `false` | Explicitly lets the Worker owner load and reconcile `<homeDir>/.kodax/integrations/a2a.json`; installs the full list/describe/spawn/task plane inside the Worker. |
2735
- | `requirements.hardDispose` | `false` | Rejects inline and daemon forms; prevents an accidental weaker ownership form. |
2736
2834
  | `homeDir` | unset | When omitted, use the exact resolved `KODAX_HOME`. When set, this is the base directory that owns `.kodax`, with the same meaning as CLI `daemon --home`; daemon state/config live under `<homeDir>/.kodax`. |
2737
2835
  | `profile` | `'default'` | Daemon uniqueness and runtime configuration namespace. |
2738
2836
  | `sessionsDir` | `<homeDir>/.kodax/sessions` | Explicit session storage override. |
2739
2837
  | `daemonStartupTimeoutMs` | `60000` | Total cold-start/concurrent-owner wait budget. |
2740
2838
  | `daemonConnectTimeoutMs` | `2000` | Per-socket connection timeout. |
2741
2839
  | `autoStartDaemon` | conditional | For `createKodaXRuntime({mode:'daemon'})`, true only when no explicit endpoint/transport is supplied. |
2742
- | `execPolicy` | unset | Trusted host-owned administrator rules and canonical trusted-project roots. Inline and Worker owners receive it directly; daemon mode accepts it only while auto-starting a new owner. |
2840
+ | `execPolicy` | unset | Trusted host-owned administrator rules and canonical trusted-project roots. The inline owner receives it directly; daemon mode accepts it only while auto-starting a new owner. |
2743
2841
  | `autoReview` | unset | Trusted host-owned administrator/model guidance for Auto review. It follows the same owner-only transport contract as `execPolicy`. |
2744
2842
  | `externalAgents` | unset | Host-installed executor factories, dispatch policy, optional credential/artifact policies, and default dispatch context. Inline owner only; see §18. |
2745
2843
  | `requirements.externalAgents` | `false` | Reject a Runtime/daemon connection that does not advertise an installed external-agent plane. |
2746
2844
 
2747
- KodaX rejects contradictory options. Worker settings without Worker isolation,
2748
- `requirements.hardDispose` on inline/daemon forms, and any explicit isolation
2749
- on daemon mode are errors. Options are never silently ignored to select a
2750
- weaker isolation form.
2845
+ The former `isolation`, `worker.*`, and `requirements.hardDispose` options were
2846
+ removed with the Worker facade in v0.7.97; supplying them is now a plain unknown-
2847
+ option error. Options are never silently ignored to select a weaker ownership
2848
+ form.
2751
2849
 
2752
2850
  ### Basic embedded usage
2753
2851
 
@@ -2811,10 +2909,11 @@ try {
2811
2909
  }
2812
2910
  ```
2813
2911
 
2814
- `createKodaXRuntime({ mode: 'daemon' })` is the high-level convenience API: when
2912
+ This is a low-level Runtime example, not the default product integration.
2913
+ `createKodaXRuntime({ mode: 'daemon' })` is a retained convenience API: when
2815
2914
  no explicit `daemonEndpoint` or `daemonTransport` is supplied it starts or reuses
2816
- the local profile daemon. `connectKodaXRuntime()` is attach-only unless
2817
- `autoStart: true` is passed.
2915
+ the local profile daemon. `connectKodaXRuntime()` is passive and rejects
2916
+ `autoStart: true`; use `ensureKodaXRuntime()` for low-level startup/update.
2818
2917
 
2819
2918
  Trusted `execPolicy` and `autoReview` options are owner bootstrap inputs, not
2820
2919
  client connection settings. For a new daemon, KodaX transfers them through a
@@ -2861,11 +2960,11 @@ verified shutdown and is not silently upgraded in place. Stop it explicitly and
2861
2960
  relaunch it before requiring the capability. The CLI's `kodax daemon stop
2862
2961
  --json` follows the same daemon-plus-supervisor boundary.
2863
2962
 
2864
- The daemon-owned slice does not close the Worker-owned child lifetime gap in
2865
- Issue 256; that owner-lease work remains open after v0.7.87, without a
2866
- replacement target assigned by this release. Worker and
2867
- executor cleanup still use identity-checked evidence and fail closed when a
2868
- descendant cannot be proven gone.
2963
+ The daemon-owned slice does not carry the former Runtime Worker's
2964
+ child-lifetime gap (Issue 256); that owner-lease work remains open after
2965
+ v0.7.87 only for constructed-handler workers, without a replacement target
2966
+ assigned by this release. Executor cleanup still uses identity-checked
2967
+ evidence and fails closed when a descendant cannot be proven gone.
2869
2968
 
2870
2969
  ### Actor settlement recovery (v0.7.84)
2871
2970
 
@@ -2886,12 +2985,16 @@ duplicate outcome. A no-op quiesce does not rewrite the Session.
2886
2985
 
2887
2986
  ### v0.7.85 Runtime and Memory release boundaries
2888
2987
 
2889
- The v0.7.85 SDK adds Session-scoped Runtime Event Journals. Persist the full
2890
- `{ sessionId, journalEpoch, seq }` cursor and always replay with `sessionId` or
2891
- `runId`; numeric Runtime-global sequences are not resumable cursors. A2A binds
2892
- one Runtime Session to each Task, and daemon clients require
2893
- `sessionEventJournal:1`. Corrupt journal indexes, cursor scope mismatches, and
2894
- ambiguous retention evidence fail closed.
2988
+ The v0.7.85 SDK originally added Session-scoped durable Runtime Event Journals;
2989
+ v0.7.97 removes that surface. Events are now a live in-process stream only:
2990
+ each envelope is `{ id, seq, time, sessionId, runId, turnId?, type, payload }`,
2991
+ where `seq` is a per-Session in-process ordering hint. It starts at `1`, resets
2992
+ when a Session is deleted and recreated, and is not comparable across restarts
2993
+ or Sessions. There is no durable `event.replay` RPC, no
2994
+ `{ sessionId, journalEpoch, seq }` cursor, and no `sessionEventJournal:1`
2995
+ capability; remote consumption reuses `session.observe` notifications, and the
2996
+ SDK `runtime.events.subscribe()` facade delivers the same live stream. A2A
2997
+ binds one Runtime Session to each Task.
2895
2998
 
2896
2999
  Memory management is conversation-first for explicit remember, correction,
2897
3000
  forget, recall, and exceptional-decision requests. Safe explicit mutations are
@@ -2899,8 +3002,8 @@ host-governed and immediate; ambiguous or inferred changes remain reviewable.
2899
3002
  F289/F290 bound review draining and lesson/verdict admission, and the
2900
3003
  experimental Memory SDK exposes the additive management facade only when the
2901
3004
  supplied controller supports it. Terminal Runs with authoritative status and
2902
- no queued interrupt input are restored at startup without replaying complete
2903
- event journals. The semantic repo-intelligence Worker retires after its idle
3005
+ no queued interrupt input are restored at startup without replaying event
3006
+ history. The semantic repo-intelligence Worker retires after its idle
2904
3007
  warm-cache window, while later cache misses start a fresh Worker.
2905
3008
 
2906
3009
  ### v0.7.86 Runtime ownership and sandbox lifecycle boundaries
@@ -3016,59 +3119,6 @@ materialization point to `{ type: 'object', properties, required? }`; only
3016
3119
  string names remain in `required`. This keeps the schema shown to the model and
3017
3120
  the provider wire contract aligned across daemon and embedded hosts.
3018
3121
 
3019
- ### Worker-hosted embedded usage
3020
-
3021
- ```ts
3022
- import { createKodaXRuntime } from '@kodax-ai/kodax/runtime';
3023
-
3024
- const runtime = await createKodaXRuntime({
3025
- mode: 'embedded',
3026
- isolation: 'worker',
3027
- worker: {
3028
- resourceLimits: { maxOldGenerationSizeMb: 1024 },
3029
- shutdownTimeoutMs: 2000,
3030
- configuredA2A: true,
3031
- },
3032
- requirements: { externalAgents: true },
3033
- });
3034
-
3035
- try {
3036
- console.log(runtime.identity.isolation); // 'worker'
3037
- console.log(runtime.identity.workerThreadId); // Node Worker thread id
3038
- // runtime.sessions/runs/events/... are identical to inline and daemon.
3039
- } finally {
3040
- await runtime.close();
3041
- }
3042
- ```
3043
-
3044
- `mode` describes ownership and sharing; `isolation` describes where a private
3045
- embedded owner executes. Inline is the lowest-latency default. Worker is useful
3046
- for Electron/Space-style hosts that need private state and deterministic V8
3047
- disposal. Daemon is for durable multi-client sharing and already uses an OS
3048
- process, so daemon + worker is rejected.
3049
-
3050
- Worker `resourceLimits` bound parts of the V8 heap only. They do not cover every
3051
- kind of native/external memory and do not make Node code safe to treat as
3052
- untrusted. Worker isolation is a fault boundary, not a security sandbox.
3053
-
3054
- Configured A2A is loaded by the Worker owner, not serialized from a parent
3055
- factory closure. `worker.configuredA2A` is therefore an explicit opt-in. When
3056
- enabled, the Worker reconciles the same user document as the CLI/daemon path,
3057
- advertises `externalAgents`, and backs `listDispatchable`, `describe`,
3058
- `preflight`, and external Actor dispatch with one real executor plane.
3059
-
3060
- Callers that cannot accept a silent fallback can require the capability:
3061
-
3062
- ```ts
3063
- await createKodaXRuntime({
3064
- mode: 'embedded',
3065
- isolation: 'worker',
3066
- requirements: { hardDispose: true },
3067
- });
3068
- ```
3069
-
3070
- Daemon hosts advertise `hardDispose: false`; Worker hosts advertise true.
3071
-
3072
3122
  ### Close, abort, and ownership semantics
3073
3123
 
3074
3124
  The same method name deliberately has deployment-specific ownership effects:
@@ -3076,17 +3126,24 @@ The same method name deliberately has deployment-specific ownership effects:
3076
3126
  | Form | `runtime.close()` | Run abort | After owner crash/termination |
3077
3127
  |---|---|---|---|
3078
3128
  | embedded / inline | Cancels owned runs and permissions and closes private runtime state. It cannot recover a host event loop blocked by arbitrary inline code. | `runs.abort(runId)` settles the Runtime handle and forwards cancellation to coding. | The embedding process owns recovery. |
3079
- | embedded / Worker | Requests shutdown, waits up to `shutdownTimeoutMs`, then always terminates the Worker. | Same Runtime abort API; closing the Runtime is the hard-disposal escalation for the whole isolate. | Pending transport requests reject; create a new Runtime explicitly. |
3080
3129
  | daemon client | Detaches only this client transport. Other REPL/Space/SDK clients and runs remain owned by the daemon. | Aborts only the addressed run. | The client connection rejects; reconnect explicitly after the daemon is healthy. |
3081
3130
 
3082
3131
  `close()` is idempotent. It is not a shared-daemon stop command. Use
3083
3132
  `kodax daemon stop`, `kodax daemon restart`, or an authenticated low-level
3084
3133
  `runtime.shutdown` request for administrative shutdown. KodaX does not
3085
- automatically retry or replay an in-flight run after a Worker/daemon owner dies,
3134
+ automatically retry or replay an in-flight run after a daemon owner dies,
3086
3135
  because provider and tool side effects may already have happened.
3087
3136
 
3088
- `runtime.shutdown` and `stopForInline()` responses mean the fenced stop was
3089
- accepted; host-close logging and owner-lock release are also intermediate
3137
+ `runtime.shutdown` performs a real idle shutdown: it takes the draining fence,
3138
+ rechecks preflight, and stops the daemon only when no active or queued run,
3139
+ Workflow, Agent turn, pending permission/user input, other logical client, or
3140
+ in-flight mutation exists; otherwise it fails with a structured `conflict`
3141
+ error and the daemon keeps running. Shutdown never changes the owner mode
3142
+ implicitly — a daemon-to-inline ownership change goes only through an explicit
3143
+ `setKodaXRuntimeOwnerMode()` call, or owner-lock release followed by
3144
+ `acquireKodaXInlineOwner()`; the former `stopForInline()` rollback and the
3145
+ crash-resumable exit-settlement transaction were removed in v0.7.97. Host-close
3146
+ logging and owner-lock release are still intermediate
3090
3147
  progress boundaries. A successful `kodax daemon stop` / `restart` additionally
3091
3148
  waits for the original daemon PID to disappear and verifies a shutdown-success
3092
3149
  outcome bound to that exact Runtime ID and PID. Before that process exits, the
@@ -3179,7 +3236,6 @@ kodax daemon status --profile default --json
3179
3236
  kodax daemon logs --profile default --lines 100
3180
3237
  kodax daemon stop --profile default --json
3181
3238
  kodax daemon restart --profile default
3182
- kodax --runtime-mode daemon
3183
3239
  ```
3184
3240
 
3185
3241
  Inside the REPL, `/status runtime` reports embedded/daemon mode, profile,
@@ -3187,14 +3243,14 @@ runtime id, endpoint/health when applicable, and active/queued counters.
3187
3243
 
3188
3244
  ### Runtime services
3189
3245
 
3190
- Every `KodaXRuntime` exposes the same service set in inline, Worker, and daemon mode:
3246
+ Every `KodaXRuntime` exposes the same service set in inline and daemon mode:
3191
3247
 
3192
3248
  | Service | Purpose |
3193
3249
  |---|---|
3194
- | `identity` | Runtime id, mode, isolation, profile, started time, package version, optional Worker thread id. |
3250
+ | `identity` | Runtime id, mode, isolation (`inline` for embedded, `process` for daemon), profile, started time, package version. |
3195
3251
  | `sessions` | Create/load/list/fork/transcript/settings/notice/rewind/compact/archive/delete. |
3196
3252
  | `runs` | Start/await/get/list/abort runs; update provider/model/reasoning for supported phases. |
3197
- | `events` | Subscribe to live events and replay persisted bounded events. |
3253
+ | `events` | Subscribe to the live in-process event stream (one `seq` ordering hint per Session). |
3198
3254
  | `permissions` | Request/list/respond to tool permissions across clients. |
3199
3255
  | `workflows` | Observe workflow process snapshots/events and lifecycle controls. |
3200
3256
  | `config` | Read/patch/reload daemon or embedded profile config. |
@@ -3202,7 +3258,6 @@ Every `KodaXRuntime` exposes the same service set in inline, Worker, and daemon
3202
3258
  | `mcp` | MCP server CRUD, validation, reload, and tool catalog listing. |
3203
3259
  | `artifacts` | Create/get/delete runtime artifact references for file/image/video inputs. |
3204
3260
  | `status` | Runtime snapshot with sessions, runs, permissions, workflows, and daemon counters. |
3205
- | `diagnostics` | Latest context-budget and tool-exposure decisions for GUI/debug surfaces. |
3206
3261
  | `admin.agentRegistrations` | List/upsert, atomically set `enabled` while preserving the full registration, or remove redacted external-agent registrations. Owner/revision-conditional mutation prevents a stale manager from changing a same-ID replacement. With no plane, list is empty and mutations fail clearly. |
3207
3262
  | `agents` | Check `enabled`, list/describe policy-filtered dispatchable agents, and preflight a selected route. |
3208
3263
  | `agentTasks` | Start/list/get/wait/continue/cancel/reconcile durable external-agent tasks and read their ordered event stream. |
@@ -3439,50 +3494,53 @@ bundles.
3439
3494
  - Preserve an unknown-code/default UI path at transport boundaries so a newer
3440
3495
  Runtime cannot turn a diagnostic extension into a failed host UI.
3441
3496
 
3442
- ### Session-scoped event cursors
3497
+ ### Session-scoped live event ordering
3443
3498
 
3444
3499
  Runtime event order is defined inside one Session, not across the Runtime.
3445
- Every event exposes a cursor:
3500
+ Since v0.7.97 the event surface is a live in-process stream; the durable
3501
+ journal, `events.replay()`, and the `{ sessionId, journalEpoch, seq }` cursor
3502
+ were removed. Every event envelope is:
3446
3503
 
3447
3504
  ```ts
3448
- type RuntimeSessionCursor = {
3505
+ type RuntimeEventEnvelope = {
3506
+ id: string;
3507
+ seq: number; // per-Session in-process ordering hint; starts at 1
3508
+ time: string;
3449
3509
  sessionId: string;
3450
- journalEpoch: string;
3451
- seq: number;
3510
+ runId: string;
3511
+ turnId?: string;
3512
+ type: RuntimeEventType;
3513
+ payload: unknown;
3452
3514
  };
3453
3515
  ```
3454
3516
 
3455
- Persist the whole cursor and resume in the same Session or Run scope:
3517
+ `seq` is an ordering hint, not a durable cursor. It starts at `1` within one
3518
+ Session, resets when that Session is deleted and recreated, and is not
3519
+ comparable across restarts or between Sessions — do not persist it as a
3520
+ resume point. Consumption is subscription-shaped and always scoped:
3456
3521
 
3457
3522
  ```ts
3458
- const page = await runtime.events.replay({ sessionId: session.id });
3459
- const after = page.at(-1)?.cursor;
3460
- const next = await runtime.events.replay({
3461
- sessionId: session.id,
3462
- ...(after ? { after } : {}),
3463
- });
3523
+ const sub = runtime.events.subscribe(
3524
+ { sessionId: session.id }, // runId optionally narrows to one Run
3525
+ (event) => renderLiveEvent(event),
3526
+ );
3527
+ await sub.ready; // daemon handshake; absent for local subscriptions
3528
+ sub.close();
3464
3529
  ```
3465
3530
 
3466
- This is a breaking replacement for unscoped `events.subscribe()` /
3467
- `events.replay()` and numeric `sinceSeq`. A scope is always required. Cursors
3468
- from another Session or an earlier journal epoch return `resync_required`; get
3469
- a fresh Session observation/replay instead. Separate Sessions may both contain
3470
- `seq: 1`, which is intentional and removes cross-Session lock contention.
3471
- Supplying both `sessionId` and `runId` validates their ownership before either
3472
- subscribe or replay, even when the Run has no retained event rows. Malformed
3473
- cursors return `invalid_argument`. Reusing a deleted Session ID starts
3474
- a new epoch and invalidates the earlier cursor. Persistence backpressure is
3475
- also isolated per Session, so a blocked Session journal does not stop unrelated
3476
- Sessions using the same embedded Runtime or home directory. Runs retain a small
3477
- journal-identity index independently of bounded event rows; if a retention
3478
- watermark becomes unreadable after child rows are trimmed, only cursors for a
3479
- journal known to that Run are forced to resync when the index is valid. A
3480
- missing or corrupt index cannot prove that an old trimmed journal is unrelated,
3481
- so that ambiguous migration case also requires a fresh snapshot.
3482
-
3483
- ### Run options across Worker/daemon boundaries
3484
-
3485
- `runs.start({ options })` is a DTO boundary in Worker and daemon forms. Do not
3531
+ Remote event consumption reuses `session.observe` notifications: an
3532
+ observation snapshot carries a `seq` high-water, every event with
3533
+ `seq <= snapshot.seq` is already reflected in the snapshot, and live listener
3534
+ events for that observation have strictly greater `seq`. Separate Sessions may
3535
+ both contain `seq: 1`; that is intentional. Supplying both `sessionId` and
3536
+ `runId` validates their ownership before the subscription is installed.
3537
+ Deleting and recreating a Session invalidates outstanding observations with
3538
+ reason `runtime_changed`; acquire a fresh observation instead of reusing a
3539
+ stale projection or sequence number.
3540
+
3541
+ ### Run options across the daemon boundary
3542
+
3543
+ `runs.start({ options })` is a DTO boundary in daemon form. Do not
3486
3544
  pass process-local objects such as `extensionRuntime`, callbacks, `AbortSignal`,
3487
3545
  LSP services, class instances, or cyclic structures. KodaX rejects them before
3488
3546
  transport instead of silently dropping fields.
@@ -3509,9 +3567,9 @@ For daemon mode, extension and MCP ownership follows daemon configuration.
3509
3567
  Configure extensions in the daemon profile and call
3510
3568
  `runtime.catalog.reloadExtensions()` or the matching config service. A CLI
3511
3569
  `--extension <path>` is intentionally rejected in daemon mode because that
3512
- process-local object cannot become part of a durable shared owner. Worker mode
3513
- has the same DTO rule; use owner-readable config/module descriptors or inline
3514
- mode for host-created extension objects.
3570
+ process-local object cannot become part of a durable shared owner. Use
3571
+ owner-readable config/module descriptors or inline mode for host-created
3572
+ extension objects.
3515
3573
 
3516
3574
  ### Permissions across clients
3517
3575
 
@@ -3565,7 +3623,7 @@ argument, `{ signal }`; abort the visible prompt when it fires.
3565
3623
  `createKodaXRuntime({ userInputTimeoutMs })` and daemon auto-start use an
3566
3624
  independent AskUser deadline (300,000 ms by default). The value must be a
3567
3625
  positive integer no greater than 2,147,483,647 and is validated before
3568
- embedded, Worker, or daemon startup. The same bound applies to
3626
+ embedded or daemon startup. The same bound applies to
3569
3627
  `permissionTimeoutMs`, except that its existing value `0` disables the
3570
3628
  permission timer. On expiry, the Runtime accepts only a model-supplied default that is
3571
3629
  valid for the rendered options and selection bounds; otherwise it dismisses
@@ -3638,25 +3696,22 @@ engine:
3638
3696
  bridge discovery resident;
3639
3697
  - tool-search/describe/call-style bridge semantics keep tools reachable;
3640
3698
  - repo-intelligence schemas remain discoverable under pressure;
3641
- - context-aware tool result budgets and compaction pressure events are surfaced
3642
- as bounded diagnostics.
3643
-
3644
- Hosts that set `capabilities.contextDiagnostics: true` can read:
3645
-
3646
- ```ts
3647
- const budget = await runtime.diagnostics.latestContextBudget({ sessionId });
3648
- const exposure = await runtime.diagnostics.latestToolExposure({ sessionId });
3649
- const cache = await runtime.diagnostics.latestProviderCacheDiagnostic({ sessionId });
3650
- ```
3651
-
3652
- Pass `{ sessionId, contextKind: 'child', agentId }` to query one logical child
3653
- even though its physical transcript uses an isolated Session. Diagnostic
3654
- payloads carry `contextId` and, for children, `parentContextId`; reconnecting
3655
- hosts can use the same latest APIs instead of fabricating identity fields.
3656
- These diagnostics are designed for status panels and debugging. Budget
3657
- snapshots contain counts, and cache diagnostics contain hashes plus
3658
- Provider-reported usage; they do not contain raw prompt or sensitive tool
3659
- input/output.
3699
+ - context-aware tool result budgets and compaction pressure surface as bounded
3700
+ diagnostic events.
3701
+
3702
+ The v0.7.96 pull-style diagnostics RPCs (`context.budget.get`,
3703
+ `tool.exposure.preview`, `provider.cache.diagnostics.get` and the
3704
+ `runtime.diagnostics.latestContextBudget()` / `latestToolExposure()` /
3705
+ `latestProviderCacheDiagnostic()` facade) were removed in v0.7.97. The
3706
+ `capabilities.contextDiagnostics: true` client capability now only gates
3707
+ delivery of diagnostic event notifications (`context.budget.snapshot`,
3708
+ `tool.exposure.planned`, `provider.cache.diagnostics`, and
3709
+ `context.compaction.skipped`) on the live event stream; consume them through
3710
+ `runtime.events.subscribe(...)` or a `session.observe` snapshot. Diagnostic
3711
+ payloads carry `contextId` and, for children, `parentContextId`. These
3712
+ diagnostics are designed for status panels and debugging: budget snapshots
3713
+ contain counts, and cache diagnostics contain hashes plus Provider-reported
3714
+ usage; they do not contain raw prompt or sensitive tool input/output.
3660
3715
 
3661
3716
  ### Protocol schema and versioning
3662
3717
 
@@ -3678,7 +3733,9 @@ fields requires a protocol version bump.
3678
3733
  ### v0.7.69 Runtime verification record
3679
3734
 
3680
3735
  This subsection is the historical verification record for the original shared
3681
- Runtime delivery. Current 0.7.80 release gates and evidence live in
3736
+ Runtime delivery. The Worker-isolation gates it records validated the Worker
3737
+ facade that v0.7.97 later removed; the current deployment shapes are inline
3738
+ embedded and daemon only. Current 0.7.80 release gates and evidence live in
3682
3739
  [`docs/release.md`](https://github.com/icetomoyo/KodaX/blob/main/docs/release.md#v0780-release-preparation).
3683
3740
 
3684
3741
  The v0.7.69 release validation covers the runtime migration, the Worker
@@ -3693,8 +3750,8 @@ daemon delivery:
3693
3750
  entries on Node 20 and Node 22;
3694
3751
  - runtime/daemon/SDK/ACP/REPL integration tests, including process-distinct SDK
3695
3752
  auto-start and multi-client sessions/permissions;
3696
- - Worker Runtime identity, service parity, hard close, capability requirements,
3697
- and contradictory-option rejection;
3753
+ - the (since-removed) Worker Runtime's identity, service parity, hard close,
3754
+ capability requirements, and contradictory-option rejection;
3698
3755
  - constructed-handler reverse tool RPC, abort bridging, CPU-loop termination,
3699
3756
  respawn, and revoke/dispose queue drainage;
3700
3757
  - context/tool-exposure eval gate;
@@ -3716,10 +3773,12 @@ daemon delivery:
3716
3773
  Tool reverse bridges, owner fencing, restart outcomes, and process-distinct
3717
3774
  client/daemon smokes with credential-canary scans;
3718
3775
  - a fresh `0.7.69` tarball consumer importing all 11 public subpaths, creating a
3719
- Worker-hosted session, running the packaged CLI, and checking packaged DTS and
3720
- Worker sidecars; plus a Windows x64 binary/version/sidecar smoke;
3776
+ session through the embedded Worker form (removed in v0.7.97), running the
3777
+ packaged CLI, and checking packaged DTS and sidecars; plus a Windows x64
3778
+ binary/version/sidecar smoke;
3721
3779
  - external fresh npm consumer installation of the `0.7.67` tarball, proving
3722
- Worker isolation and a distinct daemon PID through the published subpath;
3780
+ the embedded Worker isolation contract (removed in v0.7.97) and a distinct
3781
+ daemon PID through the published subpath;
3723
3782
  - Ubuntu Node 22 Unix-domain-socket daemon gate, including two clients sharing
3724
3783
  one runtime and cross-client permission resolution.
3725
3784
 
@@ -3749,15 +3808,15 @@ runtime a specific A2A, MCP, or HTTP client. The public contracts live in
3749
3808
 
3750
3809
  ### Ownership rule
3751
3810
 
3752
- An `AgentExecutorFactory` contains functions, so it cannot cross a Worker or
3753
- daemon DTO boundary. Install factories where the Runtime owner executes:
3811
+ An `AgentExecutorFactory` contains functions, so it cannot cross a daemon DTO
3812
+ boundary. Install factories where the Runtime owner executes:
3754
3813
 
3755
3814
  | Desired owner | Supported construction |
3756
3815
  |---|---|
3757
- | Private in-process owner | `createKodaXRuntime({ mode: 'embedded', isolation: 'inline', externalAgents })` |
3816
+ | Private in-process owner | `createKodaXRuntime({ mode: 'embedded', externalAgents })` |
3758
3817
  | New locally hosted daemon owner | `createKodaXRuntime({ mode: 'daemon', profile: '<unique>', externalAgents })` |
3759
3818
  | Existing daemon | Configure its owner, then attach with `connectKodaXRuntime({ requirements: { externalAgents: true } })`; a client cannot inject factories. |
3760
- | Runtime Worker | Use `worker: { configuredA2A: true }` for the built-in configured A2A plane. Custom factories must still be installed by a custom Worker owner; passing function-valued `externalAgents` from the parent is rejected. |
3819
+ | Built-in configured A2A plane | Wire it in the owner: `createConfiguredA2ARuntimeIntegration({ configHome })` → pass `runtimeOptions` as `externalAgents` (the KodaX CLI does this for its embedded sessions and the daemon Host it launches; an SDK-created runtime never reads `integrations/a2a.json` on its own). The former `worker: { configuredA2A: true }` opt-in was removed with the Worker facade in v0.7.97. |
3761
3820
 
3762
3821
  When `mode: 'daemon'` and `externalAgents` are supplied, the caller must win a
3763
3822
  new in-process daemon lease. KodaX rejects an already-running profile instead of
@@ -3778,7 +3837,6 @@ import { createKodaXRuntime } from '@kodax-ai/kodax/runtime';
3778
3837
 
3779
3838
  const runtime = await createKodaXRuntime({
3780
3839
  mode: 'embedded',
3781
- isolation: 'inline',
3782
3840
  externalAgents: {
3783
3841
  factories: [createReferenceAgentExecutorFactory({
3784
3842
  executorId: 'example-http',
@@ -4204,7 +4262,7 @@ await runKodaX(
4204
4262
  );
4205
4263
  ```
4206
4264
 
4207
- `memoryRecallRunner` is a process-local function binding. Worker and daemon DTO
4265
+ `memoryRecallRunner` is a process-local function binding. Daemon DTO
4208
4266
  options reject it instead of silently dropping it; configure the binding
4209
4267
  inside the Runtime owner or keep this run inline. The selector can return only
4210
4268
  exact IDs from the closed offered set and is capped at three calls per memory
@@ -4297,7 +4355,6 @@ const discovered = await discoverA2ARegistration({
4297
4355
 
4298
4356
  const runtime = await createKodaXRuntime({
4299
4357
  mode: 'embedded',
4300
- isolation: 'inline',
4301
4358
  externalAgents: {
4302
4359
  factories: [createA2AAgentExecutorFactory(client)],
4303
4360
  credentialBroker: {
@@ -4561,7 +4618,7 @@ import {
4561
4618
  } from '@kodax-ai/kodax/a2a';
4562
4619
  import { createKodaXRuntime } from '@kodax-ai/kodax/runtime';
4563
4620
 
4564
- const runtime = await createKodaXRuntime({ mode: 'embedded', isolation: 'inline' });
4621
+ const runtime = await createKodaXRuntime({ mode: 'embedded' });
4565
4622
  const server = createKodaXA2AServer({
4566
4623
  runtime,
4567
4624
  dataDir: '/var/lib/kodax/a2a',
@@ -4648,6 +4705,10 @@ The normative baseline is A2A repository commit
4648
4705
 
4649
4706
  ## 23. Shared Coder daemon for Space and IDE hosts (FEATURE_269, v0.7.69)
4650
4707
 
4708
+ > Trusted Electron Main/Host integration reference, including capabilities not
4709
+ > exposed by Product Client. UI business operations use `/client`; do not port
4710
+ > this entire Runtime facade into the renderer. See the migration guide above.
4711
+
4651
4712
  FEATURE_269 makes one local daemon the source of truth for a Coder profile.
4652
4713
  CLI, Space, IDE, and SDK clients can observe and control the same sessions and
4653
4714
  runs. The transport remains local to the current OS user; it is not a remote
@@ -4664,7 +4725,8 @@ data root.
4664
4725
  Space should own the daemon SDK client in Electron Main. Persist a random,
4665
4726
  stable `instanceId` and a separate 32+ character `instanceSecret` per Space
4666
4727
  installation. Store the secret in the OS keychain; never accept either value
4667
- from renderer or model output. `connectKodaXRuntime()` is attach-only unless `autoStart: true`.
4728
+ from renderer or model output. `connectKodaXRuntime()` is passive;
4729
+ use `ensureKodaXRuntime()` for low-level startup/update.
4668
4730
  An explicit inline rollback policy blocks auto-start until the owner policy is
4669
4731
  explicitly changed back to daemon.
4670
4732
 
@@ -4683,7 +4745,7 @@ and cannot resume the old bridge's leases. Restore the exact existing identity
4683
4745
  from verified recovery material, or explicitly treat it as a new identity.
4684
4746
 
4685
4747
  For Electron, `homeDir` is still the CLI-style base directory, not
4686
- `process.env.KODAX_HOME`. Packaged/asar applications may use `autoStart: true`
4748
+ `process.env.KODAX_HOME`. Packaged/asar applications may use `ensureKodaXRuntime()`
4687
4749
  directly; the SDK launches only the daemon child in Electron's Node execution
4688
4750
  mode and does not mutate the application's environment or start a second GUI
4689
4751
  instance. `ELECTRON_RUN_AS_NODE` exists only at the child exec boundary and is
@@ -4694,7 +4756,7 @@ Packaged auto-start requires Electron's `RunAsNode` fuse, which Electron enables
4694
4756
  by default. If an embedder deliberately disables that fuse, the packaged
4695
4757
  executable cannot serve as a detached Node host: start the daemon with an
4696
4758
  ordinary Node/CLI process and use attach-only mode instead. A packaged
4697
- `autoStart: true` timeout includes this fuse requirement in its diagnostic; the
4759
+ startup timeout includes this fuse requirement in its diagnostic; the
4698
4760
  SDK does not relaunch the GUI or silently fall back to an inline Runtime.
4699
4761
 
4700
4762
  ### Packaged Electron native artifact layout
@@ -4730,11 +4792,10 @@ evidence schema while a new build is prepared. A new process with a new embedded
4730
4792
  hash publishes its own immutable generation atomically.
4731
4793
 
4732
4794
  ```ts
4733
- import { connectKodaXRuntime } from '@kodax-ai/kodax/runtime';
4795
+ import { ensureKodaXRuntime } from '@kodax-ai/kodax/runtime';
4734
4796
 
4735
- const runtime = await connectKodaXRuntime({
4797
+ const runtime = await ensureKodaXRuntime({
4736
4798
  profile: 'coder',
4737
- autoStart: true,
4738
4799
  // Opt in only when this product remains the visible owner of the daemon.
4739
4800
  // If the product crashes, the daemon stops after its final client is gone
4740
4801
  // and governed work becomes idle.
@@ -4750,10 +4811,8 @@ const runtime = await connectKodaXRuntime({
4750
4811
  capabilities: {
4751
4812
  richEvents: true,
4752
4813
  permissionPrompts: true,
4753
- operationDeduplication: true,
4754
4814
  },
4755
4815
  requirements: {
4756
- operationDeduplication: 1,
4757
4816
  sessionObservation: 1,
4758
4817
  afterTurnInput: 1,
4759
4818
  interruptInput: 1,
@@ -4790,7 +4849,7 @@ Coder. Products that depend on same-Run delivery should require
4790
4849
  silently substitute `delivery:'after_turn'` unless that is the user's intent.
4791
4850
 
4792
4851
  The SDK requires `runtimeAutoModeGuardrail:6` and
4793
- `sharedSessionSettings:2` automatically for ordinary `autoStart: true`.
4852
+ `sharedSessionSettings:2` automatically for ordinary launcher startup.
4794
4853
  The capability gate prevents an alpha.6 client from attaching to an alpha.3
4795
4854
  daemon that advertises the older permission-before-sandbox contract. Supplying
4796
4855
  `daemonOrphanExitMs` additionally requires the
@@ -4833,11 +4892,11 @@ Require it before auto-start so an idle daemon that still exposes the legacy
4833
4892
  ordinary-history projection is replaced; a busy or otherwise unsafe owner
4834
4893
  produces the normal capability-upgrade error.
4835
4894
 
4836
- `KODAX_RUNTIME_SDK_CAPABILITIES.sandboxRuntime` is `11` in v0.7.96
4895
+ `KODAX_RUNTIME_SDK_CAPABILITIES.sandboxRuntime` is `11` in v0.7.97
4837
4896
  and `crashOutcomeModel` remains `2`. Windows auto-start requires
4838
4897
  `sandboxRuntime:11`, so an idle v10-or-older daemon is replaced. Concurrent
4839
4898
  authenticated upgrade clients converge on one fenced replacement, including
4840
- the exact prepared-ticket/revision-CAS attach window; a busy daemon or one with
4899
+ the exact revision-CAS attach window; a busy daemon or one with
4841
4900
  untrusted clients remains untouched and returns structured restart guidance. Version 6 means that
4842
4901
  trusted text transactions are host-owned and the native shell runner has no
4843
4902
  command-lifetime filesystem-effect lease; a v5 daemon cannot be reused for
@@ -4852,121 +4911,64 @@ must instead be stopped/upgraded. `reclaimStaleKodaXFileLock` remains an
4852
4911
  explicit stale-lock helper for APIs that still use file locks, not a general
4853
4912
  lock-deletion primitive.
4854
4913
 
4855
- ### v0.7.91 crash-resumable Runtime exit settlement
4856
-
4857
- Hosts that own a complete Runtime exit can use the SDK transaction instead of
4858
- duplicating stop, process-tree, Job, ACL, and owner-policy recovery logic:
4859
-
4860
- ```ts
4861
- import { settleKodaXRuntimeExit } from '@kodax-ai/kodax/runtime';
4862
-
4863
- const outcome = await settleKodaXRuntimeExit({
4864
- configHome: coderConfigHome,
4865
- profile: 'coder',
4866
- runtime, // optional; omit only when resuming a prepared ticket after relaunch
4867
- });
4868
-
4869
- if (outcome.status === 'blocked') {
4870
- // Keep the host open, relaunch the product, restart the OS, or request
4871
- // explicit manual recovery according to outcome.nextAction.
4872
- reportRuntimeExitBlock(outcome.reason, outcome.nextAction);
4873
- } else {
4874
- reportRuntimeExit(outcome.status, outcome.repairs);
4875
- }
4876
- ```
4877
-
4878
- `runtimeExitSettlement:2` is a local SDK capability and does not add a daemon
4879
- handshake requirement. The SDK writes an exact owner/process-start and platform
4880
- boot identity before cooperative stop, then returns `clean` only after the
4881
- durable shutdown outcome and required exits are verified. `recovered` may repair
4882
- only identity-scoped Windows process/Job/ACL residue, or exact POSIX owner/state
4883
- residue after a boot-identity change. Same-boot POSIX uncertainty, active work,
4884
- PID reuse, foreign markers, corrupt tickets, and replacement owners return
4885
- `blocked`; the SDK never exposes a bare-PID kill, raw marker deletion, or forced
4886
- ACL-recovery primitive. Version 2 removes the final same-boot Windows manual
4887
- cleanup hole: stale, uncontained recovery tickets are retried through the
4888
- sandbox account's own runner and clear only after an exact SID-idle proof. The
4889
- transaction has a fixed bounded deadline and does not accept caller-supplied
4890
- short timeouts.
4891
-
4892
- After a verified Windows boot change, settlement may also recover shared ACL
4893
- state when a machine-lock recheck proves that every primary and legacy marker
4894
- has a canonical non-current boot identity. The recovered scope, repair fact,
4895
- and recovery boot identity are durably recorded before a second lock-scoped
4896
- recheck removes markers. If Windows restarts again before clear, native
4897
- recovery repeats against the new boot before the recorded identity advances.
4898
- Same-boot or unverifiable markers remain `blocked`. A durable Windows
4899
- `failed` shutdown outcome ends the 170-second orderly wait and enters exact
4900
- recovery immediately. Anthropic/OpenAI `APIUserAbortError` objects are
4901
- classified by isolated SDK class identity when the request signal is already
4902
- aborted, so managed Stop stays interrupted before credential redaction.
4903
-
4904
- When the host is about to close, pass the connected Runtime so the SDK can
4905
- record the exact owner and management revision. After a crash, call the same
4906
- function with only `configHome` and `profile` to resume a still-exact prepared
4907
- ticket. Do not delete `exit-settlement.json`, clear ACL markers, or start a
4908
- replacement owner while a settlement is `prepared` or `stop_accepted`.
4914
+ ### Windows lifecycle diagnostics
4909
4915
 
4910
4916
  Windows lifecycle diagnostics use the existing process-local
4911
4917
  `setKodaXDiagnosticSink` export from `@kodax-ai/kodax/agent`. Install the sink
4912
- before connecting or settling Runtime ownership, and call its returned cleanup
4918
+ before connecting or ensuring Runtime ownership, and call its returned cleanup
4913
4919
  function when the host closes. The daemon already writes its own diagnostics
4914
4920
  to `daemon.log`; a client-process sink does not subscribe to daemon-process
4915
4921
  events.
4916
4922
 
4917
4923
  `source: 'runtime:windows'` identifies boot identity, Job membership, process
4918
- snapshot, process-start identity, and exit-owner validation stages. Probe
4924
+ snapshot, and process-start identity stages. Probe
4919
4925
  details report availability, whether a cached result was used, and (for an
4920
4926
  executed probe) elapsed time, timeout, exit code, and a bounded OS error code.
4921
- Exit validation lists the missing evidence field names without serializing
4922
- owner identities. `source: 'runtime.daemon.capabilities'` with
4927
+ `source: 'runtime.daemon.capabilities'` with
4923
4928
  `stage: 'capability-check'` records the original required capability and version
4924
- before a subsequent upgrade or settlement failure can obscure it.
4929
+ before a subsequent upgrade failure can obscure it.
4925
4930
 
4926
4931
  These records omit commands, environment variables, stdout, stderr, credentials,
4927
4932
  and identity values. They do not add probes or retries, change existing failure
4928
- caching, relax Job/identity checks, or alter settlement results. A missing
4933
+ caching, relax Job/identity checks, or alter shutdown results. A missing
4929
4934
  capability diagnostic is evidence for troubleshooting, not permission to bypass
4930
4935
  the required capability. Diagnostic sink exceptions remain isolated from the
4931
4936
  Runtime operation.
4932
4937
 
4933
4938
  ### Unreleased: interrupted Run recovery and transcript ownership
4934
4939
 
4935
- Runtime-owned managed Runs persist generated messages and tool results at
4936
- Runner commit boundaries, before a later provider request or tool can hang.
4937
- Completion still requires the canonical Session write. UI event deltas alone
4938
- are not durable conversation messages.
4939
-
4940
- The next `mode: 'managed_task'` or `mode: 'coding'` Run can receive an
4941
- `Interrupted Run Recovery` record derived from earlier unfinished Runs of the
4942
- same Session. Embedded Runtime and daemon execution share this implementation.
4943
- Only evidence anchored to a turn on the active history path is included:
4944
- journaled tool results, operations whose results are unknown, and quoted,
4945
- unconfirmed excerpts of streamed replies. Thinking and live child-actor mirrors
4946
- are excluded. The record is bounded to three Runs and 6,000 characters;
4947
- operations take the budget before reply excerpts. Results and reply text
4948
- already present in the same turn's formal history are omitted.
4949
-
4950
- This record belongs only to the provider request, never the persisted Session
4951
- or an ordinary UI conversation row. An unreadable journal emits a
4952
- `runtime.interrupted-run-recovery` warning and does not block the next Run.
4953
- Unknown-result operations may already have taken effect; verify the current
4954
- files or processes before repeating them. Streamed claims are not completion
4955
- proof. Tool-only invocations need no record because they make no model call.
4956
- Standalone `runKodaX()` / `runManagedTask()` calls do not discover Runtime
4957
- journals automatically: hosts that need automatic recovery should use
4958
- `createKodaXRuntime()` and its Run service. The exported
4959
- `KodaXInterruptedRunJournal`, `KodaXInterruptedRunOperation`, and
4960
- `KodaXInterruptedRunReply` types describe internal handoff data;
4961
- `context.interruptedRunJournals` is not a host-owned persistence protocol.
4962
-
4963
- When a Runtime owns an Ink Session, it is the lineage writer. The Ink host
4964
- saves display/settings state without minting a competing lineage, then adopts
4965
- the Runtime's durable entry ids. `FileSessionStorage` reconciles messages
4966
- against that canonical lineage. A cancellation before any result leaves the
4967
- host's existing transcript intact. Embedders must not build a second
4968
- conversation writer from streaming callbacks; use the Runtime Session APIs
4969
- and presentation overlays instead.
4940
+ The current development tree integrates the rc.14 fixes under FEATURE_298 /
4941
+ v0.7.97. Product applications use [/client](#product-client-integration), and
4942
+ the Host is the only Session writer. Ink/classic consumers render Host facts
4943
+ and submit intents; they do not save a competing transcript or lineage.
4944
+
4945
+ Runtime-owned managed Runs save generated messages and tool results at Runner
4946
+ commit boundaries. An interrupted Run can contribute a bounded recovery note
4947
+ to the next SA or AMA model request. Its sources are canonical Session/active
4948
+ lineage, Run status, and successfully saved display checkpoints. The Host
4949
+ flushes the existing writer before reading; it does not replay durable events
4950
+ or infer success from telemetry. Failed checkpoint reads/writes remain errors.
4951
+
4952
+ Evidence uses accepted input and turn identities, explicit sourceRunId /
4953
+ sourceTurnId, assistant outputId, and the assistantOutputId owning a tool call.
4954
+ A proposed tool is not an executed effect. Execution without a recorded result
4955
+ has an unknown outcome, including a displayed cancelled tool whose result was
4956
+ never saved. Already committed output is excluded by identity, so two equal
4957
+ replies with different outputIds remain distinct. Thinking, child output, and
4958
+ ordinary notices never enter the recovery record.
4959
+
4960
+ The record covers at most three Runs and 6,000 characters, giving operations
4961
+ priority over quoted, unconfirmed reply excerpts. It is transient model context,
4962
+ never a user instruction or canonical Session message. No automatic tool redo
4963
+ or recovery of uncheckpointed tokens is promised. Tool-only invocations make
4964
+ no model call and need no recovery note. Standalone callers can supply the
4965
+ internal KodaXInterruptedRunEvidence / Operation / Reply handoff types through
4966
+ context.interruptedRunEvidence; that option is not a persistence protocol.
4967
+
4968
+ Uncertain Shell cleanup retains deferred process ownership while allowing the
4969
+ next Run and Host close to proceed. ClientRunStatus and ClientRunOutcome expose
4970
+ the Host terminal.effectOutcome and Stop facts. A completed execution with
4971
+ unknown effects does not prove cleanup or confirm Stop.
4970
4972
 
4971
4973
  ### Historical v0.7.92 filesystem-effect coordinator and managed terminal authority
4972
4974
 
@@ -5001,16 +5003,13 @@ message-derived transcript plus optional display overlays. Do not treat
5001
5003
  Presentation-only synthetic completion events remain host-owned when that
5002
5004
  cache is non-empty.
5003
5005
 
5004
- Observation boundaries such as `events.subscribe()`, `events.replay()`, and
5005
- Session status projection flush pending events before answering, so they can
5006
- surface a durable-persistence failure instead of returning a stale waterline.
5007
- A determinate append failure retains one bounded batch for a later explicit
5008
- retry. If both append and rollback fail, commit state is unknowable: the error
5009
- is intentionally sticky and the Runtime must be closed/recreated rather than
5010
- guessing or replaying the batch. Latest-only progress coalescing preserves its
5011
- required first sample plus the most recent sample; discarded intermediate
5012
- snapshots are not lifecycle events, and surviving samples retain their latest
5013
- emission order.
5006
+ Observation boundaries such as `events.subscribe()` and Session status
5007
+ projection deliver the live in-process stream; since v0.7.97 removed the
5008
+ durable event journal, there is no replay boundary, durable append, or
5009
+ stale-waterline failure mode on this path. Latest-only progress coalescing
5010
+ preserves its required first sample plus the most recent sample; discarded
5011
+ intermediate snapshots are not lifecycle events, and surviving samples retain
5012
+ their latest emission order.
5014
5013
 
5015
5014
  When a healthy profile daemon is too old, the SDK first reads capabilities from
5016
5015
  the authenticated health probe, before attaching the embedder's stable client
@@ -5018,11 +5017,12 @@ identity or restoring its reverse bridge. The incompatible daemon is contacted
5018
5017
  with an ephemeral upgrade identity. The SDK requires `daemonManagement:1`,
5019
5018
  takes a revision/owner-policy fenced preflight, and replaces it only when no
5020
5019
  active or queued run, Workflow, Agent turn, pending permission/user input, or
5021
- other logical client exists. Replacement reuses the durable Runtime exit
5022
- settlement: it records a crash-resumable ticket, verifies the captured
5023
- owner/process-start identity, waits for the complete process exit and shutdown
5024
- outcome, repairs only identity-scoped remnants, restores daemon owner policy,
5025
- and then starts the packaged Runtime.
5020
+ other logical client exists. Replacement performs a fenced idle shutdown: it
5021
+ verifies the captured owner/process-start identity, sends `runtime.shutdown`,
5022
+ waits for the complete process exit, and then starts the packaged Runtime.
5023
+ v0.7.97 removed the crash-resumable exit-settlement ticket this path
5024
+ previously reused; there is no prepared-ticket state to preserve across a
5025
+ crash mid-upgrade.
5026
5026
  A busy or still-older daemon is never stopped: the connection rejects with
5027
5027
  `RuntimeDaemonCapabilityUpgradeError`, whose `recoverable` and
5028
5028
  `restartRequired` fields are `true` and whose optional `preflight` explains the
@@ -5041,8 +5041,8 @@ The packaged daemon authenticates one local OS-user/profile trust domain with
5041
5041
  a random token stored beside daemon state and a user-only local endpoint. It
5042
5042
  does not issue a different daemon token to each application in v0.7.69. The
5043
5043
  returned scope set is chosen by the host (the packaged host grants the public
5044
- local-user set). `clientInfo.instanceId` is stable attribution for origin and
5045
- operation deduplication. `instanceSecret` proves that a new authenticated
5044
+ local-user set). `clientInfo.instanceId` is stable attribution: the daemon
5045
+ derives its authenticated connection principal from it. `instanceSecret` proves that a new authenticated
5046
5046
  connection is the same stable client when it resumes that client's credential
5047
5047
  or Host Tool leases; only its hash participates in daemon-owned bridge state.
5048
5048
  Keep all three values in Electron Main. Mutually distrusting processes running
@@ -5119,9 +5119,9 @@ including its stable KodaX code, stage, bounded display message, and optional
5119
5119
  sanitized upstream metadata.
5120
5120
  Sandbox and managed-child termination failures are observed and retained as
5121
5121
  diagnostics rather than escaping as process-global unhandled rejections.
5122
- If terminal status persistence fails but the Session event journal remains
5123
- healthy, Runtime durably publishes `run.updated` with `phase:'unknown'`. If the
5124
- journal is fenced too, active `sessions.observe()` handles resolve
5122
+ If terminal status persistence fails, Runtime still publishes `run.updated`
5123
+ with `phase:'unknown'` on the live event stream. If live delivery fails too,
5124
+ active `sessions.observe()` handles resolve
5125
5125
  `invalidated` with `reason:'delivery_failed'`; consumers must discard their
5126
5126
  local projection and acquire a fresh observation instead of retaining a stale
5127
5127
  running/terminal state.
@@ -5231,10 +5231,10 @@ runtime.connection?.subscribe((state) => {
5231
5231
  });
5232
5232
  ```
5233
5233
 
5234
- The SDK reports the current `connectionId`, `runtimeEpoch`, optional
5235
- `journalEpoch`, disconnect reason, and whether a new connection may be
5234
+ The SDK reports the current `connectionId`, `runtimeEpoch`,
5235
+ disconnect reason, and whether a new connection may be
5236
5236
  attempted. It does not transparently replay requests or subscriptions. Space
5237
- creates a replacement Runtime client, checks its new epochs, resumes eligible
5237
+ creates a replacement Runtime client, checks its new epoch, resumes eligible
5238
5238
  leases, and observes the session again.
5239
5239
 
5240
5240
  `RuntimeDaemonDisconnectCode` reports only transport-observable facts:
@@ -5291,54 +5291,50 @@ restart changes `runtimeId`. The observation's `invalidated` promise reports
5291
5291
  `transport_disconnected`; after it resolves, no state derived from that
5292
5292
  observation remains authoritative. Restart recovery interrupts only a Run
5293
5293
  whose owner is definitely gone; uncertain external execution is `unknown`.
5294
- Timeout or cancellation removes the daemon request immediately. If a
5295
- third-party transport ignores cancellation and later returns an observation,
5296
- the client compensates by unsubscribing that late observation.
5294
+ Timeout or cancellation removes the daemon request immediately. A result that
5295
+ arrives after its reader abandoned the request is dropped — the transport
5296
+ sends a hygiene `request.cancel` so the Host frees the in-flight record and
5297
+ any subscription it created, but no late delivery reaches the caller.
5297
5298
 
5298
5299
  ### Durable mutations, stable ordering, and settings CAS
5299
5300
 
5300
- Every durable public control mutation uses an operation envelope. Credential
5301
- and Host Tool register/revoke/supply/complete requests are reverse-bridge
5302
- control frames and are deliberately excluded from the control journal so
5303
- secrets/results are not persisted. They still enter the daemon management
5304
- draining fence: once an atomic stop begins, they fail with typed `conflict` and
5305
- cannot change reverse-bridge state. The SDK creates an operation ID for
5306
- ordinary one-shot calls. A
5307
- product-level retry after a lost response must reuse its own stable operation
5308
- ID; changing its method, payload, resource, or authenticated principal is
5309
- rejected.
5301
+ Public control mutations no longer take an operation envelope. v0.7.97 removed
5302
+ the generic `operation: { operationId }` input, auto-generated operation IDs,
5303
+ the control journal, and the `runtime.operations.get` receipt query; mutation
5304
+ identity now comes from each mutation's own domain fields — the explicit
5305
+ `sessionId` on create, the returned `runId` on start, and the settings
5306
+ revision on CAS updates. Credential and Host Tool
5307
+ register/revoke/supply/complete requests are reverse-bridge
5308
+ control frames and persist no secrets or results. They still enter the daemon
5309
+ management draining fence: once an atomic stop begins, they fail with typed
5310
+ `conflict` and cannot change reverse-bridge state. Reconnection semantics are
5311
+ explicit: after a lost response, re-read authoritative state and reconcile in
5312
+ your product code; the SDK never transparently retries or replays a mutation.
5310
5313
 
5311
5314
  ```ts
5312
5315
  const session = await runtime.sessions.create({
5313
5316
  sessionId: stableSpaceSessionId,
5314
5317
  title: 'Shared session',
5315
5318
  surface: 'space-desktop',
5316
- operation: { operationId: loadOrCreatePendingOperationId('space-session-draft-7') },
5317
5319
  });
5318
5320
 
5319
- const operationId = loadOrCreatePendingOperationId('space-run-draft-42');
5320
5321
  const handle = await runtime.runs.start({
5321
5322
  sessionId: session.id,
5322
5323
  input: { type: 'text', text: prompt },
5323
5324
  options: { provider: 'anthropic' },
5324
- operation: { operationId },
5325
5325
  });
5326
5326
 
5327
5327
  const current = await runtime.sessions.getSettingsVersioned(session.id);
5328
5328
  const updated = await runtime.sessions.updateSettingsVersioned(
5329
5329
  session.id,
5330
5330
  { model: 'claude-sonnet-4-5' },
5331
- {
5332
- operationId: loadOrCreatePendingOperationId('space-settings-draft-9'),
5333
- expectedRevision: current.revision,
5334
- },
5331
+ { expectedRevision: current.revision },
5335
5332
  );
5336
5333
  ```
5337
5334
 
5338
- Create retries with the same explicit session and operation IDs cannot overwrite
5335
+ Re-creating with the same explicit `sessionId` cannot overwrite
5339
5336
  an existing session. Same-session starts and after-turn inputs receive a durable `sessionOrder`.
5340
- Retries with the same operation ID return the canonical result and do not
5341
- create another run. Settings use compare-and-swap; a stale revision returns a
5337
+ Settings use compare-and-swap; a stale revision returns a
5342
5338
  structured conflict and must be reloaded, never silently overwritten. The
5343
5339
  shared settings keys are `provider`, `model`, `effort`, `thinking`,
5344
5340
  `reasoningMode`, `permissionMode`, `executionCwd`, `agentMode`, and
@@ -5351,7 +5347,6 @@ const queued = await runtime.runs.submitInput({
5351
5347
  afterRunId: handle.runId,
5352
5348
  delivery: 'after_turn',
5353
5349
  input: { type: 'text', text: 'Also update the tests.' },
5354
- operation: { operationId: loadOrCreatePendingOperationId('space-input-17') },
5355
5350
  });
5356
5351
 
5357
5352
  if (!queued.accepted) {
@@ -5365,7 +5360,8 @@ This does not create a Run. Each accepted input appears as `queued` in the
5365
5360
  owning Run's `interruptInputs`. At the next safe boundary, all accumulated
5366
5361
  interrupts are drained FIFO, remain separate user messages in one next LLM
5367
5362
  request, and produce one `run.input.delivered` event whose `inputs` array is the
5368
- complete ordered batch. Exact operation retries return the same `inputId`.
5363
+ complete ordered batch. An accepted interrupt returns the `inputId` of the
5364
+ admitted item, which you keep for later reconciliation.
5369
5365
  The accepted result's `runId` is the existing owning Run (equal to
5370
5366
  `afterRunId`), not a newly created continuation.
5371
5367
 
@@ -5381,8 +5377,8 @@ and Runtime restart preserve a newly recorded reference.
5381
5377
  Since v0.7.82, submission resolves the admitted authoritative Run before it
5382
5378
  reads mutable canonical Session history. Active interrupt and after-turn
5383
5379
  requests therefore do not surface a transient `data_changed` response caused by
5384
- predecessor persistence. `after_turn` still waits for predecessor settlement,
5385
- and an exact `operationId` still produces one admission and one queue item.
5380
+ predecessor persistence. `after_turn` still waits for predecessor settlement;
5381
+ admission and queue placement are owned by the receiving Run.
5386
5382
 
5387
5383
  Interrupt admission closes when the Runner publishes its final completion or
5388
5384
  terminal error signal, or when the Run's supplied `abortSignal` aborts, even if
@@ -5405,7 +5401,6 @@ const interrupted = await runtime.runs.submitInput({
5405
5401
  afterRunId: handle.runId,
5406
5402
  delivery: 'interrupt',
5407
5403
  input: { type: 'text', text: 'Also preserve the public API.' },
5408
- operation: { operationId: loadOrCreatePendingOperationId('space-input-18') },
5409
5404
  });
5410
5405
  ```
5411
5406
 
@@ -5417,8 +5412,9 @@ Run status exposes acceptance/start/queue times, authenticated origin,
5417
5412
  `terminal.code = 'blocked'`; surface `terminal.message` when present instead of
5418
5413
  replacing it with a generic run failure. Respect `effectOutcome`; `unknown` must
5419
5414
  never be presented as success or automatically retried. After a lost response,
5420
- query `runtime.operations.get({ operationId, journalEpoch })`; applied receipts
5421
- include the canonical result. Permission grants remain daemon-owned and
5415
+ there is no operation receipt to query: re-read authoritative state with
5416
+ `runs.get(runId)` / `sessions.status(sessionId)` and reconcile explicitly.
5417
+ Permission grants remain daemon-owned and
5422
5418
  revisioned.
5423
5419
 
5424
5420
  Runtime startup restores all indexed active Runs and at most 200 recent
@@ -5494,7 +5490,7 @@ permission context contracts: Auto approvals bind to one exact text call
5494
5490
  without granting a directory, and direct plus managed provider requests carry
5495
5491
  the live permission mode refreshed on retries.
5496
5492
  `sharedSessionSettings` v2 advertises the four canonical profiles and the
5497
- input-only `auto-in-project` alias. Embedded, Worker, and daemon hosts expose
5493
+ input-only `auto-in-project` alias. Embedded and daemon hosts expose
5498
5494
  the same contract; restart or upgrade an older daemon instead of falling back
5499
5495
  to client-side routing.
5500
5496
 
@@ -5529,11 +5525,10 @@ const run = await runtime.runs.start({
5529
5525
  mode: 'scoped',
5530
5526
  providers: ['anthropic', 'openai'],
5531
5527
  },
5532
- operation: { operationId: loadOrCreatePendingOperationId('space-run-88') },
5533
5528
  });
5534
5529
  ```
5535
5530
 
5536
- The allowlist is a ceiling: an operation binding can narrow it but cannot add a
5531
+ The allowlist is a ceiling: a run binding can narrow it but cannot add a
5537
5532
  Provider. The daemon asks only when an actual primary, fallback, classifier,
5538
5533
  sidecar, compaction, Workflow, or utility wire call needs that Provider.
5539
5534
  An unauthorized Provider fails before the host callback. The secret crosses
@@ -5615,7 +5610,6 @@ await runtime.runs.start({
5615
5610
  sessionId,
5616
5611
  input: { type: 'text', text: 'Create the report artifact.' },
5617
5612
  hostTools: { leaseId: hostLease.id },
5618
- operation: { operationId: loadOrCreatePendingOperationId('space-artifact-run') },
5619
5613
  });
5620
5614
  ```
5621
5615
 
@@ -5688,16 +5682,18 @@ rollout unless the product cannot operate without it.
5688
5682
 
5689
5683
  Preflight is useful for UI, but it is not a stop authorization token. Use
5690
5684
  `runtime.daemon.inspect()` to obtain one consistent management revision,
5691
- verified owner fence, owner-policy revision, and preflight projection. Only
5692
- `runtime.daemon.stopForInline()` atomically rechecks and commits a rollback.
5693
- The management revision also advances when the preflight projection changes,
5694
- so a Workflow or AgentTask lifecycle transition between inspect and commit
5695
- invalidates the stale stop. Capability details
5685
+ verified owner fence, owner-policy revision, and preflight projection, then
5686
+ send the authenticated `runtime.shutdown` request: management rechecks
5687
+ preflight under the draining fence and commits the stop only when the daemon is
5688
+ idle, otherwise it fails with a structured `conflict` and the daemon keeps
5689
+ running. The management revision also advances when the preflight projection changes,
5690
+ so a Workflow or AgentTask lifecycle transition between inspect and stop
5691
+ invalidates the stale attempt. Capability details
5696
5692
  `daemonManagement.backgroundWorkPreflight` and
5697
5693
  `daemonManagement.reverseBridgeDrainingFence` identify this complete contract.
5698
- `runtime.operations.get()` reconciles durable mutations,
5699
5694
  `hostTools.getInvocation()` reconciles Host Tool metadata, and
5700
- `permissions.listGrants()` returns the daemon-owned persistent grant set.
5695
+ `permissions.listGrants()` returns the daemon-owned persistent grant set;
5696
+ durable mutations are reconciled by re-reading their authoritative state.
5701
5697
 
5702
5698
  Terminal notification read/unread state is intentionally client-owned in
5703
5699
  v0.7.69 (`durableRecoveryQueries.terminalAcknowledgement === false`): Space
@@ -5709,45 +5705,47 @@ truth.
5709
5705
 
5710
5706
  Daemon and inline Coder use one profile fence. Do not compose
5711
5707
  `status.preflight()` with a low-level unconditional stop: another client or run
5712
- can appear between those calls. The public rollback transaction gates new
5713
- clients and mutations, rechecks the same Runtime and management/policy
5714
- revisions, verifies there is no other client or active/queued/pending work,
5715
- commits sticky inline policy while that daemon still owns the fence, and then
5716
- requests shutdown.
5708
+ can appear between those calls. v0.7.97 removed the combined rollback
5709
+ transaction (`runtime.daemon.stopForInline()`); stopping the daemon and
5710
+ changing the owner mode are now two explicit steps, and the owner mode never
5711
+ changes implicitly. First stop the daemon through the fenced idle shutdown —
5712
+ management rechecks preflight under the draining fence and returns a
5713
+ structured `conflict` instead of stopping a busy daemon — then flip the owner
5714
+ policy while no owner lock exists:
5717
5715
 
5718
5716
  ```ts
5719
5717
  import {
5720
5718
  acquireKodaXInlineOwner,
5721
5719
  enableKodaXDaemonOwner,
5722
5720
  getKodaXRuntimeOwnerState,
5721
+ setKodaXRuntimeOwnerMode,
5723
5722
  } from '@kodax-ai/kodax/runtime';
5724
5723
 
5725
5724
  const management = await runtime.daemon.inspect();
5726
5725
  if (!management.preflight.canStop) {
5727
- showRollbackBlockers(management.preflight.blockers);
5726
+ showStopBlockers(management.preflight.blockers);
5728
5727
  return;
5729
5728
  }
5730
5729
 
5731
- const rollback = await runtime.daemon.stopForInline({
5732
- expectedRuntimeId: management.runtimeId,
5733
- expectedRevision: management.revision,
5734
- expectedOwnerPolicyRevision: management.ownerPolicy.revision,
5735
- operation: { operationId: loadOrCreatePendingOperationId('coder-inline-rollback') },
5736
- });
5730
+ // Fenced idle stop; active work returns structured `conflict`.
5731
+ const stop = await runtime.daemon.shutdown();
5737
5732
 
5738
- // `accepted` means inline policy is committed and shutdown is in progress.
5739
- // Wait through the public owner-state query; never infer release from a PID.
5733
+ // `accepted` means the stop was taken. Wait through the public owner-state
5734
+ // query; never infer release from a PID.
5740
5735
  const shutdownDeadline = Date.now() + 30_000;
5741
- while (getKodaXRuntimeOwnerState({ homeDir: kodaxHome, profile: 'coder' }).owner?.runtimeId
5742
- === rollback.runtimeId) {
5736
+ while (getKodaXRuntimeOwnerState({ homeDir: kodaxHome, profile: 'coder' }).owner) {
5743
5737
  if (Date.now() >= shutdownDeadline) throw new Error('Timed out waiting for daemon owner release.');
5744
5738
  await delay(25);
5745
5739
  }
5746
- const releasedOwner = getKodaXRuntimeOwnerState({ homeDir: kodaxHome, profile: 'coder' });
5747
- if (releasedOwner.ownerStatus !== 'unowned') {
5748
- throw new Error('Coder profile acquired a different owner during rollback.');
5749
- }
5750
5740
  await runtime.close(); // Detach only; it does not perform a second stop.
5741
+
5742
+ // Explicit daemon→inline owner-mode change; rejected while an owner lock exists.
5743
+ setKodaXRuntimeOwnerMode({
5744
+ mode: 'inline',
5745
+ expectedRevision: management.ownerPolicy.revision,
5746
+ homeDir: kodaxHome,
5747
+ profile: 'coder',
5748
+ });
5751
5749
  const inlineOwner = acquireKodaXInlineOwner({ homeDir: kodaxHome, profile: 'coder' });
5752
5750
 
5753
5751
  // Later, after the inline owner has released its fence:
@@ -5759,25 +5757,30 @@ const daemonPolicy = enableKodaXDaemonOwner({ homeDir: kodaxHome, profile: 'code
5759
5757
  Any management revision change, another logical client, active or queued run,
5760
5758
  running/paused Workflow, non-terminal/unknown AgentTask, pending
5761
5759
  AskUser/permission, or in-flight mutation returns structured `conflict`; the
5762
- daemon remains running and policy remains unchanged. Draining also rejects
5763
- credential and Host Tool state changes without journaling their secrets or
5760
+ daemon remains running and the owner mode remains unchanged. Draining also rejects
5761
+ credential and Host Tool state changes without persisting their secrets or
5764
5762
  results. The inline policy is sticky: later CLI auto-start is rejected until
5763
+ `setKodaXRuntimeOwnerMode({ mode: 'daemon', ... })` or
5765
5764
  `enableKodaXDaemonOwner()` changes it back to `daemon`. `runtime.close()` still
5766
5765
  only detaches. Stale-owner handling validates the owned lock/state and never
5767
5766
  kills a process merely because a PID was reused.
5768
5767
 
5769
5768
  Keep all trusted objects in Electron Main: daemon token/endpoint, stable client
5770
- identity, operation IDs, owner policy, keychain broker, Host Tool handlers, and
5769
+ identity, owner policy, keychain broker, Host Tool handlers, and
5771
5770
  permission-grant administration. Renderer IPC should expose product-specific
5772
5771
  commands and sanitized projections only. Never pass daemon credentials,
5773
- leases, operation epochs, or trusted session/run context to renderer or model
5772
+ leases, or trusted session/run context to renderer or model
5774
5773
  tool arguments.
5775
5774
 
5776
5775
  ---
5777
5776
 
5778
5777
  ## 24. Runtime-owned permission routing and plan bridges (v0.7.96)
5779
5778
 
5780
- The Runtime owns permission routing in inline, Worker, and daemon deployments.
5779
+ > The product equivalent is `view.interactions` plus `interactions.respond`.
5780
+ > The Runtime helpers below are for trusted Host adapters, not client-created
5781
+ > permission requests or alternate authorization owners.
5782
+
5783
+ The Runtime owns permission routing in inline and daemon deployments.
5781
5784
  Clients select one of four profiles and must not add a second preflight gate:
5782
5785
 
5783
5786
  ```ts
@@ -5950,6 +5953,10 @@ for the current permission contract.
5950
5953
 
5951
5954
  ## 25. Always-on context compaction and bounded transcript recovery (v0.7.74)
5952
5955
 
5956
+ > Product clients use `sessions.compact`, `observe`, `readItem`, `readHistory`,
5957
+ > `readHistoryEntry` and `searchHistory`. Low-level transcript/event examples
5958
+ > below do not imply an additional Product event replay surface.
5959
+
5953
5960
  Automatic large compaction is always enabled. `enabled` remains accepted for
5954
5961
  v0.7.x source compatibility, but `false` is normalized to `true`.
5955
5962
  `triggerPercent` defaults to `75` and is clamped to `15..90`. The optional
@@ -5985,16 +5992,16 @@ await runtime.sessions.compact({
5985
5992
  mode: 'scoped',
5986
5993
  providers: ['anthropic'],
5987
5994
  },
5988
- operation: {
5989
- operationId: loadOrCreatePendingOperationId(`compact:${session.id}`),
5990
- },
5991
5995
  });
5992
5996
  ```
5993
5997
 
5994
5998
  Manual compact uses the same credential-aware summary implementation as
5995
- automatic compact. Its broker target is the stable `session.compact` operation,
5996
- not a fabricated Run ID; the daemon validates lease, Provider, Session, and
5997
- operation scope. Reuse the same `operationId` after a lost response.
5999
+ automatic compact. There is no client-supplied operation envelope: the daemon
6000
+ itself mints the short-lived compaction identity for the scoped credential
6001
+ target (a `compact_<uuid>` maintenance id bound to the stable
6002
+ `session.compact` operation, not a fabricated Run ID) and validates lease,
6003
+ Provider, and Session before the summary call. After a lost response, re-read
6004
+ the Session's compaction state instead of retrying blindly.
5998
6005
 
5999
6006
  Setting `compactionTriggerTokens: 0` removes the absolute Session override.
6000
6007
  Percentage updates are normalized to `15..90`; negative/fractional absolute
@@ -6199,7 +6206,7 @@ only prevents high-frequency progress from becoming a model control signal.
6199
6206
  ## 27. Windows GUI background subprocess visibility (v0.7.75)
6200
6207
 
6201
6208
  KodaX SDK hosts do not need to add process-wide console suppression around the
6202
- Runtime. In the v0.7.75 release candidate, Runtime Worker-reachable
6209
+ Runtime. Since the v0.7.75 release candidate, Runtime-reachable
6203
6210
  non-interactive/background child processes request `windowsHide: true` at their
6204
6211
  own spawn boundary. The covered paths include:
6205
6212
 
@@ -6214,8 +6221,10 @@ commands, and PTY sessions remain interactive. POSIX-only `ps`, `tmux`, and
6214
6221
  sandbox branches are reviewed bundle-audit exceptions rather than Windows
6215
6222
  visibility paths.
6216
6223
 
6217
- `npm run build:bundle` audits every statically identifiable child-process call
6218
- reachable from `dist/runtime-worker.js`. The packaged Electron daemon smoke then
6224
+ The bundled runtime entry points ship with the `dist/semantic-worker.js` and
6225
+ `dist/constructed-handler-worker.js` sidecars (the former
6226
+ `dist/runtime-worker.js` sidecar and its build-time child-process audit were
6227
+ removed with the Worker facade in v0.7.97). The packaged Electron daemon smoke then
6219
6228
  runs 20 ordinary queries with a Win32 probe and checks that the expected Git
6220
6229
  children never own a visible console window. These checks validate the SDK
6221
6230
  boundary, but they do not replace product-level validation in the packaged host.
@@ -6309,6 +6318,9 @@ for cross-project, cache, cancellation, credential, and Windows argv checks.
6309
6318
 
6310
6319
  ## 29. Evidence-gated background Skill learning (FEATURE_263, v0.7.78)
6311
6320
 
6321
+ > Product clients consume the Host-owned `client.learning` service. Bootstrap
6322
+ > options below configure the trusted owner, not a separate UI learning engine.
6323
+
6312
6324
  F263 completes the existing Learning Center rather than introducing a second
6313
6325
  queue or client-owned Skill store. Episode review runs after durable foreground
6314
6326
  completion and stays off the active Run's latency path. A correction, failure,
@@ -6389,7 +6401,7 @@ bindings without mutating an in-flight prompt.
6389
6401
  Learning Center notification state is client-specific, but capability
6390
6402
  lifecycle and project canary state are owner-global. Renderer code should
6391
6403
  receive sanitized records/events through host IPC; it should not receive
6392
- daemon credentials or mutate files directly. Inline, Worker, and daemon
6404
+ daemon credentials or mutate files directly. Inline and daemon
6393
6405
  facades expose the same learning methods. A host missing `skillLearningLoop:1`
6394
6406
  may still support the older Ready/manual Learning Center surface, but must not
6395
6407
  claim the complete F263 project-canary contract.
@@ -6811,7 +6823,7 @@ try {
6811
6823
  when multiple projects expose the same display name or slug. `'user'` is the
6812
6824
  only supported scope. Daemon clients need the server-issued
6813
6825
  `learning:control` scope; advertising a client capability does not grant it.
6814
- Inline, Worker, and daemon facades carry the same v2 learned-record shape and
6826
+ Inline and daemon facades carry the same v2 learned-record shape and
6815
6827
  promotion method.
6816
6828
 
6817
6829
  The Runtime verifies the source is a regular non-symlink file inside the exact
@@ -6838,6 +6850,68 @@ unsupported options fail before the Runtime mutation.
6838
6850
 
6839
6851
  ---
6840
6852
 
6853
+ ## Migrating to v0.7.97
6854
+
6855
+ For the complete product-facing mapping, use the [SDK migration guide](../../docs/SDK_MIGRATION.md).
6856
+ The table below covers removals in this development tree; it does not claim a
6857
+ published `v0.7.97` package. Retained Runtime APIs are not automatically Product APIs.
6858
+
6859
+ v0.7.97 is a breaking SDK release for embedders. It removes the durable event
6860
+ journal/replay surface, the generic operation envelope/receipts, the
6861
+ crash-resumable exit-settlement protocol, and the Worker-hosted embedded
6862
+ runtime. If you upgrade a host past v0.7.96, map every removed surface to its
6863
+ replacement:
6864
+
6865
+ | Removed in v0.7.97 | Replacement |
6866
+ |---|---|
6867
+ | Operation envelope (`operation: { operationId }` on public control mutations), auto-generated operation IDs, `runtime.operations.get` receipts, and the `operationDeduplication` capability/requirement | Mutation identity comes from each mutation's own domain fields (explicit `sessionId` on create, returned `runId`, `expectedRevision` CAS on settings). After a lost response, re-read authoritative state (`runs.get`, `sessions.status`) and reconcile explicitly; there is no transparent retry or receipt query. |
6868
+ | `settleKodaXRuntimeExit()` SDK export, `daemon.rollbackToInline`, client `stopForInline`, and the `runtimeExitSettlement:2` capability | `runtime.shutdown` / `runtime.daemon.shutdown()` is a real idle shutdown (busy → structured `conflict`). Daemon→inline ownership changes are explicit: `setKodaXRuntimeOwnerMode({ mode, expectedRevision })`, or owner-lock release plus `acquireKodaXInlineOwner()`. The owner mode never changes implicitly. |
6869
+ | `event.subscribe`/`event.replay` RPCs, the `{ sessionId, journalEpoch, seq }` cursor, `journalEpoch` fields, and the `sessionEventJournal:1` capability | Events are a live in-process stream (`{ id, seq, time, sessionId, runId, turnId?, type, payload }`). Remote consumption reuses `session.observe` notifications; observation snapshots carry a `seq` high-water, live listener events are strictly greater, and `seq` never persists across restarts. Deleting/recreating a Session invalidates observations with `runtime_changed`. |
6870
+ | Diagnostics RPCs `context.budget.get`, `tool.exposure.preview`, `provider.cache.diagnostics.get` (and the `runtime.diagnostics.latest*` facade) | Removed. `capabilities.contextDiagnostics: true` only gates diagnostic event notifications (`context.budget.snapshot`, `tool.exposure.planned`, `provider.cache.diagnostics`, `context.compaction.skipped`) on the live stream. |
6871
+ | `isolation: 'worker'`, `worker: { configuredA2A: true }` (and `worker.*` options), `requirements.hardDispose`, and the `dist/runtime-worker.js` sidecar | Deleted. Use inline embedded or daemon mode. For the configured A2A plane, wire `createConfiguredA2ARuntimeIntegration({ configHome })` in the owner and pass its `runtimeOptions` as `externalAgents` — the Runtime itself never reads `integrations/a2a.json`. |
6872
+ | Late-result redelivery after an abandoned read | Removed. `request.cancel`/`request.ack` remain daemon transport-control frames only; an abandoned read gets no late delivery. |
6873
+ | The product mode surfaces: the CLI `--runtime-mode` flag, the `KODAX_RUNTIME_MODE` environment variable, and the `runtimeMode` key in `~/.kodax/config.json` | Removed in the fixed-Host release. The `kodax` CLI always starts-or-attaches the daemon owner; SDK callers keep the `mode: 'embedded' | 'daemon'` option on `createKodaXRuntime` (embedded stays a low-level path, never a product fallback). |
6874
+ | `setThinking` REPL callback | Removed. Use `setReasoningMode` (the shared settings key is `reasoningMode`). |
6875
+ | `getKodaXRuntimeOwnerPolicy` export | Removed. `getKodaXRuntimeOwnerState()` remains and reports policy, owner status, and the current owner in one call. |
6876
+
6877
+ Product UIs connect through `connectKodaXClient` from `@kodax-ai/kodax/client`.
6878
+ The Host owns execution and saved history; `sessions.observe` delivers the
6879
+ current display; `readItem` expands display references, while `readHistory`,
6880
+ `readHistoryEntry` and `searchHistory` provide canonical history and its own
6881
+ readable references. A display preview is not the full
6882
+ message. The Runtime-to-product adapter is internal and is not an SDK export.
6883
+
6884
+ Keep an input's original text, artifacts and `inputId` until its outcome is
6885
+ known. After a lost response, query that same Host with `inputs.read`; only a
6886
+ confirmed withdrawal returns a queued input to the editor. A replacement Host
6887
+ does not inherit the old Host's input identities.
6888
+
6889
+ Product rewind requires the head the user reviewed, so another client's newer
6890
+ work cannot be silently discarded:
6891
+
6892
+ ```ts
6893
+ const lineage = await client.sessions.readLineage(sessionId);
6894
+ await client.sessions.rewindSession(sessionId, {
6895
+ selector: targetEntryId,
6896
+ expectedHead: lineage?.activeEntryId ?? null,
6897
+ });
6898
+ ```
6899
+
6900
+ On `conflict`, reload the lineage and let the user review the new state before
6901
+ trying again. Rewind changes the conversation branch; it does not undo files.
6902
+ Bound REPL Memory commands use the same daemon owner, and Workflow/Skill
6903
+ execution uses real Runs with the Session's effective settings and tool policy.
6904
+
6905
+ Two compatibilities are unchanged and worth restating: the constructed-handler
6906
+ worker (repo-intelligence and managed-task workers in `@kodax-ai/coding`) is a
6907
+ separate, kept surface, and the `mode: 'embedded' | 'daemon'` option on
6908
+ `createKodaXRuntime` still selects the ownership form. Host-minted compact
6909
+ identity (`compact_<uuid>`, minted by the daemon for the scoped credential
6910
+ target of manual compaction) still exists — it is Host-internal, not a client
6911
+ envelope.
6912
+
6913
+ ---
6914
+
6841
6915
  ## Managed extension execution and Session Stop (FEATURE_299, v0.7.96)
6842
6916
 
6843
6917
  A Stop button uses one owner-side operation: