@kodax-ai/kodax 0.7.77 → 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 (98) hide show
  1. package/CHANGELOG.md +176 -4
  2. package/README.md +200 -64
  3. package/README_CN.md +153 -49
  4. package/config-templates/config.example.jsonc +114 -32
  5. package/dist/chunks/agent-ASP4MS3X.js +2 -0
  6. package/dist/chunks/argument-completer-JYQ7FX3W.js +2 -0
  7. package/dist/chunks/{chunk-XSA37BVM.js → chunk-2CFHBKRE.js} +1 -1
  8. package/dist/chunks/chunk-35PPHOQ2.js +292 -0
  9. package/dist/chunks/chunk-43QNNDHR.js +29 -0
  10. package/dist/chunks/chunk-5BNQXXGY.js +1 -0
  11. package/dist/chunks/chunk-5GO6FH7L.js +458 -0
  12. package/dist/chunks/{chunk-FSXI4MAV.js → chunk-5NDCSFOP.js} +14 -14
  13. package/dist/chunks/{chunk-3DD4QEBH.js → chunk-6FOJVETH.js} +10 -10
  14. package/dist/chunks/chunk-6XM4B6K2.js +48 -0
  15. package/dist/chunks/chunk-6YZUE6NC.js +240 -0
  16. package/dist/chunks/{chunk-HORNWBYR.js → chunk-7OEBJGHK.js} +1 -1
  17. package/dist/chunks/{chunk-OAMKECRG.js → chunk-KQLQYHWU.js} +205 -200
  18. package/dist/chunks/{chunk-IQT4RPCE.js → chunk-NXO6GWSY.js} +2 -2
  19. package/dist/chunks/chunk-T2XZTLYE.js +316 -0
  20. package/dist/chunks/chunk-TQDBTTIM.js +348 -0
  21. package/dist/chunks/{chunk-FNW2XUL5.js → chunk-UID7BLAB.js} +1 -1
  22. package/dist/chunks/chunk-VAT2QYXM.js +765 -0
  23. package/dist/chunks/chunk-YAZQTC2L.js +5 -0
  24. package/dist/chunks/chunk-YVRYHC4C.js +655 -0
  25. package/dist/chunks/{chunk-EH7AOMJ7.js → chunk-Z3KFRTSB.js} +1 -1
  26. package/dist/chunks/compaction-config-BQSSIWK5.js +2 -0
  27. package/dist/chunks/{construction-bootstrap-RPRL3L7R.js → construction-bootstrap-VQLQGWPY.js} +1 -1
  28. package/dist/chunks/{dist-FDSOIR35.js → dist-BFT5YIGU.js} +1 -1
  29. package/dist/chunks/dist-PCFE24YP.js +2 -0
  30. package/dist/chunks/host-UTFXCYYM.js +2 -0
  31. package/dist/chunks/run-manager-PJU3WIFJ.js +2 -0
  32. package/dist/chunks/utils-SID4HW2Q.js +2 -0
  33. package/dist/index.d.ts +18 -17
  34. package/dist/index.js +6 -6
  35. package/dist/kodax_cli.js +1751 -1352
  36. package/dist/kodax_resume.js +17 -17
  37. package/dist/runtime-worker.js +1680 -1299
  38. package/dist/sandbox-workspace-session.js +563 -0
  39. package/dist/sdk-a2a.d.ts +16 -16
  40. package/dist/sdk-a2a.js +8 -8
  41. package/dist/sdk-agent.d.ts +275 -60
  42. package/dist/sdk-agent.js +1 -1
  43. package/dist/sdk-coding.d.ts +33 -165
  44. package/dist/sdk-coding.js +1 -1
  45. package/dist/sdk-experimental-memory.d.ts +2 -2
  46. package/dist/sdk-experimental-memory.js +1 -1
  47. package/dist/sdk-llm.d.ts +2 -1
  48. package/dist/sdk-llm.js +1 -1
  49. package/dist/sdk-mcp.js +1 -1
  50. package/dist/sdk-media.js +1 -1
  51. package/dist/sdk-repl.d.ts +67 -25
  52. package/dist/sdk-repl.js +2 -2
  53. package/dist/sdk-runtime.d.ts +194 -147
  54. package/dist/sdk-runtime.js +1 -1
  55. package/dist/sdk-sandbox.d.ts +93 -0
  56. package/dist/sdk-sandbox.js +2 -0
  57. package/dist/sdk-session.d.ts +6 -7
  58. package/dist/sdk-session.js +1 -1
  59. package/dist/sdk-skills.d.ts +2 -2
  60. package/dist/sdk-skills.js +1 -1
  61. package/dist/semantic-worker.js +15 -15
  62. package/dist/types-chunks/{bash-prefix-extractor.d-pZdu6qt7.d.ts → bash-prefix-extractor.d-uAe2Oqda.d.ts} +126 -8
  63. package/dist/types-chunks/{capsule.d-CxCm1KZz.d.ts → capsule.d-BlSv9l3V.d.ts} +1 -1
  64. package/dist/types-chunks/{guardrail.d-CJx9RRd3.d.ts → guardrail.d-BRE_ErEj.d.ts} +1 -1
  65. package/dist/types-chunks/{guardrail.d-B0PwAZVR.d.ts → guardrail.d-CXDYRgZ3.d.ts} +200 -34
  66. package/dist/types-chunks/{history-retrieval.d-B__aEN62.d.ts → history-retrieval.d-DtCy7x64.d.ts} +1 -1
  67. package/dist/types-chunks/{integration-config.d-ojG4swOP.d.ts → integration-config.d-BNowXE8k.d.ts} +23 -8
  68. package/dist/types-chunks/{public-api.d--fF88JrC.d.ts → public-api.d-B3AohsxN.d.ts} +36 -7
  69. package/dist/types-chunks/{commands.d-BccESAMV.d.ts → repl.d-Ie_ZXb_U.d.ts} +89 -78
  70. package/dist/types-chunks/{side-query.d-5JvXhuOZ.d.ts → resolver.d-iAQ9ocLB.d.ts} +3 -66
  71. package/dist/types-chunks/{run-manager.d-B47hIqnI.d.ts → run-manager.d-D1twIhF9.d.ts} +1 -1
  72. package/dist/types-chunks/{sdk-session-CLWf8Adb.d.ts → sdk-session-DB9KksIx.d.ts} +2 -2
  73. package/dist/types-chunks/side-query.d-DTuLPcC5.d.ts +77 -0
  74. package/dist/types-chunks/{types-LanCEDj8.d.ts → types-D3g6XUQr.d.ts} +41 -2
  75. package/dist/types-chunks/{types.d-RdWRfUEs.d.ts → types.d-BA-Jwpfs.d.ts} +459 -7
  76. package/dist/types-chunks/{types.d-CODuyyqy.d.ts → types.d-BH0ZkTGf.d.ts} +1 -1
  77. package/dist/types-chunks/{types.d-DCQVBqVn.d.ts → types.d-BbtGlKZu.d.ts} +25 -3
  78. package/dist/types-chunks/{types.d-DCsKM8aT.d.ts → types.d-DVDTIfB_.d.ts} +2 -2
  79. package/dist/types-chunks/{utils.d-CDduqbFw.d.ts → utils.d-CVp6bFl9.d.ts} +22 -6
  80. package/docs/SDK_EMBEDDER_GUIDE.md +399 -55
  81. package/package.json +8 -1
  82. package/dist/chunks/agent-NGSWFE73.js +0 -2
  83. package/dist/chunks/argument-completer-WGGZPEEO.js +0 -2
  84. package/dist/chunks/chunk-27QLRH3D.js +0 -5
  85. package/dist/chunks/chunk-2MQPVY6P.js +0 -770
  86. package/dist/chunks/chunk-6WAPVAGQ.js +0 -74
  87. package/dist/chunks/chunk-AOENDSVN.js +0 -448
  88. package/dist/chunks/chunk-HV2GMZUZ.js +0 -343
  89. package/dist/chunks/chunk-JS2BHGJP.js +0 -158
  90. package/dist/chunks/chunk-ON2WG2LG.js +0 -622
  91. package/dist/chunks/chunk-RUGAAHTF.js +0 -321
  92. package/dist/chunks/chunk-TGCG7U2W.js +0 -37
  93. package/dist/chunks/compaction-config-BE7VYWH6.js +0 -2
  94. package/dist/chunks/dist-ZZBNVTKU.js +0 -2
  95. package/dist/chunks/host-QAKQVC4A.js +0 -2
  96. package/dist/chunks/run-manager-N4UFWA2D.js +0 -2
  97. package/dist/chunks/utils-AUHCI4D5.js +0 -2
  98. package/dist/types-chunks/center-types.d-BBT122uJ.d.ts +0 -91
@@ -56,6 +56,11 @@ interface SkillMetadata {
56
56
  argumentHint?: string;
57
57
  path: string;
58
58
  source: ResolvedSkillSource;
59
+ readonly learned?: {
60
+ readonly capabilityId: string;
61
+ readonly revision: number;
62
+ readonly fingerprint: string;
63
+ };
59
64
  /** If true, exclude from system prompt; still invokable by explicit slash forms. */
60
65
  disableModelInvocation: boolean;
61
66
  }
@@ -204,7 +209,22 @@ interface SkillPathsConfig {
204
209
  userPaths: string[];
205
210
  pluginPaths: string[];
206
211
  builtinPath: string;
212
+ /**
213
+ * Deprecated loose-file path. It remains in the public shape for source
214
+ * compatibility but is intentionally not discovered without a manifest.
215
+ */
207
216
  learnedPath?: string;
217
+ learnedArea?: LearnedSkillDiscoveryConfig;
218
+ }
219
+ interface LearnedSkillDiscoveryConfig {
220
+ readonly rootDir: string;
221
+ readonly expectedScope: {
222
+ readonly configHomeHash: string;
223
+ readonly tenantHash: string;
224
+ readonly projectHash: string;
225
+ };
226
+ readonly testingBindings?: Readonly<Record<string, string>>;
227
+ readonly now?: string;
208
228
  }
209
229
  /**
210
230
  * Get default skill discovery paths
@@ -215,13 +235,15 @@ interface SkillPathsConfig {
215
235
  * 3. User - ~/.agents/skills/ (AgentSkills standard)
216
236
  * 4. Plugin - (dynamic)
217
237
  * 5. Builtin - packages/skills/src/builtin/
218
- * 6. Learned - ~/.kodax/learned/skills/ (never shadows a formal source)
238
+ * Learned Skills are supplied separately through a record-gated Learned Area
239
+ * and never through a loose directory.
219
240
  */
220
241
  declare function getDefaultSkillPaths(projectRoot?: string): SkillPathsConfig;
221
242
  /**
222
243
  * All skill paths in priority order (highest to lowest)
223
244
  *
224
- * Priority: Project > User > Plugin > Builtin > Learned
245
+ * Priority: Project > User > Plugin > Builtin. Record-gated Learned Skills
246
+ * are appended by discovery after these formal sources.
225
247
  * - Project: Project-specific skills override everything else
226
248
  * - User: User preferences (~/.kodax/ and ~/.agents/)
227
249
  * - Plugin: Third-party plugins
@@ -234,4 +256,4 @@ declare function getSkillPathsFlat(config: SkillPathsConfig): Array<{
234
256
  }>;
235
257
 
236
258
  export { getDefaultSkillPaths as m, getSkillPathsFlat as n };
237
- export type { ISkillRegistry as I, ResolvedSkillSource as R, Skill as S, IVariableResolver as a, SkillArtifact as b, SkillContext as c, SkillDynamicContextExecutor as d, SkillFile as e, SkillFrontmatter as f, SkillHook as g, SkillHooks as h, SkillMetadata as i, SkillPathsConfig as j, SkillResult as k, SkillSource as l };
259
+ export type { ISkillRegistry as I, LearnedSkillDiscoveryConfig as L, ResolvedSkillSource as R, Skill as S, IVariableResolver as a, SkillArtifact as b, SkillContext as c, SkillDynamicContextExecutor as d, SkillFile as e, SkillFrontmatter as f, SkillHook as g, SkillHooks as h, SkillMetadata as i, SkillPathsConfig as j, SkillResult as k, SkillSource as l };
@@ -1,8 +1,8 @@
1
1
  import { a9 as KodaXWireReasoningEffort, a1 as KodaXToolDefinition, a3 as KodaXToolResultContentItem, k as KodaXMessage } from './types.d-DIpZJKUl.js';
2
2
  import { K as KodaXBaseProvider } from './base.d-4e74xDdy.js';
3
3
  import { C as CapabilityKind, a as CapabilityProvider } from './capability.d-K664nHOS.js';
4
- import { by as KodaXJsonValue, bm as KodaXExtensionSessionRecord, bo as KodaXExtensionStore } from './types.d-RdWRfUEs.js';
5
- import { aK as KodaXToolExecutionContext, br as ToolSideEffect } from './bash-prefix-extractor.d-pZdu6qt7.js';
4
+ import { bF as KodaXJsonValue, bt as KodaXExtensionSessionRecord, bv as KodaXExtensionStore } from './types.d-BA-Jwpfs.js';
5
+ import { aP as KodaXToolExecutionContext, bx as ToolSideEffect } from './bash-prefix-extractor.d-uAe2Oqda.js';
6
6
 
7
7
  /**
8
8
  * KodaX Constructed-World types (FEATURE_087, v0.7.28).
@@ -1,9 +1,9 @@
1
1
  import { k as KodaXMessage, F as KodaXReasoningMode, d as KodaXCustomProviderConfig, p as KodaXProviderCapabilityProfile } from './types.d-DIpZJKUl.js';
2
- import { O as KodaXContextTokenSnapshot, an as KodaXSkillDynamicContextPolicy, t as KodaXAgentMode, a7 as KodaXRepoIntelligenceMode, a1 as KodaXOptions, ao as KodaXSkillInvocationContext } from './bash-prefix-extractor.d-pZdu6qt7.js';
3
- import { bX as KodaXSessionUiHistoryItem, bM as KodaXSessionLineage, bD as KodaXSessionArtifactLedgerEntry, bn as KodaXExtensionSessionState, bm as KodaXExtensionSessionRecord, bT as KodaXSessionRuntimeInfo, eb as WorkflowProcessSource } from './types.d-RdWRfUEs.js';
4
- import { d as AgentsFile, r as AutoModeStats, x as KodaXMcpServersConfig } from './guardrail.d-B0PwAZVR.js';
2
+ import { c3 as KodaXSessionUiHistoryItem, bU as KodaXSessionLineage, bL as KodaXSessionArtifactLedgerEntry, bu as KodaXExtensionSessionState, bt as KodaXExtensionSessionRecord, b$ as KodaXSessionRuntimeInfo, e$ as WorkflowProcessSource } from './types.d-BA-Jwpfs.js';
3
+ import { O as KodaXContextTokenSnapshot, as as KodaXSkillDynamicContextPolicy, t as KodaXAgentMode, a8 as KodaXRepoIntelligenceMode, a1 as KodaXOptions, at as KodaXSkillInvocationContext } from './bash-prefix-extractor.d-uAe2Oqda.js';
4
+ import { d as AgentsFile, s as AutoModeStats, J as KodaXMcpServersConfig } from './guardrail.d-CXDYRgZ3.js';
5
5
  import * as readline from 'readline';
6
- import { R as PermissionMode, L as LearningBinding, E as LearningSurfaceSnapshot } from './public-api.d--fF88JrC.js';
6
+ import { R as PermissionMode, L as LearningBinding, E as LearningSurfaceSnapshot } from './public-api.d-B3AohsxN.js';
7
7
  import { SpawnSyncReturns } from 'child_process';
8
8
 
9
9
  /**
@@ -310,6 +310,22 @@ interface CommandCallbacks {
310
310
  rewindSession?: (selector?: string) => Promise<SessionRewindStatus>;
311
311
  getCostReport?: () => string | null;
312
312
  getRuntimeStatus?: () => Promise<RuntimeSurfaceStatus | undefined>;
313
+ /** Canonical host parser used by `/setup` for the root-owned A2A schema. */
314
+ validateSetupA2AConfig?: (value: unknown) => unknown;
315
+ /** Root-owned sandbox activation because ASRT is distributed by the host package. */
316
+ prepareSetupSandbox?: () => Promise<{
317
+ readonly status: 'ready' | 'cancelled' | 'unavailable';
318
+ readonly lines: readonly string[];
319
+ }>;
320
+ /** Explicit read-only `/sandbox` probe. Ordinary startup never calls it. */
321
+ inspectSandbox?: () => Promise<{
322
+ readonly ready: boolean;
323
+ readonly platform: string;
324
+ readonly version: string;
325
+ readonly backend: string;
326
+ readonly diagnostics: readonly string[];
327
+ readonly guidance: readonly string[];
328
+ }>;
313
329
  learning?: LearningBinding;
314
330
  getLearningSummary?: () => Promise<LearningSurfaceSnapshot>;
315
331
  openLearningCenter?: (nameOrSlug?: string) => Promise<void>;
@@ -364,7 +380,7 @@ interface CommandDefinition {
364
380
  aliases?: string[];
365
381
  description: string;
366
382
  usage?: string;
367
- detailedHelp?: () => void;
383
+ detailedHelp?: (args?: readonly string[]) => void;
368
384
  handler: CommandHandler;
369
385
  source?: CommandSource;
370
386
  priority?: CommandPriority;
@@ -406,7 +422,7 @@ interface Command {
406
422
  description: string;
407
423
  usage?: string;
408
424
  handler: CommandHandler;
409
- detailedHelp?: () => void;
425
+ detailedHelp?: (args?: readonly string[]) => void;
410
426
  source?: CommandSource;
411
427
  priority?: CommandPriority;
412
428
  location?: 'user' | 'project' | 'path';
@@ -33,8 +33,12 @@ are NOT obvious from inspecting the type definitions alone:
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
35
  25. [Always-on context compaction and bounded transcript recovery](#25-always-on-context-compaction-and-bounded-transcript-recovery-v0774)
36
- 26. [Agent mailbox control versus SDK event telemetry](#26-agent-mailbox-control-versus-sdk-event-telemetry-v0774)
37
- 27. [Windows GUI background subprocess visibility](#27-windows-gui-background-subprocess-visibility-v0775)
36
+ 26. [Agent mailbox control versus SDK event telemetry](#26-agent-mailbox-control-versus-sdk-event-telemetry-v0774)
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)).
@@ -3695,12 +3699,16 @@ const server = createKodaXA2AServer({
3695
3699
  },
3696
3700
  });
3697
3701
 
3698
- // Development only: the built-in listener refuses non-loopback hosts.
3699
- const localBaseUrl = await server.listen({ hostname: '127.0.0.1', port: 0 });
3700
- ```
3701
-
3702
- Production hosts route `GET /.well-known/agent-card.json` and canonical
3703
- 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
3704
3712
  terminator. `POST /` remains an accepted compatibility alias. `listen()` waits for durable recovery before
3705
3713
  it resolves. A host that wires `handle()` directly may explicitly await
3706
3714
  `server.whenReady()` before it starts accepting traffic; `handle()` also waits
@@ -3784,10 +3792,14 @@ SDK does not relaunch the GUI or silently fall back to an inline Runtime.
3784
3792
  ```ts
3785
3793
  import { connectKodaXRuntime } from '@kodax-ai/kodax/runtime';
3786
3794
 
3787
- const runtime = await connectKodaXRuntime({
3788
- profile: 'coder',
3789
- autoStart: true,
3790
- 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
3791
3803
  clientInfo: {
3792
3804
  name: 'kodax-space',
3793
3805
  version: '0.1.32',
@@ -3819,10 +3831,10 @@ const runtime = await connectKodaXRuntime({
3819
3831
  sharedSessionSettings: 1,
3820
3832
  durableRecoveryQueries: 1,
3821
3833
  daemonManagement: 1,
3822
- runtimeAutoModeGuardrail: 3,
3823
- },
3824
- });
3825
- ```
3834
+ runtimeAutoModeGuardrail: 4,
3835
+ },
3836
+ });
3837
+ ```
3826
3838
 
3827
3839
  Requirements are server facts, not authorization requests. Check
3828
3840
  `runtime.grantedScopes` before enabling controls. Missing capabilities or
@@ -3832,21 +3844,35 @@ Coder. Products that depend on same-Run delivery should require
3832
3844
  (for example, SA execution) still return `unsupported_capability`; do not
3833
3845
  silently substitute `delivery:'after_turn'` unless that is the user's intent.
3834
3846
 
3835
- The v0.7.73 SDK requires `runtimeAutoModeGuardrail:3` automatically for
3836
- `autoStart: true`, even when the caller omits it from `requirements`. If the healthy
3837
- profile daemon advertises v1 or v2, the SDK first requires `daemonManagement:1`,
3838
- takes a revision/owner-policy fenced preflight, and replaces it only when no
3839
- active or queued run, Workflow, Agent turn, pending permission/user input, or
3840
- other logical client exists. A busy or still-older daemon is never stopped: the
3841
- connection rejects with `RuntimeDaemonCapabilityUpgradeError`, whose
3842
- `recoverable` and `restartRequired` fields are `true` and whose optional
3843
- `preflight` explains the blockers. Attach-only connections never mutate daemon
3844
- ownership and must request `runtimeAutoModeGuardrail:1` explicitly when they
3845
- depend only on the v1 owner contract, v2 for bounded input, effective-default
3846
- metadata, structured diagnostics, and speculative-window parity, or v3 for
3847
- opaque exact grant suggestions and concrete permission matchers. Capability
3848
- requirements are minimum versions: v3 satisfies v1/v2, v2 satisfies v1, and an
3849
- 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.
3850
3876
 
3851
3877
  The `coderFeatureMatrix` capability reports daemon availability for managed
3852
3878
  runs, transcript/session operations, Todo projection, managed tasks, Workflow,
@@ -4076,9 +4102,11 @@ Write/Edit content may differ). Generic extension calls can receive only an
4076
4102
  exact in-memory Session grant. Raw command/argv data is not stored in the
4077
4103
  matcher; grants and audit contain only its fingerprint plus a bounded,
4078
4104
  secret-redacted operator label. Clients must not keep separate persistent
4079
- permission rule stores. Runtime capability `runtimeAutoModeGuardrail` v3 advertises this
4080
- opaque concrete-grant contract; restart or upgrade an older daemon instead of
4081
- 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.
4082
4110
 
4083
4111
  ### Broker a Space keychain credential
4084
4112
 
@@ -4357,9 +4385,9 @@ engine/denial/breaker state per Session. It reuses bounded context-specific
4357
4385
  guardrails across turns while provider/model, repository boundary, execution
4358
4386
  directory, classifier model, and timeout remain the same. Updating one of
4359
4387
  those inputs selects a new context guardrail by design without copying stale
4360
- state from a queued turn. Active runs, queued runs, explicit settings updates,
4361
- and automatic LLM-to-rules fallback merge through the same Session mutation
4362
- 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.
4363
4391
 
4364
4392
  ### What an embedder should expect
4365
4393
 
@@ -4369,16 +4397,22 @@ The Runtime's execution order is fixed:
4369
4397
  Runtime Auto Mode guardrail -> host permission bridge only for escalate -> tool execution
4370
4398
  ```
4371
4399
 
4372
- Consequently, an LLM/rules `allow` does not create a pending permission request
4373
- just because a host installed a static approval hook. `block` does not become a
4374
- spurious approval prompt. A real `escalate` uses the existing shared
4375
- `runtime.permissions` flow, so another authorized client may render and answer
4376
- it. Hosts should subscribe to permission events to display such a request, but
4377
- must not treat a missing request as an error for a safe tool call.
4378
-
4379
- The classifier deadline remains 20 seconds by default and includes connection
4380
- setup, provider Retry-After/backoff, inference, and stream completion. KodaX
4381
- 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
4382
4416
  provider call it removes assistant prose/thinking and image paths, limits each
4383
4417
  tool result to 2 KiB and the serialized permission-relevant transcript to
4384
4418
  8 KiB, then enforces 16 KiB action and 32 KiB total-prompt ceilings plus a
@@ -4405,14 +4439,21 @@ session repository safety boundary, whereas relative operands resolve from the
4405
4439
  validated `executionCwd`. In particular, quoted Python/JavaScript/regexp source
4406
4440
  inside a shell command is not a path operand.
4407
4441
 
4408
- The user-level `.kodax` directory is a credential/configuration boundary, not
4409
- an ordinary project path. Direct shell mutations, output redirects, and
4410
- recognized nested-shell payloads whose target is provably beneath that
4411
- directory are rejected before LLM classification. The check is segment-safe
4412
- and Windows case-insensitive. KodaX deliberately does not scan arbitrary
4413
- quoted language source for path-looking substrings: doing so would turn Python,
4414
- JavaScript, YAML, and regular expressions into false Tier-0 matches. Trusted
4415
- 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.
4416
4457
 
4417
4458
  ### 0.7.x source compatibility
4418
4459
 
@@ -4773,6 +4814,309 @@ for cross-project, cache, cancellation, credential, and Windows argv checks.
4773
4814
 
4774
4815
  ---
4775
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.
5117
+
5118
+ ---
5119
+
4776
5120
  ## See also
4777
5121
 
4778
5122
  - [README.md](../README.md) — end-user CLI quick start