stitchkit 0.101.3 → 0.103.0

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 (40) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/application/diagnostic-journal-contract.d.ts +46 -7
  3. package/dist/application/diagnostic-journal-contract.d.ts.map +1 -1
  4. package/dist/application/diagnostic-journal-frame.d.ts +9 -0
  5. package/dist/application/diagnostic-journal-frame.d.ts.map +1 -0
  6. package/dist/application/diagnostic-journal-manager.d.ts.map +1 -1
  7. package/dist/application/diagnostic-journal-read-contract.d.ts +110 -0
  8. package/dist/application/diagnostic-journal-read-contract.d.ts.map +1 -0
  9. package/dist/application/diagnostic-journal-reader.d.ts +13 -0
  10. package/dist/application/diagnostic-journal-reader.d.ts.map +1 -0
  11. package/dist/application/diagnostic-journal-recovery.d.ts +4 -0
  12. package/dist/application/diagnostic-journal-recovery.d.ts.map +1 -0
  13. package/dist/application/diagnostic-journal-storage.d.ts +2 -0
  14. package/dist/application/diagnostic-journal-storage.d.ts.map +1 -1
  15. package/dist/entrypoints/application/diagnostic-journal.d.ts +1 -0
  16. package/dist/entrypoints/application/diagnostic-journal.d.ts.map +1 -1
  17. package/dist/entrypoints/application/diagnostic-journal.js +213 -19
  18. package/dist/entrypoints/application.d.ts +1 -0
  19. package/dist/entrypoints/application.d.ts.map +1 -1
  20. package/dist/entrypoints/application.js +10 -2
  21. package/dist/entrypoints/tools/contract.js +1 -1
  22. package/dist/entrypoints/tools.js +4 -3
  23. package/dist/index-z94wht4y.js +156 -0
  24. package/dist/{index-5107q189.js → index-zax7resm.js} +13 -1
  25. package/dist/tools/transfer/view-file-contract.d.ts.map +1 -1
  26. package/dist/tools/transfer/view-file.d.ts.map +1 -1
  27. package/llms/application-diagnostic-journal.txt +2 -0
  28. package/llms/application.2.txt +157 -267
  29. package/llms/application.3.txt +278 -0
  30. package/llms/application.txt +43 -158
  31. package/llms/stitchkit.txt +4 -4
  32. package/llms/tools.2.txt +9 -0
  33. package/llms/tools.3.txt +1 -1
  34. package/llms/{upgrading-0.61.0-0.73.0.txt → upgrading-0.61.0-0.74.0.txt} +64 -3
  35. package/llms/{upgrading-0.74.0-0.101.0.txt → upgrading-0.75.0-0.103.0.txt} +56 -64
  36. package/llms/upgrading.txt +2 -2
  37. package/llms-full.txt +115 -9
  38. package/llms.txt +6 -6
  39. package/package.json +1 -1
  40. package/dist/index-h124epcf.js +0 -103
@@ -0,0 +1,278 @@
1
+ # stitchkit/application — stitchkit docs slice, part 3 of 3
2
+
3
+ > Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
4
+ > `llms.txt` in this package.
5
+
6
+ Parts of this slice:
7
+ - `llms/application.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md)
8
+ - `llms/application.2.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md) · Guide: Application migration recipes (docs/guide/application-migration-recipes.md)
9
+ - `llms/application.3.txt`: API reference: `stitchkit/application` (docs/api/reference.md)
10
+
11
+ ==============================================================================
12
+ # API reference: `stitchkit/application` (docs/api/reference.md)
13
+ ==============================================================================
14
+
15
+ ## `stitchkit/application`
16
+
17
+ Server-only process-local application composition. See the
18
+ [application kernel guide](../guide/application-kernel.md) and
19
+ [architecture](../architecture/application-kernel.md). Complete consumer
20
+ cutovers are covered by the executable
21
+ [migration recipes](../guide/application-migration-recipes.md).
22
+
23
+ ### Kernel and resources
24
+
25
+ | Export | Kind | Summary |
26
+ |--------|------|---------|
27
+ | `createApplication` | function | compose a validated resource DAG into one startup, readiness, admission and shutdown state machine |
28
+ | `StateStore` / `StateStoreUpdate` | _type_ | async atomic read/update boundary shared by durable application state machines |
29
+ | `createProcessLifecycleLedger` / `ProcessLifecycleLedger` / `ProcessLifecycleLedgerConfig` | function / _type_ | durable bounded run history and typed fact subscription |
30
+ | `LifecycleRunSchema` / `LifecycleRun` / `LifecycleStateSchema` / `LifecycleState` / `LifecycleTerminationSchema` / `LifecycleTermination` | schema / _type_ | versioned process-run state — open (`active`, `draining` with `unavailableAt`) and ended (`clean`, `forced`, `startup-failed`, `hot-reload`, `abnormal`) |
31
+ | `PreviousExitSchema` / `PreviousExit` / `StartFact` / `ReadyFact` / `DrainingFact` / `ShutdownFact` / `ProcessLifecycleFact` | schema / _type_ | first-boot, hot-reload, clean, forced, startup-failed, handoff and abnormal lifecycle facts; `processGapMs` on start, `downtimeMs` (unavailable → ready) on ready |
32
+ | `transitionProcessStart` / `transitionProcessReady` / `transitionProcessDraining` / `transitionProcessShutdown` | function | pure idempotent runId+pid-owned transitions |
33
+ | `LifecycleTransition` / `TransitionStartInput` / `TransitionRunInput` / `TransitionShutdownInput` / `SameVersionOverlap` / `VersionChangeOverlap` | _type_ | pure transition inputs (`TransitionRunInput` for ready and draining, extended with `forced` for shutdown), the same-build overlap policy (`abnormal` default / `handoff`), the version-change overlap policy (`handoff` default / `abnormal`) and state+fact result |
34
+ | `lifecycleLedgerResource` / `LifecycleLedgerResource` / `LifecycleLedgerResourceConfig` | function / _type_ | managed-resource adapter that records start, readiness, admission stop (draining) and shutdown |
35
+ | `createNotificationOutbox` / `NotificationOutbox` / `NotificationOutboxConfig` | function / _type_ | bounded at-least-once queue with durable claims, leases, retries and supersede |
36
+ | `NotificationOutboxItem` / `NotificationOutboxReceipt` / `NotificationOutboxState` / `NotificationSend` / `NotificationFailureClassification` / `DroppedNotification` / `EnqueueNotification` | _type_ | versioned queue records, stable send identity and delivery decisions |
37
+ | `notificationOutboxStateSchema` | function | strict persisted-state schema over an application payload schema |
38
+ | `notificationOutboxResource` / `NotificationOutboxResource` / `NotificationOutboxResourceConfig` | function / _type_ | thin managed-resource scheduler over an outbox handle |
39
+ | `createDirectoryInbox` (from `stitchkit/application/directory-inbox`) / `DirectoryInbox` / `DirectoryInboxConfig` / `DirectoryInboxDelivery` / `DirectoryInboxResource` | function / _type_ | managed resource delivering each `<name>.json` entry another program drops into a directory to the application at least once, after readiness; separate durable taken/done records, leases, bounded retry |
40
+ | `DirectoryInboxStateSchema` / `DirectoryInboxState` / `DirectoryInboxRejection` / `DirectoryInboxRejectionReasonSchema` / `DirectoryInboxRejectionReason` | schema / _type_ | the inbox's claims, receipts and rejections (`invalid`, `too-large`, `attempt-limit`) |
41
+ | `ApplicationHandle.restart` | method | replace one resource and everything that depends on it, leaving the rest of the graph running and the process epoch unchanged |
42
+ | `ApplicationRestartInputSchema` / `ApplicationRestartInput` | schema / _type_ | the resource to replace, by id, and optionally `gracePeriodMs` / `forceTimeoutMs` for this restart — the application's own shutdown budget otherwise |
43
+ | `ApplicationRestartResultSchema` / `ApplicationRestartResult` | schema / _type_ | the subtree that was actually taken down and brought back, in start order, with the outcome, the reason on anything but success, and how long it took |
44
+ | `ApplicationRestartOutcomeSchema` / `ApplicationRestartOutcome` | schema / _type_ | `restarted`, `failed` or `refused` — a refusal (unknown id, shutting down, not yet ready) is not a failure and touches nothing |
45
+ | `ApplicationResourceFailure` | _type_ | one resource failure with the cause its phase label cannot carry — delivered to `onResourceFailure` |
46
+ | `ApplicationResourcePhase` | _type_ | the phase a managed resource failed in — the vocabulary of `ApplicationResourceShutdown.failures` |
47
+ | `ApplicationShutdownOptionsSchema` / `ApplicationShutdownOptions` | schema / _type_ | the two shutdown budgets and an abort signal — without the HTTP-only `retryAfterSeconds` |
48
+ | `ApplicationShutdownBudgetSchema` / `ApplicationShutdownBudget` | schema / _type_ | the same two budgets without a signal — `ApplicationConfig.shutdown`, the default for `shutdown()` and the only budget a failed startup's rollback can read |
49
+ | `ActivityTokenBrand` | const | the brand symbol `ActivityToken` carries, exported so `ActivityProjection` is implementable |
50
+ | `defineManagedResource` | function | retain the exact typed resource declaration; every invoked start is rollback-eligible |
51
+ | `managedServerResource` | function | own a managed server's lifecycle without copying its HTTP/WebSocket shutdown machine — a thunk is called during `start`, and the handle is published to dependants |
52
+ | `managedResourceDependencyId` | function | the id of a dependency declared either as a string or as the resource itself |
53
+ | `createApplicationHealthHandler` | function | build a Fetch-clean liveness or readiness response from the sanitized application snapshot |
54
+ | `createApplicationOperationalHandlers` | function | compose always-readable status plus the canonical readiness/liveness handlers |
55
+ | `ApplicationAdmissionError` | class | stable `APPLICATION_NOT_ACCEPTING` rejection from `admission.run(...)` |
56
+ | `ApplicationConfig` / `ApplicationHandle` | _type_ | application declaration and its start/snapshot/subscription/admission/shutdown handle |
57
+ | `ApplicationAdmission` / `ApplicationOperationLease` | _type_ | atomic process-local admission and idempotent release primitive |
58
+ | `ManagedResource` / `ManagedResourceContext` / `ManagedResourceStartResult` | _type_ | resource lifecycle callbacks, shared deadlines, health reporting, separate readiness/completion promises and the value a resource publishes to its dependants |
59
+ | `ManagedResourceAdmission` | _type_ | `context.admission`: `acquire()` now or `null`, and `acquireWhenAccepting(signal)` for a resource that fetches work — a poller waits instead of fetching while the application is starting or degraded; rejects on abort and once the application can no longer admit |
60
+ | `ManagedResourceDependency` | _type_ | a dependency named by id or given as the resource itself — the second form is what `context.use(...)` can type |
61
+ | `ManagedResourcePublished` | _type_ | the value type `context.use(resource)` returns, recovered from that resource's own `start` |
62
+ | `ManagedResourcePublishesNoValue` | _type_ | what `context.use(...)` returns for a resource that publishes nothing — a branded refusal rather than `never`, so reading it does not silently compile |
63
+ | `ManagedServerResourceConfig` | _type_ | the server or a sync/async factory receiving `ManagedResourceContext`, plus stable ID, dependencies and server shutdown policy (`retryAfterSeconds`, `realtimeCloseTimeoutMs`) |
64
+ | `ManagedServerResource` | _type_ | the resource `managedServerResource` returns, whose `start` publishes the `ManagedServerHandle` |
65
+ | `ApplicationHealthHandlerOptions` / `ApplicationHealthHandlerOptionsSchema` | _type_ / schema | liveness/readiness selection and sanitized `Retry-After` policy |
66
+ | `ApplicationOperationalHandlers` / `ApplicationOperationalHandlersOptions` / `ApplicationOperationalHandlersOptionsSchema` | _type_ / schema | conventional status/readiness/liveness route surface and shared retry policy |
67
+
68
+ ### Bounded admission
69
+
70
+ | Export | Kind | Summary |
71
+ |--------|------|---------|
72
+ | `createBoundedAdmission` | function | process-local no-queue global/per-key concurrency and rate leases, optionally composed with application admission |
73
+ | `BoundedAdmissionPolicySchema` / `BoundedAdmissionPolicy` | schema / _type_ | finite global budget and optional finite per-key budget with `maxKeys`, declared either as one flat ceiling or as a resolver — never both |
74
+ | `BoundedAdmissionPerKeyLimitsSchema` / `BoundedAdmissionPerKeyLimits` | schema / _type_ | one key's resolved ceiling: `maxConcurrent` and optional `rate` |
75
+ | `BoundedAdmissionPerKeyLimitResolver` | _type_ | `(key) => limits`, resolved on a key's first admission and cached until the key is evicted |
76
+ | `BoundedRateBudgetSchema` / `BoundedRateBudget` | schema / _type_ | `{ limit, intervalMs }` monotonic sliding-window budget |
77
+ | `BoundedAdmissionStateSchema` / `BoundedAdmissionState` | schema / _type_ | `accepting \| draining \| closed` |
78
+ | `BoundedAdmissionRefusalReasonSchema` / `BoundedAdmissionRefusalReason` | schema / _type_ | exact local/upstream refusal vocabulary |
79
+ | `BoundedAdmissionSnapshotSchema` / `BoundedAdmissionSnapshot` | schema / _type_ | absolute active/lifetime/refusal/rate-accounting counters |
80
+ | `BoundedAdmission` / `BoundedAdmissionConfig` / `BoundedAdmissionClock` | _type_ | handle, policy/upstream/clock configuration and monotonic clock seam |
81
+ | `BoundedAdmissionResult` / `BoundedAdmissionLeaseResult` / `BoundedAdmissionRefusedResult` | _type_ | explicit leased-or-refused acquisition result; retry time exists only for rate bounds |
82
+ | `BoundedOperationLease` | _type_ | idempotent release lease, optionally carrying its key |
83
+ | `BoundedOperationRunContext` / `BoundedOperationRunOptions` | _type_ | underlying work signal and caller abort/timeout wait budget |
84
+ | `BoundedAdmissionDrainOptions` / `BoundedAdmissionDrainResult` / `BoundedAdmissionForceResult` | _type_ | bounded drain inputs and honest remaining-work results |
85
+ | `BoundedAdmissionRefusalError` | class | `run()` refusal with reason and optional `retryAfterMs` |
86
+ | `BoundedOperationWaitError` | class | caller wait ended as `cancelled` or `timed-out`; underlying capacity remains leased until work settles |
87
+
88
+ ### Revision wake-up
89
+
90
+ | Export | Kind | Summary |
91
+ |--------|------|---------|
92
+ | `createRevisionSignal` | function | finite broadcast wait for the next monotonic process-local revision |
93
+ | `RevisionSignal` / `RevisionSignalConfig` / `RevisionSignalClock` / `RevisionSignalTimer` | _type_ | signal handle, waiter bound and replaceable timer boundary |
94
+ | `RevisionSignalWaitOptions` | _type_ | optional caller `signal` and positive `timeoutMs`; absent options wait until advance or close |
95
+ | `RevisionSignalWaitOutcomeSchema` / `RevisionSignalWaitOutcome` | schema / _type_ | `changed \| timed-out \| aborted \| closed \| capacity` |
96
+ | `RevisionSignalWaitResultSchema` / `RevisionSignalWaitResult` | schema / _type_ | terminal wait outcome with the revision observed at settlement |
97
+ | `RevisionSignalAdvanceResultSchema` / `RevisionSignalAdvanceResult` | schema / _type_ | successful `advanced` or post-close `closed`, with the resulting revision |
98
+ | `RevisionSignalStateSchema` / `RevisionSignalState` | schema / _type_ | `open \| closed` lifecycle |
99
+ | `RevisionSignalSnapshotSchema` / `RevisionSignalSnapshot` | schema / _type_ | current revision, finite pending count and lifetime outcome counters |
100
+
101
+ ### Bounded delivery
102
+
103
+ | Export | Kind | Summary |
104
+ |--------|------|---------|
105
+ | `createBoundedChannel` | function | finite single-reader async channel with explicit ordered or latest-value policy |
106
+ | `BoundedChannelPolicySchema` / `BoundedChannelPolicy` | schema / _type_ | `ordered \| latest` retention policy |
107
+ | `BoundedChannelStateSchema` / `BoundedChannelState` | schema / _type_ | `open \| draining \| closed \| failed` |
108
+ | `BoundedChannelSnapshotSchema` / `BoundedChannelSnapshot` | schema / _type_ | exact retained count/bytes, waiter and outcome counters |
109
+ | `BoundedChannel` / `BoundedChannelConfig` / `BoundedChannelCloseOptions` | _type_ | iterator/offer handle, explicit count/byte/size policy and drain/discard close mode |
110
+ | `BoundedChannelOfferResult` | _type_ | `delivered`, `queued`, `coalesced`, or reasoned `refused` outcome |
111
+ | `BoundedChannelReaderError` | class | refusal of a second concurrent pending `next()` |
112
+ | `createCreditWindow` | function | finite byte-credit lease window with exact once-only replenishment |
113
+ | `CreditWindow` / `CreditWindowSnapshot` / `CreditWindowSnapshotSchema` | _type_ / schema | byte-credit handle and absolute accounting record |
114
+ | `CreditAcquireResult` / `CreditLease` | _type_ | reasoned refusal or idempotently releasable byte-credit lease |
115
+ | `CreditAcquireWaitOptions` | _type_ | `signal` / `timeoutMs` for the waiting `acquire` overload; absent budget waits until credit, close or abort |
116
+ | `CreditWaitResult` / `CreditWaitRefusalReason` | _type_ | waiting-acquire outcome; `insufficient-credit` is absent by construction, `timed-out` and `aborted` replace it |
117
+
118
+ ### Bounded diagnostic journal
119
+
120
+ | Export | Kind | Summary |
121
+ |--------|------|---------|
122
+ | `createDiagnosticJournal` | function | create one schema-owned FIFO JSONL writer with bounded retained memory, exclusive local path ownership and finite rotation |
123
+ | `DiagnosticJournalConfig` / `DiagnosticJournal` | _type_ | owner schema/path/limits/failure observer and the synchronous `submit`, bounded-wait `flush`/`close`, status handle |
124
+ | `DiagnosticJournalLimitsSchema` / `DiagnosticJournalLimits` | schema / _type_ | positive event, pending-item, pending-byte, file-byte and retained-file limits |
125
+ | `DiagnosticJournalLockPolicySchema` / `DiagnosticJournalLockPolicy` | schema / _type_ | `refuse` (default) or `reclaim-stale`, which reclaims only a lock whose recorded owner is provably gone |
126
+ | `readDiagnosticJournalLockDiagnosis` / `DiagnosticJournalLockDiagnosis` | function / _type_ | why a `reclaim-stale` acquisition refused — attribution, PID liveness and optional process `identity` evidence (`matched`, `different-boot`, `reused-pid`, `pid-gone`, `legacy`, `unavailable`) — read off the thrown `EEXIST` |
127
+ | `DiagnosticJournalSubmitResultSchema` / `DiagnosticJournalSubmitResult` | schema / _type_ | accepted epoch/sequence or explicit invalid, oversized, capacity, closed or failed refusal |
128
+ | `DiagnosticJournalStatusSchema` / `DiagnosticJournalStatus` | schema / _type_ | state, limits, exact admission/write/failure counters, pending ownership, rotations, partial tails and last safe sequences |
129
+ | `DiagnosticJournalFrameSchema` / `DiagnosticJournalFrame` | schema / _type_ | version-1 JSONL frame carrying process epoch, contiguous accepted sequence and schema-validated JSON event |
130
+ | `DiagnosticJournalWaitResultSchema` / `DiagnosticJournalWaitResult` | schema / _type_ | flush settlement boundary with truthful settled, timed-out or cancelled result |
131
+ | `DiagnosticJournalCloseResultSchema` / `DiagnosticJournalCloseResult` | schema / _type_ | physical close or caller timeout/cancellation without pretending an active write stopped |
132
+ | `DiagnosticJournalStateSchema` / `DiagnosticJournalState` | schema / _type_ | `open \| draining \| closed \| failed` |
133
+ | `DiagnosticJournalRefusalReasonSchema` / `DiagnosticJournalRefusalReason` | schema / _type_ | `closed \| failed \| invalid \| oversized \| item-capacity \| byte-capacity` |
134
+ | `DiagnosticJournalFailurePhaseSchema` / `DiagnosticJournalFailurePhase` | schema / _type_ | internal `write \| rotation \| close` failure phase exposed only to status and the isolated observer |
135
+ | `DiagnosticJournalWaitOptions` / `DiagnosticJournalFailure` | _type_ | caller wait signal/timeout and isolated internal failure callback record |
136
+ | `DiagnosticJournalAnomalySchema` / `DiagnosticJournalAnomaly` | schema / _type_ | corrupt-row reason, file, zero-based byte offset, one-based line, tail/interior position and skipped bytes |
137
+ | `createDiagnosticJournalReadResultSchema` / `DiagnosticJournalReadResult` | function / _type_ | owner-schema frame output or explicit anomaly; retains transformed event output types |
138
+ | `DiagnosticJournalRecoveryStatusSchema` / `DiagnosticJournalRecoveryStatus` | schema / _type_ | bounded startup inspection counts and first/last anomaly locations |
139
+ | `DiagnosticJournalRecoveryError` | class | torn single-file startup refusal carrying recovery observations, preserving evidence and releasing its lock |
140
+
141
+ `accepted` is bounded in-memory admission and `written` is completed append, not `fsync` or durable
142
+ delivery. Its filesystem reader is in the diagnostic-journal leaf; there is no managed replay/upload API. See the
143
+ [guide](../guide/application-kernel.md#bounded-local-diagnostic-journal),
144
+ [architecture](../architecture/diagnostic-journal.md) and [ADR
145
+ 0134](../decisions/0134-diagnostic-journal-is-bounded-local-evidence.md).
146
+
147
+ ### Managed schedules
148
+
149
+ | Export | Kind | Summary |
150
+ |--------|------|---------|
151
+ | `createManagedSchedule` | function | fixed-rate process-local timer that activates after top-level readiness and participates in drain |
152
+ | `ManagedScheduleOverlapSchema` / `ManagedScheduleOverlap` | schema / _type_ | `skip`, `queue-one` or bounded `parallel` overlap policy |
153
+ | `ManagedScheduleErrorPolicySchema` / `ManagedScheduleErrorPolicy` | schema / _type_ | `continue` or `stop-schedule` after an observed callback failure |
154
+ | `ManagedScheduleDescriptorSchema` / `ManagedScheduleDescriptor` | schema / _type_ | immutable public schedule identity and cadence policy |
155
+ | `ManagedScheduleStatusSchema` / `ManagedScheduleStatus` | schema / _type_ | absolute schedule state, revision, counters and timestamps |
156
+
157
+ Schedule authoring additionally exports `ManagedSchedule`, `ManagedScheduleConfig`,
158
+ `ManagedScheduleRunContext`, `ManagedScheduleClock` and `ManagedScheduleTimer`.
159
+ The clock exposes monotonic cadence/deadline arithmetic and a wall-clock projection for portable
160
+ status timestamps; it is a deterministic test boundary, not a durable scheduler.
161
+
162
+ ### Application and activity projection
163
+
164
+ | Export | Kind | Summary |
165
+ |--------|------|---------|
166
+ | `createActivityProjection` | function | aggregate anonymous process-local activity into declared bounded stages and absolute snapshots |
167
+ | `createApplicationSnapshotSink` | function | latest-value delivery with one write in flight and one replaceable pending revision |
168
+ | `applicationLifecycleEvent` | function | project a sanitized lifecycle fact from a canonical application snapshot |
169
+ | `createApplicationEventSink` | function | bounded failure-isolated lifecycle-event delivery; events are not canonical state |
170
+ | `ActivitySnapshotSchema` / `ActivitySnapshot` | schema / _type_ | epoch, monotonic revision, timestamps, declared stages and aggregate counts |
171
+ | `ApplicationSnapshotSinkStatusSchema` / `ApplicationSnapshotSinkStatus` | schema / _type_ | immutable latest-value sink delivery and coalescing counters |
172
+ | `ApplicationLifecycleEventSchema` / `ApplicationLifecycleEvent` | schema / _type_ | sanitized operator-facing application lifecycle fact |
173
+
174
+ Activity authoring additionally exports `ActivityId`, `ActivityIdSchema`,
175
+ `ActivityStageId`, `ActivityStageIdSchema`, `ActivityStageSnapshot`,
176
+ `ActivityStageSnapshotSchema`, `ActivityLiveState`, `ActivityLiveStateSchema`,
177
+ `ActivityProjection`, `ActivityProjectionConfig`,
178
+ `ActivityProjectionSubscriberError`, `ActivityToken` and `ActivityTransition`.
179
+ Latest-value delivery exports `ApplicationSnapshotSink`,
180
+ `ApplicationSnapshotSinkConfig`, `ApplicationSnapshotSinkError` and
181
+ `RevisionedApplicationSnapshot`; event delivery exports `ApplicationEventSink`
182
+ and `ApplicationEventSinkConfig`.
183
+
184
+ ### Canonical application records
185
+
186
+ These are also published on their own as
187
+ [`stitchkit/application/schemas`](#stitchkitapplicationschemas), which carries
188
+ no server runtime and can therefore be imported from a browser bundle.
189
+
190
+ The entrypoint exports each Zod schema beside its inferred type:
191
+ `ApplicationIdSchema` / `ApplicationId`, `ApplicationLifecycleSchema` /
192
+ `ApplicationLifecycle`, `ApplicationHealthSchema` / `ApplicationHealth`,
193
+ `ManagedResourceStateSchema` / `ManagedResourceState`,
194
+ `ApplicationAdmissionSnapshotSchema` / `ApplicationAdmissionSnapshot`,
195
+ `ManagedResourceSnapshotSchema` / `ManagedResourceSnapshot`,
196
+ `ApplicationSnapshotSchema` / `ApplicationSnapshot`,
197
+ `ApplicationStatusProjectionSchema` / `ApplicationStatusProjection` with
198
+ `projectApplicationStatus` — what a status or probe endpoint may publish, and
199
+ the function that derives it from a snapshot,
200
+ `ApplicationResourceShutdownSchema` / `ApplicationResourceShutdown`, and
201
+ `ApplicationShutdownResultSchema` / `ApplicationShutdownResult`.
202
+
203
+ ### Decisions
204
+
205
+ A pipeline of policies that each vote `allow`, `deny` or `defer`, sharing its
206
+ vocabulary with an event topic declared `mode: 'decision'`.
207
+
208
+ | Export | Kind | Summary |
209
+ |--------|------|---------|
210
+ | `createDecisionPipeline` | function | run policies in declaration order; the first terminal verdict wins and the rest do not run |
211
+ | `DecisionPipelineConfig` | _type_ | `policyTimeoutMs` — how long one policy has to answer. Required, no default: a policy that never settles hangs every caller of the operation it guards |
212
+ | `PolicyDecisionSchema` / `PolicyDecision` | schema / _type_ | `allow`, `deny` with a reason, or `defer` — a deny cannot be silent |
213
+ | `DecisionPolicy` / `DecisionPipeline` | _types_ | one named voter over the caller's subject, and the pipeline it composes into |
214
+ | `DecisionResult` / `DecisionTraceEntry` | _types_ | the verdict, and the trace of what actually ran — not what was declared |
215
+ | `DecisionUndecidedError` | class | every policy deferred and no undecided outcome was declared: an unanswered question, raised rather than guessed |
216
+ | `DecisionPolicyError` | class | a policy returned a non-decision, threw, or ran past `policyTimeoutMs` — one error for all three, carrying the policy id and the trace so far |
217
+
218
+ ### Keyspace and watched reads
219
+
220
+ | Export | Kind | Summary |
221
+ |--------|------|---------|
222
+ | `defineKeyspace` / `keyspaceResource` | function | a named record set read synchronously from memory and written through one serialised chain; backend first, then memory, then the change event |
223
+ | `openKeyspace` / `OpenedKeyspace` | function / type | the same keyspace opened directly, for an application that owns its own lifecycle rather than declaring resources to a kernel |
224
+ | `KeyspaceBackend` / `KeyspaceDeclaration` / `KeyspaceChange` / `KeyspaceResourceConfig` / `OpenKeyspace` | _types_ | the four-method durability port, the declaration, the announced change, the resource's options and the published handle. `backend` takes a value or a **factory** — a factory is called once per generation, so a restarted keyspace gets a backend that was never closed |
225
+ | `memoryKeyspaceBackend` / `sqliteKeyspaceBackend` / `SqliteKeyspaceBackendConfig` | function / type | a disposable in-process backend, and one table with a key and a JSON payload over a caller-owned database |
226
+ | `SqliteDatabase` / `SqliteStatement` / `SqliteValue` | _types_ | the minimal synchronous SQLite boundary the framework types against |
227
+ | `createWatchHub` / `watchKey` | function | one read per question however many are asking: single-flight per key, re-read on a declared topic, publish only what changed |
228
+ | `WatchHub` / `WatchHubConfig` / `WatchOperation` / `WatchSubscriber` / `AttachedWatcher` | _types_ | the hub, its read/watchable/invalidation policy, the operation identity, and one connection's attachment |
229
+
230
+ → [ADR 0152](../decisions/0152-a-keyspace-is-memory-that-nothing-reaches-before-it-is-durable.md),
231
+ [ADR 0153](../decisions/0153-a-watched-read-is-one-read-per-question.md).
232
+
233
+ ### Managed change subscriptions and scoped watches
234
+
235
+ `changeSubscriptionResource` (`stitchkit/application`) accepts
236
+ `ChangeSubscriptionConfig`: `id`, unique `keys` (1–128, at most 256 characters each),
237
+ `connect(signal)`, `reconcile(key, context)`, required `reconcileIntervalMs` (10 ms–1 h),
238
+ optional `timeoutMs` (30000; 1 ms–1 h), `backoff`, and `onError`.
239
+ `ChangeConnection` supplies `subscribe({ signal, hint, disconnected })`, which completes subscription
240
+ before the first read; `close()` releases it. `ChangeReconciliation` exposes `signal`
241
+ and a synchronous `commit(callback)` guard against late publication. Drivers must
242
+ honor cancellation. Uncooperative work retains its slot until settled instead of
243
+ allowing overlapping connections/reads. Errors reach `onError`; no raw payload or
244
+ connection string is logged by this resource. Recovery runs after reconnect and
245
+ periodically even when no notification arrives.
246
+
247
+ `WatchHubConfig` adds `maxSources` (1024), `maxSubscribers` (1024), and optional
248
+ `reconcileIntervalMs` (10 ms–1 h). `hub.attach(subscriber, scope?)` accepts a
249
+ `WatchAdmissionScope` containing a **server-verified** `key` (1–512 characters) and
250
+ revocation `signal`. The key separates sharing and is the optional third argument
251
+ of `read(operation, args, scope)`; a key's `instance` routes frames and never
252
+ separates sources. Attached over `maxSubscribers`, a subscriber gets a watcher whose
253
+ `open` refuses with `Watch subscriber capacity exceeded`; `attach` does not throw
254
+ for capacity. It must represent account, session and permissions;
255
+ never trust a client-supplied owner ID as that scope.
256
+
257
+
258
+
259
+ ### Notification action and projection receipts
260
+
261
+ `NotificationOutboxConfig.delivery` accepts `NotificationDeliveryConfig`:
262
+ immutable executor `version`, pure `actions(payload)` plan selector (1–128 unique
263
+ names, each at most 128 characters), and idempotent `project(notification, receipts)`.
264
+ `send` receives optional `action` and stable `idempotencyKey`, and returns a JSON
265
+ remote receipt (void becomes null). A result that is not JSON or does not fit the
266
+ byte budget is kept as `receipt: null` with `unrecorded: 'not-json' | 'too-large'`;
267
+ the action stays confirmed and is not sent again. `retiredVersions` maps earlier
268
+ plan versions to their `NotificationProjection` so queued items drain after an
269
+ executor upgrade; an unknown version is reported to `onError` as
270
+ `NotificationPlanVersionError` and waits, spending no attempt and not consulting
271
+ `classify`, for an executor that knows it. `NotificationDeliveryStateSchema` validates the
272
+ optional `NotificationDeliveryState` on queued items and completed receipts:
273
+ `version`, `actions`, `receipts` and optional `projectedAt`. Checkpoints share the
274
+ existing atomic StateStore and lease fence. Receipt retention and serialized byte
275
+ budgets still apply. Single-send configuration remains valid without `delivery`.
276
+ A remote result lost before its checkpoint may be sent again; provider idempotency
277
+ or reconciliation is required. A projection may repeat after a crash before its
278
+ checkpoint. Business-transaction enqueue and durable quarantine are not implied.
@@ -1,4 +1,4 @@
1
- # stitchkit/application — stitchkit docs slice, part 1 of 2
1
+ # stitchkit/application — stitchkit docs slice, part 1 of 3
2
2
 
3
3
  > Generated from the `docs/` tree by `bun run gen:llms`. The index of all slices is
4
4
  > `llms.txt` in this package.
@@ -6,7 +6,8 @@
6
6
 
7
7
  Parts of this slice:
8
8
  - `llms/application.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md)
9
- - `llms/application.2.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md) · Guide: Application migration recipes (docs/guide/application-migration-recipes.md) · API reference: `stitchkit/application` (docs/api/reference.md)
9
+ - `llms/application.2.txt`: Guide: Managed application kernel (docs/guide/application-kernel.md) · Guide: Application migration recipes (docs/guide/application-migration-recipes.md)
10
+ - `llms/application.3.txt`: API reference: `stitchkit/application` (docs/api/reference.md)
10
11
 
11
12
  ==============================================================================
12
13
  # Guide: Managed application kernel (docs/guide/application-kernel.md)
@@ -18,7 +19,7 @@ description: Compose process-local resources, schedules, readiness, drain and op
18
19
  type: architecture
19
20
  status: active
20
21
  created: 2026-08-23
21
- updated: 2026-09-04 14:11 +07:00
22
+ updated: 2026-09-30 17:41 +07:00
22
23
  ---
23
24
 
24
25
  # Managed application kernel
@@ -665,10 +666,47 @@ short-lived reclaim guard.
665
666
 
666
667
  `flush()` means every accepted append through that call's boundary settled. It is not `fsync`, a
667
668
  durable receipt, exactly-once execution or remote delivery. Timeout/cancellation bound only the
668
- waiter; the writer retains physical capacity until settlement. There is no reader or upload API.
669
- Use a durable application store or deployment-owned log collector when restart recovery, replay or
669
+ waiter; the writer retains physical capacity until settlement. There is no upload or managed replay API.
670
+ Use a durable application store or deployment-owned log collector when durable restart recovery, replay or
670
671
  aggregation is required. → [ADR 0134](../decisions/0134-diagnostic-journal-is-bounded-local-evidence.md).
671
672
 
673
+ For finite inspection, use the shared reader with an explicit oldest-to-newest list of existing
674
+ files. Keep anomaly reporting outside the journal being inspected:
675
+
676
+ ```ts
677
+ import { readDiagnosticJournal } from 'stitchkit/application/diagnostic-journal'
678
+ import { z } from 'zod'
679
+
680
+ const eventSchema = z.object({
681
+ kind: z.enum(['resource_failed', 'recovery_started']),
682
+ resource: z.string().max(80),
683
+ }).strict()
684
+
685
+ for await (const row of readDiagnosticJournal({
686
+ paths: ['/var/lib/example/diagnostic.jsonl.1', '/var/lib/example/diagnostic.jsonl'],
687
+ eventSchema,
688
+ maxLineBytes: 4 * 1024,
689
+ })) {
690
+ if (row.type === 'anomaly') internalLogger.warn(row.anomaly)
691
+ else inspectEvent(row.frame.event)
692
+ }
693
+ ```
694
+
695
+ The reader bounds memory by line size plus a fixed chunk, skips oversized/damaged rows with
696
+ explicit anomalies, and still returns valid rows before and after them. `offset` is zero-based
697
+ bytes; `line` is one-based. `position` distinguishes the file's tail from interior damage.
698
+ A valid frame lacking its final LF yields a warning with `skippedBytes: 0` and its frame.
699
+ Each file's size is captured at open; concurrent appends are excluded. Missing files, permissions,
700
+ symlinks, non-regular files and mid-read truncation throw rather than masquerading as bad data.
701
+ The caller owns file selection and coordination with an active rotator.
702
+
703
+ Writer startup inspects retained and active files under its lock. On damage,
704
+ `journal.getStatus().recovery` contains counts and first/last anomaly locations, reconstructed
705
+ again on restart from the preserved bytes. This describes startup observations, not live
706
+ continuous inspection. `maxFiles: 1` cannot preserve a torn active file by rotation and throws
707
+ `DiagnosticJournalRecoveryError` before removing any evidence; configure at least two slots.
708
+ Normal rotation retains the existing finite eviction policy. → [ADR 0219](../decisions/0219-journal-damage-is-data-and-io-failure-is-failure.md).
709
+
672
710
  Shutdown performs one phase barrier at a time: stop admission everywhere,
673
711
  cancel future schedules, drain admitted work, then close in reverse stable
674
712
  topological order. Every hook shares the same grace deadline. Forced cleanup
@@ -854,156 +892,3 @@ The responsibility change is more important than line count:
854
892
  Durable job tables, lifecycle journals/outboxes, provider inboxes and business
855
893
  retry rules do **not** disappear. They were never process-local glue and remain
856
894
  application-owned.
857
-
858
- ## Durable process facts and owner notifications
859
-
860
- `createProcessLifecycleLedger` records a bounded versioned list of process runs.
861
- Start, readiness, draining and shutdown target both `runId` and `pid`, so hot
862
- reload and PID reuse cannot close the wrong generation. `lifecycleLedgerResource`
863
- drives it from the kernel's phases: `start` records the start, `activate` the
864
- readiness, `stopAdmission` the drain — the run's `unavailableAt`, the moment it
865
- stops answering new work — and `close` / `force` the stop. A run that stops
866
- without ever becoming ready (a failed startup rolls back with `close` only)
867
- ends as `startup-failed`, not `clean`.
868
-
869
- A start classifies what happened to the newest run before it, and the
870
- classification is decided by four facts — whether that run recorded its own
871
- exit, whether the pid is the same, whether the version changed and whether it
872
- ever became ready:
873
-
874
- | newest run | same pid | version | `previousExit` | predecessor's `termination` |
875
- |---|---|---|---|---|
876
- | none | — | — | `first-boot` | — |
877
- | recorded `stoppedAt` | — | — | `clean` / `forced` / `startup-failed` / `abnormal` as recorded | unchanged |
878
- | still open | yes | — | `hot-reload` | `hot-reload`, closed at the new start |
879
- | still open | no | changed | `handoff` (default) | stays open; it records its own stop later |
880
- | still open | no | changed, `versionChangeOverlap: 'abnormal'` | `abnormal` / `startup-failed` | closed at the new start, as for the same version |
881
- | still open, was ready | no | same | `abnormal` (default) | `abnormal`, closed at the new start — an upper bound, the crash time is unknown |
882
- | still open, never ready | no | same | `startup-failed` (default) | `startup-failed`, closed at the new start |
883
-
884
- Every other open run the start finds was abandoned too and is closed the same
885
- way — two crashes in a row leave two open runs, and both are closed, not only
886
- the newest. Open means `active` or `draining`.
887
-
888
- A version of `unknown` on either side is never a version change, so a dev build
889
- after a crashed release reads `abnormal`, not `handoff`. `forced` means the
890
- process itself acknowledged a kill; `abnormal` means a successor found it dead.
891
-
892
- ### Downtime is the window nobody answered in
893
-
894
- `ReadyFact.downtimeMs` is `readyAt` of the new run minus `unavailableAt` of the
895
- last run that served — the predecessor's drain plus the successor's boot. A
896
- 110 s forced drain followed by a 4 s boot is 114 s of downtime; the gap between
897
- the two processes alone would read 4 s before and after that defect was fixed.
898
- Runs that never became ready answered nobody, so the count passes them: after a
899
- failed start it still opens where the last serving run stopped answering. It is
900
- `0` when that run still answers (a handoff whose predecessor has not drained
901
- yet) and `null` on first boot and when the end was never timed — a crash or a
902
- hot reload records no `unavailableAt`. `unavailableSince` names the moment it is
903
- counted from. The gap between two processes is still there, under its own
904
- name: `StartFact.processGapMs` is the start minus the predecessor's recorded
905
- stop.
906
-
907
- The ledger records what the process says while it can say it. stitchkit never
908
- calls `process.exit` (ADR 0074), so a stop is recorded on the kernel's `close`
909
- or `force` path, both awaited. An application that exits the process on its
910
- own before its shutdown settles loses that last write; the successor then
911
- finds the run open and closes it as `abnormal`, keeping the `unavailableAt`
912
- already recorded — which is why the drain moment is written first, at
913
- `stopAdmission`, and the downtime survives a stop that was never recorded.
914
-
915
- The `abnormal` default is a choice, and it is the single-process deployment:
916
- one process per build, a new pid of the same build means the old one stopped
917
- answering. Where processes of **one** build overlap on purpose — a cluster, a
918
- zero-downtime reload of the same build — pass `sameVersionOverlap: 'handoff'`
919
- to the ledger, and every open run stays open until it records its own
920
- shutdown. The cost of that setting is symmetric: a real crash under it is
921
- reported as a handoff and the dead run stays open in the ledger until
922
- retention drops it.
923
-
924
- A version change is the other axis, and its default is the opposite:
925
- `handoff`, because a release that starts the new build before stopping the
926
- old one is the common zero-downtime shape. Where builds never overlap — one
927
- process per deployment (a pm2 fork, a systemd unit, one container), the old
928
- one stopped before the new one starts — pass `versionChangeOverlap:
929
- 'abnormal'`. An open predecessor of another build then died without
930
- recording its exit, most often killed during the release itself: it is closed
931
- as `abnormal` (or `startup-failed`) at the new start, `downtimeMs` is `null`
932
- instead of `0`, and `previousVersion` / `versionChanged` still describe the
933
- release. A predecessor that did record its stop is read as before, and its
934
- downtime is measured. The two settings compose: `sameVersionOverlap:
935
- 'handoff'` keeps open only the runs of a build allowed to overlap the new one.
936
-
937
- The list is kept in the order the transitions wrote it —
938
- every write goes through one atomic update, so that order is the causal one,
939
- and a successor whose clock lags its predecessor still finds it at the head;
940
- `startedAt` is data, not the sort key. Retention (`retain`, default 20) drops
941
- finished runs first and an open one — a live handoff predecessor — only when
942
- nothing finished is left. Facts are published through the ledger's own
943
- subscription and resource value; `ApplicationEventSink` remains the strict
944
- application-state stream.
945
-
946
- `createNotificationOutbox` is the transport-neutral durable delivery side. It
947
- persists before send, claims an item with an expiring lease, carries one stable
948
- idempotency key into the transport, retries under an injected clock and records
949
- terminal drops. The guarantee is at-least-once: a crash after remote acceptance
950
- but before the receipt is persisted may redeliver, so transports should use the
951
- key when they support deduplication. The retry budget is sized for the outage
952
- an owner notification has to outlive, not for a flaky call: the default backoff
953
- doubles from one second and caps at sixty (`backoffDelay`, the one formula the
954
- client's resumable streams also use, with jitter 0), and the 99 waits between
955
- the default `maxAttempts` of 100 sum to 1+2+4+8+16+32 s plus 93 × 60 s — about
956
- 94 minutes — before `onDropped` sees `attempt-limit`.
957
- `state()` is a read and never fails on the bounds a transition enforces — a file
958
- that grew past `maxStateBytes` under an older limit is inspectable and is
959
- trimmed by the next transition. Two bounds do fail loudly: `enqueue` past
960
- `maxQueue` throws rather than dropping silently, and a `backoffMs` that returns
961
- `NaN`, a negative or an infinite delay rejects the flush. `stop()` lets the
962
- send in flight finish and claims nothing more; a `send` without its own
963
- deadline holds `stop()` — and so the resource's `force()` — for that one call,
964
- so give the transport a timeout. Superseding a key that is being sent right now
965
- does not recall it: the send completes, and only its receipt is not written.
966
-
967
- `createDirectoryInbox` is the receiving side for another program on the same
968
- host: it drops entries — a release transition, say — into a directory, and
969
- the application takes each one at least once. It is a managed resource of its
970
- own (`createDirectoryInbox({ id, directory, schema, handle })`, imported from
971
- `stitchkit/application/directory-inbox` because it touches files; its types
972
- and schemas are in `stitchkit/application`) and publishes a handle with
973
- `flush()` and `state()`. The producer writes each entry
974
- atomically as `<name>.json` — a temporary name, then a rename; names that start
975
- with a dot are never read. Entries are delivered in name order, and only after
976
- `activate`: none reaches the application before it is ready. `stopAdmission`
977
- stops taking new ones, `drain` waits for the one in flight, and `force` aborts
978
- the `signal` its handler was given.
979
-
980
- Taken and done are separate durable records. Before `handle` runs, the entry
981
- is claimed with a lease (`leaseMs`, default five minutes); after it returns,
982
- a receipt replaces the claim and only then is the file removed. A process that
983
- died mid-delivery leaves a claim, and the entry is taken again once the lease
984
- runs out — at least once, not exactly once, so a handler that sends somewhere
985
- should carry the entry's `key` as its idempotency key. A process that died
986
- after the receipt leaves only the file, which the next pass removes without
987
- delivering it again. A handler that throws is retried after a backoff from one
988
- second doubling to five minutes; an entry that fails `schema`, is over
989
- `maxEntryBytes` or was taken `maxAttempts` times (default 20 — the count
990
- survives restarts, so an entry whose handling kills the process is not taken
991
- forever) is moved to `rejected/` with its reason and reported to `onRejected`,
992
- and the entries after it keep flowing. The state lives in
993
- `<directory>/.inbox-state.json` under `createFileStateStore`'s inter-process
994
- lock unless a `store` is supplied.
995
-
996
- These primitives depend on the structural `StateStore`. On a server,
997
- `createFileStateStore` supplies the shared Zod-validated JSON adapter with an
998
- inter-process lock, unique temporary file, fsync and atomic rename. The lock
999
- is a file with a heartbeat: the holder refreshes its mtime every third of
1000
- `staleLockMs` (default 3 s), a contender waits up to `lockTimeoutMs` (default
1001
- 10 s), and the stale bound must sit inside the timeout — otherwise a crashed
1002
- holder blocks every update until the lock ages out, which the constructor
1003
- refuses. A lock whose heartbeat is stale is reclaimed once its recorded pid is
1004
- gone; a live or unverifiable pid (a reused number, another user's process)
1005
- keeps it for ten stale bounds — and never fewer than thirty missed heartbeats,
1006
- so a scheduler stall on a loaded host cannot pull a live lock from under its
1007
- holder — after which the heartbeat wins and the lock is abandoned. Temporary files a crashed writer left beside the state are swept on
1008
- the store's first update. Ledger corruption may be declared reconstructable;
1009
- an outbox must fail closed rather than silently discard pending delivery.
@@ -79,12 +79,12 @@ own, recorded as an ADR.
79
79
  | `stitchkit/geo` | server (Bun or Node) | evolving | managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter |
80
80
  | `stitchkit/oauth` | browser **and** server | evolving | provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics |
81
81
  | `stitchkit/google` | server (Bun or Node) | evolving | optional Google code exchange and verified OIDC identity adapter |
82
- | `stitchkit/observability` | server | stable<br>_redefined in 2 of the 46 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
82
+ | `stitchkit/observability` | server | stable<br>_redefined in 2 of the 48 minors since 0.56.2, most recently 0.92.0_ | request/tool event projections — `createObservability`, trace context, sanitisation |
83
83
  | `stitchkit/testing` | tests on Bun or Node | stable | in-process generated clients over a real Fetch handler, plus the managed-resource conformance kit |
84
84
  | `stitchkit/declaration` | browser + build and deployment tooling (Bun or Node) | evolving | `ProjectDeclarationSchema` — the one machine-readable statement a repository makes about itself |
85
85
  | `stitchkit/react` | browser + server rendering | stable | `createCursorQuery`, `createCacheBridge`, QueryClient and `ApiError` retry policy |
86
86
  | `stitchkit/react/keyboard` | browser | evolving | which part of a screen gets a key — ordered layers, one Escape per level, list zones with real focus; see [keyboard guide](keyboard.md) |
87
- | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the 46 minors since 0.56.2, most recently 0.97.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
87
+ | `stitchkit/agent-runtime` | server | evolving<br>_redefined in 22 of the 48 minors since 0.56.2, most recently 0.97.0_ | optional durable conversation/run loop, history, models, prompts, fencing and events |
88
88
  | `stitchkit/agent-runtime/sandbox` | server | evolving | optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see [sandbox guide](sandbox.md) |
89
89
  | `stitchkit/agent-runtime/testing` | tests on Bun or Node | evolving | credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit |
90
90
  | `stitchkit/agent-runtime/harness` | server | evolving | resource-aware process-local facade over the canonical Agent runtime; supervision stays outside |
@@ -94,11 +94,11 @@ own, recorded as an ADR.
94
94
  | `stitchkit/agent-runtime/sqlite/bun` | server (Bun) | evolving | durable built-in SQLite store for the agent runtime |
95
95
  | `stitchkit/agent-runtime/sqlite/node` | server (Node ≥ 22.5) | evolving | durable built-in SQLite store for the agent runtime |
96
96
  | `stitchkit-tui` | terminal (Bun) | evolving | optional official OpenTUI host over a caller-composed headless runtime |
97
- | `stitchkit/application` | browser + server | evolving<br>_redefined in 10 of the 46 minors since 0.56.2, most recently 0.100.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
97
+ | `stitchkit/application` | browser + server | evolving<br>_redefined in 11 of the 48 minors since 0.56.2, most recently 0.103.0_ | managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown |
98
98
  | `stitchkit/application/grammy` | server | evolving | a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter |
99
99
  | `stitchkit/application/opentelemetry` | server | evolving | maps application snapshots onto an injected OpenTelemetry `Meter` |
100
100
  | `stitchkit/application/schemas` | browser + server | evolving | the application's snapshot, health and shutdown schemas alone, without the kernel |
101
- | `stitchkit/application/diagnostic-journal` | server | evolving | the local diagnostic journal — the one part of the kernel that spawns, locks and writes files |
101
+ | `stitchkit/application/diagnostic-journal` | server | evolving | the local diagnostic journal — an exclusive bounded writer and snapshot reader with explicit anomalies |
102
102
  | `stitchkit/application/directory-inbox` | server | evolving | the directory inbox — entries another program drops into a directory, delivered to the application at least once |
103
103
 
104
104
  Rule of thumb: browser code imports `stitchkit` and `stitchkit/react`; server
package/llms/tools.2.txt CHANGED
@@ -365,6 +365,15 @@ multimodal content beside structured per-item `errors`, and charges every item
365
365
  to one total 20 MB batch budget. Its MCP and Agent presenters are built in;
366
366
  remote fetch cancellation follows the active call signal.
367
367
 
368
+ `paths` is one path/URL string or an actual array of strings (at most 20).
369
+ Pass `{ paths: ['image.png'] }`, not `{ paths: '["image.png"]' }`: a JSON
370
+ array written as text fails input validation before any file or network access,
371
+ with the hint `paths is a list written as text — pass an array of paths or one
372
+ path`. The same rule applies to array items and the raw `mountViewFile` input.
373
+ Ordinary file names containing brackets, such as `[preview].png`, remain valid.
374
+ A local file with an unsupported extension is refused before reading; its
375
+ per-item error identifies the caller's path and the extension it saw.
376
+
368
377
  The older `mountWait`, `mountDownload`, `mountUpload` and `mountViewFile`
369
378
  functions remain
370
379
  intentional raw MCP adapters with their text-envelope behavior. Use them under
package/llms/tools.3.txt CHANGED
@@ -113,7 +113,7 @@ payload.
113
113
  | `ToolCallContext` | _type_ | the context every tool hook receives — `{ source, mcp? }` plus whatever the mount's `context` added |
114
114
  | `ViewFileOptions` | _type_ | shared URL/managed-file-boundary policy for `defineViewFileTool`, `mountViewFile` and `resolveMedia` |
115
115
  | `ViewFileOutput` | _type_ | neutral managed batch result with multimodal `content` and per-item `errors` |
116
- | `ViewFileInputSchema` | constant | fixed one-or-many media path/URL input schema |
116
+ | `ViewFileInputSchema` | constant | one media path/URL or an array of at most 20; rejects a JSON array written as text, including in array items, before IO |
117
117
  | `ViewFileOutputSchema` | constant | Zod schema for the neutral managed view-file batch result |
118
118
  | `ViewFileErrorSchema` | constant | Zod schema for one structured per-item view failure |
119
119
  | `McpAnnotations` | _type_ | MCP annotations on a media result |