@plurnk/plurnk-service 1.7.0 → 1.8.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.
- package/.env.defaults +29 -42
- package/INSTALL.md +49 -10
- package/README.md +11 -1
- package/SPEC.md +631 -279
- package/digest-sql/channel-dispositions/dispositions.sql +15 -0
- package/digest-sql/channel-state/state.sql +6 -0
- package/digest-sql/curation/curation.sql +5 -0
- package/digest-sql/derivations/derivations.sql +4 -0
- package/digest-sql/embeddings/embeddings.sql +4 -0
- package/digest-sql/entry-dispositions/dispositions.sql +15 -0
- package/digest-sql/entry-state/state.sql +6 -0
- package/digest-sql/token-counts/token-counts.sql +2 -0
- package/dist/Paths.d.ts +2 -5
- package/dist/Paths.d.ts.map +1 -1
- package/dist/Paths.js +9 -21
- package/dist/Paths.js.map +1 -1
- package/dist/build-info.json +1 -1
- package/dist/content/read-projector.d.ts.map +1 -1
- package/dist/content/read-projector.js +4 -3
- package/dist/content/read-projector.js.map +1 -1
- package/dist/core/BudgetReadout.d.ts.map +1 -1
- package/dist/core/BudgetReadout.js +12 -22
- package/dist/core/BudgetReadout.js.map +1 -1
- package/dist/core/ChannelWrite.d.ts.map +1 -1
- package/dist/core/ChannelWrite.js.map +1 -1
- package/dist/core/ChannelWrite.sql +2 -1
- package/dist/core/Dispatcher.d.ts +7 -6
- package/dist/core/Dispatcher.d.ts.map +1 -1
- package/dist/core/Dispatcher.js +34 -88
- package/dist/core/Dispatcher.js.map +1 -1
- package/dist/core/Engine.d.ts +11 -8
- package/dist/core/Engine.d.ts.map +1 -1
- package/dist/core/Engine.js +45 -27
- package/dist/core/Engine.js.map +1 -1
- package/dist/core/Engine.sql +112 -107
- package/dist/core/ExecutorRegistry.d.ts +8 -2
- package/dist/core/ExecutorRegistry.d.ts.map +1 -1
- package/dist/core/ExecutorRegistry.js +6 -3
- package/dist/core/ExecutorRegistry.js.map +1 -1
- package/dist/core/HostPaths.d.ts +29 -0
- package/dist/core/HostPaths.d.ts.map +1 -0
- package/dist/core/HostPaths.js +74 -0
- package/dist/core/HostPaths.js.map +1 -0
- package/dist/core/LegacyHome.d.ts +10 -0
- package/dist/core/LegacyHome.d.ts.map +1 -0
- package/dist/core/LegacyHome.js +170 -0
- package/dist/core/LegacyHome.js.map +1 -0
- package/dist/core/LogBody.d.ts +1 -1
- package/dist/core/LogBody.d.ts.map +1 -1
- package/dist/core/LogBody.js +2 -2
- package/dist/core/LogBody.js.map +1 -1
- package/dist/core/LogEntryProjection.js +1 -1
- package/dist/core/LogEntryProjection.js.map +1 -1
- package/dist/core/LogVisibility.d.ts +28 -0
- package/dist/core/LogVisibility.d.ts.map +1 -0
- package/dist/core/LogVisibility.js +215 -0
- package/dist/core/LogVisibility.js.map +1 -0
- package/dist/core/LoopLifecycle.d.ts +1 -0
- package/dist/core/LoopLifecycle.d.ts.map +1 -1
- package/dist/core/LoopLifecycle.js +8 -0
- package/dist/core/LoopLifecycle.js.map +1 -1
- package/dist/core/LoopLifecycle.sql +10 -0
- package/dist/core/OperatorConfig.d.ts +6 -0
- package/dist/core/OperatorConfig.d.ts.map +1 -0
- package/dist/core/OperatorConfig.js +92 -0
- package/dist/core/OperatorConfig.js.map +1 -0
- package/dist/core/OverflowTurn.d.ts +11 -0
- package/dist/core/OverflowTurn.d.ts.map +1 -0
- package/dist/core/OverflowTurn.js +77 -0
- package/dist/core/OverflowTurn.js.map +1 -0
- package/dist/core/Owner.js +2 -2
- package/dist/core/Owner.js.map +1 -1
- package/dist/core/PacketBuilder.d.ts +3 -15
- package/dist/core/PacketBuilder.d.ts.map +1 -1
- package/dist/core/PacketBuilder.js +48 -121
- package/dist/core/PacketBuilder.js.map +1 -1
- package/dist/core/ProblemLog.js +1 -1
- package/dist/core/ProblemLog.js.map +1 -1
- package/dist/core/ProposalLifecycle.d.ts.map +1 -1
- package/dist/core/ProposalLifecycle.js +3 -23
- package/dist/core/ProposalLifecycle.js.map +1 -1
- package/dist/core/ProviderInstantiate.d.ts +9 -5
- package/dist/core/ProviderInstantiate.d.ts.map +1 -1
- package/dist/core/ProviderInstantiate.js +99 -104
- package/dist/core/ProviderInstantiate.js.map +1 -1
- package/dist/core/ResourceMutations.d.ts.map +1 -1
- package/dist/core/ResourceMutations.js +5 -3
- package/dist/core/ResourceMutations.js.map +1 -1
- package/dist/core/SchemeRegistry.d.ts +0 -1
- package/dist/core/SchemeRegistry.d.ts.map +1 -1
- package/dist/core/SchemeRegistry.js +7 -11
- package/dist/core/SchemeRegistry.js.map +1 -1
- package/dist/core/ToolResources.d.ts +19 -0
- package/dist/core/ToolResources.d.ts.map +1 -0
- package/dist/core/ToolResources.js +122 -0
- package/dist/core/ToolResources.js.map +1 -0
- package/dist/core/Turn.d.ts +27 -0
- package/dist/core/Turn.d.ts.map +1 -0
- package/dist/core/Turn.js +43 -0
- package/dist/core/Turn.js.map +1 -0
- package/dist/core/Turn.sql +72 -0
- package/dist/core/TurnOps.d.ts +7 -0
- package/dist/core/TurnOps.d.ts.map +1 -0
- package/dist/core/TurnOps.js +63 -0
- package/dist/core/TurnOps.js.map +1 -0
- package/dist/core/TurnRunner.d.ts +12 -4
- package/dist/core/TurnRunner.d.ts.map +1 -1
- package/dist/core/TurnRunner.js +1045 -898
- package/dist/core/TurnRunner.js.map +1 -1
- package/dist/core/WorkerName.d.ts +1 -1
- package/dist/core/WorkerName.d.ts.map +1 -1
- package/dist/core/env-defaults.d.ts.map +1 -1
- package/dist/core/env-defaults.js +7 -5
- package/dist/core/env-defaults.js.map +1 -1
- package/dist/core/fork.d.ts.map +1 -1
- package/dist/core/fork.js +15 -4
- package/dist/core/fork.js.map +1 -1
- package/dist/core/fork.sql +57 -27
- package/dist/core/git-env.d.ts +0 -1
- package/dist/core/git-env.d.ts.map +1 -1
- package/dist/core/git-env.js +0 -3
- package/dist/core/git-env.js.map +1 -1
- package/dist/core/git-membership.d.ts.map +1 -1
- package/dist/core/git-membership.js +10 -26
- package/dist/core/git-membership.js.map +1 -1
- package/dist/core/git-state.d.ts.map +1 -1
- package/dist/core/git-state.js +13 -14
- package/dist/core/git-state.js.map +1 -1
- package/dist/core/operation-target-groups.d.ts +3 -0
- package/dist/core/operation-target-groups.d.ts.map +1 -0
- package/dist/core/operation-target-groups.js +53 -0
- package/dist/core/operation-target-groups.js.map +1 -0
- package/dist/core/packet-inject.d.ts +0 -1
- package/dist/core/packet-inject.d.ts.map +1 -1
- package/dist/core/packet-inject.js +6 -13
- package/dist/core/packet-inject.js.map +1 -1
- package/dist/core/packet-wire.d.ts +4 -0
- package/dist/core/packet-wire.d.ts.map +1 -1
- package/dist/core/packet-wire.js +208 -44
- package/dist/core/packet-wire.js.map +1 -1
- package/dist/core/plurnk-uri.d.ts +1 -1
- package/dist/core/plurnk-uri.d.ts.map +1 -1
- package/dist/core/plurnk-uri.js +3 -3
- package/dist/core/plurnk-uri.js.map +1 -1
- package/dist/core/teaching.d.ts.map +1 -1
- package/dist/core/teaching.js +4 -5
- package/dist/core/teaching.js.map +1 -1
- package/dist/core/worker-settings.d.ts +9 -0
- package/dist/core/worker-settings.d.ts.map +1 -0
- package/dist/core/worker-settings.js +25 -0
- package/dist/core/worker-settings.js.map +1 -0
- package/dist/core/workspace-settings.d.ts +0 -11
- package/dist/core/workspace-settings.d.ts.map +1 -1
- package/dist/core/workspace-settings.js +3 -47
- package/dist/core/workspace-settings.js.map +1 -1
- package/dist/digest/Digest.d.ts.map +1 -1
- package/dist/digest/Digest.js +164 -92
- package/dist/digest/Digest.js.map +1 -1
- package/dist/digest/digest.sql +8 -2
- package/dist/observe/genai.d.ts +9 -0
- package/dist/observe/genai.d.ts.map +1 -0
- package/dist/observe/genai.js +31 -0
- package/dist/observe/genai.js.map +1 -0
- package/dist/observe/spans.d.ts +3 -3
- package/dist/observe/spans.d.ts.map +1 -1
- package/dist/observe/spans.js +20 -5
- package/dist/observe/spans.js.map +1 -1
- package/dist/schemes/EffectPolicy.d.ts +3 -0
- package/dist/schemes/EffectPolicy.d.ts.map +1 -1
- package/dist/schemes/EffectPolicy.js +38 -6
- package/dist/schemes/EffectPolicy.js.map +1 -1
- package/dist/schemes/Exec.d.ts.map +1 -1
- package/dist/schemes/Exec.js +55 -13
- package/dist/schemes/Exec.js.map +1 -1
- package/dist/schemes/Log.d.ts +6 -2
- package/dist/schemes/Log.d.ts.map +1 -1
- package/dist/schemes/Log.js +73 -22
- package/dist/schemes/Log.js.map +1 -1
- package/dist/schemes/Log.sql +25 -7
- package/dist/schemes/Prompt.d.ts.map +1 -1
- package/dist/schemes/Prompt.js +1 -2
- package/dist/schemes/Prompt.js.map +1 -1
- package/dist/schemes/QuestionTool.d.ts +10 -0
- package/dist/schemes/QuestionTool.d.ts.map +1 -0
- package/dist/schemes/QuestionTool.js +81 -0
- package/dist/schemes/QuestionTool.js.map +1 -0
- package/dist/schemes/Skill.d.ts.map +1 -1
- package/dist/schemes/Skill.js +4 -1
- package/dist/schemes/Skill.js.map +1 -1
- package/dist/schemes/Worker.d.ts.map +1 -1
- package/dist/schemes/Worker.js +20 -3
- package/dist/schemes/Worker.js.map +1 -1
- package/dist/schemes/_entry-crud.sql +19 -1
- package/dist/schemes/_entry-find.d.ts +5 -3
- package/dist/schemes/_entry-find.d.ts.map +1 -1
- package/dist/schemes/_entry-find.js +102 -22
- package/dist/schemes/_entry-find.js.map +1 -1
- package/dist/schemes/_entry-find.sql +8 -6
- package/dist/schemes/_entry-graph.sql +2 -6
- package/dist/schemes/_entry-manifest.d.ts.map +1 -1
- package/dist/schemes/_entry-manifest.js +12 -1
- package/dist/schemes/_entry-manifest.js.map +1 -1
- package/dist/schemes/_search-index.d.ts.map +1 -1
- package/dist/schemes/_search-index.js +37 -25
- package/dist/schemes/_search-index.js.map +1 -1
- package/dist/server/Daemon.d.ts +58 -7
- package/dist/server/Daemon.d.ts.map +1 -1
- package/dist/server/Daemon.js +551 -113
- package/dist/server/Daemon.js.map +1 -1
- package/dist/server/DrainSupervisor.d.ts +12 -9
- package/dist/server/DrainSupervisor.d.ts.map +1 -1
- package/dist/server/DrainSupervisor.js +59 -10
- package/dist/server/DrainSupervisor.js.map +1 -1
- package/dist/server/client-input.d.ts +5 -2
- package/dist/server/client-input.d.ts.map +1 -1
- package/dist/server/client-input.js +53 -34
- package/dist/server/client-input.js.map +1 -1
- package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
- package/dist/server/dispatch-as-plurnk.js +28 -6
- package/dist/server/dispatch-as-plurnk.js.map +1 -1
- package/dist/server/drain.sql +26 -11
- package/dist/server/envelope.d.ts +1 -1
- package/dist/server/envelope.d.ts.map +1 -1
- package/dist/server/envelope.js +4 -4
- package/dist/server/envelope.js.map +1 -1
- package/dist/server/envelope.sql +25 -1
- package/dist/server/lifecycle-recovery.sql +11 -1
- package/dist/server/logEntry.d.ts +2 -1
- package/dist/server/logEntry.d.ts.map +1 -1
- package/dist/server/logEntry.js +3 -2
- package/dist/server/logEntry.js.map +1 -1
- package/dist/server/logEntry.sql +7 -0
- package/dist/server/loop-model.d.ts +2 -2
- package/dist/server/loop-model.d.ts.map +1 -1
- package/dist/server/loop-model.js +23 -33
- package/dist/server/loop-model.js.map +1 -1
- package/dist/server/loopDocs.d.ts.map +1 -1
- package/dist/server/loopDocs.js +61 -10
- package/dist/server/loopDocs.js.map +1 -1
- package/dist/server/loopDocs.sql +4 -2
- package/dist/server/model-catalog.d.ts +3 -0
- package/dist/server/model-catalog.d.ts.map +1 -0
- package/dist/server/model-catalog.js +83 -0
- package/dist/server/model-catalog.js.map +1 -0
- package/dist/server/model-route.d.ts +7 -0
- package/dist/server/model-route.d.ts.map +1 -0
- package/dist/server/model-route.js +47 -0
- package/dist/server/model-route.js.map +1 -0
- package/dist/server/module-discovery.d.ts +13 -0
- package/dist/server/module-discovery.d.ts.map +1 -0
- package/dist/server/module-discovery.js +78 -0
- package/dist/server/module-discovery.js.map +1 -0
- package/dist/server/skillDocs.d.ts +9 -0
- package/dist/server/skillDocs.d.ts.map +1 -0
- package/dist/server/skillDocs.js +212 -0
- package/dist/server/skillDocs.js.map +1 -0
- package/dist/server/skillDocs.sql +14 -0
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +182 -123
- package/dist/service.js.map +1 -1
- package/migrations/001_schema.sql +424 -65
- package/package.json +37 -37
- package/dist/core/ExecutableTools.d.ts +0 -11
- package/dist/core/ExecutableTools.d.ts.map +0 -1
- package/dist/core/ExecutableTools.js +0 -49
- package/dist/core/ExecutableTools.js.map +0 -1
- package/dist/core/JournalTurn.d.ts +0 -9
- package/dist/core/JournalTurn.d.ts.map +0 -1
- package/dist/core/JournalTurn.js +0 -14
- package/dist/core/JournalTurn.js.map +0 -1
- package/dist/core/JournalTurn.sql +0 -10
- package/dist/core/git-iso.d.ts +0 -13
- package/dist/core/git-iso.d.ts.map +0 -1
- package/dist/core/git-iso.js +0 -267
- package/dist/core/git-iso.js.map +0 -1
- package/dist/core/search-gate.d.ts +0 -17
- package/dist/core/search-gate.d.ts.map +0 -1
- package/dist/core/search-gate.js +0 -77
- package/dist/core/search-gate.js.map +0 -1
- package/dist/digest/Digest.sql +0 -1
package/SPEC.md
CHANGED
|
@@ -26,18 +26,51 @@ flowchart LR
|
|
|
26
26
|
| **agent** | PLURNK | The plurnk runtime. Acts in-workspace as the reserved `plurnk` worker ({§actor-boundary} self-hosting), never a privileged singleton owning its own entries ({§entry-owner}, {§machine-processes}). |
|
|
27
27
|
| **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
|
|
28
28
|
| **worker** | Core | Durable actor and private history over one workspace. Owns its loops and log rows, may carry a `parent_worker_id`, and has one process-local cancellation scope while active. |
|
|
29
|
-
| **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413
|
|
30
|
-
| **turn** | Core | One
|
|
29
|
+
| **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 input-capacity failure · 429 model-turn ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
|
|
30
|
+
| **turn** | Core | One durable, producer-neutral batch of ordered operations. A turn may be authored by a model, client, plugin, or `_plurnk`; only a model turn assembles a packet and owns an emission call. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
|
|
31
31
|
| **model call** | Core/provider | One logical `provider.generate` invocation. Emission attempts and BARE inferences share this durable accounting owner; provider retries remain cardinal physical requests beneath it. Identity: `(turn_id, sequence)`. |
|
|
32
|
-
| **op** |
|
|
32
|
+
| **op** | Producer/core | One DSL operation a producer submits, parsed into a `PlurnkStatement`. One admitted source-backed turn produces an ordered PLAN…SEND program. |
|
|
33
33
|
| **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
|
|
34
|
-
| **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an
|
|
34
|
+
| **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an `op='error'` row ({§operation-results}). A source artifact carries no fabricated operation. |
|
|
35
35
|
| **dispatch** | Core | Routing a statement to its scheme's op handler. |
|
|
36
36
|
| **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
|
|
37
37
|
| **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
|
|
38
38
|
| **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
|
|
39
39
|
| **session** | Retired/unqualified | Not a PLURNK lifecycle noun. Use the actual core noun; a third-party standard may use only its explicitly qualified protocol term. <!-- lexicon-allow: this row defines the retired noun --> |
|
|
40
40
|
|
|
41
|
+
### §turn-record Producer-neutral turn record
|
|
42
|
+
|
|
43
|
+
A turn is the durable container for one producer's ordered operations. Packet
|
|
44
|
+
and provider fields are optional evidence belonging only to model inference;
|
|
45
|
+
their absence never makes a client, plugin, or `_plurnk` turn exceptional.
|
|
46
|
+
|
|
47
|
+
| Field | Contract |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `producer` | Required actor class: `model`, `client`, `plugin`, or `_plurnk`. |
|
|
50
|
+
| `kind` | Required purpose: `inference`, `initialization`, `overflow`, or `operation`. Model iff inference; initialization and overflow require `_plurnk`. |
|
|
51
|
+
| `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the exact terminal SEND/operation disposition and timestamp; a completed 102 is therefore distinct from an open 102. |
|
|
52
|
+
| Operations | Ordered by `(turn_id, sequence)` on one exact worker/loop/turn chain. Each row's `origin` is the turn producer or `_plurnk` making a system observation; the observation does not impersonate the producer. |
|
|
53
|
+
| `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one undecorated actionless log item under {§turn-ops-entry}. The item supplements rather than replaces the executed operation rows. |
|
|
54
|
+
| Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
|
|
55
|
+
|
|
56
|
+
One lifecycle owner opens, optionally records inference evidence, and completes
|
|
57
|
+
every turn. Initialization, overflow recovery, client dispatch, and model
|
|
58
|
+
inference use that same path. `plugin` is the producer identity for
|
|
59
|
+
plugin-authored operation turns; exposing that path must not introduce a
|
|
60
|
+
parallel record or lifecycle. The sole identity transition is an open,
|
|
61
|
+
evidence-free model/inference candidate becoming `_plurnk`/overflow before
|
|
62
|
+
provider admission. Process-restart recovery completes any turn whose producer
|
|
63
|
+
vanished.
|
|
64
|
+
|
|
65
|
+
§turn-ops-admission-path **Source acquisition varies; admitted-turn execution does not.**
|
|
66
|
+
A provider response, deterministic `_plurnk` program, or future client/plugin
|
|
67
|
+
program crosses one admission boundary into the same executor. That executor
|
|
68
|
+
parses once, dispatches the admitted statements in order, records their ordinary
|
|
69
|
+
outcomes and the exact `turnOps`, and completes the turn from its SEND ruling.
|
|
70
|
+
Provider attempts, grammar recovery, reasoning, and accounting end before this
|
|
71
|
+
shared seam. A programmatic operation batch that supplied no Plurnk source does
|
|
72
|
+
not fabricate verbatim source.
|
|
73
|
+
|
|
41
74
|
### §storage-terms Storage terms
|
|
42
75
|
|
|
43
76
|
| Term | Meaning |
|
|
@@ -64,9 +97,9 @@ Independent axes on entries and channels. Confusion across them is a recurring s
|
|
|
64
97
|
|
|
65
98
|
| Term | Meaning |
|
|
66
99
|
|---|---|
|
|
67
|
-
| **writer** | The identity authoring a write. One of `model \| client \|
|
|
100
|
+
| **writer** | The identity authoring a write. One of `model \| client \| _plurnk \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
|
|
68
101
|
| **origin** | Synonym for writer in log_entries (`log_entries.origin`). Historical naming; treat as equivalent. |
|
|
69
|
-
| **writable_by** | The set of writers a scheme accepts. Subset of `{model, client,
|
|
102
|
+
| **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
|
|
70
103
|
|
|
71
104
|
### §engine-rails Engine rails
|
|
72
105
|
|
|
@@ -183,6 +216,19 @@ OpenTelemetry may observe PLURNK; it never becomes product state, failure transp
|
|
|
183
216
|
|
|
184
217
|
Configuration uses the standard `OTEL_*` environment: `OTEL_TRACES_EXPORTER` / `OTEL_METRICS_EXPORTER` select `otlp` or `console` per signal (a missing or `none` value keeps that signal off; no SDK default selects an exporter), `OTEL_SERVICE_NAME` names the service (default `plurnk-service`), case-insensitive `true` in `OTEL_SDK_DISABLED` turns the boundary off, and OTLP exporters honor `OTEL_EXPORTER_OTLP_*`. An unknown exporter name fails daemon boot; a typo never silently disables observation. OTel Logs and direct draft semantic-convention use are excluded. HTTP spans carry only an AG-UI-owned bounded route class, never an input pathname or query. Spans otherwise carry high-cardinality identifiers; metric labels stay low-cardinality. Prompts, reasoning, file bodies, arbitrary URLs, secrets, and plugin payloads are never recorded as attributes or metric values by default. Exporter failure cannot change product results or client lifecycle. Daemon, telemetry, and database teardown are independent reverse-ownership phases; every phase runs and aggregate failure preserves every cause.
|
|
185
218
|
|
|
219
|
+
§observability-genai-conventions **GenAI convention projection.** Provider
|
|
220
|
+
request spans use the OpenTelemetry GenAI semantic conventions: a
|
|
221
|
+
CLIENT-kind `gen_ai.client.request` span carrying `gen_ai.operation.name`
|
|
222
|
+
(`chat`), `gen_ai.system` (the provider alias), and `gen_ai.request.model`;
|
|
223
|
+
on settlement it gains `gen_ai.usage.input_tokens` and
|
|
224
|
+
`gen_ai.usage.output_tokens` from validated accounting plus
|
|
225
|
+
`gen_ai.response.finish_reasons`; failures carry `error.type` as the class
|
|
226
|
+
name only. Plurnk custom attributes (attempt, kind, status, loop/turn ids)
|
|
227
|
+
ride alongside and never replace the convention attributes. The redaction
|
|
228
|
+
boundary is unchanged — no prompts, reasoning, bodies, or URLs. This is the
|
|
229
|
+
sanctioned exception to the blanket draft-convention exclusion; no other
|
|
230
|
+
draft convention is projected.
|
|
231
|
+
|
|
186
232
|
### §in-process In-process architecture
|
|
187
233
|
|
|
188
234
|
Composed daemon internals + admin CLI. Four plug points:
|
|
@@ -190,7 +236,7 @@ Composed daemon internals + admin CLI. Four plug points:
|
|
|
190
236
|
- **Providers** ({§provider}) — LLM transports. Engine sends a turn's messages, receives raw content + usage; engine parses the content into `PlurnkStatement[]`.
|
|
191
237
|
- **Schemes** ({§scheme}) — addressed capabilities. A scheme handler interprets targets under its prefix and owns its storage substrate.
|
|
192
238
|
- **Mimetypes** ({§mimetype}) — content interpretation. Render-time handlers consume channel content; framework owns the dispatch.
|
|
193
|
-
- **Executors** ({§exec} / {§bundled-set}) — EXEC runtime dispatch for subprocess,
|
|
239
|
+
- **Executors** ({§exec} / {§bundled-set}) — EXEC runtime dispatch for subprocess, data, and pure-computation runtimes; web discovery rides the ordinary MCP surface.
|
|
194
240
|
|
|
195
241
|
Core's internal owners compose without becoming new package or public seams:
|
|
196
242
|
|
|
@@ -199,7 +245,7 @@ Core's internal owners compose without becoming new package or public seams:
|
|
|
199
245
|
| `Daemon` | Process/module lifecycle, dependency composition, provider policy, notifications, and the external client façade. |
|
|
200
246
|
| `DrainSupervisor` | One worker's queue consumer, drain identity, wake obligations, cancellation scope, poll/park timers, and terminal cleanup. |
|
|
201
247
|
| `Engine` | Loop lifecycle and the public turn, dispatch, derivation, and proposal façades. |
|
|
202
|
-
| `TurnRunner` |
|
|
248
|
+
| `TurnRunner` | Model inference plus `_plurnk` initialization/overflow turns from materialization through operation settlement. |
|
|
203
249
|
| `Dispatcher` | Operation admission/routing, scheme execution, proposal waiting, curation, and durable log writes. |
|
|
204
250
|
| `ResourceMutations` | EDIT/COPY/MOVE selection, anchor preconditions, cross-scheme effects, and mutation settlement. |
|
|
205
251
|
|
|
@@ -294,17 +340,49 @@ ambient shared-state changes still cross only through the environment door.
|
|
|
294
340
|
Git membership includes tracked and untracked-but-not-ignored project files
|
|
295
341
|
({§membership-auto-add}); it does not stage them or run `git add`.
|
|
296
342
|
|
|
297
|
-
§
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
§actor-boundary-
|
|
306
|
-
|
|
307
|
-
|
|
343
|
+
§turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
|
|
344
|
+
`<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the kernel-owned
|
|
345
|
+
`worker://plurnk/agents.md` entry and the engine foists one READ of it into
|
|
346
|
+
each model worker's first turn — visible, logged, line-addressable. Absent
|
|
347
|
+
file: no entry, no stunt, nothing 404s. The global XDG configuration `AGENTS.md`
|
|
348
|
+
remains system-prompt policy ({§policy-sections}); the stunt carries only
|
|
349
|
+
local repo guidance.
|
|
350
|
+
|
|
351
|
+
§actor-boundary-doc-injection **The project AGENTS.md uses the actor
|
|
352
|
+
path.** The project's `AGENTS.md` is materialized as
|
|
353
|
+
`worker://plurnk/agents.md` through a `DispatchAsPlurnk` EDIT, then foisted as
|
|
354
|
+
one READ into each model worker's turn 0 ({§turn0-agents-stunt}). The
|
|
355
|
+
materializing EDIT remains in the `plurnk` worker's log; the model sees the
|
|
356
|
+
shared entry through its own READ.
|
|
357
|
+
|
|
358
|
+
§actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS`
|
|
359
|
+
foists turn-0 discovery into the worker's first turn, so a worker opens with a
|
|
360
|
+
navigable map instead of blank. An enabled preview executes exactly six baseline
|
|
361
|
+
bodyless FIND surveys in order: authored skills (`## FIND0 [+init,+skills]
|
|
362
|
+
(worker://plurnk/skills/*.md) <1,-1>`), Plurnk-generated reference families
|
|
363
|
+
(`## FIND0 [+init,+skills] (worker://plurnk/skills/plurnk/*.md) <1,-1>`), enabled
|
|
364
|
+
tool families (`## FIND0 [+init,+tools] (worker://plurnk/tools/*.md) <1,-1>`),
|
|
365
|
+
project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init]
|
|
366
|
+
(worker:///*)`), and the worker's own space (`## FIND0 [+init] (worker://~/*)`).
|
|
367
|
+
The catalogs select every direct document independently of its authored body;
|
|
368
|
+
ordinary READ supplies its examples and complete instructions on demand. Their
|
|
369
|
+
log classifications make the opening discovery one `init` set while retaining
|
|
370
|
+
`skills` or `tools` on the corresponding rows ({§log-item-tags}). A shallow
|
|
371
|
+
result renders direct entries normally and every deeper first-segment directory
|
|
372
|
+
as an actionable `dir/**` summary with its recursive `items` and `tokens`;
|
|
373
|
+
tool-family rows also carry the concise `{§scheme-catalog-summary}` that drives
|
|
374
|
+
on-demand capability discovery. Ordinary surveys use FIND's markerless first-16
|
|
375
|
+
page, whose range metadata reports the requested and returned page against the
|
|
376
|
+
complete result total; only the small curated skills and tools surfaces
|
|
377
|
+
explicitly select all. The opening survey demonstrates both `*` and `**` without
|
|
378
|
+
normalizing an all-results override. Every survey executes even when empty
|
|
379
|
+
because zero results are useful orientation. A positive `N` explicitly caps
|
|
380
|
+
only the file map's rendered rows, using the map's actual
|
|
381
|
+
direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
|
|
382
|
+
unset / `0` disables previews. `log://` is absent because the current worker's
|
|
383
|
+
log already renders in present mode.
|
|
384
|
+
|
|
385
|
+
§worker-initialization-entry **Worker initialization is a real `_plurnk` turn.** A worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, orienting READ/FIND, and terminal `SEND0 [102]` rows. Every row is structurally classified `_plurnk` and `init`. The PLAN states `* Discover the tooling available and survey the workspace file root.`; SEND hands off with `Next: Address the prompt.` The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate.
|
|
308
386
|
|
|
309
387
|
### §machine-processes The machine and its processes: workspace, worker, fork
|
|
310
388
|
|
|
@@ -340,14 +418,14 @@ terminal history.**
|
|
|
340
418
|
| Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
|
|
341
419
|
| Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
|
|
342
420
|
| Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
|
|
343
|
-
| Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags,
|
|
421
|
+
| Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, folded body intervals, and the matching observation cursor are copied as terminal history. |
|
|
344
422
|
| §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but `model_calls`, emission-admission rows, and physical provider requests are not: one issued call or request has one owning worker. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
|
|
345
423
|
| Private worker entries (`worker://~/...`) | Worker | Deep-copied with ownership remapped; parent and child then diverge. |
|
|
346
424
|
| Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
|
|
347
425
|
|
|
348
426
|
§machine-processes-worker-is-its-log **A worker's conversational memory of
|
|
349
427
|
the shared world is its log, with no hidden per-worker snapshot beside it.**
|
|
350
|
-
OPEN/FOLD changes
|
|
428
|
+
OPEN/FOLD changes canonical folded body intervals on that worker's rows ({§open-fold});
|
|
351
429
|
environment changes arrive as attributed log entries ({§env-delta}). Private
|
|
352
430
|
worker entries are deliberate scratch that the worker reads and writes through
|
|
353
431
|
`worker://~/...`, not an invisible mirror of shared state. The environment door
|
|
@@ -356,7 +434,7 @@ therefore carries only shared project-file and shared-entry changes
|
|
|
356
434
|
|
|
357
435
|
§machine-processes-model-worker-readable **A worker's log is private to packets, not to the workspace.** Isolation ({§actor-boundary}) governs what an *actor* sees — its own worker, never a sibling's. It does not wall off the client interface: `readLog({ workspaceId, workerId })` may read any ownership-verified worker in that workspace, and `listWorkers` enumerates them. A client-interface module chooses the default worker from its own conversation binding. The read is observation, never packet membership — no actor sees it.
|
|
358
436
|
|
|
359
|
-
§machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `
|
|
437
|
+
§machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `_plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by a fork. `listWorkers` returns it, so a client interface identifies actor class without parsing the name, which is set at instantiation and immutable (a worker is permanent history, {§machine-processes-worker-is-its-log}).
|
|
360
438
|
|
|
361
439
|
§worker-provider-identity **A worker owns a durable provider identity distinct
|
|
362
440
|
from its database id.** Creation mints a globally unique, opaque 128-bit value;
|
|
@@ -380,7 +458,7 @@ or membership overlay requires a new workspace.
|
|
|
380
458
|
|
|
381
459
|
### §worker-scheme The worker:// scheme — the knowledgebase (commons, own space, named spaces, the kernel surface) and worker control (spawn, irc, fork, terminate, cap, collect)
|
|
382
460
|
|
|
383
|
-
§worker-authority-carving **The authority names the OWNER:** `worker:///notes.md` is in the COMMONS — a shared blackboard; `worker://~/draft.md` is the calling worker's own private space; `worker://<name>/result.md` is a named worker's space; `worker://plurnk/
|
|
461
|
+
§worker-authority-carving **The authority names the OWNER:** `worker:///notes.md` is in the COMMONS — a shared blackboard; `worker://~/draft.md` is the calling worker's own private space; `worker://<name>/result.md` is a named worker's space; `worker://plurnk/skills/…` is the kernel's published surface, world-readable ({§skills-materialization}). Storage keys the owner on the entries.owner_id column ({§entry-owner}) — the pathname is always the bare entry path, and a FIND's result paths re-apply the queried authority so the model sees the address it typed. `~` is the sole current-worker sigil and cannot be minted; `commons` and `plurnk` are internal worker names unavailable for minting. Every other mintable authority, including `self`, is a literal worker name ({§worker-name}).
|
|
384
462
|
|
|
385
463
|
§worker-name-minting **URI ingestion is permissive; worker minting is not.**
|
|
386
464
|
Every model/client worker-creation door applies the contracts-owned
|
|
@@ -425,7 +503,7 @@ literal `workers.name` value.
|
|
|
425
503
|
| `KILL` | existing literal name, `~` | Terminate the named worker or caller. |
|
|
426
504
|
|
|
427
505
|
- §worker-scheme-spawn **Spawn** — `## WORK0 (worker://<name>)` with a task body creates a new worker sister (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
|
|
428
|
-
- §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
|
|
506
|
+
- §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). A fresh receiving loop retains that worker's durable model, spawn override, and reasoning policy; the sender and daemon default do not re-select it. `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
|
|
429
507
|
- §worker-scheme-fork **Fork** — `## FORK0 (worker://<name>)` with a task body branches the
|
|
430
508
|
current worker into a **named** sister: its log is deep-copied
|
|
431
509
|
({§machine-processes-fork-copies-the-log}), which continues with `task`; the
|
|
@@ -685,7 +763,7 @@ Three current entry points:
|
|
|
685
763
|
- §provider-surface-capacity `provider.assessRequestCapacity(messages, maxOutputTokens?, signal?)` — provider-owned intersection of request-shaped token evidence and every known physical input limit. It admits, rejects only a proven exact overflow, or defers ambiguity to upstream ({§tokenomics-context-envelope-admission}). `generate` performs this assessment for its exact request and preserves the evidence on success and capacity failure.
|
|
686
764
|
- §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — the cancellable complete-request measurement primitive used by provider capacity assessment, with `exact`, `upper_bound`, `estimate`, or `unavailable` provenance. Core never substitutes this physical fact for its curation ruler.
|
|
687
765
|
|
|
688
|
-
§provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF
|
|
766
|
+
§provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF admission also consumes `constrainsOutput` ({§grammar-configuration-admission}).
|
|
689
767
|
|
|
690
768
|
§meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
|
|
691
769
|
|
|
@@ -703,9 +781,11 @@ Three current entry points:
|
|
|
703
781
|
|
|
704
782
|
A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission asks whether the exchange has a trustworthy frame: its first parsed operation is PLAN, its last parsed operation is a terminal SEND, every hard parse error is bounded between those anchors, and no `unparsedTail` exists. Missing anchors, an error outside the frame, or a boundary-destroying tail rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}).
|
|
705
783
|
|
|
706
|
-
|
|
784
|
+
§safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, or OPEN only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order; scheduling may still move the complete operation class under {§op-mode-phases}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
|
|
707
785
|
|
|
708
|
-
|
|
786
|
+
Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `model_calls` row and its emission-specific `turn_attempts` admission row. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. Beneath the model call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone extends `turns.packet` with response evidence; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
|
|
787
|
+
|
|
788
|
+
The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
|
|
709
789
|
|
|
710
790
|
An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND signal `200` or an already-drained signal `202` from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
|
|
711
791
|
The Problem recovery states that only the failed operation needs correction
|
|
@@ -759,27 +839,42 @@ it or reinterpret a malformed tag list.
|
|
|
759
839
|
service-side caching, per-loop selection, context-cap handling, and local GBNF
|
|
760
840
|
verification. Cataloged providers use Models.dev metadata and official AI SDK
|
|
761
841
|
bindings; an operator declaration covers an uncataloged compatible endpoint;
|
|
762
|
-
plugin discovery is the last protocol-extension seam.
|
|
842
|
+
plugin discovery is the last protocol-extension seam. Cache identity includes
|
|
843
|
+
the alias, wire route, and complete provider-knob projection; a registered
|
|
844
|
+
preconstructed handle occupies that same identity and cannot shadow changed
|
|
845
|
+
tuning.
|
|
763
846
|
|
|
764
|
-
§grammar-
|
|
847
|
+
§grammar-configuration-admission **Optional local GBNF is admitted without model generation.**
|
|
765
848
|
The ANTLR grammar always defines and validates the PLURNK language. Separately,
|
|
766
|
-
an operator may configure `
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
849
|
+
an operator may configure global `PLURNK_PROVIDERS_GBNF` or
|
|
850
|
+
`PLURNK_PROVIDERS_GBNF_<alias>` for a local
|
|
851
|
+
llama-server. Startup requires the provider to advertise GBNF transport and a
|
|
852
|
+
reasoning-compatible configuration, but daemon lifecycle grants no inference
|
|
853
|
+
or spending authority and therefore generates no verification tokens. The
|
|
854
|
+
setting is resolved globally for an exact route and per alias for a declared
|
|
855
|
+
alias; it is unset by default. Configuring it on a cloud
|
|
856
|
+
or endpoint-managed provider is an error, not a request for best-effort
|
|
857
|
+
filtering. Every user-authorized constrained generation proves transport through
|
|
858
|
+
its exact pre-projection evidence ({§rail-truth-engine-verdict}). Alias-scoped
|
|
859
|
+
`PLURNK_PROVIDERS_GBNF_DEBUG` is the explicit exception: it deliberately
|
|
860
|
+
withholds transport while retaining local grammar validation and the engine's
|
|
861
|
+
withheld-rail verdict. Runtime injection uses the provider's registered alias,
|
|
862
|
+
falling back only to a real process-active alias; an alias-free route uses the
|
|
863
|
+
global setting and ignores unrelated suffixes. A configured package variant or
|
|
864
|
+
explicit path that cannot be loaded also fails; it never silently becomes
|
|
865
|
+
unconstrained.
|
|
866
|
+
|
|
867
|
+
§grammar-rail-registration **Rail variants are built-in names or import
|
|
868
|
+
specifiers.** A bare variant (no `/`, no `:`) resolves as a built-in rail
|
|
869
|
+
subpath under `@plurnk/plurnk-contracts`. Any other variant form is an import
|
|
870
|
+
specifier — an absolute or relative operator file path, or a package export
|
|
871
|
+
subpath (e.g. `@acme/plurnk-rails/custom.gbnf`) — resolved through the Node
|
|
872
|
+
resolution chain, so a third-party rail package plugs in with no built-in
|
|
873
|
+
registry. An unresolvable or unreadable rail fails the constrained generation
|
|
874
|
+
loudly; it never silently becomes unconstrained.
|
|
780
875
|
|
|
781
876
|
§gbnf-requires-reasoning Both shipped PLURNK rails require reasoning. The same alias-scoped configuration
|
|
782
|
-
must resolve reasoning to `adaptive` or
|
|
877
|
+
must resolve reasoning to `adaptive` or a supported fixed effort; `off` with GBNF is rejected before
|
|
783
878
|
the probe or any model generation. Reasoning-off remains valid when no GBNF rail
|
|
784
879
|
is configured.
|
|
785
880
|
|
|
@@ -787,9 +882,9 @@ is configured.
|
|
|
787
882
|
For a configured local GBNF, the provider returns the pre-projection sentence as
|
|
788
883
|
`grammarEvidence` under `plurnk-providers` {§gbnf-response-observation}. The engine
|
|
789
884
|
requires that evidence, independently validates `grammarEvidence.input` with the
|
|
790
|
-
artifact's declared response root, and
|
|
791
|
-
stamps `railsAttached: "client"`
|
|
792
|
-
plus `railsVerdict`; it never validates projected
|
|
885
|
+
artifact's declared response root, and requires `transported: true` unless the
|
|
886
|
+
operator explicitly enabled debug mode. It stamps `railsAttached: "client"`
|
|
887
|
+
when transported or `"withheld"` in debug mode plus `railsVerdict`; it never validates projected
|
|
793
888
|
`assistant.content` as though the required reasoning enclosure were still
|
|
794
889
|
present. A non-accept verdict emits one `grammar_unenforced` notice. A raw
|
|
795
890
|
position at or after `contentStart` is translated to a content offset; a failure
|
|
@@ -962,7 +1057,9 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
|
|
|
962
1057
|
|
|
963
1058
|
- §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). A FIND signal classifies the FIND result row and never changes this candidate set ({§log-item-tags}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not a plugin seam and grants no protocol scheme an alternate READ path.
|
|
964
1059
|
- §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND works uniformly across schemes by construction: `EntryFind` and `Log.find` run the one shared primitive rather than re-implementing it per scheme. Log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
|
|
965
|
-
- §
|
|
1060
|
+
- §channel-selection-visibility **Channel selection is decision-time information, not a guess** — every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, mimetype, tokens, and lines (default channel first), and matcher locations name the channel their line coordinates address. The packet never presents channels as equal and indistinguishable; extents derive from the stored channels by construction. Budget enforcement stays with {§overflow-turn} — this is information, not a second guard.
|
|
1061
|
+
|
|
1062
|
+
- §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{channel?,locator?,region?}`; `channel` names the entry channel the finding was located in and is absent for channel-less resources such as log rows, so line coordinates cannot be mis-attributed across channels of the same resource ({§channel-selection-visibility}). `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
|
|
966
1063
|
|
|
967
1064
|
`## SEND0 [410] (path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
|
|
968
1065
|
|
|
@@ -981,7 +1078,7 @@ interface PlurnkSchemeContext {
|
|
|
981
1078
|
readonly workerId: number;
|
|
982
1079
|
readonly loopId: number;
|
|
983
1080
|
readonly turnId: number;
|
|
984
|
-
readonly writer: "model" | "client" | "
|
|
1081
|
+
readonly writer: "model" | "client" | "_plurnk" | "plugin"; // WriterTier
|
|
985
1082
|
readonly signal: AbortSignal | undefined;
|
|
986
1083
|
readonly streamEventNotify?: StreamEventNotify;
|
|
987
1084
|
readonly wakeWorkerNotify?: WakeWorkerNotify;
|
|
@@ -1008,7 +1105,7 @@ Engine → scheme guarantees:
|
|
|
1008
1105
|
returns `200`, while only a retained live representation may return `102`
|
|
1009
1106
|
({§read-preparation}). No public handler can replace READ.
|
|
1010
1107
|
- Exact FIND uses the same resolved identity and representation preparation
|
|
1011
|
-
before standard entry selection, then composes the exact
|
|
1108
|
+
before standard entry selection, then composes the exact selected channel's
|
|
1012
1109
|
durable producer result with the core-owned query projection. Broad FIND may invoke a custom `find()` for
|
|
1013
1110
|
genuinely protocol-owned candidate enumeration, or `prepareFind()` followed
|
|
1014
1111
|
by the standard catalog query. Acquisition never owns matcher, pagination,
|
|
@@ -1121,7 +1218,7 @@ model-independent ruler for stored/catalog weights and the model-facing curation
|
|
|
1121
1218
|
confined to provider-owned physical capacity assessment
|
|
1122
1219
|
({§tokenomics-context-envelope-admission}).
|
|
1123
1220
|
|
|
1124
|
-
§persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass.
|
|
1221
|
+
§persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass. Every addressable entry channel supplies the exact readable representation its READ exposes; `LogBody` resolves each log row's canonical full body from its durable tx/rx envelope. Acquisition schemes project remote source material before storing addressable channels; search never introduces a second hidden text projection. The channel content, mimetype, resolved text/binary classification, mimetype projection identity, embedder configuration, and applicable search exclusion form a content hash. Complete artifacts own FTS, vectors, symbol definitions, and references; each `entry_channels` row or log row holds only its own attachment hash. Binary, empty, and excluded derivations do not invoke handler projections and therefore use one fixed no-projection identity.
|
|
1125
1222
|
|
|
1126
1223
|
§search-exclusion **File-search eligibility is Core policy.**
|
|
1127
1224
|
`PLURNK_SERVICE_SEARCH_EXCLUDE` is a comma-separated table of anchored
|
|
@@ -1129,21 +1226,21 @@ body-glob patterns. Patterns containing `/` match the full pathname; every
|
|
|
1129
1226
|
other pattern matches the basename. Whitespace around entries is ignored, an
|
|
1130
1227
|
empty setting excludes nothing, and the first match is the observable reason.
|
|
1131
1228
|
|
|
1132
|
-
| Search subject
|
|
1133
|
-
|
|
1134
|
-
| `file` entry
|
|
1135
|
-
| Other-scheme
|
|
1136
|
-
| Log projection
|
|
1229
|
+
| Search subject | Exclusion evaluation |
|
|
1230
|
+
|----------------------|---------------------------------------------------------|
|
|
1231
|
+
| `file` entry | Apply the configured repository-path patterns once. |
|
|
1232
|
+
| Other-scheme channel | Always eligible; its pathname is a resource identity. |
|
|
1233
|
+
| Log projection | Always eligible; it has no repository-path membership. |
|
|
1137
1234
|
|
|
1138
1235
|
A match produces the `excluded` derivation disposition and suppresses graph,
|
|
1139
|
-
FTS, and vectors while leaving the stored
|
|
1236
|
+
FTS, and vectors while leaving the stored channel and direct READ unchanged. The
|
|
1140
1237
|
same reason participates in the derivation hash and is surfaced by diagnostics
|
|
1141
1238
|
and digests. Mimetype detection and projection do not read or report this
|
|
1142
1239
|
scheme policy.
|
|
1143
1240
|
|
|
1144
1241
|
```mermaid
|
|
1145
1242
|
flowchart LR
|
|
1146
|
-
E["entry
|
|
1243
|
+
E["entry channel"] --> P["exact addressed READ"]
|
|
1147
1244
|
L["log result envelope"] --> P
|
|
1148
1245
|
P --> H["content-addressed derivation"]
|
|
1149
1246
|
H --> F["FTS"]
|
|
@@ -1156,7 +1253,7 @@ flowchart LR
|
|
|
1156
1253
|
G --> Q
|
|
1157
1254
|
```
|
|
1158
1255
|
|
|
1159
|
-
§derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected candidate—and graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Normal execution joins the eager workspace warm before model dispatch, so that response is an interface invariant and diagnostic, not a lazy-search mode.
|
|
1256
|
+
§derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected channel candidate—and every channel in graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Normal execution joins the eager workspace warm before model dispatch, so that response is an interface invariant and diagnostic, not a lazy-search mode.
|
|
1160
1257
|
|
|
1161
1258
|
The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the `@graph` matcher cannot name an empty symbol; that one definition is omitted from graph storage without suppressing FTS, vectors, or the remaining definitions. Invalid references and other persistence violations still fail the resource derivation explicitly.
|
|
1162
1259
|
|
|
@@ -1247,8 +1344,9 @@ Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkState
|
|
|
1247
1344
|
|
|
1248
1345
|
### §line-anchors Text line anchors
|
|
1249
1346
|
|
|
1250
|
-
A scheme declaring `textEditScopes: true` with model
|
|
1251
|
-
the contracts-owned {§text-line-anchor-syntax}.
|
|
1347
|
+
A scheme declaring `lineAnchors: true`, or `textEditScopes: true` with model
|
|
1348
|
+
write authority, publishes the contracts-owned {§text-line-anchor-syntax}.
|
|
1349
|
+
Model-writable `textEditScopes` implies anchors; `lineAnchors` alone makes no EDIT claim. For canonical model-facing
|
|
1252
1350
|
resource identity `R`, one-based line ordinal `L`, configured non-negative
|
|
1253
1351
|
neighbor count `C`, and ordered content array `W` containing that line and up to
|
|
1254
1352
|
`C` complete lines on either side (all excluding separators), core hashes the
|
|
@@ -1345,13 +1443,15 @@ copied with log history on fork.
|
|
|
1345
1443
|
|
|
1346
1444
|
### §open-fold OPEN / FOLD
|
|
1347
1445
|
|
|
1348
|
-
AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: null }`.
|
|
1446
|
+
AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: TextLineMarker | null }`.
|
|
1349
1447
|
|
|
1350
|
-
OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD
|
|
1448
|
+
OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded. The canonical body remains complete through log READ/FIND regardless of visibility. Rows and bodies persist, and classification changes still land when visibility is a no-op. Malformed targets, unsupported coordinate arity, and nonexistent exact coordinates fail at their owning boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
|
|
1351
1449
|
|
|
1352
1450
|
### §jsonplurnk The Log's wire format
|
|
1353
1451
|
|
|
1354
|
-
The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every content line
|
|
1452
|
+
The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. `"display":"none","body":""` means no canonical body, `"display":"folded"` withholds the whole body, and `"display":"open"` appends the visible body. A partially hidden open row also carries `"folded":["<scope>",...]`; coordinate gaps in its body make the omission explicit without renumbering later lines. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. It leads each entry object; the remaining members follow in stable alphabetical order. A present authored operation annotation appears as `annotation`; its absence omits the field. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an automatic bounded projection differs from the visibility-selected body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. Every row's accounting: {§packet-token-accounting}.
|
|
1453
|
+
|
|
1454
|
+
- §packet-token-accounting Every row reports its real weight so the packet self-reconciles against the budget: `tokensMetadata` is its active non-body share (always present — no row reads as free), `tokensBody` is the projected body's weight whenever a canonical body exists, and `tokensActive` is the complete row's weight in the packet right now. A folded or bodyless row has `tokensActive = tokensMetadata`; a wholly or partially open row has `tokensActive = tokensMetadata + tokensBody`. Thus FOLD removes the rendered body's weight while KILL removes `tokensActive`; on a folded row `tokensBody` previews the body share an OPEN would activate. The completed row, including its accounting fields and framing, is measured to a fixed point. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
|
|
1355
1455
|
|
|
1356
1456
|
### §retrieval-packet-metadata READ/FIND packet metadata
|
|
1357
1457
|
|
|
@@ -1363,7 +1463,7 @@ The packet projects one actionable owner for each retrieval fact:
|
|
|
1363
1463
|
| exact-coordinate READ | none | top-level `region` | none |
|
|
1364
1464
|
| READ-shaped materialization notice | none | none | generic body `lines` |
|
|
1365
1465
|
| catalog/path FIND | compact `resource` range | none | none |
|
|
1366
|
-
| broad matcher FIND | compact `resource` range | per-resource match-location counts | nonzero complete `matchLocationCount` |
|
|
1466
|
+
| broad matcher FIND | compact `resource` range | per-resource match-location counts; a resource with exactly one match also carries that match's `locator`/`region` | nonzero complete `matchLocationCount` |
|
|
1367
1467
|
| exact matcher FIND | compact `matchLocation` range | each row's locator/region | none |
|
|
1368
1468
|
|
|
1369
1469
|
The compact range is `{ unit, total, requested: [first,last], returned?:
|
|
@@ -1379,17 +1479,19 @@ generic body `lines` remains available on READ-shaped materialization notices
|
|
|
1379
1479
|
that have no retrieval extent. FIND content weights follow {§jsonplurnk};
|
|
1380
1480
|
ordinary bounded bodies expose their displayed and complete chunk extents there.
|
|
1381
1481
|
|
|
1382
|
-
### §
|
|
1482
|
+
### §turn-ops-entry The admitted turn program
|
|
1483
|
+
|
|
1484
|
+
§turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the item, `origin` is the turn producer, no target exists, `tx` is empty, and the source lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because it is the turn program, not another operation. It is line-numbered and OPEN/FOLD/KILL-able like any log body. The worker-initialization `turnOps` is born OPEN because it is the worked orientation example; every other `turnOps`, including model inference and overflow recovery, is born FOLDED and remains available on demand. Log-KILL clears the `writableBy` gate for a model-authored item (Log's handler surface — kill only — keeps every other mutating op at 501). The shared executor writes exactly one after every admitted source-backed turn.
|
|
1383
1485
|
|
|
1384
|
-
§
|
|
1486
|
+
§rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, and the exact latest rejected response. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
|
|
1385
1487
|
|
|
1386
1488
|
- §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with `## READ0 (worker:///docs/)`. A rendered operation row appends its canonical model-facing `/OP`, not a fourth resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive suffix is authoritative and a disagreement resolves 404. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ` deliberately filters the canonical suffix.
|
|
1387
1489
|
- §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: `## FOLD0 (log:///1/2)` folds turn 1/2's rows. OPEN and FOLD may instead take only a tag filter ({§log-item-tags}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless operation without tags or a matcher is 400.
|
|
1388
|
-
- §log-curation-set-selection **
|
|
1490
|
+
- §log-curation-set-selection **Row selection and body scope are independent** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. Thus `## FOLD0 (log:///**/READ) <17,-1>` may change long READs and no-op on short ones while reporting every selected row in `matched`.
|
|
1389
1491
|
|
|
1390
|
-
§fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's
|
|
1492
|
+
§fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's folded intervals before and after, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, visibility changes, tag changes, and landed effects commit in one database statement with each before state as a collision guard. The authored program also survives verbatim in its `turnOps` item. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
|
|
1391
1493
|
|
|
1392
|
-
§kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its
|
|
1494
|
+
§kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its authored program survives in its `turnOps` item. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
|
|
1393
1495
|
|
|
1394
1496
|
### §log-sensitive-request-evidence Durable request evidence
|
|
1395
1497
|
|
|
@@ -1404,7 +1506,7 @@ secret detection.
|
|
|
1404
1506
|
| Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
|
|
1405
1507
|
| Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
|
|
1406
1508
|
| Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
|
|
1407
|
-
| Model-call evidence and
|
|
1509
|
+
| Model-call evidence and source artifacts | `model_calls.response` under {§emission-admission}, `turnOps` under {§turn-ops-log-curation}, and `emissionAttempt` under {§rejected-emission-entry} remain exact forensic evidence and are the explicit exception. |
|
|
1408
1510
|
|
|
1409
1511
|
### §copy COPY (engine-orchestrated)
|
|
1410
1512
|
|
|
@@ -1471,7 +1573,8 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
|
|
|
1471
1573
|
as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
|
|
1472
1574
|
identity-bearing: `https://example.com/page` queries
|
|
1473
1575
|
`(https, /example.com/page)`, never `(https, /page)`.
|
|
1474
|
-
- §find-
|
|
1576
|
+
- §find-channel-selection The target selects a channel under {§channel-selection}. That channel controls candidate eligibility, every matcher dialect's content or derivation, match-evidence coordinates, and exact producer-result composition. A selected channel absent from an exact entry is 404; a broad scope simply excludes entries lacking it. Successful resource-mode results remain complete default-first channel groups, so sibling channels are navigable catalog metadata rather than additional matches.
|
|
1577
|
+
- §find-glob-filter-on-content `body` matcher operates on the addressed entry channel (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
|
|
1475
1578
|
- §find-semantic-selection Every matcher operates only over the candidate set selected by `(target)`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope. Markerless semantic FIND therefore uses the same `<1,16>` default as every other matcher. Integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while `<0.7>` applies the threshold and the ordinary first-16 page.
|
|
1476
1579
|
- §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
|
|
1477
1580
|
- §find-result-projection **The authored target shape determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsWeightTotal, returnedItemsWeightTotal }`:
|
|
@@ -1481,14 +1584,15 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
|
|
|
1481
1584
|
| exact | absent | `resource` | the one catalog channel group |
|
|
1482
1585
|
| glob or folder | absent | `resource` | catalog channel groups |
|
|
1483
1586
|
| glob or folder | present | `resource` | matching channel groups with `matchLocationCount` on `[0]` |
|
|
1484
|
-
| exact | present | `matchLocation` | flat `{ locator?, region? }` locations |
|
|
1587
|
+
| exact | present | `matchLocation` | flat `{ channel?, locator?, region? }` locations |
|
|
1485
1588
|
|
|
1486
1589
|
A glob or folder remains resource mode when it resolves to one path. An exact
|
|
1487
1590
|
target remains location mode when it has many locations. A valid exact match
|
|
1488
1591
|
with no addressable location is status 200 with `matchingPathCount: 1`,
|
|
1489
1592
|
`matchLocationCount: 0`, and no fabricated row; a matcher selecting no
|
|
1490
1593
|
resource is 204. A body-less broad empty catalog survey is status 200; an
|
|
1491
|
-
absent exact resource is 404.
|
|
1594
|
+
absent exact resource is 404. Every entry-channel location names its `channel`
|
|
1595
|
+
({§channel-selection-visibility}); log rows carry none.
|
|
1492
1596
|
|
|
1493
1597
|
Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
|
|
1494
1598
|
complete selection before pagination; the packet curates those facts under
|
|
@@ -1498,9 +1602,15 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
|
|
|
1498
1602
|
contains one nonempty, flat channel array per resource. Element `[0]` is always
|
|
1499
1603
|
the default channel and carries the bare resource path; later elements carry
|
|
1500
1604
|
their complete `path#channel` addresses. Each channel is
|
|
1501
|
-
`{ path, mimetype, weight, lines, parseIssues? }`; `parseIssues` is the
|
|
1605
|
+
`{ path, mimetype, weight, lines, summary?, parseIssues? }`; `parseIssues` is the
|
|
1502
1606
|
positive-only advisory projection of `{§mimetype-parse-issues}` for the exact
|
|
1503
|
-
|
|
1607
|
+
channel derivation under `{§scheme-catalog-parse-issues}`.
|
|
1608
|
+
|
|
1609
|
+
§scheme-catalog-summary **Catalog summary.** `summary` is the exact channel
|
|
1610
|
+
derivation's `{§mimetype-summary}` clipped to at most 256 Unicode code points
|
|
1611
|
+
including a visible terminal ellipsis; absent metadata is omitted.
|
|
1612
|
+
|
|
1613
|
+
Resource-level `stream` and broad-match
|
|
1504
1614
|
`matchLocationCount` live only on `[0]`. A single-channel resource is therefore
|
|
1505
1615
|
a one-element array, with no path-owning wrapper or duplicated channel map.
|
|
1506
1616
|
A terminal single-star path scope is a one-level map: direct entries retain
|
|
@@ -1520,7 +1630,9 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
|
|
|
1520
1630
|
final model-facing representation from `weight` to `tokens`
|
|
1521
1631
|
({§json-result-rendering}), so universal packet numbering makes result
|
|
1522
1632
|
ordinal N addressable as line N, matching `<N>` pagination without a second
|
|
1523
|
-
coordinate system.
|
|
1633
|
+
coordinate system. A returned page begins at `range.returned[0]`, and every
|
|
1634
|
+
page left-pads its ordinals to the decimal width of `range.total`; content
|
|
1635
|
+
therefore keeps one stable column across the complete result set. Pagination is the only FIND materialization bound; no
|
|
1524
1636
|
hidden complete row or location collection is retained behind the public
|
|
1525
1637
|
projection.
|
|
1526
1638
|
|
|
@@ -1577,7 +1689,6 @@ the loop continue; repeated offenses terminate through the engine's 500.
|
|
|
1577
1689
|
live obligations. If work has completed but is unobserved, it continues
|
|
1578
1690
|
directly to the next packet because the wake edge has already fired; only a
|
|
1579
1691
|
genuinely empty set with no successful same-turn FOLD resolves immediately like `[200]`.
|
|
1580
|
-
- §send-300-choices **SEND signal `300` is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
|
|
1581
1692
|
|
|
1582
1693
|
### §exec EXEC
|
|
1583
1694
|
|
|
@@ -1628,10 +1739,12 @@ target at its run boundary.
|
|
|
1628
1739
|
core-owned temporary file after acceptance. Core reparses the complete authored
|
|
1629
1740
|
address and resolves one exact `<1,-1>` READ through
|
|
1630
1741
|
{§universal-read-composition}; internal source consumption never borrows the
|
|
1631
|
-
model-facing 16-line preview.
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1742
|
+
model-facing 16-line preview. Each spawn creates its file with an exclusive,
|
|
1743
|
+
process- and database-coordinate-independent identity. The file lives through
|
|
1744
|
+
the executor run and core removes it after the subscription's terminal result
|
|
1745
|
+
has settled. A removal failure is reported to daemon diagnostics with its
|
|
1746
|
+
complete cause; it cannot rewrite the execution result, stream state, or
|
|
1747
|
+
completion wake.
|
|
1635
1748
|
|
|
1636
1749
|
Loop-flag authority follows the selected runtime's declaration:
|
|
1637
1750
|
|
|
@@ -1715,11 +1828,19 @@ edge. Stream closure remains a wake edge under every poll policy.
|
|
|
1715
1828
|
|
|
1716
1829
|
§exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of newly publishable stream content each turn, {§exec-stream}), never a same-turn receipt.
|
|
1717
1830
|
|
|
1831
|
+
§effect-policy-tunable **Effect admission is deployment-tunable.** The default
|
|
1832
|
+
map (`host` proposes; `read`/`pure` auto-run) is the contract; the operator may
|
|
1833
|
+
override it deployment-wide with `PLURNK_SERVICE_EFFECT_POLICY`, a
|
|
1834
|
+
comma-separated `<effect>:<policy>` list (e.g. `read:propose` proposes even
|
|
1835
|
+
read effects). Unlisted effects keep the default. An invalid entry — unknown
|
|
1836
|
+
effect, unknown policy, or a non-`<effect>:<policy>` shape — fails daemon boot
|
|
1837
|
+
loudly rather than degrading admission.
|
|
1838
|
+
|
|
1718
1839
|
After all non-SEND operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the EXEC streams it started, then dispatches its terminal SEND against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before disposition, not sibling-operation serialization: dependent EXECs remain separate observed turns.
|
|
1719
1840
|
|
|
1720
1841
|
§exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*.
|
|
1721
1842
|
Each turn the environment-observation injector publishes newly publishable content
|
|
1722
|
-
from each owned channel as an `origin=
|
|
1843
|
+
from each owned channel as an `origin=_plurnk` READ at
|
|
1723
1844
|
`<runtime>:///<coord>#<channel>`, preserving the channel's current mimetype:
|
|
1724
1845
|
|
|
1725
1846
|
| channel mimetype | while active | at terminal state |
|
|
@@ -1732,7 +1853,7 @@ The per-channel cursor advances only through content actually published, so an
|
|
|
1732
1853
|
active atomic document or trailing partial JSONL record never reaches the model
|
|
1733
1854
|
as malformed structured data. Ongoing observations are folded and a terminal
|
|
1734
1855
|
observation is born OPEN; a terminal state with no newly publishable body still
|
|
1735
|
-
produces one conclusion row. Every READ then obeys {§body-projection} and
|
|
1856
|
+
produces one bodyless conclusion row. Every READ then obeys {§body-projection} and
|
|
1736
1857
|
therefore renders its selected result complete. A stream that closes before a
|
|
1737
1858
|
same-turn wait remains pending until this terminal READ crosses the next packet
|
|
1738
1859
|
boundary. The EXEC row separately records the authored invocation.
|
|
@@ -1747,17 +1868,17 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
|
|
|
1747
1868
|
§exec-env-scoped **Scoped environment.** An EXEC subprocess inherits the *project's* environment — its `.env`, the standard shell vars — so the model's commands run as the project expects; but never plurnk's own secrets: the provider API keys and `PLURNK_*` config are stripped before the spawn, so a model-executed command can't `printenv` the engine's keys. The service owns the scoping policy (the denylist); the executor spawns with the env it is handed.
|
|
1748
1869
|
|
|
1749
1870
|
- §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits EXEC followed by SEND signal `102` as ever; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
|
|
1750
|
-
- §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then
|
|
1871
|
+
- §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then records ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `weight` = the canonical resulting span's curation weight, and `attrs.kind="entry_materialized"`. The requested tags classify that log row under {§log-item-tags}; they never become resource metadata or duplicate into attrs. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured materializer, and local-projection routes as exact HTTP acquisition ({§http-materializer-plugins}). A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's path, weight, and log classifications, and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
|
|
1751
1872
|
|
|
1752
1873
|
### §proposal The proposal lifecycle
|
|
1753
1874
|
|
|
1754
|
-
§proposal-202-pauses A side-effecting op does not execute on dispatch — it **proposes**. The scheme returns **202** (an EXEC `host` runtime {§exec}, an EDIT to a member file {§membership}); the engine writes the log row `state='proposed'`, registers a waiter keyed by `logEntryId`, and **pauses `dispatch`** awaiting a resolution. The
|
|
1875
|
+
§proposal-202-pauses A side-effecting op does not execute on dispatch — it **proposes**. The scheme returns **202** (an EXEC `host` runtime {§exec}, an EDIT to a member file {§membership}); the engine writes the log row `state='proposed'`, registers a waiter keyed by `logEntryId`, and **pauses `dispatch`** awaiting a resolution. The provider exchange and emitted operation are already durable, while the turn remains open until dispatch settles; {§engine-rails} therefore sees the *resolved* status, never the provisional 202. On accept the status becomes 200 and the scheme's effect runs.
|
|
1755
1876
|
|
|
1756
1877
|
**Resolution arrives through one lifecycle:**
|
|
1757
1878
|
|
|
1758
1879
|
- **Client disposition** ({§methods-proposal-resolve}) — a client interface delivers accept, reject, or cancel; AG-UI uses standard resume entries ({§agui-proposal-resolve}).
|
|
1759
1880
|
- **Loop disposition** ({§proposal-disposition}) — core applies the exact automatic accept/reject before observational subscribers run; automatic policy is not an event listener or client fallback.
|
|
1760
|
-
- §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review
|
|
1881
|
+
- §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait.
|
|
1761
1882
|
|
|
1762
1883
|
**The decision drives a one-way state transition** on `log_entries.state` (resolution is idempotent — `WHERE state='proposed'`, so a second resolution 404s):
|
|
1763
1884
|
|
|
@@ -1808,17 +1929,14 @@ removes ownerless rows without fabricating cancellation, payload, or replay.
|
|
|
1808
1929
|
|
|
1809
1930
|
`ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The decision table is complete and ordered:
|
|
1810
1931
|
|
|
1811
|
-
|
|
1932
|
+
| `auto` | stale target | `noProposals` | Disposition |
|
|
1933
|
+
| ------ | ------------ | ------------- | --------------------------------------------------------- |
|
|
1934
|
+
| true | true | any | loop reject, outcome `stale_read_clobber` |
|
|
1935
|
+
| true | false | any | loop accept |
|
|
1936
|
+
| false | any | true | loop reject, outcome `no_review_channel` |
|
|
1937
|
+
| false | any | false | client |
|
|
1812
1938
|
|
|
1813
|
-
|
|
1814
|
-
| ------ | ---------------- | ------------ | ------------- | ------------------------------------------------------------------ |
|
|
1815
|
-
| true | yes | any | any | client |
|
|
1816
|
-
| true | no | true | any | loop reject, outcome `stale_read_clobber` |
|
|
1817
|
-
| true | no | false | any | loop accept |
|
|
1818
|
-
| false | any | any | true | loop reject, outcome `no_review_channel` |
|
|
1819
|
-
| false | any | any | false | client |
|
|
1820
|
-
|
|
1821
|
-
Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination, but its operator-question exception still leaves that question client-owned ({§send-300-choices}). Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
|
|
1939
|
+
Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
|
|
1822
1940
|
|
|
1823
1941
|
---
|
|
1824
1942
|
|
|
@@ -1837,7 +1955,7 @@ settles it as interruption (`500`) and errors active channels before evaluating
|
|
|
1837
1955
|
loops ({§worker-lifecycle-restart-recovery}); it never reports cancellation (`499`) or
|
|
1838
1956
|
pretends to reconstruct an opaque plugin connection.
|
|
1839
1957
|
|
|
1840
|
-
§subscriptions-fold-keeps-subscription FOLD/OPEN
|
|
1958
|
+
§subscriptions-fold-keeps-subscription FOLD/OPEN changes a log row's folded body intervals ({§open-fold}), never the subscription registry. Curation of a streaming entry's log body leaves the live stream running: visibility is render-only, never cancellation.
|
|
1841
1959
|
|
|
1842
1960
|
### §chunk-accumulation Chunk accumulation
|
|
1843
1961
|
|
|
@@ -1974,10 +2092,17 @@ freshness remains the owning family's concern.
|
|
|
1974
2092
|
| Family | Lean framework | Service-owned default leaves |
|
|
1975
2093
|
|-----------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
1976
2094
|
| Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
|
|
1977
|
-
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`,
|
|
2095
|
+
| Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format leaves. |
|
|
1978
2096
|
| | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format leaves. |
|
|
1979
|
-
| | | Fixed `embeddings`
|
|
1980
|
-
| Executors | `@plurnk/plurnk-execs` | `common`, `git`, `jq`, `
|
|
2097
|
+
| | | Fixed `embeddings` artifact. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
|
|
2098
|
+
| Executors | `@plurnk/plurnk-execs` | `common`, `git`, `jq`, `sqlite`, and `wasm` leaves under the `@plurnk/plurnk-execs-*` prefix. |
|
|
2099
|
+
|
|
2100
|
+
The independently published `application-pdf` handler and `tokenizers`
|
|
2101
|
+
artifact are opt-in leaves. Installing either beside the service admits it
|
|
2102
|
+
through ordinary package discovery without changing the service manifest. The
|
|
2103
|
+
default local embedding artifact owns the exact counter for its own model;
|
|
2104
|
+
remote embedding deployments install `tokenizers` when their provider does not
|
|
2105
|
+
supply an exact counter.
|
|
1981
2106
|
|
|
1982
2107
|
**Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
|
|
1983
2108
|
operator declarations, local adapters, and finally installed AI SDK provider
|
|
@@ -2022,12 +2147,32 @@ service manifest edit.
|
|
|
2022
2147
|
|
|
2023
2148
|
## §operator-config Operator Configuration
|
|
2024
2149
|
|
|
2150
|
+
### §host-path-layout Host filesystem layout
|
|
2151
|
+
|
|
2152
|
+
On XDG-compatible hosts, artifact semantics select the default location. An
|
|
2153
|
+
unset or empty base variable uses the XDG default; a relative value is invalid
|
|
2154
|
+
and is ignored rather than resolved against the working directory.
|
|
2155
|
+
|
|
2156
|
+
| Class | Base | Plurnk member |
|
|
2157
|
+
|---|---|---|
|
|
2158
|
+
| Configuration | `$XDG_CONFIG_HOME` (default `~/.config`) | `plurnk/.env`, `plurnk/AGENTS.md` |
|
|
2159
|
+
| Durable user data | `$XDG_DATA_HOME` (default `~/.local/share`) | `plurnk/plurnk.db` and SQLite sidecars |
|
|
2160
|
+
| Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) | Reserved; no directory is created without an owned artifact. |
|
|
2161
|
+
| Reproducible cache | `$XDG_CACHE_HOME` (default `~/.cache`) | Reserved; no directory is created without an owned artifact. |
|
|
2162
|
+
| Shared global Agent Skills | User home | `.agents/skills/<name>/SKILL.md` |
|
|
2163
|
+
|
|
2164
|
+
The service creates only a directory required by the current command. A newly
|
|
2165
|
+
created configuration or data directory uses mode `0700`; a newly seeded
|
|
2166
|
+
secret-bearing `.env` uses `0600`. Existing user-owned permissions are not
|
|
2167
|
+
rewritten. Explicit Plurnk path overrides retain `~/` expansion and their
|
|
2168
|
+
ordinary precedence; XDG variables themselves require absolute paths.
|
|
2169
|
+
|
|
2025
2170
|
§operator-config-precedence Configuration is one environment cascade. Higher-priority sources preserve or replace values supplied by every lower source:
|
|
2026
2171
|
|
|
2027
2172
|
| Priority | Source | Ordering |
|
|
2028
2173
|
|---------:|------------------------------------|-----------------------------------------------------------|
|
|
2029
2174
|
| 1 | Assembled package `.env.defaults` | Set-if-unset floor; one owner per key. |
|
|
2030
|
-
| 2 |
|
|
2175
|
+
| 2 | `$XDG_CONFIG_HOME/plurnk/.env` | User-level ambient configuration. |
|
|
2031
2176
|
| 3 | `./.env` | Working-directory ambient configuration. |
|
|
2032
2177
|
| 4 | `--config=<path>` | Singular service-owned explicit file. |
|
|
2033
2178
|
| 5 | `--env-file*` | Repeatable explicit files; later selected files win. |
|
|
@@ -2036,17 +2181,27 @@ service manifest edit.
|
|
|
2036
2181
|
|
|
2037
2182
|
Node's pre-script env-file form and the executable's post-script form share the same later-file-wins ordering. `--env-file-if-exists` skips an absent file without changing the order of selected files.
|
|
2038
2183
|
|
|
2039
|
-
§operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics)
|
|
2184
|
+
§operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics) and applies it set-if-unset under every operator source. `plurnk-service config defaults` renders the same complete, owner-labelled aggregate to stdout on demand, preserving comments and optional declarations without persisting a second copy or exposing effective secret values. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
|
|
2185
|
+
|
|
2186
|
+
§operator-config-discovery The conventional `plurnk-service config` command
|
|
2187
|
+
family is a view over the environment cascade, never another configuration
|
|
2188
|
+
representation. `config` reports the canonical `.env`, actual source order,
|
|
2189
|
+
and model-selection state; `config edit` opens that file through `$VISUAL` or
|
|
2190
|
+
`$EDITOR`; `config defaults` emits the aggregate above; and `config check`
|
|
2191
|
+
validates the provider-free configuration contracts without starting a model
|
|
2192
|
+
or provider request. The seeded `.env`, first-run diagnostic, service help, and
|
|
2193
|
+
missing-model recovery all signpost `plurnk-service config defaults` as the
|
|
2194
|
+
complete installed option catalog.
|
|
2040
2195
|
|
|
2041
|
-
Model selection
|
|
2196
|
+
Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` optionally declares a friendly route and tuning scope; `PLURNK_MODEL=<selector>` selects either that alias or an exact provider/model route. `PLURNK_MODEL_CHILD=<selector>` uses the same vocabulary for the default child provider; unset means inherit the spawning loop's provider. Operator selections and alias declarations live in `.env`, not `.env.defaults`.
|
|
2042
2197
|
|
|
2043
2198
|
| Var | Default | Purpose |
|
|
2044
2199
|
|-------------------------------------------------------------|---------|---------|
|
|
2045
|
-
| `PLURNK_SERVICE_DB_PATH` |
|
|
2200
|
+
| `PLURNK_SERVICE_DB_PATH` | `$XDG_DATA_HOME/plurnk/plurnk.db` | SQLite file path; an explicit non-empty value overrides the derived default. |
|
|
2046
2201
|
| `PLURNK_HOST` | `127.0.0.1` | Bind address for the listener. Local-only by default. |
|
|
2047
2202
|
| `PLURNK_PORT` | `3044` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
|
|
2048
2203
|
| §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, branch batching, and `git`/`isogit` executors; every other value denies them before executor registration or packet teaching. |
|
|
2049
|
-
| `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts cumulatively across every `202` park/resume. |
|
|
2204
|
+
| `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
|
|
2050
2205
|
| `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
|
|
2051
2206
|
| §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
|
|
2052
2207
|
| `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
|
|
@@ -2060,7 +2215,6 @@ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-insta
|
|
|
2060
2215
|
| `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
|
|
2061
2216
|
| `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
|
|
2062
2217
|
| `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
|
|
2063
|
-
| `PLURNK_SERVICE_MD_<ALIAS>` | (unset) | Operator reference doc: materializes `<path>` as `worker://plurnk/<ALIAS>.md`, auto-READ into every model worker's turn 0 ({§actor-boundary-doc-injection}). `~` expands to home. |
|
|
2064
2218
|
| `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
|
|
2065
2219
|
| `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
|
|
2066
2220
|
|
|
@@ -2069,14 +2223,13 @@ Every core knob listed is enforced at its owning read site; `.env.defaults` is t
|
|
|
2069
2223
|
**Two override semantics — ceiling vs default.** Which kind a var is determines what "override" means across the cascade:
|
|
2070
2224
|
|
|
2071
2225
|
- **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call seam argument. `PLURNK_SERVICE_GIT_ALLOWED` ({§operator-config-git-ceiling}), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
|
|
2072
|
-
- **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({
|
|
2226
|
+
- **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({selector})` request overrides it) and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
|
|
2073
2227
|
|
|
2074
2228
|
§operator-config-shipped-defaults **The shipped `.env.defaults` is itself under
|
|
2075
|
-
test.** It has no active `
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
otherwise invisible by construction.
|
|
2229
|
+
test.** It has no active `PLURNK_MODEL`; no active local GBNF constraint; and
|
|
2230
|
+
the policy renders in exactly one packet section. Every other tier runs the
|
|
2231
|
+
test cascade, so shipped-default regressions are otherwise invisible by
|
|
2232
|
+
construction.
|
|
2080
2233
|
|
|
2081
2234
|
§operator-config-flag-parity The companion **flag-parity** check binds code and
|
|
2082
2235
|
template both ways: every `PLURNK_SERVICE_*` the service reads has a
|
|
@@ -2124,12 +2277,10 @@ boundary. Operator-arcane knobs stay environment-only.
|
|
|
2124
2277
|
| Field | Admitted value | Composition / owner |
|
|
2125
2278
|
| ---------------------- | ---------------------------------------------- | ------------------------------------------------------------- |
|
|
2126
2279
|
| `settings.filesItems` | Integer `>= -1` | Explicit replacement {§operator-config-workspace-files-items} |
|
|
2127
|
-
| `settings.mdDocs` | Array of `{ alias: [\w.-]+, content: string }` | Alias-keyed union {§operator-config-workspace-md-docs} |
|
|
2128
2280
|
| `settings.maxCommands` | Non-negative integer | Tightening ceiling {§operator-config-workspace-max-commands} |
|
|
2129
2281
|
| `settings.git` | Boolean | Tightening denial {§operator-config-workspace-git} |
|
|
2130
2282
|
| `settings.client` | Nonempty string | Stable self-identification {§client-metadata} |
|
|
2131
2283
|
| `settings.execs` | Record of policy-key to string | Subtractive executor layer {§operator-config-workspace-execs} |
|
|
2132
|
-
| `settings.questions` | Boolean | Affirmative question request {§send-300-choices} |
|
|
2133
2284
|
|
|
2134
2285
|
The composition families remain distinct so one setting's semantics never
|
|
2135
2286
|
leak into another.
|
|
@@ -2137,8 +2288,6 @@ leak into another.
|
|
|
2137
2288
|
*Defaults — explicit-wins (the client replaces/merges freely):*
|
|
2138
2289
|
|
|
2139
2290
|
- §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), with ordinary markerless pages (`-1`), or with the file list explicitly capped (`N`, other surveys remain markerless). A single scalar — the client value wins outright.
|
|
2140
|
-
- §operator-config-workspace-md-docs `settings.mdDocs` (`[{alias, content}]`) **unions** with the server's `PLURNK_SERVICE_MD_*` docs, keyed by alias — a client adds its own repo docs atop the operator's systemwide policy doc. On alias collision the client wins before I/O (a deliberate shadow), so the unselected operator path is not read; every selected non-empty operator path is required, and absence or another read failure rejects materialization with its cause. The client sends content (it owns the file), not a path.
|
|
2141
|
-
|
|
2142
2291
|
*Ceilings — most-restrictive-wins (the client may only narrow, never widen):*
|
|
2143
2292
|
|
|
2144
2293
|
- §operator-config-workspace-max-commands `settings.maxCommands` (number)
|
|
@@ -2158,9 +2307,8 @@ leak into another.
|
|
|
2158
2307
|
effective workspace registry is authoritative and the settings layer only
|
|
2159
2308
|
intersects it: settings cannot register or re-enable a runtime. A canonical
|
|
2160
2309
|
key for a currently absent tag is accepted as inert policy and applies if a
|
|
2161
|
-
workspace capability provider later publishes that tag. Dispatch
|
|
2162
|
-
model-facing
|
|
2163
|
-
document materialization use the same registered-set intersection and policy
|
|
2310
|
+
workspace capability provider later publishes that tag. Dispatch and
|
|
2311
|
+
model-facing tool-resource materialization use the same registered-set intersection and policy
|
|
2164
2312
|
predicate, so a workspace-disabled tag is neither executable nor taught.
|
|
2165
2313
|
|
|
2166
2314
|
Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
|
|
@@ -2199,6 +2347,18 @@ recovers durable lifecycle, and starts modules in registration order. Shutdown
|
|
|
2199
2347
|
closes started and self-closing modules in reverse order and surfaces aggregated
|
|
2200
2348
|
close failures.
|
|
2201
2349
|
|
|
2350
|
+
§module-discovery **Third-party daemon-module composition is manifest
|
|
2351
|
+
discovery.** A package declares `plurnk: { kind: "module", module:
|
|
2352
|
+
"<export-subpath>" }`; the export is one DaemonModule (an object, or a no-arg
|
|
2353
|
+
factory returning one). At boot, core scans installed packages under the
|
|
2354
|
+
executor family's discovery and trust rules ({§plugin-discovery}) and
|
|
2355
|
+
registers every trusted declaring module before any module setup runs, in
|
|
2356
|
+
package-enumeration order. The service's explicit composition — the AG-UI,
|
|
2357
|
+
hooks, and MCP modules — carries init options and is wired in service.ts;
|
|
2358
|
+
discovery never duplicates those packages. An untrusted declaring package is
|
|
2359
|
+
skipped with a boot warning, never executed. A module export that is neither
|
|
2360
|
+
an object nor a no-arg factory fails boot loudly.
|
|
2361
|
+
|
|
2202
2362
|
§module-shutdown-order `Daemon.stop()` returns only after active worker drains,
|
|
2203
2363
|
streaming producers, derivations, mimetypes, schemes, and every accepted
|
|
2204
2364
|
conclusion-wake task have settled in dependency order. The supervisor owns each
|
|
@@ -2206,6 +2366,12 @@ asynchronous wake task from acceptance through settlement; a task failure
|
|
|
2206
2366
|
participates in the shutdown aggregate. The database may be released only after
|
|
2207
2367
|
the final wake barrier resolves.
|
|
2208
2368
|
|
|
2369
|
+
§crash-only-stop The settle sequence is deadline-bounded
|
|
2370
|
+
(`PLURNK_SERVICE_STOP_TIMEOUT_MS`, default 30000): past the deadline each wait
|
|
2371
|
+
is abandoned with a named error instead of hanging the daemon on a child that
|
|
2372
|
+
never closes. A wedged child costs a forced shutdown; it must never cost an
|
|
2373
|
+
unbounded one.
|
|
2374
|
+
|
|
2209
2375
|
```mermaid
|
|
2210
2376
|
flowchart LR
|
|
2211
2377
|
stop[Stop accepting work] --> drains[Settle worker drains]
|
|
@@ -2251,13 +2417,14 @@ Its function names are transport-neutral library calls, not public wire names.
|
|
|
2251
2417
|
| §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates and delivers one accept, reject, or cancel decision to the engine. An unknown or already-resolved id fails; the client protocol owns how the decision arrived. |
|
|
2252
2418
|
| §client-interaction-list Client interactions | `pendingClientInteractions(workspaceId)` | Intersects durable interaction rows with their live operation waiters and returns the contracts-owned projection; a row alone is not a resumable interaction. |
|
|
2253
2419
|
| §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates and delivers one resolved payload or cancellation. Unknown, ownerless, and already-resolved identities fail before affecting an operation. |
|
|
2254
|
-
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?,
|
|
2420
|
+
| §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, selector?, childSelector? })` | Validates a model worker and provider policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
|
|
2255
2421
|
| §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)` | Begins durable structured cancellation of the worker tree and reaps its process-local scopes. The boolean reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. |
|
|
2256
|
-
| §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action
|
|
2422
|
+
| §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop. Every statement is an ordered client/operation turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep its turn, loop, and action promise open until resolution. Core exposes no per-op method family. |
|
|
2257
2423
|
| Client observation | `look({ workspaceId, workerId, statement })` | Runs an already-parsed READ through the full resolver without a log row. A non-READ statement is rejected ({§op-look}). |
|
|
2258
2424
|
| §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. `limit` defaults to 100 and is capped at 1000. |
|
|
2259
2425
|
| §methods-entry-read Reads | `readEntry({ workspaceId, workerId, target, channel?, offset? })` | Resolves the selector from that worker's perspective and returns {§entry-read-result}, either complete or as one channel suffix, without creating action evidence. |
|
|
2260
2426
|
| Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
|
|
2427
|
+
| Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
|
|
2261
2428
|
| Client capabilities | `listClientDisplayCapabilities()` | Composes sorted scheme declarations ({§manifest-client-display}) followed by sorted MIME declarations ({§mimetype-client-display}) into the validated shared wire ({§client-display-capabilities}). The internal `exec` operation handler is excluded; its addressable runtime-tag scheme faces remain included. |
|
|
2262
2429
|
| §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings?, constraints? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, materializes current docs and constraints, starts derivation warming, and emits global `workspace/created`. `projectRoot` is established here or the workspace remains headless. |
|
|
2263
2430
|
| §methods-workspace-attach Workspace lifecycle | `attachWorkspace({ workspaceId, workerId?, workerName? })` | Validates ownership and returns a client envelope for an existing world. It does not retain caller or transport binding state in core. |
|
|
@@ -2306,8 +2473,8 @@ workspace lifecycle calls return exactly the workspace and selected client actor
|
|
|
2306
2473
|
carry no conversation-worker or action-loop binding. Core retains no connection,
|
|
2307
2474
|
thread, or current-workspace mapping. A module may replace its own binding with a
|
|
2308
2475
|
later create or attach result without requiring a new transport; it resolves the
|
|
2309
|
-
conversation worker separately, while each client action allocates its own
|
|
2310
|
-
|
|
2476
|
+
conversation worker separately, while each client action allocates its own
|
|
2477
|
+
administrative loop under {§connection-lifecycle}.
|
|
2311
2478
|
|
|
2312
2479
|
§methods-worker-name-reserved **Client worker-name admission.** Attach,
|
|
2313
2480
|
fresh-conversation, and fork apply {§worker-name-minting} before lookup or
|
|
@@ -2315,24 +2482,118 @@ creation. A client therefore cannot forge or resume an internal worker, insert
|
|
|
2315
2482
|
a non-mintable spelling, or make the client registry diverge from model worker
|
|
2316
2483
|
control.
|
|
2317
2484
|
|
|
2318
|
-
§
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2485
|
+
§worker-settings **The worker carries its own behavioral rules.** The
|
|
2486
|
+
workspace is the world — how things are; each worker is an actor inside it,
|
|
2487
|
+
carrying the rules its loops obey. Those rules live in one JSON bag
|
|
2488
|
+
(`workers.settings`), declared by the client at worker creation and mutable
|
|
2489
|
+
between loops through `readWorkerSettings`/`setWorkerSettings`; the bag is
|
|
2490
|
+
validated at the client-input boundary against a closed known-key set, and
|
|
2491
|
+
unknown keys never persist. A fork begins with the default empty bag — no
|
|
2492
|
+
inherited rules, no live link. Readers are permissive: malformed persisted
|
|
2493
|
+
JSON yields the default rules, never a read failure. There is no servicewide
|
|
2494
|
+
or workspace ceiling on a worker's own rules; each client decides for its own
|
|
2495
|
+
workers.
|
|
2496
|
+
|
|
2497
|
+
§question-tool **The native request-user-input tool.** Core registers one
|
|
2498
|
+
in-process `question` runtime at boot. Its body is the MCP2 2026-07-28
|
|
2499
|
+
form-elicitation shape verbatim — `{ message, requestedSchema }` — and its
|
|
2500
|
+
`results` channel carries the standard `ElicitResult`
|
|
2501
|
+
(`{ action: "accept", content }` or `{ action: "cancel" }`); nothing bespoke
|
|
2502
|
+
crosses the wire. The executor maps the body onto the contracts-owned
|
|
2503
|
+
`ClientInteractionRequest` (toolName `question`) and awaits the shared
|
|
2504
|
+
client-interaction lifecycle — durable pause, reconnect discovery,
|
|
2505
|
+
cancellation, and the answer-as-resolution all come from
|
|
2506
|
+
{§client-interactions}; there is no loopback MCP and no proposal masquerade.
|
|
2507
|
+
Effect `read`: the tool observes the human's answer and is never
|
|
2508
|
+
proposal-gated. Admission is per-worker under {§worker-settings}: the tool
|
|
2509
|
+
exists for a worker only when that worker's `requestUserInput` rule is set.
|
|
2510
|
+
|
|
2511
|
+
§worker-tool-admission **Per-worker tool admission.** A runtime may be
|
|
2512
|
+
admitted per worker through the reserved tool tree's visibility rule: the
|
|
2513
|
+
find/read faces of the worker scheme drop a tool doc for an asking worker
|
|
2514
|
+
whose own rules don't admit it, before matching and rendering, so counts,
|
|
2515
|
+
weights, and the catalog text all agree — the tool does not exist for that
|
|
2516
|
+
worker's FIND. Dispatch enforces the same boundary with an explicit
|
|
2517
|
+
not-available outcome. Admission reads the worker's behavioral rules
|
|
2518
|
+
({§worker-settings}) at the operation boundary, never at registration.
|
|
2519
|
+
|
|
2520
|
+
§model-catalog **Model discovery is a bounded local projection, not provider
|
|
2521
|
+
activity.** Core composes the release-pinned Models.dev snapshot with
|
|
2522
|
+
provider-owned `{§model-catalog-readiness}`. The default query includes only
|
|
2523
|
+
providers configured enough to attempt; `availability: "all"` includes every
|
|
2524
|
+
catalog model with structured missing-configuration causes. Provider and text
|
|
2525
|
+
filters apply before deterministic selector ordering and offset/limit paging;
|
|
2526
|
+
the default page is 50 and the schema caps it at 100. Discovery never probes,
|
|
2527
|
+
authenticates, invokes, or selects a model, and catalog data never enters model
|
|
2528
|
+
packets or state snapshots.
|
|
2529
|
+
|
|
2530
|
+
§worker-model-selection **Worker-owned model selection.** Every model worker
|
|
2531
|
+
owns one durable model, persisted as a nullable `model_routes` foreign key.
|
|
2532
|
+
The root conversation worker is seeded once — from an explicit selection, else
|
|
2533
|
+
the daemon default — and never re-seeded from a later default change. A
|
|
2534
|
+
deliberately modelless daemon leaves the worker unset and rejects model work
|
|
2535
|
+
until an explicit selection. Starting a loop snapshots the worker's resolved
|
|
2536
|
+
model onto the loop; inject, park, wake, retry, reconnect, and restart
|
|
2537
|
+
continue from the loop snapshot and never re-resolve through the alias
|
|
2538
|
+
cascade. A WORK/FORK child copies the spawning loop's effective spawn model
|
|
2539
|
+
(spawn override ?? model) onto the new worker by value at creation; it retains
|
|
2540
|
+
no live link and begins with no override, so a later parent change affects
|
|
2541
|
+
only that worker's future loops and descendants. Client operation actors and
|
|
2542
|
+
Plurnk-owned bookkeeping workers run no model loops and own no model
|
|
2543
|
+
selection. An explicit selection or spawn-override change while the worker
|
|
2544
|
+
holds a live or parked loop is a precise `409 worker-loop-active`, never a
|
|
2545
|
+
silent retroactive switch of the immutable loop snapshot; select after
|
|
2546
|
+
concluding or cancelling the loop.
|
|
2547
|
+
|
|
2548
|
+
A client-created branch copies the source worker's durable model, spawn
|
|
2549
|
+
override, and reasoning policy by value alongside its history. It retains no
|
|
2550
|
+
live policy link to the source worker.
|
|
2551
|
+
|
|
2552
|
+
§worker-reasoning-policy **Reasoning is a durable worker policy.** Each selected
|
|
2553
|
+
worker model has exactly one member of the shared `{§reasoning-policy-wire}`;
|
|
2554
|
+
a modelless worker has none. A declared alias's scoped environment value—or the
|
|
2555
|
+
global provider value for an exact route—seeds the policy only when the worker
|
|
2556
|
+
first receives its model. Model identity and reasoning
|
|
2557
|
+
policy are persisted atomically, while visibility of returned reasoning and
|
|
2558
|
+
token ceilings remain separate concerns. An explicit policy change validates
|
|
2559
|
+
the exact policy against both the worker model and its optional spawn model and
|
|
2560
|
+
is refused while the worker owns a live or parked loop. Client inspection
|
|
2561
|
+
returns the supported-policy intersection of those two routes. Inspection or
|
|
2562
|
+
mutation materializes the daemon-default model and policy onto an uninitialized
|
|
2563
|
+
model worker before answering; a deliberately modelless daemon remains unset.
|
|
2564
|
+
|
|
2565
|
+
Starting a loop snapshots the worker's policy beside its model. Restart, retry,
|
|
2566
|
+
park, wake, and injection retain that immutable snapshot. WORK, FORK, and BARE
|
|
2567
|
+
inherit the spawning loop's policy by value; no descendant consults a later
|
|
2568
|
+
environment or parent-worker change. Unsupported policies fail with a precise
|
|
2569
|
+
provider-boundary problem rather than being silently weakened or translated.
|
|
2570
|
+
|
|
2571
|
+
§methods-loop-run-model **Per-loop model selection.** `runLoop` accepts one
|
|
2572
|
+
optional `selector`: either a declared alias or an exact `<provider>/<model>`
|
|
2573
|
+
route. An exact route stores no fabricated alias and receives no alias-scoped
|
|
2574
|
+
configuration. An explicit selection persists onto the
|
|
2575
|
+
addressed worker before the loop snapshots it; an omitted selector is not a
|
|
2576
|
+
selection and continues the worker's durable model
|
|
2577
|
+
({§worker-model-selection}). The fully resolved provider identity and reasoning
|
|
2578
|
+
policy are persisted on the loop and remain immutable through turns, parks,
|
|
2579
|
+
wakes, and restart ({§worker-reasoning-policy}).
|
|
2580
|
+
Injecting into an existing loop with a conflicting explicit selection fails
|
|
2581
|
+
before work is accepted. Provider instances are cached; no resume path
|
|
2582
|
+
substitutes a boot default for missing or malformed durable selection.
|
|
2326
2583
|
|
|
2327
2584
|
§methods-loop-run-child-provider **Child-provider selection is one durable
|
|
2328
|
-
subcall policy.** Optional `
|
|
2329
|
-
|
|
2330
|
-
`PLURNK_MODEL_CHILD`, while explicit `
|
|
2331
|
-
persists the
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2585
|
+
subcall policy.** Optional `childSelector` uses the same alias-or-exact-route
|
|
2586
|
+
vocabulary for every WORK/FORK descendant and BARE inference; omitted uses
|
|
2587
|
+
`PLURNK_MODEL_CHILD`, while explicit `childSelector: null` means inherit. An
|
|
2588
|
+
explicit override persists onto the addressed worker before the loop
|
|
2589
|
+
snapshots it; an omitted selector continues the worker's durable override
|
|
2590
|
+
({§worker-model-selection}). Core persists the resolved policy on each loop. A
|
|
2591
|
+
child runs on the spawning loop's effective spawn model and carries the same
|
|
2592
|
+
policy deeper; inherit uses the spawning loop's provider and remains inherit.
|
|
2593
|
+
BARE consumes the selection without spawning a child. Packet admission is
|
|
2594
|
+
unchanged: a smaller WORK is valid when its packet fits, and an oversized
|
|
2595
|
+
inherited FORK terminates through the ordinary child-loop result without
|
|
2596
|
+
preflight assembly or provider fallback.
|
|
2336
2597
|
|
|
2337
2598
|
§methods-log-coordinate **Log coordinate.** Every `LogEntry` returned by
|
|
2338
2599
|
`readLog` or emitted through `log/entry` carries `loop_seq` and `turn_seq`
|
|
@@ -2344,6 +2605,13 @@ preserve causal `source` and parse the row's JSON `attrs` into structured data;
|
|
|
2344
2605
|
they also project the row's complete sorted `tags` classification. Client
|
|
2345
2606
|
interfaces do not reconstruct these fields from operation or origin.
|
|
2346
2607
|
|
|
2608
|
+
§methods-readable-reasoning **Readable provider reasoning remains derived
|
|
2609
|
+
provider evidence.** On the model SEND row only, `readLog` and `log/entry`
|
|
2610
|
+
project a nonempty admitted `packet.assistant.reasoning` as the optional
|
|
2611
|
+
`reasoning` field. The durable packet remains the sole stored representation;
|
|
2612
|
+
core does not copy readable reasoning into log attributes or bodies. A turn
|
|
2613
|
+
without readable reasoning omits the field.
|
|
2614
|
+
|
|
2347
2615
|
§op-look **LOOK ownership.** A client-interface module owns the public LOOK
|
|
2348
2616
|
spelling and grammar parsing. It rewrites a valid LOOK statement to READ and
|
|
2349
2617
|
hands the AST to core's `look`; core owns the full resolver and the no-log
|
|
@@ -2387,10 +2655,10 @@ outward envelope that requires it and owns workspace fan-out.
|
|
|
2387
2655
|
|
|
2388
2656
|
A module client is an actor ({§machine-processes}). Its dispatched side effects
|
|
2389
2657
|
write to its own client worker with `origin="client"`; one client action owns
|
|
2390
|
-
one
|
|
2391
|
-
|
|
2392
|
-
but
|
|
2393
|
-
lifecycle. Multiple client actors have distinct workers.
|
|
2658
|
+
one administrative loop, and its statements become ordered operation turns
|
|
2659
|
+
inside that loop. A proposal may hold its turn and loop across an external
|
|
2660
|
+
interrupt/resume, but those records preserve durable evidence rather than
|
|
2661
|
+
defining the public client lifecycle. Multiple client actors have distinct workers.
|
|
2394
2662
|
|
|
2395
2663
|
`runLoop` targets a separate model worker holding the conversation with
|
|
2396
2664
|
`origin="model"`. Both workers share workspace state, while a packet renders
|
|
@@ -2415,14 +2683,14 @@ implementation status, and superseded alternatives belong in forge issues.
|
|
|
2415
2683
|
|
|
2416
2684
|
`PacketBuilder.buildRequestPacket` owns the engine's default ordered section
|
|
2417
2685
|
list. Trusted scheme plugins may transform that first-class list before it is
|
|
2418
|
-
rendered or measured;
|
|
2686
|
+
rendered or measured; {§overflow-turn} remains an engine-owned post-build rail.
|
|
2419
2687
|
|
|
2420
2688
|
```mermaid
|
|
2421
2689
|
flowchart LR
|
|
2422
2690
|
defaults[Engine section drafts] --> transforms[Trusted scheme transforms<br/>and boundary validation]
|
|
2423
2691
|
transforms --> render[Render system and user slots]
|
|
2424
2692
|
render --> measure[Budget substitution and<br/>core-owned measurement]
|
|
2425
|
-
measure --> rail[Engine
|
|
2693
|
+
measure --> rail[Engine budget admission and dispatch]
|
|
2426
2694
|
```
|
|
2427
2695
|
|
|
2428
2696
|
#### §packet-cache-monotone Default order and cache locality
|
|
@@ -2434,21 +2702,19 @@ Conditional absence never reorders the surviving default sections.
|
|
|
2434
2702
|
| 1 | system | `definition` | Framework definition; leads the most stable prefix. |
|
|
2435
2703
|
| 2 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
|
|
2436
2704
|
| 3 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
|
|
2437
|
-
| 4 | system | `
|
|
2438
|
-
| 5 | system | `
|
|
2439
|
-
| 6 |
|
|
2440
|
-
| 7 |
|
|
2441
|
-
| 8 | user | `
|
|
2442
|
-
| 9 | user | `
|
|
2443
|
-
| 10 | user | `
|
|
2444
|
-
| 11 | user | `
|
|
2445
|
-
| 12 | user | `
|
|
2446
|
-
| 13 | user | `
|
|
2447
|
-
| 14 | user | `budget` | Model-facing packet pressure; omitted when capacity is unknown. |
|
|
2448
|
-
| 15 | user | `prompt` | Current prompt-entry pointers. |
|
|
2705
|
+
| 4 | system | `schemes` | Active resource catalogue. |
|
|
2706
|
+
| 5 | system | `inject` | Present only when operator notes are configured. |
|
|
2707
|
+
| 6 | user | `log` | Append-mostly model-visible history. |
|
|
2708
|
+
| 7 | user | `child-streams` | Per-turn status; empty content is omitted. |
|
|
2709
|
+
| 8 | user | `child-workers` | Per-turn status; empty content is omitted. |
|
|
2710
|
+
| 9 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
|
|
2711
|
+
| 10 | user | `notices` | Per-turn observations; empty content is omitted. |
|
|
2712
|
+
| 11 | user | `git` | Per-turn workspace status; empty content is omitted. |
|
|
2713
|
+
| 12 | user | `budget` | `Context Token Budget`; omitted when capacity is unknown. |
|
|
2714
|
+
| 13 | user | `prompt` | Current prompt-entry pointers. |
|
|
2449
2715
|
|
|
2450
2716
|
The order favors prefix-cache locality where semantics permit: the definition
|
|
2451
|
-
and privileged policy lead
|
|
2717
|
+
and privileged policy lead the resource directory, while the append-mostly
|
|
2452
2718
|
log leads the volatile user-status clump. It does **not** claim that every system byte is
|
|
2453
2719
|
immutable or that the complete packet is globally monotone in volatility:
|
|
2454
2720
|
capabilities, operator notes, and policies can change. Trust is a separate
|
|
@@ -2469,7 +2735,7 @@ sections. It receives no separate engine, database, actor, or request context.
|
|
|
2469
2735
|
This is strictly a trusted in-process seam, admitted through the common plugin
|
|
2470
2736
|
trust gate; an external client action cannot invoke it. Whole-list transformation is
|
|
2471
2737
|
the fork-avoidance valve for alternate packet shapes ({§ecosystem}), while
|
|
2472
|
-
|
|
2738
|
+
overflow recovery and folding remain closed engine concerns.
|
|
2473
2739
|
|
|
2474
2740
|
### §tokenomics Tokenomics: four facts, one curation ruler
|
|
2475
2741
|
|
|
@@ -2484,8 +2750,8 @@ time of measurement.
|
|
|
2484
2750
|
| Provider usage and cost | Provider-reported input/output/cache/reasoning tokens and monetary evidence | After every physical request | Durable physical-request forensics under {§provider-usage}; never curation state or a preflight estimate. |
|
|
2485
2751
|
|
|
2486
2752
|
- §tokenomics-weight-stored-at-write **Curation weight, stored at write.** `entry_channels.weight` weighs the complete channel content. `log_entries.weight` weighs the complete canonical `LogBody` content before coordinate and packet presentation; persistence `tx`/`rx` envelopes contribute nothing merely by existing, and proposal settlement recomputes the value when the canonical result changes. Bodyless rows therefore weigh zero. The stored number is a stable content-depth measurement, not a provider-token prediction.
|
|
2487
|
-
- §tokenomics-render-weight-budget **Packet curation budget.**
|
|
2488
|
-
- §tokenomics-context-percent **Curation percent.**
|
|
2753
|
+
- §tokenomics-render-weight-budget **Packet curation budget.** `tokensActiveTotal` measures the *complete assembled packet* after section transforms and readout substitution; it is not a sum of log-row `tokensActive` fields. Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns final values into those widths; final substitution is length-invariant and the displayed total equals the stored request weight. `tokensActiveMax` is the provider-derived curation calibration. A `SUM` of stored content weights measures a different artifact and cannot substitute for packet render weight.
|
|
2754
|
+
- §tokenomics-context-percent **Curation percent.** `tokensActiveTotal` carries packet weight as a percentage of `tokensActiveMax`. It reads the capacity already resolved by the provider; no extra provider call.
|
|
2489
2755
|
- §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits and the configured total output envelope. Its resolved `inputCapacity` is the numeric curation-budget calibration as well as the physical denominator exposed to clients. That reuse is policy, not a unit conversion: Core compares stable curation weight with it only to shape context, while provider request-shaped evidence alone admits or rejects I/O. `PLURNK_SERVICE_PROMPT_BUDGET`, `PLURNK_SERVICE_SAFETY`, and the additive reasoning/completion reserve knobs are retired; local and custom deployments tune context window, total output budget, optional reasoning subset, and prompt-projection percentage at their owning layers.
|
|
2490
2756
|
- §tokenomics-prompt-projection-share **Prompt projection is stable packet policy.**
|
|
2491
2757
|
`PLURNK_SERVICE_PROMPT_PROJECTION` is a required alias-scoped percentage in
|
|
@@ -2496,15 +2762,15 @@ time of measurement.
|
|
|
2496
2762
|
one prompt's projection byte-stable as the worker log evolves.
|
|
2497
2763
|
- §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays unknown.** When the provider cannot derive `inputCapacity`, Core omits denominator-dependent curation telemetry and uses the ordinary bounded prompt projection. The provider still sends requests whose measurement or limits are estimates or unavailable: ambiguity defers to the upstream capacity oracle rather than becoming a local rejection.
|
|
2498
2764
|
|
|
2499
|
-
§tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
|
|
2765
|
+
§tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest packet-bearing model-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. Packetless chronology cannot erase an assembled-request gauge. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
|
|
2500
2766
|
|
|
2501
2767
|
- **Derivation is eager and exhaustive.** Workspace creation and searchable-resource changes start one coalesced warm. The first model turn joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
|
|
2502
2768
|
- §membership-binary-sniff **Binary truth beats the label; no entry dominates the corpus.** A tracked member whose HEAD bytes contain NUL enters {§membership-source-projection} as `application/octet-stream` **regardless of what extension-based detection claims**; byte-level evidence outranks a default label. Every eligible text is tiled losslessly to the embedder window and every tile is embedded before its derivation attaches; semantic ranking max-pools the best chunk per candidate.
|
|
2503
2769
|
- §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
|
|
2504
|
-
- §tokenomics-neutral-telemetry **Curation telemetry is state,
|
|
2770
|
+
- §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section contains exactly two fields on separate lines: `tokensActiveTotal: N (P%)` and `tokensActiveMax: M`. It never presents their difference as free response tokens. The protocol definition directly requires FOLD, KILL, or trimming of irrelevant log items to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Packet-level composition, rankings, and physical token speculation are absent.
|
|
2505
2771
|
- §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as stable content identity. `weight` is stored beside that content and is never keyed or recomputed by model.
|
|
2506
|
-
- §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own logical response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd`
|
|
2507
|
-
- §tokenomics-negative-pressure **Negative curation pressure is honest
|
|
2772
|
+
- §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own logical response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. The derived aggregate usage sums every reported quantity the same way. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
|
|
2773
|
+
- §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `tokensActiveTotal` and its percentage above `tokensActiveMax`. Crossing the maximum diverts that would-be model turn into {§overflow-turn}; no over-ceiling packet reaches `provider.generate`. Automatic recovery does not create a strike or consume a model-turn allowance.
|
|
2508
2774
|
|
|
2509
2775
|
### §membership Workspace identity, membership, disk co-location
|
|
2510
2776
|
|
|
@@ -2537,7 +2803,7 @@ flowchart LR
|
|
|
2537
2803
|
| Internal entries | Workspace or worker entries are canonical store state. Writing one never implies a project-file write. |
|
|
2538
2804
|
| Authority | Service flags set the membership ceiling; workspace constraints narrow it; client or loop auto resolves proposals. `origin` is attribution. |
|
|
2539
2805
|
|
|
2540
|
-
§web-search-retrieval **Web
|
|
2806
|
+
§web-search-retrieval **Web discovery is an ordinary MCP concern; retrieval is a first-class composition.** PLURNK owns no search runtime: a search-capable MCP server (e.g. Brave Search) participates through the ordinary MCP contract — admission, read-effect classification, tool documentation, and packet projection are identical to every other MCP tool ({§mcp-tool-presentation}). An executor that wants to materialize discovered pages uses the generic `content: null` `entry()` request ({§exec-entry-sink}): the guarded `WebFetcher` sink fetches candidates in parallel, off the write-serialization chain, and materializes successful bodies as ordinary HTTP entries. Every candidate whose `entry()` call rejects, regardless of failure reason, is mechanically omitted from the model-facing result directory; survivors retain upstream order. Without an entry sink the executor cannot test materialization and omits the verdict.
|
|
2541
2807
|
|
|
2542
2808
|
Search prefetch and direct HTTP READ materialize the same resource contract:
|
|
2543
2809
|
protocol + canonical authority (including a non-default port) + path + serialized
|
|
@@ -2547,13 +2813,10 @@ media type, and projection identity remain explicit auxiliary evidence. A
|
|
|
2547
2813
|
normal
|
|
2548
2814
|
`## READ0 (https://host/path?query)` therefore publishes only the sanitized body
|
|
2549
2815
|
under that exact URL—never raw HTML, response headers, or a channel-selection
|
|
2550
|
-
lesson. FIND and embeddings consume the
|
|
2551
|
-
|
|
2552
|
-
`PLURNK_SERVICE_EXEC_HOLD`, the cycle holds until acquisition concludes
|
|
2553
|
-
({§exec-hold-until-concluded}), so the next packet contains final
|
|
2554
|
-
materialization verdicts and folded ambient rows for every acquired page.
|
|
2816
|
+
lesson. FIND and embeddings consume the addressed stored channel representation
|
|
2817
|
+
and never re-fetch a match.
|
|
2555
2818
|
|
|
2556
|
-
§
|
|
2819
|
+
§web-retrieval-live Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin materialize→FIND and persistence/publication separation. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page; live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions.
|
|
2557
2820
|
|
|
2558
2821
|
**Git is the substrate and the repository is the boundary:**
|
|
2559
2822
|
|
|
@@ -2564,19 +2827,14 @@ materialization verdicts and folded ambient rows for every acquired page.
|
|
|
2564
2827
|
or nested independent repository is not discovered or managed by this
|
|
2565
2828
|
workspace. When Git is absent there is no filesystem walk; `pick` is then the
|
|
2566
2829
|
sole source.
|
|
2567
|
-
- §git-native-default **Core Git reads use native Git
|
|
2568
|
-
|
|
2830
|
+
- §git-native-default **Core Git reads use native Git.** Membership and status
|
|
2831
|
+
execute the installed Git binary. An absent or failed binary yields no
|
|
2832
|
+
automatic Git membership or status; core has no alternate implementation or
|
|
2833
|
+
fallback. An independently installed `isogit` executor remains an explicit,
|
|
2834
|
+
model-invoked subset for shellless deployments, not an ambient Git backend.
|
|
2569
2835
|
- §membership-git-hermetic Native Git runs with ambient `GIT_*` and
|
|
2570
2836
|
global/system config scrubbed, so repository identity follows `project_root`,
|
|
2571
2837
|
never the daemon's launch environment.
|
|
2572
|
-
- §git-isomorphic-opt-in `PLURNK_SERVICE_GIT_ISO=1` explicitly selects the
|
|
2573
|
-
in-process isomorphic-git backend for a deployment that cannot spawn Git. The
|
|
2574
|
-
alternative is never an automatic fallback: an absent native binary yields
|
|
2575
|
-
no automatic Git membership or status, never an isomorphic retry; an
|
|
2576
|
-
incompatible isomorphic repository surfaces its preserved upstream cause
|
|
2577
|
-
and directs the operator back to the default. The isomorphic untracked scan
|
|
2578
|
-
remains differential-gated against native
|
|
2579
|
-
`ls-files --others --exclude-standard`.
|
|
2580
2838
|
- §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
|
|
2581
2839
|
- §membership-create-parents **Parent-complete creation.** An accepted File creation—whether authored as EDIT or as a COPY/MOVE destination—recursively creates missing parent directories before writing and registering the new member.
|
|
2582
2840
|
|
|
@@ -2601,13 +2859,14 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
|
|
|
2601
2859
|
| Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
|
|
2602
2860
|
| Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
|
|
2603
2861
|
|
|
2604
|
-
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ
|
|
2862
|
+
§derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
|
|
2605
2863
|
|
|
2606
|
-
The artifact also retains a positive `{§mimetype-parse-issues}` count
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2864
|
+
The artifact also retains a positive `{§mimetype-parse-issues}` count and the
|
|
2865
|
+
full normalized `{§mimetype-summary}` when the exact parsed channel reported
|
|
2866
|
+
either. Both remain advisory alongside a normally completed semantic
|
|
2867
|
+
disposition; zero, empty, and unavailable evidence persist as absence. Catalog
|
|
2868
|
+
projection attaches either only to that channel, never to a sibling whose
|
|
2869
|
+
content the artifact does not describe.
|
|
2611
2870
|
|
|
2612
2871
|
Every completed artifact records one terminal disposition: `vector`, `lexical`
|
|
2613
2872
|
(only no embedder or an operator size ceiling), `excluded` (the configured
|
|
@@ -2621,11 +2880,11 @@ every non-vector attachment with its disposition and reason. Successful
|
|
|
2621
2880
|
optional projection degradations continue indexing and surface their framework
|
|
2622
2881
|
Notice once per identical observation in a maintenance pass.
|
|
2623
2882
|
|
|
2624
|
-
§semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json`
|
|
2883
|
+
§semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
|
|
2625
2884
|
|
|
2626
2885
|
Lossless chunk admission requires either the embedder's own counter or an exact fallback tokenizer. An empirical estimate never proves that content fits the declared token window. When pending readable content would require vectors and only an estimate is available, maintenance surfaces its degradation Notice and fails before embedding or attaching a derivation; no/disabled embedding and the established empty, binary, excluded, and maximum-size dispositions remain non-vector outcomes.
|
|
2627
2886
|
|
|
2628
|
-
§semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact
|
|
2887
|
+
§semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact addressed channel representation READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized representation, its channel remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected channels. Client notices report compact aggregate progress; the digest records every non-vector address, terminal disposition, and reason for forensic inspection.
|
|
2629
2888
|
|
|
2630
2889
|
§membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
|
|
2631
2890
|
|
|
@@ -2647,55 +2906,57 @@ beneath each call. Its constraints distinguish pending calls, response
|
|
|
2647
2906
|
evidence, and response-less errors while monetary classification remains
|
|
2648
2907
|
explicit.
|
|
2649
2908
|
|
|
2650
|
-
### §
|
|
2909
|
+
### §overflow-turn Budget enforcement: automated recovery turns
|
|
2651
2910
|
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2911
|
+
Budget recovery is an ordinary state-machine transition, not a private packet
|
|
2912
|
+
mutation. Every candidate model request first crosses the model-facing curation
|
|
2913
|
+
ceiling and then, only if admitted, the provider's request-shaped physical
|
|
2914
|
+
capacity boundary:
|
|
2656
2915
|
|
|
2657
2916
|
```mermaid
|
|
2658
2917
|
flowchart TD
|
|
2659
|
-
assemble["Assemble and measure<br/>request
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
fold -->
|
|
2664
|
-
|
|
2665
|
-
|
|
2918
|
+
assemble["Assemble and measure<br/>candidate request"] --> budget{"Weight ≤ curation ceiling?"}
|
|
2919
|
+
budget -->|yes| generate["Provider generate"]
|
|
2920
|
+
budget -->|no| recover["Keep turn packetless<br/>reclassify as `_plurnk` overflow"]
|
|
2921
|
+
recover --> fold["Dispatch PLAN, whole-body FOLD ops,<br/>and SEND through ordinary dispatch"]
|
|
2922
|
+
fold --> verify{"Rebuilt request fits?"}
|
|
2923
|
+
verify -->|yes| next["Next model turn"]
|
|
2924
|
+
verify -->|no| stop["Terminal 413"]
|
|
2925
|
+
next --> assemble
|
|
2926
|
+
generate --> capacity{"Provider capacity failure?"}
|
|
2666
2927
|
capacity -->|no| response["Classify completed response"]
|
|
2667
2928
|
capacity -->|yes| prompt{"Withholding automatic<br/>prompt bodies changes request?"}
|
|
2668
|
-
prompt -->|yes|
|
|
2669
|
-
|
|
2670
|
-
prompt -->|no|
|
|
2671
|
-
boundary -->|yes| retryBoundary["Persist failure;<br/>roll back, rebuild, retry"]
|
|
2672
|
-
retryBoundary --> generate
|
|
2673
|
-
boundary -->|no| stop["Persist terminal 413"]
|
|
2929
|
+
prompt -->|yes| retry["Persist failure;<br/>rebuild and retry"]
|
|
2930
|
+
retry --> generate
|
|
2931
|
+
prompt -->|no| stop
|
|
2674
2932
|
```
|
|
2675
2933
|
|
|
2676
|
-
§
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
-
|
|
2684
|
-
|
|
2685
|
-
- §
|
|
2686
|
-
- §
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
The
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2934
|
+
§overflow-turn-only **Recovery occurs only after measured overflow and before
|
|
2935
|
+
provider I/O.** After packet assembly, Core compares render weight
|
|
2936
|
+
({§tokenomics}) with the provider-derived curation ceiling. An admitted packet
|
|
2937
|
+
ships untouched. An over-ceiling candidate is never stored as a model request
|
|
2938
|
+
and never reaches `provider.generate`; its already-created database turn instead
|
|
2939
|
+
becomes a packetless `_plurnk` turn. Packetless initialization and recovery turns
|
|
2940
|
+
remain ordinary turn chronology but do not consume `maxTurns`, model-call,
|
|
2941
|
+
emission-attempt, usage, or cost accounting.
|
|
2942
|
+
|
|
2943
|
+
- §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its PLAN body is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk in the next turn.` The final sentence requires the successor's substantive operations to be one dedicated, comprehensive bulk-curation program; mandatory PLAN and SEND framing still applies. Its exact `turnOps` is born FOLDED; successful FOLD rows follow {§fold-open-meta-operations} and therefore remain durable but packet-suppressed. Every recovery row carries `_plurnk` and `overflow`; no model call, synthetic receipt, or parallel explanation exists.
|
|
2944
|
+
- §overflow-turn-curation **The preceding turn owns the pressure it introduced.** Core deterministically selects every body already created in the packetless candidate turn, every body created by the immediately preceding completed turn in that worker's chronology, and every older body whose visibility that preceding turn's successful OPEN increased. Every selected body is FOLDed whole (`<1,-1>`) through ordinary dispatch. Already-wholly-folded and bodyless rows require no operation. Core performs no relevance judgment, exempts no operation or resource kind, reconstructs no interval delta, re-runs no authored selector, and chooses no unrelated older history.
|
|
2945
|
+
- §overflow-turn-hard-413 **Recovery fails hard when the causal fold cannot fit.** After the ordinary FOLDs land, Core rebuilds and remeasures once. If the plan changes no visibility or the rebuilt request still exceeds the ceiling, the loop terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem; Core neither submits excess bytes nor chooses unrelated older history. Separately, every `provider.generate` assesses physical capacity under {§provider-surface-capacity}. Core may retry a provider capacity rejection only after withholding automatic prompt-body projection when that changes the request. If it cannot produce changed bytes or the changed request is still rejected, the request-only model turn and provider-owned Problem terminalize at **413 Content Too Large**.
|
|
2946
|
+
|
|
2947
|
+
- §tokenomics-fetch-fits-free **A retrieval larger than the available packet room remains addressable.** Its complete row lands in the model turn that requested it. If the following candidate packet exceeds the curation ceiling, {§overflow-turn-curation} FOLDs the new body and classifies it `_plurnk` and `overflow`; the exact body remains durable and selectively re-OPENable.
|
|
2948
|
+
|
|
2949
|
+
- §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND signal `200`) · `499` model-abandoned (signal `499`, or a cancel) · `429` maxTurns exhausted · `413` token-ceiling recovery failure or provider input-capacity failure after changed-request recovery · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `## SEND0 [202] <T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` unless a successful same-turn FOLD requires the curated next packet · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
|
|
2950
|
+
|
|
2951
|
+
§overflow-turn-surface **The packet is the resulting state, not an account of it.**
|
|
2952
|
+
The first request after recovery is assembled by the ordinary packet path from
|
|
2953
|
+
the actual durable log after the recovery turn. It therefore carries the prior
|
|
2954
|
+
causal rows genuinely FOLDED, the recovery PLAN and SEND genuinely OPEN, and
|
|
2955
|
+
the recovery `turnOps` genuinely FOLDED. Successful recovery FOLD receipts are
|
|
2956
|
+
absent under the universal curation rule. No notice, reconstruction, auto-open,
|
|
2957
|
+
or overflow-specific projection simulates what `_plurnk` did; OPENing the exact
|
|
2958
|
+
`turnOps` reveals the program that did it. The model retains complete authority
|
|
2959
|
+
to reverse or refine that curation through ordinary log operations.
|
|
2699
2960
|
|
|
2700
2961
|
### §env-delta The environment delta: what changed since the model last looked
|
|
2701
2962
|
|
|
@@ -2711,7 +2972,7 @@ flowchart LR
|
|
|
2711
2972
|
kernel --> events
|
|
2712
2973
|
typed --> events
|
|
2713
2974
|
events --> pull["Pre-turn lossless pull<br/>(cursor, captured high-water]"]
|
|
2714
|
-
pull --> log["Observer's self-contained log<br/>origin=
|
|
2975
|
+
pull --> log["Observer's self-contained log<br/>origin=_plurnk; born FOLDed"]
|
|
2715
2976
|
log --> packet["Packet lists coordinate;<br/>OPEN recalls exact body"]
|
|
2716
2977
|
```
|
|
2717
2978
|
|
|
@@ -2755,7 +3016,7 @@ cross this door, while an ancestry-authorized explicit READ remains available.
|
|
|
2755
3016
|
| Field | Meaning |
|
|
2756
3017
|
| ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
2757
3018
|
| `worker_id` | The worker whose self-contained log owns the materialized row. |
|
|
2758
|
-
| `origin` | The actor tier that wrote the row; a materialized delta is `
|
|
3019
|
+
| `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
|
|
2759
3020
|
| `source` | The causal identity. Worker causes use the canonical `worker://<name>` control identity; non-worker causes use a stable subsystem token (currently `file`); self-authored rows omit it. |
|
|
2760
3021
|
|
|
2761
3022
|
§env-delta-no-coalescing **Only filesystem observation nets.** One filesystem
|
|
@@ -2904,7 +3165,7 @@ leaves the request-only record, while rejected exchanges remain in
|
|
|
2904
3165
|
|
|
2905
3166
|
| Turn state | `turns.packet` |
|
|
2906
3167
|
| ----------------------------- | ----------------------------------------------- |
|
|
2907
|
-
| No model request assembled
|
|
3168
|
+
| No model request assembled (including initialization and overflow turns) | SQL `NULL` |
|
|
2908
3169
|
| Request assembled | `{ weight, sections }` |
|
|
2909
3170
|
| Response admitted | `{ weight, sections, assistant, assistantRaw }` |
|
|
2910
3171
|
|
|
@@ -2921,9 +3182,27 @@ leaves the request-only record, while rejected exchanges remain in
|
|
|
2921
3182
|
`StoredPacket` is the one core type and validation path for this algebra. The
|
|
2922
3183
|
flat schema enforces its root states; typed reads additionally validate every
|
|
2923
3184
|
section and parsed operation. A hard budget stop remains request-only. Client,
|
|
2924
|
-
setup, filesystem-narration, and executor-materialization turns are
|
|
2925
|
-
|
|
2926
|
-
|
|
3185
|
+
setup, filesystem-narration, and executor-materialization turns are ordinary
|
|
3186
|
+
operation turns and therefore store `NULL`. Digest projects exact operation
|
|
3187
|
+
source independently from this optional model-exchange record; a request-only
|
|
3188
|
+
turn receives a note instead of a fabricated response.
|
|
3189
|
+
|
|
3190
|
+
§digest-turn-artifact-identity **Digest packet artifacts project durable turns.**
|
|
3191
|
+
After selectors are applied, digest retains every turn with exact `turnOps` or
|
|
3192
|
+
a stored provider request, orders those turns by durable chronology, and names
|
|
3193
|
+
them contiguously from `packet000`. The producer does not affect projection.
|
|
3194
|
+
|
|
3195
|
+
| Artifact | Present when | Authority |
|
|
3196
|
+
|----------|--------------|-----------|
|
|
3197
|
+
| `packetNNN.assistant.md` | The turn has `turnOps` | Exact persisted `turnOps` source |
|
|
3198
|
+
| `packetNNN.system.md`, `packetNNN.user.md` | The turn stored a provider request | Stored packet sections projected through `PacketWire` |
|
|
3199
|
+
| `packetNNN.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
|
|
3200
|
+
| `packetNNN.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
|
|
3201
|
+
|
|
3202
|
+
A source-backed turn without provider participation therefore produces only
|
|
3203
|
+
`assistant.md`; a request-only turn produces no fabricated assistant. A
|
|
3204
|
+
source-less programmatic turn with no provider request has no forensic payload
|
|
3205
|
+
to project and reserves no ordinal.
|
|
2927
3206
|
|
|
2928
3207
|
The external tokenless draft and transformation boundary is owned by
|
|
2929
3208
|
{§scheme-packet-transform}. Core alone extends each validated draft with its
|
|
@@ -2952,13 +3231,13 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
|
|
|
2952
3231
|
|
|
2953
3232
|
§encrypted-reasoning-carrier **Encrypted reasoning is opaque client evidence.**
|
|
2954
3233
|
When a provider returns encrypted reasoning items, core attaches that list to
|
|
2955
|
-
the admitted model
|
|
3234
|
+
the admitted model `turnOps` row's `attrs.reasoning`. `log/entry` and `readLog`
|
|
2956
3235
|
carry it to AG-UI, which may project correlated standard reasoning entities.
|
|
2957
3236
|
Core never decodes the blobs or renders them into a model packet; readable
|
|
2958
3237
|
reasoning text remains separate in `assistant.reasoning`. The provider-detail
|
|
2959
3238
|
identity and derived classification retain their exact provider-normalized
|
|
2960
3239
|
meaning from {§provider-encrypted-reasoning}; core never reinterprets either as
|
|
2961
|
-
a client entity. The
|
|
3240
|
+
a client entity. The source row and logical model call remain the lossless
|
|
2962
3241
|
evidence when a downstream standard cannot represent the complete list.
|
|
2963
3242
|
|
|
2964
3243
|
§body-projection **One full body, one packet projection.** Every durable log row has one canonical full body resolved from its stored tx/rx envelope by `LogBody`. READ and FIND over `log:///`, persistent search derivation, and packet rendering all consume that same meaning. Only packet rendering may project it:
|
|
@@ -2972,7 +3251,7 @@ evidence when a downstream standard cannot represent the complete list.
|
|
|
2972
3251
|
| every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
|
|
2973
3252
|
| bodyless row | `"display":"none","body":""` |
|
|
2974
3253
|
|
|
2975
|
-
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, not ordinary content that the model should have to retrieve from itself. Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again.
|
|
3254
|
+
READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, not ordinary content that the model should have to retrieve from itself. Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Actionless source artifacts, SEND/WORK/FORK bodies, EXEC commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When an OPEN projection differs from its canonical body, `chunk` follows the displayed `body` with the exact selected and complete extents defined by {§jsonplurnk}; complete and FOLDED bodies omit it. `## READ0 (log:///<coordinate>/<OP>)` applies its default or explicit text range to the canonical body; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. `## FIND0 (log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores the producer's projection without changing its bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
|
|
2976
3255
|
|
|
2977
3256
|
§prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **Active User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
|
|
2978
3257
|
|
|
@@ -2990,8 +3269,8 @@ that loop has no `op='prompt'` row, oldest first. Every still-undelivered frame
|
|
|
2990
3269
|
at conclusion is re-ordinalized into one source-keyed recovery loop; that loop's
|
|
2991
3270
|
first turn publishes the complete ordered set exactly once. Recovery retries
|
|
2992
3271
|
complete the same queued loop and never mint duplicate work. The automatic
|
|
2993
|
-
|
|
2994
|
-
contract.
|
|
3272
|
+
overflow turn preserves prompt rows; explicit OPEN/FOLD/KILL follows the ordinary
|
|
3273
|
+
log contract.
|
|
2995
3274
|
|
|
2996
3275
|
§packet-catalog **Catalogs are query results, not packet state.** The packet
|
|
2997
3276
|
stores no materialized manifest. Complete and one-level entry directories,
|
|
@@ -3002,7 +3281,7 @@ their row shape, and their ordering are ordinary FIND projections owned by
|
|
|
3002
3281
|
|
|
3003
3282
|
The model's runtime alert surface has two distinct kinds of information:
|
|
3004
3283
|
|
|
3005
|
-
- **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery
|
|
3284
|
+
- **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery `emissionAttempt` under {§invalid-emission-attempts}.
|
|
3006
3285
|
- **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `embed_progress`, and `grammar_unenforced` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
|
|
3007
3286
|
|
|
3008
3287
|
The `log` is durable product truth. The `errors` section points at its failures
|
|
@@ -3039,16 +3318,15 @@ retain distinct contracts and lifetimes.
|
|
|
3039
3318
|
| failure | row | status |
|
|
3040
3319
|
|---|---|---|
|
|
3041
3320
|
| action failure | the failed op's own row; the owning scheme supplies Problem Details | 4xx/5xx |
|
|
3042
|
-
| provider input capacity | `op='error'`, origin `
|
|
3043
|
-
| max commands exceeded | `op='error'`, origin `
|
|
3044
|
-
| idle turn | `op='error'`, origin `
|
|
3321
|
+
| provider input capacity | `op='error'`, origin `_plurnk`, source `provider`; exact provider-owned `capacity-exceeded` Problem Details | 413 |
|
|
3322
|
+
| max commands exceeded | `op='error'`, origin `_plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
|
|
3323
|
+
| idle turn | `op='error'`, origin `_plurnk`, source `rail`; `engine/rail/idle-turn` Problem Details | 409 |
|
|
3045
3324
|
|
|
3046
3325
|
| notice `kind` | Source | Position |
|
|
3047
3326
|
|---|---|---|
|
|
3048
3327
|
| `grammar_unenforced` | engine rail verdict, or a forwarded provider transport anomaly such as a discarded-channel escape | content-offset when the observed position maps into content; none for a reasoning-prefix divergence |
|
|
3049
3328
|
| `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
|
|
3050
3329
|
| `embed_progress` | repository materialization/indexing lifecycle ({§mimetype-surface}); structured phase, count, and percent; `level: info` except terminal failure | none |
|
|
3051
|
-
| `search_progress` | aggregate search-page acquisition lifecycle; structured phase, counts, and percent; never candidate URLs or per-result notices | none |
|
|
3052
3330
|
|
|
3053
3331
|
§notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `grammar_unenforced` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
|
|
3054
3332
|
|
|
@@ -3060,7 +3338,7 @@ retain distinct contracts and lifetimes.
|
|
|
3060
3338
|
|
|
3061
3339
|
| Surface | Contract |
|
|
3062
3340
|
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
3063
|
-
| Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its
|
|
3341
|
+
| Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its package-owned SqlRite statements; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
|
|
3064
3342
|
| `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
|
|
3065
3343
|
| `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
|
|
3066
3344
|
| `workerId` | Narrows workers and every dependent loop, turn, logical model call, emission attempt, physical request, and log row to that one worker. |
|
|
@@ -3073,7 +3351,7 @@ turn.** It cannot execute operations or alter the audited history.
|
|
|
3073
3351
|
|
|
3074
3352
|
| Aspect | Contract |
|
|
3075
3353
|
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
3076
|
-
| Scope | One interview for each worker with model-bearing turns;
|
|
3354
|
+
| Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
|
|
3077
3355
|
| Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. |
|
|
3078
3356
|
| Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
|
|
3079
3357
|
| Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
|
|
@@ -3082,49 +3360,122 @@ turn.** It cannot execute operations or alter the audited history.
|
|
|
3082
3360
|
|
|
3083
3361
|
§turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
|
|
3084
3362
|
|
|
3085
|
-
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's own folded
|
|
3086
|
-
|
|
3087
|
-
### §tools
|
|
3088
|
-
|
|
3089
|
-
§tools-
|
|
3363
|
+
§notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's own folded `turnOps`. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
|
|
3364
|
+
|
|
3365
|
+
### §tools Executable tool resources
|
|
3366
|
+
|
|
3367
|
+
§tools-resource-discovery **Executable capability discovery uses ordinary
|
|
3368
|
+
Plurnk resources.** No generated tool table rides the system packet. Every
|
|
3369
|
+
available, workspace-enabled runtime with an admitted invocation materializes one family document at
|
|
3370
|
+
`worker://plurnk/skills/plurnk/<runtime>.md`. A general runtime's document contains its
|
|
3371
|
+
{§executor-tool-document}; a runtime with an exact
|
|
3372
|
+
{§executor-tool-registry} instead materializes one child document per enabled
|
|
3373
|
+
target at `worker://plurnk/skills/plurnk/<runtime>/<encoded-target>.md`. Its compact
|
|
3374
|
+
family document summarizes the server or runtime and lists every enabled target
|
|
3375
|
+
as a directly copyable `## EXEC0` heading with its input signature. Each heading
|
|
3376
|
+
uses {§operation-annotation} for the target summary and an exact child-document
|
|
3377
|
+
address; it never advertises a generic invocation that dispatch would reject.
|
|
3378
|
+
Target filenames use one deterministic percent-encoded path segment; the child
|
|
3379
|
+
document retains the exact unencoded target as invocation authority, exposes its
|
|
3380
|
+
annotated invocation form through Summary metadata, and carries the richer
|
|
3381
|
+
input-side contract. General-runtime summaries similarly expose their compact
|
|
3382
|
+
executable witness ({§executor-tool-document}). Tool-result/output schemas remain
|
|
3383
|
+
ordinary evidence and never enter these documents.
|
|
3090
3384
|
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3385
|
+
```mermaid
|
|
3386
|
+
flowchart LR
|
|
3387
|
+
Survey["Turn 0 FIND<br/>tools/*.md"] --> Families["family paths + summaries"]
|
|
3388
|
+
Families --> Read["READ selected family"]
|
|
3389
|
+
Read --> Exec["EXEC annotated invocation"]
|
|
3390
|
+
Read --> Detail["READ exact child<br/>only when needed"]
|
|
3391
|
+
Detail --> Exec
|
|
3392
|
+
```
|
|
3097
3393
|
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3394
|
+
§tools-resource-materialization The runtime registry, workspace executor
|
|
3395
|
+
policy, tool resources, and dispatch use one effective workspace snapshot. A
|
|
3396
|
+
workspace-disabled, unavailable, detached, replaced, or removed runtime has no
|
|
3397
|
+
tool resource; an exact registry's empty set publishes no executable family and
|
|
3398
|
+
admits no invocation. Reconciliation deletes stale family and child documents
|
|
3399
|
+
before upserting the current set. `PLURNK_SERVICE_DOCS_EXCLUDE` does not hide an
|
|
3400
|
+
enabled executable; executor enablement is the sole user-configured filter
|
|
3401
|
+
shared by discovery and dispatch. A runtime declaration may carry
|
|
3402
|
+
`resourcesPath` — the generated-doc root. Absent, its docs live in the internal
|
|
3403
|
+
`/skills/plurnk` namespace; present (attached MCP families: `/tools`), the
|
|
3404
|
+
family and its child tool docs materialize under that root. Turn 0 surveys the
|
|
3405
|
+
families (`## FIND0 [+init,+tools] (worker://plurnk/tools/*.md)`, one row per
|
|
3406
|
+
server carrying its summary) and, for each server named in
|
|
3407
|
+
`PLURNK_MCP_EXPANDED`, its complete tool tree (`tools/<server>/**`). The child
|
|
3408
|
+
summary IS its invocation form so the discovery row teaches the call.
|
|
3409
|
+
Attached tools are capabilities like every other runtime; the model never
|
|
3410
|
+
learns an origin.
|
|
3411
|
+
|
|
3412
|
+
§skills-materialization **The workspace skills surface.** Plurnk discovers one
|
|
3413
|
+
ordered union of standard Agent Skills: project
|
|
3414
|
+
`<projectRoot>/.agents/skills/<name>/SKILL.md`, user-global
|
|
3415
|
+
`~/.agents/skills/<name>/SKILL.md`, then the exact bundled skill
|
|
3416
|
+
membership published by `@plurnk/plurnk-meta`. Collisions resolve project over
|
|
3417
|
+
global over bundled by directory/name before a shadowed lower-precedence body
|
|
3418
|
+
is read. Plurnk never seeds or mutates the shared global root absent an explicit
|
|
3419
|
+
user installation action. Every admitted skill requires standard `name` and
|
|
3420
|
+
`description` frontmatter with `name` matching its directory; an invalid or
|
|
3421
|
+
unreadable discovered skill fails materialization with its path and cause.
|
|
3422
|
+
|
|
3423
|
+
Each admitted skill becomes one kernel-owned
|
|
3424
|
+
`worker://plurnk/skills/<name>.md` entry at workspace boot and creation.
|
|
3425
|
+
`worker://plurnk/skills/index.md` always exists and lists the effective union,
|
|
3426
|
+
including the bundled discovery skill, so the turn-0 `+init,+skills` FIND survey always
|
|
3427
|
+
shows the surface. The materialized index and each standard skill expose an
|
|
3428
|
+
exact H2 `Summary`; a skill's required `description` becomes that summary while
|
|
3429
|
+
its instructions body is preserved verbatim. Frontmatter is parsed as YAML;
|
|
3430
|
+
admission consumes its standard discovery keys. Reconciliation deletes retired skill entries
|
|
3431
|
+
before upserting the current set; turn admission refreshes the surface under the
|
|
3432
|
+
workspace gate before packet assembly, so an explicitly installed or removed
|
|
3433
|
+
skill is discoverable in the first subsequent model turn while an unchanged set
|
|
3434
|
+
dispatches nothing.
|
|
3435
|
+
The bundled `find-skills` skill is an attributed, release-pinned adaptation of
|
|
3436
|
+
the upstream standard skill and targets the universal Agent Skills location;
|
|
3437
|
+
it does not create a Plurnk registry or MCP-like enablement mechanism. Skills
|
|
3438
|
+
are user-, project-, or package-installed teaching admitted through the kernel
|
|
3439
|
+
surface; they never override instruction authority.
|
|
3440
|
+
|
|
3441
|
+
The catalog describes workspace capabilities, not temporary authority. Loop
|
|
3442
|
+
mode remains a dispatch concern: an ask-mode EXEC receives the ordinary exact
|
|
3443
|
+
403 restriction instead of requiring a second per-loop documentation overlay.
|
|
3444
|
+
Optional non-EXEC operations remain a separate `## Enabled Optional Operations`
|
|
3445
|
+
section because they are language extensions rather than executable tools.
|
|
3107
3446
|
|
|
3108
3447
|
### §schemes user.schemes — the resource directory
|
|
3109
3448
|
|
|
3110
|
-
§schemes-directory A `## Resources` section renders in the system slot **after the policy sections
|
|
3449
|
+
§schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available this workspace, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized as the kernel-generated skill `worker://plurnk/skills/plurnk/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+skills] (worker://plurnk/skills/plurnk/*.md)` survey ({§skills-materialization}), keeping the raw packet free of doc links. Meta-owned `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc.
|
|
3111
3450
|
|
|
3112
3451
|
### §inject system.inject — the operator injection
|
|
3113
3452
|
|
|
3114
|
-
§packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policy → project policy →
|
|
3453
|
+
§packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policy → project policy → resources → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
|
|
3115
3454
|
|
|
3116
3455
|
### §policy system.policy — the client's policy injection
|
|
3117
3456
|
|
|
3118
|
-
§policy-sections
|
|
3457
|
+
§policy-sections One section rides the system slot **after the definition and before capability teaching**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}). Policy is the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker://plurnk/agents.md` entry ({§turn0-agents-stunt}); all other reference material is skills under the skills tree ({§skills-materialization}).
|
|
3119
3458
|
|
|
3120
|
-
On first run, and only when
|
|
3459
|
+
On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
|
|
3121
3460
|
`AGENTS.md` from `@plurnk/plurnk-meta/PLURNK_PERSONALITY.md` ({§teaching-corpus}).
|
|
3122
3461
|
It reads that required source before creating the service home; a failed read
|
|
3123
3462
|
surfaces with its cause and leaves no apparently initialized home.
|
|
3124
3463
|
After that bootstrap the file is user-owned: edits and deletion persist, and a
|
|
3125
3464
|
later boot never refreshes or recreates it.
|
|
3126
3465
|
|
|
3127
|
-
§
|
|
3466
|
+
§legacy-home-transition A legacy `~/.plurnk` is never an ambient fallback. If
|
|
3467
|
+
legacy state exists while canonical destinations do not, ordinary startup
|
|
3468
|
+
fails with the exact `plurnk-service paths migrate` recovery. That explicit,
|
|
3469
|
+
idempotent command refuses destination conflicts and a live database owner,
|
|
3470
|
+
moves known user configuration and durable SQLite files to their semantic
|
|
3471
|
+
homes, byte-verifies the complete copied set before removing any source,
|
|
3472
|
+
discards only recognized generated references, and removes the empty legacy
|
|
3473
|
+
directory. A pre-commit failure rolls back canonical files and directories
|
|
3474
|
+
created by that attempt. Unknown legacy members or simultaneous
|
|
3475
|
+
legacy/canonical state fail without guessing. No dual read or dual write survives
|
|
3476
|
+
the transition.
|
|
3477
|
+
|
|
3478
|
+
§schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workspaceId)` renders the effective directory, `SchemeRegistry.docs(workspaceId)` resolves corpus-or-manifest documentation, and `referenceEntries(workspaceId)` supplies the current `/skills/plurnk/` generated-skill set when core publishes workspace capabilities ({§skills-materialization}). One materializer reconciles the reserved scope exactly: vanished contributions are deleted before current documents are upserted, so an excluded scheme or disabled, detached, replaced, or removed runtime cannot leave a stale model-facing contract.
|
|
3128
3479
|
|
|
3129
3480
|
### §packet-git-status The Git status section — compact repository state
|
|
3130
3481
|
|
|
@@ -3285,15 +3636,16 @@ projection, and binary handling. Text scope meaning does not vary by mimetype.
|
|
|
3285
3636
|
§render-rule-line-navigable-prefix Every textual content body with a source
|
|
3286
3637
|
`startLine` renders with a coordinate prefix on each physical line, independent
|
|
3287
3638
|
of mimetype. A successful exact READ whose active scheme declares
|
|
3288
|
-
`textEditScopes: true`
|
|
3639
|
+
`lineAnchors: true`, or `textEditScopes: true` with model write authority, supplies `@hash N:` with one
|
|
3289
3640
|
or more ASCII spaces before `N` under
|
|
3290
|
-
{§line-anchors};
|
|
3641
|
+
{§line-anchors}; generated FIND rows render a result ordinal left-padded to the
|
|
3642
|
+
complete result total's width; every other body renders `N:` left-padded to its own largest line number's width, so every body keeps one stable content column. JSON, XML, and HTML are therefore just as
|
|
3291
3643
|
line-addressable as markdown and source code. The prefix is a packet
|
|
3292
3644
|
presentation aid, never part of canonical content; matchers and mutations
|
|
3293
3645
|
consume canonical bytes before rendering. A producer may set `startLine: null`
|
|
3294
3646
|
only when its content is already source-numbered, such as an effect receipt.
|
|
3295
3647
|
|
|
3296
|
-
§render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND,
|
|
3648
|
+
§render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
|
|
3297
3649
|
|
|
3298
3650
|
An `EDIT` log row renders its bounded effect receipt (`rx.receipt`) as row
|
|
3299
3651
|
metadata and join context, not its input statement. Proposal-gated file EDITs
|
|
@@ -3343,7 +3695,7 @@ Carried from the contract walk; durable.
|
|
|
3343
3695
|
{§copy-move-observation}.
|
|
3344
3696
|
- **READ rx** prefixes every textual line under {§render-rule}; eligible
|
|
3345
3697
|
editable resources carry `@hash N:`, and all others carry `N:`.
|
|
3346
|
-
- **FIND body matcher** applies to entry
|
|
3698
|
+
- **FIND body matcher** applies to the addressed entry channel (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope and channel select candidates; the path-glob is the (target). FIND's signal classifies its own log item ({§log-item-tags}).
|
|
3347
3699
|
- **OPEN/FOLD** operate on the **log** (`log:///`), not entries ({§open-fold}) — FOLD collapses a log row to its path, OPEN restores its body. Aimed at an entry scheme they return 501.
|
|
3348
3700
|
- **SEND signal `410`** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND signal `499`** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
|
|
3349
3701
|
- **File scheme** detects with `Mimetypes.detect({ path })` and classifies with the same configured service ({§mimetype-classification-consumption}). Handler-declared binary sources materialize through {§membership-source-projection}; projected bodies are READ-able, while source-aware EDIT remains 415.
|