@kodax-ai/kodax 0.7.76 → 0.7.78

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 (130) hide show
  1. package/CHANGELOG.md +758 -371
  2. package/LICENSE +158 -158
  3. package/README.md +1702 -1508
  4. package/README_CN.md +1019 -869
  5. package/config-templates/config.example.jsonc +86 -4
  6. package/config-templates/integrations/a2a.example.jsonc +98 -98
  7. package/config-templates/integrations/extensions.example.jsonc +7 -7
  8. package/config-templates/integrations/mcp.example.jsonc +16 -16
  9. package/dist/builtin/code-review/SKILL.md +22 -22
  10. package/dist/builtin/skill-creator/scripts/aggregate-benchmark.d.ts +46 -46
  11. package/dist/builtin/skill-creator/scripts/analyze-benchmark.d.ts +46 -46
  12. package/dist/builtin/skill-creator/scripts/compare-runs.d.ts +62 -62
  13. package/dist/builtin/skill-creator/scripts/generate-review.d.ts +33 -33
  14. package/dist/builtin/skill-creator/scripts/grade-evals.d.ts +73 -73
  15. package/dist/builtin/skill-creator/scripts/improve-description.d.ts +23 -23
  16. package/dist/builtin/skill-creator/scripts/init-skill.d.ts +14 -14
  17. package/dist/builtin/skill-creator/scripts/install-skill.d.ts +29 -29
  18. package/dist/builtin/skill-creator/scripts/package-skill.d.ts +38 -38
  19. package/dist/builtin/skill-creator/scripts/quick-validate.d.ts +8 -8
  20. package/dist/builtin/skill-creator/scripts/run-eval.d.ts +66 -66
  21. package/dist/builtin/skill-creator/scripts/run-loop.d.ts +49 -49
  22. package/dist/builtin/skill-creator/scripts/run-trigger-eval.d.ts +58 -58
  23. package/dist/chunks/agent-ASP4MS3X.js +2 -0
  24. package/dist/chunks/argument-completer-JYQ7FX3W.js +2 -0
  25. package/dist/chunks/chunk-2CFHBKRE.js +5 -0
  26. package/dist/chunks/chunk-35PPHOQ2.js +292 -0
  27. package/dist/chunks/chunk-43QNNDHR.js +29 -0
  28. package/dist/chunks/chunk-5BNQXXGY.js +1 -0
  29. package/dist/chunks/chunk-5GO6FH7L.js +458 -0
  30. package/dist/chunks/chunk-5NDCSFOP.js +78 -0
  31. package/dist/chunks/chunk-6FOJVETH.js +22 -0
  32. package/dist/chunks/chunk-6XM4B6K2.js +48 -0
  33. package/dist/chunks/chunk-6YZUE6NC.js +240 -0
  34. package/dist/chunks/{chunk-RDXRM3UI.js → chunk-7OEBJGHK.js} +1 -1
  35. package/dist/chunks/chunk-KQLQYHWU.js +386 -0
  36. package/dist/chunks/chunk-NXO6GWSY.js +46 -0
  37. package/dist/chunks/chunk-T2XZTLYE.js +316 -0
  38. package/dist/chunks/chunk-TQDBTTIM.js +348 -0
  39. package/dist/chunks/{chunk-SMT2JSM3.js → chunk-UID7BLAB.js} +9 -9
  40. package/dist/chunks/chunk-VAT2QYXM.js +765 -0
  41. package/dist/chunks/chunk-YAZQTC2L.js +5 -0
  42. package/dist/chunks/chunk-YVRYHC4C.js +655 -0
  43. package/dist/chunks/{chunk-PXKSE54E.js → chunk-Z3KFRTSB.js} +1 -1
  44. package/dist/chunks/compaction-config-BQSSIWK5.js +2 -0
  45. package/dist/chunks/{construction-bootstrap-5F5KF2BZ.js → construction-bootstrap-VQLQGWPY.js} +1 -1
  46. package/dist/chunks/dist-BFT5YIGU.js +2 -0
  47. package/dist/chunks/dist-PCFE24YP.js +2 -0
  48. package/dist/chunks/host-UTFXCYYM.js +2 -0
  49. package/dist/chunks/run-manager-PJU3WIFJ.js +2 -0
  50. package/dist/chunks/utils-SID4HW2Q.js +2 -0
  51. package/dist/index.d.ts +21 -19
  52. package/dist/index.js +6 -6
  53. package/dist/kodax_bootstrap.js +25 -25
  54. package/dist/kodax_cli.js +1787 -1341
  55. package/dist/kodax_resume.js +17 -17
  56. package/dist/provider-capabilities.json +392 -362
  57. package/dist/runtime-worker.js +1707 -1279
  58. package/dist/sandbox-workspace-session.js +563 -0
  59. package/dist/sdk-a2a.d.ts +18 -17
  60. package/dist/sdk-a2a.js +8 -8
  61. package/dist/sdk-agent.d.ts +320 -70
  62. package/dist/sdk-agent.js +1 -1
  63. package/dist/sdk-coding.d.ts +135 -168
  64. package/dist/sdk-coding.js +1 -1
  65. package/dist/sdk-experimental-memory.d.ts +14 -597
  66. package/dist/sdk-experimental-memory.js +1 -1
  67. package/dist/sdk-llm.d.ts +219 -6
  68. package/dist/sdk-llm.js +1 -1
  69. package/dist/sdk-mcp.js +1 -1
  70. package/dist/sdk-media.d.ts +1 -1
  71. package/dist/sdk-media.js +1 -1
  72. package/dist/sdk-repl.d.ts +70 -27
  73. package/dist/sdk-repl.js +2 -2
  74. package/dist/sdk-runtime.d.ts +212 -149
  75. package/dist/sdk-runtime.js +1 -1
  76. package/dist/sdk-sandbox.d.ts +93 -0
  77. package/dist/sdk-sandbox.js +2 -0
  78. package/dist/sdk-session.d.ts +8 -8
  79. package/dist/sdk-session.js +1 -1
  80. package/dist/sdk-skills.d.ts +2 -2
  81. package/dist/sdk-skills.js +1 -1
  82. package/dist/semantic-worker.js +15 -15
  83. package/dist/types-chunks/{base.d-ChvpaKjZ.d.ts → base.d-4e74xDdy.d.ts} +13 -1
  84. package/dist/types-chunks/{bash-prefix-extractor.d-r1beOESM.d.ts → bash-prefix-extractor.d-uAe2Oqda.d.ts} +319 -9
  85. package/dist/types-chunks/{capability-learning.d-DPrYxRjF.d.ts → capability-learning.d-CVsdHw4j.d.ts} +1 -1
  86. package/dist/types-chunks/{capsule.d-zeqV4IQX.d.ts → capsule.d-BlSv9l3V.d.ts} +2 -2
  87. package/dist/types-chunks/{guardrail.d-CWYD1bdL.d.ts → guardrail.d-BRE_ErEj.d.ts} +1 -1
  88. package/dist/types-chunks/{guardrail.d-qjuKJZ31.d.ts → guardrail.d-CXDYRgZ3.d.ts} +201 -35
  89. package/dist/types-chunks/{history-retrieval.d-BKTJIrVd.d.ts → history-retrieval.d-DtCy7x64.d.ts} +2 -2
  90. package/dist/types-chunks/{integration-config.d-ojG4swOP.d.ts → integration-config.d-BNowXE8k.d.ts} +23 -8
  91. package/dist/types-chunks/{public-api.d-CX4B11qY.d.ts → public-api.d-B3AohsxN.d.ts} +37 -8
  92. package/dist/types-chunks/{commands.d-DUxnK2TU.d.ts → repl.d-Ie_ZXb_U.d.ts} +89 -78
  93. package/dist/types-chunks/{side-query.d-DWTMsndP.d.ts → resolver.d-iAQ9ocLB.d.ts} +23 -74
  94. package/dist/types-chunks/{run-manager.d-B9fEIjZk.d.ts → run-manager.d-D1twIhF9.d.ts} +1 -1
  95. package/dist/types-chunks/{sdk-session-B0fhAOPa.d.ts → sdk-session-DB9KksIx.d.ts} +3 -3
  96. package/dist/types-chunks/side-query.d-DTuLPcC5.d.ts +77 -0
  97. package/dist/types-chunks/types-D3g6XUQr.d.ts +662 -0
  98. package/dist/types-chunks/{types.d-sRLugmjy.d.ts → types.d-BA-Jwpfs.d.ts} +506 -11
  99. package/dist/types-chunks/{types.d-DEctY20M.d.ts → types.d-BH0ZkTGf.d.ts} +2 -2
  100. package/dist/types-chunks/{types.d-DCQVBqVn.d.ts → types.d-BbtGlKZu.d.ts} +25 -3
  101. package/dist/types-chunks/{types.d-CSmF0t0n.d.ts → types.d-DIpZJKUl.d.ts} +15 -0
  102. package/dist/types-chunks/{types.d-Bm_y6YuM.d.ts → types.d-DVDTIfB_.d.ts} +4 -4
  103. package/dist/types-chunks/{utils.d-D0wPxz8y.d.ts → utils.d-CVp6bFl9.d.ts} +23 -7
  104. package/docs/SDK_EMBEDDER_GUIDE.md +592 -119
  105. package/package.json +9 -1
  106. package/scripts/kodax-bin.cjs +28 -28
  107. package/scripts/production-env.cjs +25 -25
  108. package/dist/chunks/agent-7X5CFET2.js +0 -2
  109. package/dist/chunks/argument-completer-3NHIKB4N.js +0 -2
  110. package/dist/chunks/chunk-4PWPNCNK.js +0 -158
  111. package/dist/chunks/chunk-7FJNLJLF.js +0 -369
  112. package/dist/chunks/chunk-COQYLD4U.js +0 -5
  113. package/dist/chunks/chunk-D3T24FJW.js +0 -78
  114. package/dist/chunks/chunk-EI4JBQKL.js +0 -46
  115. package/dist/chunks/chunk-HGT6WQ24.js +0 -321
  116. package/dist/chunks/chunk-HS3XHF3R.js +0 -622
  117. package/dist/chunks/chunk-IDCGNQ4H.js +0 -5
  118. package/dist/chunks/chunk-KAY2XLCP.js +0 -74
  119. package/dist/chunks/chunk-OD6LVXU6.js +0 -329
  120. package/dist/chunks/chunk-OSF3H4RR.js +0 -22
  121. package/dist/chunks/chunk-TGMBHGZO.js +0 -427
  122. package/dist/chunks/chunk-VWSLC2WO.js +0 -770
  123. package/dist/chunks/chunk-Y3AMP22L.js +0 -37
  124. package/dist/chunks/compaction-config-7J2XE35D.js +0 -2
  125. package/dist/chunks/dist-2RA7LSH3.js +0 -2
  126. package/dist/chunks/dist-URKXBOC6.js +0 -2
  127. package/dist/chunks/host-RKZ2OGFT.js +0 -2
  128. package/dist/chunks/run-manager-7RM4HEH6.js +0 -2
  129. package/dist/chunks/utils-X3TEH6IO.js +0 -2
  130. package/dist/types-chunks/center-types.d-BBT122uJ.d.ts +0 -91
@@ -28,13 +28,17 @@ are NOT obvious from inspecting the type definitions alone:
28
28
  18. [External-agent executor plane](#18-external-agent-executor-plane-feature_258-v0767)
29
29
  19. [Session surface filtering and cursor pagination](#19-session-surface-filtering-and-cursor-pagination-feature_261-v0767)
30
30
  20. [Cost-disciplined workflow routing and telemetry](#20-cost-disciplined-workflow-routing-and-telemetry-feature_259-v0767)
31
- 21. [Experimental governed memory — `/experimental-memory`](#21-experimental-governed-memory--experimental-memory-feature_260-v0768)
31
+ 21. [Experimental governed memory — `/experimental-memory`](#21-experimental-governed-memory--experimental-memory-feature_260--feature_275-v0768v0777)
32
32
  22. [Bidirectional A2A 1.0 — `/a2a`](#22-bidirectional-a2a-10--a2a-feature_267-v0769)
33
33
  23. [Shared Coder daemon for Space and IDE hosts](#23-shared-coder-daemon-for-space-and-ide-hosts-feature_269-v0769)
34
34
  24. [Runtime-owned Auto Mode and plan-approval bridges](#24-runtime-owned-auto-mode-and-plan-approval-bridges-v0772v0773)
35
- 25. [Always-on context compaction and bounded transcript recovery](#25-always-on-context-compaction-and-bounded-transcript-recovery-v0774)
35
+ 25. [Always-on context compaction and bounded transcript recovery](#25-always-on-context-compaction-and-bounded-transcript-recovery-v0774)
36
36
  26. [Agent mailbox control versus SDK event telemetry](#26-agent-mailbox-control-versus-sdk-event-telemetry-v0774)
37
37
  27. [Windows GUI background subprocess visibility](#27-windows-gui-background-subprocess-visibility-v0775)
38
+ 28. [Host-configurable Shell Execution Contract](#28-host-configurable-shell-execution-contract-v0777)
39
+ 29. [Evidence-gated background Skill learning](#29-evidence-gated-background-skill-learning-feature_263-v0778)
40
+ 30. [Standalone sandbox SDK](#30-standalone-sandbox-sdk-v0778)
41
+ - [Learned Skill promotion reference](#learned-skill-promotion-reference-v0778)
38
42
 
39
43
  §1–§3 (and the Phase-7/8 MCP-popout surface in §1) land in v0.7.42
40
44
  under FEATURE_186 (see [ADR-032](ADR.md#adr-032-sdk-embedder-surface-closure-feature_186-v0742)).
@@ -2775,11 +2779,11 @@ await runtime.mcp.upsertServer('filesystem', {
2775
2779
  });
2776
2780
  await runtime.mcp.reloadServers();
2777
2781
 
2778
- const commands = await runtime.catalog.commands(process.cwd());
2779
- const skills = await runtime.catalog.skills({ projectRoot: process.cwd() });
2780
- ```
2781
-
2782
- This is the intended path for KodaX Space, IDE adapters, and settings UIs:
2782
+ const commands = await runtime.catalog.commands(process.cwd());
2783
+ const skills = await runtime.catalog.skills({ projectRoot: process.cwd() });
2784
+ ```
2785
+
2786
+ This is the intended path for KodaX Space, IDE adapters, and settings UIs:
2783
2787
  session defaults go through `sessions.updateSettings()`, one-turn overrides go
2784
2788
  through `runs.start({ options })`, and daemon/profile config goes through
2785
2789
  `config`, `catalog`, and `mcp`.
@@ -2799,12 +2803,19 @@ engine:
2799
2803
  Hosts that set `capabilities.contextDiagnostics: true` can read:
2800
2804
 
2801
2805
  ```ts
2802
- const budget = await runtime.diagnostics.latestContextBudget({ sessionId });
2803
- const exposure = await runtime.diagnostics.latestToolExposure({ sessionId });
2804
- ```
2805
-
2806
- These diagnostics are designed for status panels and debugging. They should not
2807
- contain raw sensitive tool input/output.
2806
+ const budget = await runtime.diagnostics.latestContextBudget({ sessionId });
2807
+ const exposure = await runtime.diagnostics.latestToolExposure({ sessionId });
2808
+ const cache = await runtime.diagnostics.latestProviderCacheDiagnostic({ sessionId });
2809
+ ```
2810
+
2811
+ Pass `{ sessionId, contextKind: 'child', agentId }` to query one logical child
2812
+ even though its physical transcript uses an isolated Session. Diagnostic
2813
+ payloads carry `contextId` and, for children, `parentContextId`; reconnecting
2814
+ hosts can use the same latest APIs instead of fabricating identity fields.
2815
+ These diagnostics are designed for status panels and debugging. Budget
2816
+ snapshots contain counts, and cache diagnostics contain hashes plus
2817
+ Provider-reported usage; they do not contain raw prompt or sensitive tool
2818
+ input/output.
2808
2819
 
2809
2820
  ### Protocol schema and versioning
2810
2821
 
@@ -3219,7 +3230,7 @@ workflow's structured findings, verification results, and quality gates.
3219
3230
 
3220
3231
  ---
3221
3232
 
3222
- ## 21. Experimental governed memory — `/experimental-memory` (FEATURE_260, v0.7.68)
3233
+ ## 21. Experimental governed memory — `/experimental-memory` (FEATURE_260 + FEATURE_275, v0.7.68–v0.7.77)
3223
3234
 
3224
3235
  KodaX has one durable memory plane: the F228 Memory Control Plane. FEATURE_260
3225
3236
  adds a thin, opt-in agent/session API over that plane; it does not add a second
@@ -3280,11 +3291,53 @@ await session.complete({
3280
3291
  await session.close();
3281
3292
  ```
3282
3293
 
3283
- `recall()` is synchronous: exact observations/hints can be returned immediately,
3284
- while an optional semantic prefetch finishes for a later matching decision.
3285
- `query()` is deliberate and read-only; one distinct query is admitted per
3286
- decision epoch, and the result is bounded to at most three prompt-safe hints and
3287
- 512 estimated tokens. `undefined` means there is no governed reminder to inject.
3294
+ `recall()` is synchronous and exact. `query()` is deliberate and read-only; one
3295
+ distinct query is admitted per decision epoch, and the result is bounded to at
3296
+ most three prompt-safe hints and 512 estimated tokens. `undefined` means there
3297
+ is no governed reminder to inject.
3298
+
3299
+ ### Sparse foreground intervention (FEATURE_275, v0.7.77)
3300
+
3301
+ `MemorySession.intervene()` replaces the old timing-ineffective semantic
3302
+ prefetch. It is awaited only after `tool_failure`, `verification_failure`, or a
3303
+ durably committed `context_compacted` event, then supplies at most three
3304
+ prompt-safe, low-authority evidence items to the next Action-LLM request. The
3305
+ candidate set is rebuilt from current objective/open todos, recent governed
3306
+ observations, and a fresh F228 pack. Exact selection is deterministic; stale,
3307
+ unknown, malformed, timed-out, cancelled, or failed semantic results are
3308
+ discarded without blocking the coding run.
3309
+
3310
+ Top-level coding runs wire the deterministic path automatically and make zero
3311
+ selector calls by default. An inline host that deliberately wants semantic
3312
+ selection can provide the coding-owned forced-tool runner:
3313
+
3314
+ ```ts
3315
+ import {
3316
+ createCodingMemoryInterventionRunner,
3317
+ runKodaX,
3318
+ } from '@kodax-ai/kodax/coding';
3319
+ import { resolveProvider } from '@kodax-ai/kodax/llm';
3320
+
3321
+ const memoryRecallRunner = createCodingMemoryInterventionRunner({
3322
+ provider: resolveProvider('zhipu-coding'),
3323
+ model: 'glm-5.2',
3324
+ });
3325
+
3326
+ await runKodaX(
3327
+ {
3328
+ provider: 'zhipu-coding',
3329
+ model: 'glm-5.2',
3330
+ memoryRecallRunner,
3331
+ },
3332
+ 'Finish the repository migration and verify it.',
3333
+ );
3334
+ ```
3335
+
3336
+ `memoryRecallRunner` is a process-local function binding. Worker and daemon DTO
3337
+ options reject it instead of silently dropping it; configure the binding
3338
+ inside the Runtime owner or keep this run inline. The selector can return only
3339
+ exact IDs from the closed offered set and is capped at three calls per memory
3340
+ Session.
3288
3341
 
3289
3342
  ### Evidence, tracing, and persistence boundaries
3290
3343
 
@@ -3294,9 +3347,11 @@ decision epoch, and the result is bounded to at most three prompt-safe hints and
3294
3347
  material. `rewind()` removes observations after a sequence boundary.
3295
3348
  - `complete()` can emit an Outcome Digest through `persistOutcomeDigest` and run
3296
3349
  bounded episode review through `reviewEpisode`; cancellation creates neither.
3297
- - `onTrace` receives policy-versioned `MemoryDecisionReceipt` metadata that links
3298
- candidates, selection, injection, and later outcome influence. Receipts are
3299
- trace-only and contain no hidden reasoning.
3350
+ - `onTrace` receives policy-versioned `MemoryDecisionReceipt` metadata that links
3351
+ offered `candidateIds`, validated `selectedCandidateIds`, exposed
3352
+ `injectedEvidenceRefs`, triggers, and later outcome influence. Receipts are
3353
+ trace-only and contain no hidden reasoning; exposure is not proof of
3354
+ causality.
3300
3355
  - Durable memory mutation remains owned by F228's
3301
3356
  proposal/preview/fingerprint/apply flow. `/memory` is the CLI governance
3302
3357
  surface; direct file/shell writes to managed memory roots are denied.
@@ -3644,12 +3699,16 @@ const server = createKodaXA2AServer({
3644
3699
  },
3645
3700
  });
3646
3701
 
3647
- // Development only: the built-in listener refuses non-loopback hosts.
3648
- const localBaseUrl = await server.listen({ hostname: '127.0.0.1', port: 0 });
3649
- ```
3650
-
3651
- Production hosts route `GET /.well-known/agent-card.json` and canonical
3652
- JSON-RPC `POST /a2a` to `server.handle(request)` behind their own TLS
3702
+ // Development only: the built-in listener refuses non-loopback hosts.
3703
+ const localBaseUrl = await server.listen({ hostname: '127.0.0.1', port: 0 });
3704
+ ```
3705
+
3706
+ The listener also refuses an explicit port blocked by WHATWG Fetch clients.
3707
+ With `port: 0`, it retries ephemeral allocation rather than returning a URL
3708
+ that Fetch would reject before connecting.
3709
+
3710
+ Production hosts route `GET /.well-known/agent-card.json` and canonical
3711
+ JSON-RPC `POST /a2a` to `server.handle(request)` behind their own TLS
3653
3712
  terminator. `POST /` remains an accepted compatibility alias. `listen()` waits for durable recovery before
3654
3713
  it resolves. A host that wires `handle()` directly may explicitly await
3655
3714
  `server.whenReady()` before it starts accepting traffic; `handle()` also waits
@@ -3733,10 +3792,14 @@ SDK does not relaunch the GUI or silently fall back to an inline Runtime.
3733
3792
  ```ts
3734
3793
  import { connectKodaXRuntime } from '@kodax-ai/kodax/runtime';
3735
3794
 
3736
- const runtime = await connectKodaXRuntime({
3737
- profile: 'coder',
3738
- autoStart: true,
3739
- homeDir: coderRuntimeBaseDir, // owns <coderRuntimeBaseDir>/.kodax
3795
+ const runtime = await connectKodaXRuntime({
3796
+ profile: 'coder',
3797
+ autoStart: true,
3798
+ // Opt in only when this product remains the visible owner of the daemon.
3799
+ // If the product crashes, the daemon stops after its final client is gone
3800
+ // and governed work becomes idle.
3801
+ daemonOrphanExitMs: 30_000,
3802
+ homeDir: coderRuntimeBaseDir, // owns <coderRuntimeBaseDir>/.kodax
3740
3803
  clientInfo: {
3741
3804
  name: 'kodax-space',
3742
3805
  version: '0.1.32',
@@ -3768,10 +3831,10 @@ const runtime = await connectKodaXRuntime({
3768
3831
  sharedSessionSettings: 1,
3769
3832
  durableRecoveryQueries: 1,
3770
3833
  daemonManagement: 1,
3771
- runtimeAutoModeGuardrail: 3,
3772
- },
3773
- });
3774
- ```
3834
+ runtimeAutoModeGuardrail: 4,
3835
+ },
3836
+ });
3837
+ ```
3775
3838
 
3776
3839
  Requirements are server facts, not authorization requests. Check
3777
3840
  `runtime.grantedScopes` before enabling controls. Missing capabilities or
@@ -3781,21 +3844,35 @@ Coder. Products that depend on same-Run delivery should require
3781
3844
  (for example, SA execution) still return `unsupported_capability`; do not
3782
3845
  silently substitute `delivery:'after_turn'` unless that is the user's intent.
3783
3846
 
3784
- The v0.7.73 SDK requires `runtimeAutoModeGuardrail:3` automatically for
3785
- `autoStart: true`, even when the caller omits it from `requirements`. If the healthy
3786
- profile daemon advertises v1 or v2, the SDK first requires `daemonManagement:1`,
3787
- takes a revision/owner-policy fenced preflight, and replaces it only when no
3788
- active or queued run, Workflow, Agent turn, pending permission/user input, or
3789
- other logical client exists. A busy or still-older daemon is never stopped: the
3790
- connection rejects with `RuntimeDaemonCapabilityUpgradeError`, whose
3791
- `recoverable` and `restartRequired` fields are `true` and whose optional
3792
- `preflight` explains the blockers. Attach-only connections never mutate daemon
3793
- ownership and must request `runtimeAutoModeGuardrail:1` explicitly when they
3794
- depend only on the v1 owner contract, v2 for bounded input, effective-default
3795
- metadata, structured diagnostics, and speculative-window parity, or v3 for
3796
- opaque exact grant suggestions and concrete permission matchers. Capability
3797
- requirements are minimum versions: v3 satisfies v1/v2, v2 satisfies v1, and an
3798
- older daemon never satisfies a newer requirement.
3847
+ The SDK requires `runtimeAutoModeGuardrail:4` automatically for ordinary
3848
+ `autoStart: true`. Supplying `daemonOrphanExitMs` additionally requires the
3849
+ dedicated `daemonOrphanExit:1` capability and passes the option only when
3850
+ spawning a new daemon. It does not silently reinterpret an already-running
3851
+ persistent daemon: the SDK uses the normal fenced capability-upgrade path and
3852
+ replaces it only when preflight proves that doing so is safe. After the daemon
3853
+ has observed a logical client, final-client detach arms the requested grace
3854
+ period; a new client cancels it, and active/queued runs, Workflow, Agent turns,
3855
+ pending permission/user input, or other governed work defer exit until
3856
+ preflight is idle. Omit the option for CLI-style daemons that are intentionally
3857
+ persistent.
3858
+
3859
+ An embedder can inspect `KODAX_RUNTIME_SDK_CAPABILITIES.daemonOrphanExit`
3860
+ before calling an auto-start API. This prevents an older SDK from spawning a
3861
+ persistent daemon and only then discovering that it cannot honor the requested
3862
+ lifecycle policy. The connected daemon capability remains the authoritative
3863
+ check that the current host actually enabled the policy.
3864
+
3865
+ When a healthy profile daemon is too old, the SDK first requires
3866
+ `daemonManagement:1`, takes a revision/owner-policy fenced preflight, and
3867
+ replaces it only when no active or queued run, Workflow, Agent turn, pending
3868
+ permission/user input, or other logical client exists. A busy or still-older
3869
+ daemon is never stopped: the connection rejects with
3870
+ `RuntimeDaemonCapabilityUpgradeError`, whose `recoverable` and
3871
+ `restartRequired` fields are `true` and whose optional `preflight` explains the
3872
+ blockers. Attach-only connections never mutate daemon ownership and must request
3873
+ the exact capabilities they depend on. Capability requirements are minimum
3874
+ versions: v4 satisfies v1-v3, v3 satisfies v1/v2, v2 satisfies v1, and an older
3875
+ daemon never satisfies a newer requirement.
3799
3876
 
3800
3877
  The `coderFeatureMatrix` capability reports daemon availability for managed
3801
3878
  runs, transcript/session operations, Todo projection, managed tasks, Workflow,
@@ -3945,13 +4022,17 @@ complete ordered batch. Exact operation retries return the same `inputId`.
3945
4022
  The accepted result's `runId` is the existing owning Run (equal to
3946
4023
  `afterRunId`), not a newly created continuation.
3947
4024
 
3948
- Interrupt admission closes when the Runner publishes its final completion or
3949
- terminal error signal, or when the Run's supplied `abortSignal` aborts, even if
3950
- the outer Run is still settling. Non-terminal observer diagnostics do not close
3951
- the window. A submission after closure returns `accepted:false` with
3952
- `reason:'interrupt_window_closed'` and is not queued. Keep the original input
3953
- available for retry after the Run ends; do not silently change its delivery to
3954
- `after_turn`. As a final race/recovery
4025
+ Interrupt admission closes when the Runner publishes its final completion or
4026
+ terminal error signal, or when the Run's supplied `abortSignal` aborts, even if
4027
+ the outer Run is still settling. Non-terminal observer diagnostics do not close
4028
+ the window. Same-Run lifecycle continuations also have a fixed internal
4029
+ allowance beyond the configured iteration ceiling; the Runner closes admission
4030
+ before its final absolute generation so repeated submissions cannot keep one
4031
+ Run alive indefinitely. The allowance never expands an admitted manifest's
4032
+ `maxIterations` governance cap. A submission after closure returns
4033
+ `accepted:false` with `reason:'interrupt_window_closed'` and is not queued. Keep
4034
+ the original input available for retry after the Run ends; do not silently
4035
+ change its delivery to `after_turn`. As a final race/recovery
3955
4036
  guard, inspect terminal Run status: any `interruptInputs` entry whose state is
3956
4037
  `terminal` was not delivered. Reconcile it by `inputId` and present a visible
3957
4038
  non-delivery outcome rather than leaving a pending queue indicator.
@@ -3968,13 +4049,13 @@ const interrupted = await runtime.runs.submitInput({
3968
4049
 
3969
4050
  Run status exposes acceptance/start/queue times, authenticated origin,
3970
4051
  `sessionOrder`, and a single terminal fact. Important terminal codes include
3971
- `runtime_restarted`, `daemon_crashed`, `credential_unavailable`,
3972
- `host_not_dispatched`, `host_outcome_unknown`, and
3973
- `control_history_untrusted`. Managed tasks that require user input use
3974
- `terminal.code = 'blocked'`; surface `terminal.message` when present instead of
3975
- replacing it with a generic run failure. Respect `effectOutcome`; `unknown` must
3976
- never be presented as success or automatically retried. After a lost response,
3977
- query `runtime.operations.get({ operationId, journalEpoch })`; applied receipts
4052
+ `runtime_restarted`, `daemon_crashed`, `credential_unavailable`,
4053
+ `host_not_dispatched`, `host_outcome_unknown`, and
4054
+ `control_history_untrusted`. Managed tasks that require user input use
4055
+ `terminal.code = 'blocked'`; surface `terminal.message` when present instead of
4056
+ replacing it with a generic run failure. Respect `effectOutcome`; `unknown` must
4057
+ never be presented as success or automatically retried. After a lost response,
4058
+ query `runtime.operations.get({ operationId, journalEpoch })`; applied receipts
3978
4059
  include the canonical result. Permission grants remain daemon-owned and
3979
4060
  revisioned.
3980
4061
 
@@ -4021,9 +4102,11 @@ Write/Edit content may differ). Generic extension calls can receive only an
4021
4102
  exact in-memory Session grant. Raw command/argv data is not stored in the
4022
4103
  matcher; grants and audit contain only its fingerprint plus a bounded,
4023
4104
  secret-redacted operator label. Clients must not keep separate persistent
4024
- permission rule stores. Runtime capability `runtimeAutoModeGuardrail` v3 advertises this
4025
- opaque concrete-grant contract; restart or upgrade an older daemon instead of
4026
- falling back to a client-side alias.
4105
+ permission rule stores. Runtime capability `runtimeAutoModeGuardrail` v4
4106
+ advertises this opaque concrete-grant contract plus the intent-aligned
4107
+ retry/Accept-edits behavior that never changes the engine to rules. Embedded,
4108
+ Worker, and daemon hosts all report `fallbackPersistsEngine:false`; restart or
4109
+ upgrade an older daemon instead of falling back to a client-side alias.
4027
4110
 
4028
4111
  ### Broker a Space keychain credential
4029
4112
 
@@ -4302,9 +4385,9 @@ engine/denial/breaker state per Session. It reuses bounded context-specific
4302
4385
  guardrails across turns while provider/model, repository boundary, execution
4303
4386
  directory, classifier model, and timeout remain the same. Updating one of
4304
4387
  those inputs selects a new context guardrail by design without copying stale
4305
- state from a queued turn. Active runs, queued runs, explicit settings updates,
4306
- and automatic LLM-to-rules fallback merge through the same Session mutation
4307
- queue; fallback is persisted before a later classification reads the engine.
4388
+ state from a queued turn. Active runs, queued runs, explicit settings updates,
4389
+ and explicit engine changes merge through the same Session mutation queue.
4390
+ Classifier infrastructure failures do not mutate the engine to rules.
4308
4391
 
4309
4392
  ### What an embedder should expect
4310
4393
 
@@ -4314,16 +4397,22 @@ The Runtime's execution order is fixed:
4314
4397
  Runtime Auto Mode guardrail -> host permission bridge only for escalate -> tool execution
4315
4398
  ```
4316
4399
 
4317
- Consequently, an LLM/rules `allow` does not create a pending permission request
4318
- just because a host installed a static approval hook. `block` does not become a
4319
- spurious approval prompt. A real `escalate` uses the existing shared
4320
- `runtime.permissions` flow, so another authorized client may render and answer
4321
- it. Hosts should subscribe to permission events to display such a request, but
4322
- must not treat a missing request as an error for a safe tool call.
4323
-
4324
- The classifier deadline remains 20 seconds by default and includes connection
4325
- setup, provider Retry-After/backoff, inference, and stream completion. KodaX
4326
- does not solve timeouts by extending that deadline indefinitely. Before the
4400
+ Exactly modeled ordinary reads and workspace/system-temp mutations are admitted
4401
+ before classifier latency, independent of sandbox readiness. Other calls are
4402
+ reviewed against the latest genuine user request, bounded user-only intent
4403
+ evidence, and exact operation facts. Consequently, an LLM/rules `allow` does
4404
+ not create a pending permission request just because a host installed a static
4405
+ approval hook. Classifier concerns, critical deterministic matches, and rules
4406
+ concerns use the existing shared
4407
+ `runtime.permissions` flow, so another authorized client may render and answer
4408
+ it. Hosts should subscribe to permission events to display such a request, but
4409
+ must not treat a missing request as an error for a safe tool call.
4410
+
4411
+ The classifier deadline remains 20 seconds by default and includes connection
4412
+ setup, provider Retry-After/backoff, inference, and stream completion. KodaX
4413
+ retries one timeout/provider/response-contract failure once; a second failure
4414
+ uses the Accept-edits safety boundary and never switches to Auto[rules].
4415
+ KodaX does not solve timeouts by extending that deadline indefinitely. Before the
4327
4416
  provider call it removes assistant prose/thinking and image paths, limits each
4328
4417
  tool result to 2 KiB and the serialized permission-relevant transcript to
4329
4418
  8 KiB, then enforces 16 KiB action and 32 KiB total-prompt ceilings plus a
@@ -4350,14 +4439,21 @@ session repository safety boundary, whereas relative operands resolve from the
4350
4439
  validated `executionCwd`. In particular, quoted Python/JavaScript/regexp source
4351
4440
  inside a shell command is not a path operand.
4352
4441
 
4353
- The user-level `.kodax` directory is a credential/configuration boundary, not
4354
- an ordinary project path. Direct shell mutations, output redirects, and
4355
- recognized nested-shell payloads whose target is provably beneath that
4356
- directory are rejected before LLM classification. The check is segment-safe
4357
- and Windows case-insensitive. KodaX deliberately does not scan arbitrary
4358
- quoted language source for path-looking substrings: doing so would turn Python,
4359
- JavaScript, YAML, and regular expressions into false Tier-0 matches. Trusted
4360
- configuration changes should use the KodaX config CLI or SDK configuration API.
4442
+ Every Runtime permission request has a deadline. If the host does not answer,
4443
+ the current operation is not executed and the guardrail returns a stable
4444
+ `approval_timeout` result telling the main model to try a safer, narrower, or
4445
+ reversible approach, or stop and wait for explicit user approval. A timeout is
4446
+ not serialized as an ordinary user rejection.
4447
+
4448
+ The user-level `.kodax` directory is a credential/configuration boundary, not
4449
+ an ordinary project path. Direct shell mutations, output redirects, and
4450
+ recognized nested-shell payloads whose target is provably beneath that
4451
+ directory are identified before LLM classification and routed to permission
4452
+ approval rather than permanently policy-blocked. The check is segment-safe and
4453
+ Windows case-insensitive. KodaX deliberately does not scan arbitrary
4454
+ quoted language source for path-looking substrings: doing so would turn Python,
4455
+ JavaScript, YAML, and regular expressions into false Tier-0 matches. Trusted
4456
+ configuration changes should use the KodaX config CLI or SDK configuration API.
4361
4457
 
4362
4458
  ### 0.7.x source compatibility
4363
4459
 
@@ -4609,49 +4705,426 @@ parent transcript commits and acknowledges the completion, later restores do
4609
4705
  not replay it. Legacy snapshots without the explicit pending set do not infer
4610
4706
  replay work from historical mailbox content.
4611
4707
 
4612
- This separation changes no Actor event capability or daemon version: existing
4613
- SDK snapshot, replay, and long-poll clients keep their telemetry surface. It
4614
- only prevents high-frequency progress from becoming a model control signal.
4708
+ This separation changes no Actor event capability or daemon version: existing
4709
+ SDK snapshot, replay, and long-poll clients keep their telemetry surface. It
4710
+ only prevents high-frequency progress from becoming a model control signal.
4711
+
4712
+ ---
4713
+
4714
+ ## 27. Windows GUI background subprocess visibility (v0.7.75)
4715
+
4716
+ KodaX SDK hosts do not need to add process-wide console suppression around the
4717
+ Runtime. In the v0.7.75 release candidate, Runtime Worker-reachable
4718
+ non-interactive/background child processes request `windowsHide: true` at their
4719
+ own spawn boundary. The covered paths include:
4720
+
4721
+ - memory and Git metadata probes;
4722
+ - provider CLI execution and ACP servers;
4723
+ - LSP acquisition and language servers;
4724
+ - clipboard helpers, worktrees, review commands, and extension commands;
4725
+ - managed-task checkpoints and sandbox helpers.
4726
+
4727
+ The contract is intentionally narrow. Explicit external editors, terminal
4728
+ commands, and PTY sessions remain interactive. POSIX-only `ps`, `tmux`, and
4729
+ sandbox branches are reviewed bundle-audit exceptions rather than Windows
4730
+ visibility paths.
4731
+
4732
+ `npm run build:bundle` audits every statically identifiable child-process call
4733
+ reachable from `dist/runtime-worker.js`. The packaged Electron daemon smoke then
4734
+ runs 20 ordinary queries with a Win32 probe and checks that the expected Git
4735
+ children never own a visible console window. These checks validate the SDK
4736
+ boundary, but they do not replace product-level validation in the packaged host.
4737
+ KodaX Space should install the exact v0.7.75 tarball and complete
4738
+ [`ISSUE_205_v0.7.75_REGRESSION_GUIDE.md`](test-guides/ISSUE_205_v0.7.75_REGRESSION_GUIDE.md)
4739
+ on Windows 10 and Windows 11 as a non-blocking product validation follow-up.
4740
+ This follow-up does not gate SDK packaging, tagging, or publication.
4615
4741
 
4616
4742
  ---
4617
4743
 
4618
- ## 27. Windows GUI background subprocess visibility (v0.7.75)
4744
+ ## 28. Host-configurable Shell Execution Contract (v0.7.77)
4619
4745
 
4620
- KodaX SDK hosts do not need to add process-wide console suppression around the
4621
- Runtime. In the v0.7.75 release candidate, Runtime Worker-reachable
4622
- non-interactive/background child processes request `windowsHide: true` at their
4623
- own spawn boundary. The covered paths include:
4746
+ The shared daemon is long-lived, so its startup `process.env.PATH` is not a
4747
+ reliable description of every project's toolchain. A host can opt a Session
4748
+ into a serializable shell contract:
4624
4749
 
4625
- - memory and Git metadata probes;
4626
- - provider CLI execution and ACP servers;
4627
- - LSP acquisition and language servers;
4628
- - clipboard helpers, worktrees, review commands, and extension commands;
4629
- - managed-task checkpoints and sandbox helpers.
4750
+ ```ts
4751
+ await runtime.sessions.updateSettings(session.id, {
4752
+ executionCwd: projectDirectory,
4753
+ shellExecution: {
4754
+ version: 1,
4755
+ shell: {
4756
+ kind: 'pwsh', // pwsh | powershell | cmd | bash | zsh
4757
+ profile: 'default',
4758
+ },
4759
+ environment: {
4760
+ inherit: 'filtered',
4761
+ // Trusted host code, not model input. Use it for a directory-aware
4762
+ // activation command when the shell profile does not switch on cwd.
4763
+ setup: 'fnm use --silent-if-unchanged',
4764
+ windowsPath: 'registry',
4765
+ },
4766
+ cache: {
4767
+ ttlMs: 30_000,
4768
+ refreshToken: 'toolchain-revision-1',
4769
+ },
4770
+ probeTimeoutMs: 10_000,
4771
+ },
4772
+ });
4773
+ ```
4630
4774
 
4631
- The contract is intentionally narrow. Explicit external editors, terminal
4632
- commands, and PTY sessions remain interactive. POSIX-only `ps`, `tmux`, and
4633
- sandbox branches are reviewed bundle-audit exceptions rather than Windows
4634
- visibility paths.
4775
+ An individual Run can supply `options.context.shellExecution`; a concrete Run
4776
+ contract overrides the Session setting. An omitted value or explicit
4777
+ `undefined` does not erase the Session setting. Use a `null` Session patch to
4778
+ remove it.
4635
4779
 
4636
- `npm run build:bundle` audits every statically identifiable child-process call
4637
- reachable from `dist/runtime-worker.js`. The packaged Electron daemon smoke then
4638
- runs 20 ordinary queries with a Win32 probe and checks that the expected Git
4639
- children never own a visible console window. These checks validate the SDK
4640
- boundary, but they do not replace product-level validation in the packaged host.
4641
- KodaX Space should install the exact v0.7.75 tarball and complete
4642
- [`ISSUE_205_v0.7.75_REGRESSION_GUIDE.md`](test-guides/ISSUE_205_v0.7.75_REGRESSION_GUIDE.md)
4643
- on Windows 10 and Windows 11 as a non-blocking product validation follow-up.
4644
- This follow-up does not gate SDK packaging, tagging, or publication.
4780
+ The contract supports an optional absolute `shell.executable` (for example Git
4781
+ Bash) and bounded fixed `shell.args`. Command/file/persistence/profile/server
4782
+ and working-directory control flags are rejected from those fixed arguments.
4783
+ `environment.set` is for non-secret host variables. `denyPatterns` can remove
4784
+ additional names but cannot weaken the built-in Provider credential deny set.
4785
+ `inherit: "none"` retains only the OS variables required to start the selected
4786
+ shell. On Windows, `windowsPath: "registry"` re-reads current Machine/User
4787
+ environment values instead of reusing the daemon's startup PATH.
4788
+
4789
+ Resolution is two-stage and uses the effective cwd:
4790
+
4791
+ 1. sanitize the bootstrap environment, including credentials for built-in,
4792
+ custom, active, inactive, and stacked runtime Providers;
4793
+ 2. start the selected shell, load the requested profile/setup, capture a
4794
+ random-framed environment, validate and sanitize it again;
4795
+ 3. execute the actual command through that same explicit interpreter.
4796
+
4797
+ The cache is in-memory and isolated by normalized contract, canonical cwd,
4798
+ Session scratch identity, credential deny names, and refresh generation. TTL
4799
+ is bounded to ten minutes; zero disables caching. Daemon restart clears it.
4800
+ `clearShellExecutionEnvironmentCache()` is available for an in-process owner
4801
+ that needs immediate global invalidation.
4802
+
4803
+ Native children, nested Actor turns, Workflow child paths, and deterministic
4804
+ build/test/lint evaluators inherit the effective contract. Runtime exact-command
4805
+ permission grants bind the interpreter family and contract fingerprint, so a
4806
+ grant created under cmd cannot silently authorize the same command after a
4807
+ switch to PowerShell or Bash.
4808
+
4809
+ Configured-shell failures are visible and fail closed: KodaX does not reinterpret
4810
+ the command through another shell. When `shellExecution` is absent, KodaX keeps
4811
+ the pre-v0.7.77 platform-shell behavior for compatibility. See
4812
+ [`ISSUE_214_v0.7.77_REGRESSION_GUIDE.md`](test-guides/ISSUE_214_v0.7.77_REGRESSION_GUIDE.md)
4813
+ for cross-project, cache, cancellation, credential, and Windows argv checks.
4814
+
4815
+ ---
4816
+
4817
+ ## 29. Evidence-gated background Skill learning (FEATURE_263, v0.7.78)
4818
+
4819
+ F263 completes the existing Learning Center rather than introducing a second
4820
+ queue or client-owned Skill store. Episode review runs after durable foreground
4821
+ completion and stays off the active Run's latency path. A correction, failure,
4822
+ or verifier result is Memory evidence first; it does not itself authorize a
4823
+ Skill mutation.
4824
+
4825
+ A low-risk declarative Skill can enter automatic project-scoped testing only
4826
+ after an explicit preserve-as-Skill request with verified terminal evidence,
4827
+ or repeated independent root episodes plus independent verified artifact
4828
+ evidence. The owner writes an immutable revision and its canonical capability
4829
+ record before discovery can expose it. Formal/builtin/plugin/human Skills keep
4830
+ precedence and cannot be shadowed. Protected/formal changes, user-global
4831
+ promotion, and Extension authoring remain explicit user actions.
4832
+
4833
+ Hosts that require this behavior should negotiate both Runtime capabilities:
4834
+
4835
+ ```ts
4836
+ const runtime = await createKodaXRuntime({
4837
+ mode: 'daemon',
4838
+ requirements: {
4839
+ learningCenter: 1,
4840
+ skillLearningLoop: 1,
4841
+ },
4842
+ clientInfo: {
4843
+ name: 'my-host',
4844
+ instanceId: stableClientId,
4845
+ instanceSecret: keychainSecret,
4846
+ },
4847
+ });
4848
+
4849
+ const snapshot = await runtime.learning.getSnapshot();
4850
+ const page = await runtime.learning.list({ limit: 50 });
4851
+
4852
+ for await (const event of runtime.learning.subscribe({
4853
+ afterRevision: snapshot.revision,
4854
+ })) {
4855
+ renderLearningEvent(event);
4856
+ }
4857
+ ```
4858
+
4859
+ `runtime.learning` is the authoritative host surface:
4860
+
4861
+ | Need | API |
4862
+ |---|---|
4863
+ | Render inventory or one exact record | `list()` / `get()` |
4864
+ | Render client-specific badges | `getSnapshot()` |
4865
+ | Replay or follow durable lifecycle events | `events()` / `subscribe()` |
4866
+ | Clear or defer only this client's notice | `acknowledge()` / `snooze()` |
4867
+ | Explicitly control a learned revision | `reject()` / `disable()` / `rollback()` / `review()` / `trust()` |
4868
+ | Promote to the user scope | `promote(nameOrSlugOrId, 'user')` |
4869
+
4870
+ Do not scan learned files and infer activation from their presence. Discovery
4871
+ requires the canonical record, matching project identity, lifecycle,
4872
+ fingerprint, regular-file checks, formal-name policy, and exact revision.
4873
+ Testing admission permits one concurrent root binding and at most three
4874
+ exact-revision invocations. Promotion requires independently verified success;
4875
+ failed or inconclusive canaries return to Ready/attention. A Run retains the
4876
+ revision it captured at admission, so rollback or replacement affects future
4877
+ bindings without mutating an in-flight prompt.
4878
+
4879
+ Learning Center notification state is client-specific, but capability
4880
+ lifecycle and project canary state are owner-global. Renderer code should
4881
+ receive sanitized records/events through host IPC; it should not receive
4882
+ daemon credentials or mutate files directly. Inline, Worker, and daemon
4883
+ facades expose the same learning methods. A host missing `skillLearningLoop:1`
4884
+ may still support the older Ready/manual Learning Center surface, but must not
4885
+ claim the complete F263 project-canary contract.
4886
+
4887
+ ---
4888
+
4889
+ ## 30. Standalone sandbox SDK (v0.7.78)
4890
+
4891
+ ASRT containment is a public SDK capability, not an Auto[LLM]-only
4892
+ implementation detail. Import the dedicated subpath when a host needs to
4893
+ sandbox its own commands or scripts:
4894
+
4895
+ ```ts
4896
+ import {
4897
+ activateKodaXSandbox,
4898
+ doctorKodaXSandbox,
4899
+ getKodaXSandboxCapability,
4900
+ getKodaXSandboxSetupGuidance,
4901
+ runKodaXSandboxed,
4902
+ } from '@kodax-ai/kodax/sandbox';
4903
+
4904
+ const capability = getKodaXSandboxCapability();
4905
+ const doctor = await doctorKodaXSandbox({ refresh: true });
4906
+
4907
+ if (!doctor.ready) {
4908
+ showSandboxInfo(getKodaXSandboxSetupGuidance(doctor));
4909
+ // Call only from an explicit setup/onboarding action. On Windows this may
4910
+ // display UAC; ordinary SDK calls never invoke it automatically.
4911
+ const activation = await activateKodaXSandbox();
4912
+ if (activation.status !== 'ready') {
4913
+ showSandboxInfo(activation.guidance);
4914
+ }
4915
+ }
4916
+ ```
4917
+
4918
+ Platform behavior:
4919
+
4920
+ - Windows uses the pinned ASRT restricted-user/WFP setup. The parent terminal
4921
+ does not need to be elevated; the one-time installer requests UAC itself.
4922
+ - macOS uses Seatbelt through `sandbox-exec` and requires ripgrep. Guide users
4923
+ to `brew install ripgrep` when doctor reports it missing.
4924
+ - Linux uses bubblewrap and requires `bubblewrap`, `socat`, and `ripgrep`.
4925
+ Present the emitted `apt`/`dnf`/`pacman` guidance; do not run `sudo` or a
4926
+ package manager silently.
4927
+
4928
+ Do not call `activateKodaXSandbox()` during ordinary Runtime startup, tool
4929
+ execution, or a background permission check. KodaX's own first-run/setup UI
4930
+ checks once; a declined UAC prompt or missing dependency is reported there and
4931
+ is not repeatedly surfaced until the user runs setup again.
4932
+
4933
+ ### Run a host-owned command with an explicit policy
4934
+
4935
+ ```ts
4936
+ import os from 'node:os';
4937
+ import path from 'node:path';
4938
+ import { runKodaXSandboxed } from '@kodax-ai/kodax/sandbox';
4939
+
4940
+ const result = await runKodaXSandboxed({
4941
+ command: process.execPath,
4942
+ args: ['scripts/generate-report.mjs'],
4943
+ cwd: projectDirectory,
4944
+ filesystem: {
4945
+ allowRead: [projectDirectory, process.execPath],
4946
+ allowWrite: [projectDirectory, os.tmpdir()],
4947
+ denyRead: [path.join(os.homedir(), '.ssh')],
4948
+ denyWrite: [path.join(projectDirectory, '.git', 'config')],
4949
+ },
4950
+ network: {
4951
+ mode: 'allowlist',
4952
+ origins: ['https://api.example.com'],
4953
+ },
4954
+ // false by default: start with KodaX's minimal execution environment.
4955
+ inheritEnvironment: false,
4956
+ env: { REPORT_FORMAT: 'pdf' },
4957
+ timeoutMs: 120_000,
4958
+ maxOutputBytes: 2 * 1024 * 1024,
4959
+ });
4960
+
4961
+ if (result.status === 'unavailable') {
4962
+ // The command was NOT run. Decide explicitly whether your product should
4963
+ // wait for setup, reject the operation, or use its own non-sandbox path.
4964
+ showSandboxInfo(getKodaXSandboxSetupGuidance(result.doctor));
4965
+ } else if (result.exitCode !== 0) {
4966
+ throw new Error(result.stderr || `sandboxed command exited ${result.exitCode}`);
4967
+ }
4968
+ ```
4969
+
4970
+ The generic executor supports network `allow`, `deny`, and exact HTTP(S)
4971
+ origin `allowlist` modes plus filesystem policy roots, environment inheritance,
4972
+ timeout, cancellation, and bounded output. ASRT permits ordinary reads by
4973
+ default: `denyRead` removes access and a more specific `allowRead` carves access
4974
+ back. `allowWrite` defines the writable roots, while `denyWrite` removes
4975
+ subtrees and always takes precedence over `allowWrite`. The HTTP(S) `origins`
4976
+ are normalized to the hostname/port pair enforced by ASRT's network proxy. It
4977
+ never silently runs without containment: sandbox unavailability is the typed
4978
+ `{ status: 'unavailable', sandboxed: false, doctor }` result.
4979
+
4980
+ KodaX's own local workspace-shell policy supplies a stricter `denyRead` set
4981
+ than the generic SDK default: common home credential locations, sensitive
4982
+ private-key/environment filenames, and the complete resolved agent home are
4983
+ denied. Home-local executable search paths nested below those roots are not
4984
+ re-granted. This policy belongs to KodaX's command adapter; a standalone SDK
4985
+ host must declare the sensitive paths required by its own threat boundary.
4986
+
4987
+ `command` and `args` remain separate process arguments. On Windows KodaX uses
4988
+ an encoded bootstrap followed by `shell: false`, so `%VAR%`, `&`, embedded
4989
+ quotes, and spaces are not expanded or re-parsed by the host shell. The
4990
+ explicit environment policy is overlaid into ASRT's fresh restricted-user
4991
+ environment; ASRT-owned proxy, CA, and Git safety variables retain precedence.
4992
+ `timeoutMs` covers the complete broker lifecycle, including ASRT
4993
+ initialization, the command, and cleanup. Windows ACL initialization on a cold
4994
+ path can take tens of seconds, so do not reuse a classifier-scale 20–30 second
4995
+ deadline unless that early cancellation is intentional.
4996
+
4997
+ This is intentionally different from KodaX's local permission fallback. When
4998
+ ASRT is unavailable, Auto[LLM] still makes the same deterministic/LLM/user
4999
+ permission decision and an admitted local shell may use the ordinary execution
5000
+ path; only OS containment is absent. The same local fallback applies when
5001
+ ASRT preparation or backend initialization fails before the target process
5002
+ starts. KodaX never retries after the target has started, so a sandbox fault
5003
+ cannot duplicate command side effects. Remote A2A admitted Skill scripts
5004
+ retain their stronger isolation contract and do not fall back to an
5005
+ unsandboxed script. Embedded and daemon Runtime capability metadata expose
5006
+ `sandboxRuntime` with the platform backend, ASRT version, supported control
5007
+ dimensions, elevation behavior, and fallback semantics.
5008
+
5009
+ Local workspace commands reuse one long-lived ASRT session per canonical
5010
+ workspace. Session-level ACL/WFP initialization is warmed once; the owner
5011
+ coordinates short wrap/cleanup RPCs without locking across the target process
5012
+ lifetime, so concurrent and background targets do not block later preparation.
5013
+ Per-command target attestation and fallback remain independent. Session reset
5014
+ happens only after an idle drain or host-process shutdown, never on the
5015
+ interactive command critical path. A cold first command may still wait for
5016
+ platform initialization, but later commands must not repeatedly pay that
5017
+ setup/reset cost. Abort signals and the command deadline cover that prepare
5018
+ wait; a cancelled/timed-out prepare never starts the target or changes to the
5019
+ ordinary fallback path. Explicit
5020
+ Windows system-temp operations that ASRT cannot safely ACL-manage are not
5021
+ selected for containment and keep the already-approved normal execution path.
5022
+
5023
+ An unhealthy session fails the current prepare immediately so the host can use
5024
+ its normal permission fallback. Cleanup continues out of band. On Windows the
5025
+ owner first closes its command input and allows up to 130 seconds for ASRT
5026
+ 0.0.65's two serial ACL cleanup helpers to finish; only then may process-tree
5027
+ termination be forced. The failed workspace session is not replaced until
5028
+ that bounded cleanup settles, preventing a replacement from racing stale ACL
5029
+ recovery. macOS and Linux use the same EOF-first sequence with a shorter
5030
+ bounded termination grace.
5031
+
5032
+ Runtime event streams may also contain one terminal `tool.sandbox` observation
5033
+ associated with the tool ID. `applied` is emitted only after the in-sandbox
5034
+ bootstrap confirms that the real target process reached Node's `spawn` event;
5035
+ wrapper startup alone is not sufficient. Before that handshake, a local
5036
+ backend failure may fall back to normal execution. After it, KodaX never
5037
+ restarts the target:
5038
+
5039
+ ```ts
5040
+ runtime.events.subscribe({ sessionId: session.id, type: 'tool.sandbox' }, (event) => {
5041
+ if (event.type !== 'tool.sandbox') return;
5042
+ const { observation } = event.payload.update;
5043
+ // observation.state: 'applied' | 'fallback' | 'not_selected'
5044
+ diagnostics.recordSandboxRoute(observation);
5045
+ });
5046
+ ```
5047
+
5048
+ This event is optional diagnostics, not conversation content. It is never added
5049
+ to model-visible messages. Default consumer UX should not render it in startup
5050
+ output, command cards, notifications, or conversation history; expose it only
5051
+ in an explicit advanced diagnostics view. KodaX's own Ink REPL does not
5052
+ subscribe to the event and refreshes human-readable status only when the user
5053
+ runs `/sandbox`. Explicit JSON output and SDK subscriptions retain the
5054
+ structured event for professional diagnostics. `/sandbox` is read-only and
5055
+ never activates the backend or requests elevation.
5056
+
5057
+ ---
5058
+
5059
+ ## Learned Skill promotion reference (v0.7.78)
5060
+
5061
+ Promotion is the explicit transfer of one immutable, reviewed `ready` or
5062
+ `active_learned` Skill revision into the formal user catalog. It is not the
5063
+ evidence-driven `testing -> active_learned` canary transition. The public named
5064
+ service type is exported from the Runtime SDK:
5065
+
5066
+ ```ts
5067
+ import {
5068
+ createKodaXRuntime,
5069
+ type RuntimeLearningService,
5070
+ } from '@kodax-ai/kodax/runtime';
5071
+
5072
+ const runtime = await createKodaXRuntime({
5073
+ requirements: {
5074
+ learningCenter: 1,
5075
+ skillLearningLoop: 1,
5076
+ },
5077
+ });
5078
+
5079
+ const learning: RuntimeLearningService = runtime.learning;
5080
+ const record = await learning.get('normalize-release-notes');
5081
+
5082
+ try {
5083
+ await learning.promote(record.capabilityId, 'user');
5084
+ } finally {
5085
+ await runtime.close();
5086
+ }
5087
+ ```
5088
+
5089
+ `name`, `slug`, and exact `capabilityId` are accepted. Exact IDs are preferred
5090
+ when multiple projects expose the same display name or slug. `'user'` is the
5091
+ only supported scope. Daemon clients need the server-issued
5092
+ `learning:control` scope; advertising a client capability does not grant it.
5093
+ Inline, Worker, and daemon facades carry the same v2 learned-record shape and
5094
+ promotion method.
5095
+
5096
+ The Runtime verifies the source is a regular non-symlink file inside the exact
5097
+ project Learned Area and that its content still matches the recorded
5098
+ fingerprint. It then creates the configured user Skill destination—normally
5099
+ `~/.kodax/skills/<slug>/SKILL.md`—with atomic exclusive-publish semantics.
5100
+ Existing identical content is idempotent; the final path appears only after the
5101
+ complete temporary file is synced. Different formal content returns an
5102
+ `action_failed` error and is never overwritten. On success the canonical
5103
+ project record changes to `promoted_user`.
5104
+
5105
+ Terminal users can inspect the same contract with:
5106
+
5107
+ ```text
5108
+ /learn promote --help
5109
+ /learn help promote
5110
+ /help learn promote
5111
+ ```
5112
+
5113
+ The canonical command is
5114
+ `/learn promote <name|slug|capability-id> --scope user`; omitting the scope is a
5115
+ backward-compatible shorthand for the same user scope. Unknown, duplicate, or
5116
+ unsupported options fail before the Runtime mutation.
4645
5117
 
4646
5118
  ---
4647
5119
 
4648
5120
  ## See also
4649
-
4650
- - [README.md](../README.md) — end-user CLI quick start
5121
+
5122
+ - [README.md](../README.md) — end-user CLI quick start
4651
5123
  - [docs/ADR.md ADR-024](ADR.md#adr-024-npm-发布物正名-kodax-aikodax--sdk-subpath-exports-形式化-v0739) — SDK subpath architecture rationale
4652
5124
  - [docs/ADR.md ADR-032](ADR.md#adr-032-sdk-embedder-surface-closure-feature_186-v0742) — FEATURE_186 design record (all 8 phases)
4653
5125
  - [docs/ADR.md ADR-057](ADR.md#adr-057-large-compaction-is-an-always-on-context-scoped-full-coverage-transaction) — v0.7.74 compaction and exact-history ownership
4654
- - [docs/ADR.md ADR-058](ADR.md#adr-058-model-agent-wait-is-mailbox-control-not-event-telemetry) — mailbox control versus Actor telemetry
4655
- - [docs/features/v0.7.42.md FEATURE_186](features/v0.7.42.md#feature_186-sdk-embedder-surface-closure--kodax-space-gap-list--mcp-popout) — gap-by-gap landing matrix
5126
+ - [docs/ADR.md ADR-058](ADR.md#adr-058-model-agent-wait-is-mailbox-control-not-event-telemetry) — mailbox control versus Actor telemetry
5127
+ - [docs/features/v0.7.42.md FEATURE_186](features/v0.7.42.md#feature_186-sdk-embedder-surface-closure--kodax-space-gap-list--mcp-popout) — gap-by-gap landing matrix
4656
5128
  - [docs/features/v0.7.74.md](features/v0.7.74.md) — v0.7.74 release-candidate design and verification record
4657
5129
  - [docs/features/v0.7.75.md](features/v0.7.75.md) — v0.7.75 Windows GUI and Sidecar/Runtime stabilization candidate
5130
+ - [docs/features/v0.7.77.md](features/v0.7.77.md) — v0.7.77 adaptive-quality, governed-memory, and release-hardening record