@evoclock/pi-agentic-driver 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agentic-driver/router.defaults.json +64 -0
- package/LICENSE +11 -8
- package/README.md +94 -29
- package/extensions/attended-authority-guard.ts +1 -1
- package/extensions/code-phage.js +1 -1
- package/extensions/herdr-communication.ts +9 -2
- package/extensions/herdr-dispatch.ts +1 -1
- package/extensions/herdr-lifecycle.ts +5 -4
- package/extensions/linux-microvm.ts +1 -1
- package/extensions/pulse.ts +105 -0
- package/extensions/task-board.ts +1 -1
- package/lib/adapters/diff-scope.mjs +1 -1
- package/lib/adapters/evidence.mjs +1 -1
- package/lib/adapters/narrative.mjs +1 -1
- package/lib/adapters/review-feedback.mjs +1 -1
- package/lib/adapters/visualization.mjs +1 -1
- package/lib/code-phage-core.mjs +1 -1
- package/lib/python_ast_metrics.py +1 -1
- package/lib/typescript_ast_metrics.mjs +1 -1
- package/package.json +17 -3
- package/scripts/aidr_writing_review.js +1 -1
- package/scripts/enforcement/attended_authority_guard.js +1 -1
- package/scripts/enforcement/guest_containment_taxonomy.v1.json +1 -1
- package/scripts/enforcement/herdr_async_dispatch_pi.js +66 -4
- package/scripts/enforcement/herdr_communication_pi.js +55 -19
- package/scripts/enforcement/herdr_lifecycle_pi.js +3 -3
- package/scripts/enforcement/linux_microvm_cutover_pi.js +1 -1
- package/scripts/enforcement/native_tui_context.js +1 -1
- package/scripts/enforcement/pulse_core_pi.js +292 -0
- package/scripts/enforcement/pulse_scheduler_pi.js +1083 -0
- package/scripts/enforcement/router_engine_pi.js +483 -0
- package/scripts/enforcement/router_ranking_pi.js +146 -0
- package/scripts/enforcement/router_replacement_pi.js +98 -0
- package/scripts/enforcement/router_runtime_pi.js +299 -0
- package/scripts/enforcement/router_schemas_pi.js +604 -0
- package/scripts/enforcement/router_store_pi.js +438 -0
- package/scripts/enforcement/task_board_core_pi.js +597 -48
- package/skills/pulse/SKILL.md +39 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": "agentic-driver.router-config.v1",
|
|
3
|
+
"revision": 1,
|
|
4
|
+
"endpoints": {
|
|
5
|
+
"local-default": {
|
|
6
|
+
"url": "http://127.0.0.1:8080",
|
|
7
|
+
"kind": "llama-server"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"seats": [
|
|
11
|
+
{
|
|
12
|
+
"schema": "agentic-driver.seat.v1",
|
|
13
|
+
"seatId": "local-default",
|
|
14
|
+
"kind": "local",
|
|
15
|
+
"provider": "llama-server",
|
|
16
|
+
"accountId": null,
|
|
17
|
+
"endpointRef": "local-default",
|
|
18
|
+
"model": "replace-with-installed-model",
|
|
19
|
+
"capabilities": ["implement", "review"],
|
|
20
|
+
"containmentTier": "none",
|
|
21
|
+
"maxConcurrency": 1,
|
|
22
|
+
"costClass": "free",
|
|
23
|
+
"quotaCollector": null,
|
|
24
|
+
"clusterMembership": null,
|
|
25
|
+
"enabled": false,
|
|
26
|
+
"deprecated": null
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"models": {
|
|
30
|
+
"replace-with-installed-model": {
|
|
31
|
+
"aliases": [],
|
|
32
|
+
"contextWindow": 32768,
|
|
33
|
+
"capabilities": ["implement", "review"]
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"collectors": {},
|
|
37
|
+
"eligibility": {
|
|
38
|
+
"rules": [],
|
|
39
|
+
"reserve": {
|
|
40
|
+
"floorPercent": 40,
|
|
41
|
+
"scope": "account-window",
|
|
42
|
+
"coldStartFraction": 0.25,
|
|
43
|
+
"estimateSamples": 20,
|
|
44
|
+
"estimateMinSamples": 5,
|
|
45
|
+
"estimateOutlierSigma": 3,
|
|
46
|
+
"ownerInteractiveOverride": false
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"preferences": {
|
|
50
|
+
"order": [{ "seatId": "local-default" }],
|
|
51
|
+
"costPolicy": "free-first"
|
|
52
|
+
},
|
|
53
|
+
"ranking": {
|
|
54
|
+
"enabled": false,
|
|
55
|
+
"janusUrl": "http://127.0.0.1:7431",
|
|
56
|
+
"maxCandidates": 8,
|
|
57
|
+
"fallback": "preference-order"
|
|
58
|
+
},
|
|
59
|
+
"localHealth": {
|
|
60
|
+
"probeSeconds": 60,
|
|
61
|
+
"warmStateTracking": true
|
|
62
|
+
},
|
|
63
|
+
"secrets": {}
|
|
64
|
+
}
|
package/LICENSE
CHANGED
|
@@ -723,14 +723,17 @@ on the Software.
|
|
|
723
723
|
COMMERCIAL LICENCE OPTION
|
|
724
724
|
================================================================================
|
|
725
725
|
|
|
726
|
-
|
|
727
|
-
General Public License
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
726
|
+
Commercial use, modification, and distribution are permitted under
|
|
727
|
+
the GNU Affero General Public License when all AGPL obligations and
|
|
728
|
+
the additional terms of Section 7(b) above are followed. This includes
|
|
729
|
+
the network-use source-disclosure obligation of Section 13 and the
|
|
730
|
+
required preservation of attribution.
|
|
731
|
+
|
|
732
|
+
A separate commercial licence is available for organisations that
|
|
733
|
+
require proprietary modifications, do not wish to disclose covered
|
|
734
|
+
source as required by the AGPL, need alternative attribution terms, or
|
|
735
|
+
otherwise cannot or do not wish to comply with the AGPL. Contact the
|
|
736
|
+
author for details.
|
|
734
737
|
|
|
735
738
|
When published, the commercial licence template will be available at
|
|
736
739
|
COMMERCIAL.md in this repository.
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pi-agentic-driver
|
|
1
|
+
# pi-agentic-driver
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<img src="assets/Yamagane-origami.png" alt="pi-agentic-driver, Yamagane origami mark" width="140"/>
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL%20v3-blue?style=flat" alt="License: AGPL v3"/></a>
|
|
9
9
|
<a href="https://www.npmjs.com/package/@evoclock/pi-agentic-driver"><img src="https://img.shields.io/npm/v/@evoclock/pi-agentic-driver?style=flat" alt="npm version"/></a>
|
|
10
|
-
<img src="https://img.shields.io/badge/version-0.9.0-blue?style=flat" alt="Version 0.9.0"/>
|
|
11
10
|
<img src="https://img.shields.io/badge/status-active%20development%20%26%20testing-orange?style=flat" alt="Status"/>
|
|
12
11
|
<img src="https://img.shields.io/badge/JavaScript-F7DF1E?style=flat&logo=javascript&logoColor=black" alt="JavaScript"/>
|
|
13
12
|
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat&logo=typescript&logoColor=white" alt="TypeScript"/>
|
|
@@ -53,6 +52,7 @@ proofs for agentic workflows.
|
|
|
53
52
|
| `agentic_kanban_board_write` | Adds cards to the board through the trusted writer, which records who authorized the work. | shipped |
|
|
54
53
|
| `agentic_kanban_board_update` | Moves, closes, flags, edits, or removes cards on the board, always recording who authorized the change. | shipped |
|
|
55
54
|
| `agentic_kanban_board_dispatch` | Claims an eligible board card for automated contained work and creates its assignment envelope. | shipped |
|
|
55
|
+
| `agentic_kanban_pulse` | Checks for ready work and available capacity, then starts assignments under the board policy. | shipped |
|
|
56
56
|
|
|
57
57
|
**Status: active development and testing.** Each extension ships only after
|
|
58
58
|
it passes fixture-based acceptance, native tests, live-session checks, and
|
|
@@ -66,7 +66,7 @@ components are listed here for transparency and are not packaged.
|
|
|
66
66
|
<details>
|
|
67
67
|
<summary><strong>code-phage, advisory code review</strong> <em>(released, 0.1.1)</em></summary>
|
|
68
68
|
|
|
69
|
-
`code_phage` reviews a proposed change against a stated goal before the agent
|
|
69
|
+
The `code_phage` tool reviews a proposed change against a stated goal before the agent
|
|
70
70
|
writes or commits code. Give it a goal, candidate files, accepted
|
|
71
71
|
requirements, and test paths. It will:
|
|
72
72
|
|
|
@@ -109,8 +109,10 @@ only, not a runtime dependency).
|
|
|
109
109
|
<details>
|
|
110
110
|
<summary><strong>herdr-communication, controlled role communication</strong> <em>(released, 0.2.1)</em></summary>
|
|
111
111
|
|
|
112
|
-
`agentic_herdr_communication` exchanges controlled, marked reports with
|
|
113
|
-
configured Pi worker roles running under [Herdr](https://herdr.dev/)
|
|
112
|
+
The `agentic_herdr_communication` tool exchanges controlled, marked reports with
|
|
113
|
+
configured Pi worker roles running under [Herdr](https://herdr.dev/) (validated
|
|
114
|
+
against Herdr 0.9.1; the trust seam accepts the Homebrew-managed herdr binary
|
|
115
|
+
across versions rather than pinning one).
|
|
114
116
|
|
|
115
117
|
- **List and observe.** Worker roles are filtered to trusted repositories: a
|
|
116
118
|
checked-in registry plus canonical-path validation. Unlisted or
|
|
@@ -133,7 +135,7 @@ configured Pi worker roles running under [Herdr](https://herdr.dev/) 0.8.2.
|
|
|
133
135
|
<details>
|
|
134
136
|
<summary><strong>herdr-lifecycle, role-labelled worker dispatch</strong> <em>(released, 0.2.1)</em></summary>
|
|
135
137
|
|
|
136
|
-
`agentic_herdr_spawn_worker` turns one natural-language request into Herdr's
|
|
138
|
+
The `agentic_herdr_spawn_worker` tool turns one natural-language request into Herdr's
|
|
137
139
|
native lifecycle. Choose a placement (`right`, `below`, or `tab`), a safe role
|
|
138
140
|
label, a model from the active Pi model roster, and a trusted repository. The
|
|
139
141
|
extension:
|
|
@@ -165,7 +167,7 @@ for the wider task and model-routing workflow.
|
|
|
165
167
|
<details>
|
|
166
168
|
<summary><strong>herdr-dispatch, continuous worker journeys</strong> <em>(released, 0.5.0)</em></summary>
|
|
167
169
|
|
|
168
|
-
`agentic_worker_dispatch` runs controlled worker journeys and observes worker
|
|
170
|
+
The `agentic_worker_dispatch` tool runs controlled worker journeys and observes worker
|
|
169
171
|
liveness. Two actions:
|
|
170
172
|
|
|
171
173
|
- **pulse** reports whether a worker role is alive, its current state, and
|
|
@@ -192,7 +194,7 @@ silently, and return results as untrusted evidence.
|
|
|
192
194
|
|
|
193
195
|
|
|
194
196
|
<details>
|
|
195
|
-
<summary><strong>task board, planned and automated work you can see</strong> <em>(released, 0.9.
|
|
197
|
+
<summary><strong>task board and Pulse, planned and automated work you can see</strong> <em>(released, 0.9.1)</em></summary>
|
|
196
198
|
|
|
197
199
|
Keep planned work in canonical `TASKS.md`. You can read it directly or use
|
|
198
200
|
the generated `board.md` view in Obsidian. Agents use the same canonical
|
|
@@ -216,10 +218,10 @@ For automated work, you set an explicit policy for the board. It defines:
|
|
|
216
218
|
|
|
217
219
|
Without a valid policy, automated dispatch is refused.
|
|
218
220
|
|
|
219
|
-
`agentic_kanban_board_dispatch` claims the highest-priority eligible card
|
|
220
|
-
creates a single-attempt assignment envelope
|
|
221
|
-
|
|
222
|
-
|
|
221
|
+
The `agentic_kanban_board_dispatch` tool claims the highest-priority eligible card. It
|
|
222
|
+
creates a single-attempt assignment envelope that binds the card, repository,
|
|
223
|
+
starting revision, assigned branch, allowed paths, stopping point, expiry, and
|
|
224
|
+
interaction profile.
|
|
223
225
|
|
|
224
226
|
Blocked, altered, expired, reused, or unauthorized assignments fail closed.
|
|
225
227
|
The journey validates the authenticated envelope before each consequential
|
|
@@ -232,9 +234,16 @@ Claims and envelopes are kept in authenticated state beside `TASKS.md`. The
|
|
|
232
234
|
derived `board.md` view shows active claims but never becomes an authority
|
|
233
235
|
source.
|
|
234
236
|
|
|
237
|
+
The `agentic_kanban_pulse` tool checks the board for ready work and available capacity.
|
|
238
|
+
A check only reports which work is ready to run. It does not claim cards.
|
|
239
|
+
|
|
240
|
+
Interactive host work needs explicit policy and one native confirmation for
|
|
241
|
+
the batch. Automated work requires containment and never falls back to the
|
|
242
|
+
host.
|
|
243
|
+
|
|
235
244
|
Coming next:
|
|
236
245
|
|
|
237
|
-
-
|
|
246
|
+
- contained Pulse execution through Testudo;
|
|
238
247
|
- Vogelkop support for the shared card fields; and
|
|
239
248
|
- our own Obsidian plugin for canonical `TASKS.md`.
|
|
240
249
|
|
|
@@ -259,7 +268,7 @@ writer's voice.*
|
|
|
259
268
|
<details>
|
|
260
269
|
<summary><strong>AI;DR, writing review</strong> <em>(released, 0.4.2)</em></summary>
|
|
261
270
|
|
|
262
|
-
`agentic_aidr` reviews the last assistant response, supplied prose, or a
|
|
271
|
+
The `agentic_aidr` tool reviews the last assistant response, supplied prose, or a
|
|
263
272
|
Markdown file. It checks four principles:
|
|
264
273
|
|
|
265
274
|
- **Clarity.** Each sentence carries one useful idea.
|
|
@@ -299,8 +308,8 @@ QEMU/KVM virtual machine on a Linux host. The job cannot reach the host, the
|
|
|
299
308
|
network, or anything else outside the machine. The system deletes the machine
|
|
300
309
|
after the job ends.
|
|
301
310
|
|
|
302
|
-
Isolation is off at the start of every session.
|
|
303
|
-
|
|
311
|
+
Isolation is off at the start of every session. Use the `/agentic-isolation-enable`
|
|
312
|
+
command in the Pi TUI, and confirm. The model cannot run
|
|
304
313
|
that command. Every cutover run asks for its own confirmation too. Nothing is
|
|
305
314
|
saved to settings, and headless sessions stay blocked.
|
|
306
315
|
|
|
@@ -527,10 +536,9 @@ acceptance with all prohibited effects absent.
|
|
|
527
536
|
|
|
528
537
|
### Portable repository contract
|
|
529
538
|
|
|
530
|
-
`templates/AGENTS.md` is a starting contract you can copy into any
|
|
531
|
-
that uses Pi agents. It asks for controlled tasks and realistic tests, and
|
|
532
|
-
treats agent reports as untrusted evidence. It never overwrites an existing
|
|
533
|
-
`AGENTS.md`; add your project rules below it.
|
|
539
|
+
The `templates/AGENTS.md` file is a starting contract you can copy into any
|
|
540
|
+
repository that uses Pi agents. It asks for controlled tasks and realistic tests, and
|
|
541
|
+
treats agent reports as untrusted evidence. It never overwrites an existing `AGENTS.md`. Add your project rules below it.
|
|
534
542
|
|
|
535
543
|
## Install
|
|
536
544
|
|
|
@@ -540,24 +548,24 @@ From npm:
|
|
|
540
548
|
pi install npm:@evoclock/pi-agentic-driver
|
|
541
549
|
```
|
|
542
550
|
|
|
543
|
-
Or from Git at
|
|
551
|
+
Or from Git at the latest release tag (see the repo's tags for the current one; the npm badge above shows the live version):
|
|
544
552
|
|
|
545
553
|
```sh
|
|
546
|
-
pi install git:github.com/evoclock/pi-agentic-driver
|
|
554
|
+
pi install git:github.com/evoclock/pi-agentic-driver@<latest-tag>
|
|
547
555
|
```
|
|
548
556
|
|
|
549
|
-
Released extensions load
|
|
557
|
+
Released extensions load independently.
|
|
550
558
|
|
|
551
559
|
### Choose which extensions load
|
|
552
560
|
|
|
553
|
-
A normal install loads all
|
|
561
|
+
A normal install loads all packaged extensions by default. You can load only the
|
|
554
562
|
extensions you want with the object form in your Pi settings:
|
|
555
563
|
|
|
556
564
|
```json
|
|
557
565
|
{
|
|
558
566
|
"packages": [
|
|
559
567
|
{
|
|
560
|
-
"source": "npm:@evoclock/pi-agentic-driver
|
|
568
|
+
"source": "npm:@evoclock/pi-agentic-driver",
|
|
561
569
|
"extensions": [
|
|
562
570
|
"extensions/aidr.ts",
|
|
563
571
|
"extensions/code-phage.js"
|
|
@@ -567,12 +575,69 @@ extensions you want with the object form in your Pi settings:
|
|
|
567
575
|
}
|
|
568
576
|
```
|
|
569
577
|
|
|
570
|
-
The package
|
|
571
|
-
`herdr-dispatch.ts
|
|
578
|
+
The package includes the `herdr-communication.ts`, `herdr-lifecycle.ts`, and
|
|
579
|
+
`herdr-dispatch.ts` extensions. It also includes `linux-microvm.ts`. Use `pi config` to enable or
|
|
572
580
|
disable individual resources from an installed package. You are not required
|
|
573
581
|
to use every extension.
|
|
574
582
|
|
|
583
|
+
## Router configuration
|
|
584
|
+
|
|
585
|
+
Board Pulse selects a route seat through the capacity/policy router. The
|
|
586
|
+
router reads a closed configuration file and a local-first SQLite file for
|
|
587
|
+
operational state (reservations, observations, route-decision audit).
|
|
588
|
+
|
|
589
|
+
- **Repository defaults** ship at `.agentic-driver/router.defaults.json`. The
|
|
590
|
+
template contains no accounts and one disabled placeholder seat, so it loads
|
|
591
|
+
out of the box and schedules nothing until you enable a real seat.
|
|
592
|
+
- **User profile (precedence over defaults):**
|
|
593
|
+
`~/.config/agentic-driver/router/profile.json`, or the path in the
|
|
594
|
+
`AGENTIC_DRIVER_ROUTER_PROFILE` environment variable. A profile section
|
|
595
|
+
replaces the matching defaults section wholesale; the merged config must
|
|
596
|
+
validate or the router refuses to produce decisions (fails closed).
|
|
597
|
+
- **Operational state:** `~/.local/share/agentic-driver/router/state.db`, or
|
|
598
|
+
`AGENTIC_DRIVER_ROUTER_DB`. This store is operational state only. The
|
|
599
|
+
authenticated claims file and the board writer remain the only dispatch
|
|
600
|
+
authority, and SQLite is repaired from them, never the reverse.
|
|
601
|
+
- **Runtime requirement:** the operational store uses the built-in
|
|
602
|
+
`node:sqlite` module. Node.js 22.5 or newer is required.
|
|
603
|
+
|
|
604
|
+
### Tunable configuration values
|
|
605
|
+
|
|
606
|
+
Every numeric policy in the router is a configuration key — never a
|
|
607
|
+
constant in code. All keys are **required**. The repository defaults below
|
|
608
|
+
are conservative starting values. Your profile overrides them. A missing key
|
|
609
|
+
is a configuration validation failure: the router fails closed rather than
|
|
610
|
+
guess. Changing a value participates in the configuration digest, so cached
|
|
611
|
+
routing decisions computed under the old values no longer apply.
|
|
612
|
+
|
|
613
|
+
| Section | Key | Default | What it controls |
|
|
614
|
+
|---|---|---|---|
|
|
615
|
+
| `eligibility.reserve` | `floorPercent` | 40 | Share of every quota window kept in reserve (per account, per window). Headroom for an unexpected burst and your next interactive session, without idling the account. |
|
|
616
|
+
| `eligibility.reserve` | `scope` | `account-window` | How widely the reserve floor applies (per account per window at launch). |
|
|
617
|
+
| `eligibility.reserve` | `coldStartFraction` | 0.25 | Consumption assumed for a seat with too little history: deliberately generous, so a mis-estimate fails eligibility instead of draining the account. |
|
|
618
|
+
| `eligibility.reserve` | `estimateSamples` | 20 | How many recent dispatches the consumption estimate averages: enough to smooth outliers, quick enough to track a model change. |
|
|
619
|
+
| `eligibility.reserve` | `estimateMinSamples` | 5 | Below this many observations the average is treated as noise and the cold-start value is used instead. |
|
|
620
|
+
| `eligibility.reserve` | `estimateOutlierSigma` | 3 | Outlier cut for the estimate: one unusually slow dispatch cannot inflate the average, real tail latency is kept. |
|
|
621
|
+
| `eligibility.reserve` | `ownerInteractiveOverride` | false | Whether your own interactive dispatches bypass the reserve rule (they do not, at launch). |
|
|
622
|
+
| `ranking` | `janusUrl` | `http://127.0.0.1:8787` | The local janus evaluation service endpoint used for semantic ranking. |
|
|
623
|
+
| `ranking` | `maxCandidates` | 8 | At most eight eligible seats are ranked per request; preference order trims first. |
|
|
624
|
+
| `ranking` | `fallback` | `preference-order` | What happens when ranking is unavailable: dispatch falls back to your preference order and never blocks. |
|
|
625
|
+
| `gate` | `threshold` | 0.9 | The dispatch gate's confidence threshold. A task is only dispatched when the evaluation clears it. Lower it only with evidence from your own audit log. |
|
|
626
|
+
| `gate` | `timeoutMs` | 8000 | How long the gate waits for an evaluation. On timeout there is no verdict and dispatch is blocked (fail closed). |
|
|
627
|
+
| `gate` | `requestBudgetTokens` | 30000 | Maximum size of a gate evaluation request. Normal evaluations use under a thousand tokens. |
|
|
628
|
+
| seat record | `maxConcurrency` | 4 | How many workers one seat may run at once. The default suits a typical single machine or hosted seat. Tune it per seat: a cluster takes more, a constrained subscription endpoint may take less. |
|
|
629
|
+
| automation policy | `maxConcurrent` | 4 | How many workers may run at once across all seats. The default is a conservative start. Tune it to the capacity you actually have, and raise it when you add seats or hardware. |
|
|
630
|
+
|
|
631
|
+
Seats are named for infrastructure, not models: `dgx-spark-cluster`,
|
|
632
|
+
`mac-studio`, `merge-gateway-worker`. The model is a mutable field on the
|
|
633
|
+
seat, so changing models never renumbers your configuration. Each seat also
|
|
634
|
+
carries `scopeStatements`: plain-language descriptions of what the seat is
|
|
635
|
+
for. The dispatch gate reads them when judging whether a task fits.
|
|
636
|
+
|
|
575
637
|
## License
|
|
576
638
|
|
|
577
|
-
AGPL-3.0-
|
|
578
|
-
see [LICENSE](LICENSE).
|
|
639
|
+
AGPL-3.0-only with author-attribution additional terms (Section 7(b));
|
|
640
|
+
see [LICENSE](LICENSE). Commercial use, forks, and substantial modifications
|
|
641
|
+
are permitted when all AGPL and attribution obligations are followed. A
|
|
642
|
+
separate commercial licence is available for organisations requiring
|
|
643
|
+
proprietary modifications or other terms incompatible with the AGPL.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
4
|
export default async function attendedAuthorityGuard(pi) {
|
|
5
5
|
const module = await import(new URL("../scripts/enforcement/attended_authority_guard.js", import.meta.url).href);
|
package/extensions/code-phage.js
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
|
|
4
|
+
import { statSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
3
6
|
|
|
4
7
|
export default async function herdrCommunicationPi(pi) {
|
|
5
|
-
const
|
|
8
|
+
const moduleUrl = new URL("../scripts/enforcement/herdr_communication_pi.js", import.meta.url);
|
|
9
|
+
// Native ESM retains transitive modules across Pi's Jiti extension reload.
|
|
10
|
+
// Bind this import to the current file revision so /reload cannot reuse it.
|
|
11
|
+
moduleUrl.searchParams.set("mtime", String(statSync(fileURLToPath(moduleUrl)).mtimeMs));
|
|
12
|
+
const module = await import(moduleUrl.href);
|
|
6
13
|
return module.registerHerdrCommunicationInterface(pi);
|
|
7
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
4
|
export default async function herdrDispatchPi(pi) {
|
|
5
5
|
const dispatch = await import(new URL("../scripts/enforcement/herdr_async_dispatch_pi.js", import.meta.url).href);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import { registerHerdrLifecycleInterface } from "../scripts/enforcement/herdr_lifecycle_pi.js";
|
|
5
|
+
|
|
6
|
+
export default function herdrLifecyclePi(pi) {
|
|
7
|
+
return registerHerdrLifecycleInterface(pi);
|
|
7
8
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
4
|
import { registerLinuxMicroVMCutoverInterface, registerIsolationSwitchCommands, createIsolationSwitch } from "../scripts/enforcement/linux_microvm_cutover_pi.js";
|
|
5
5
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
|
|
4
|
+
// Board Pulse provider extension. Registers the deterministic
|
|
5
|
+
// agentic_kanban_pulse tool and owns the optional fixed-interval timer. The
|
|
6
|
+
// board is resolved per tool call from the calling session's working
|
|
7
|
+
// directory; a workspace with no board file gets a structured
|
|
8
|
+
// board-unavailable result. Board Pulse is capacity scheduling; it is
|
|
9
|
+
// distinct from Herdr worker liveness pulse.
|
|
10
|
+
//
|
|
11
|
+
// No resources start in the extension factory: the timer is created and
|
|
12
|
+
// started only on session_start and cleared idempotently on session_shutdown
|
|
13
|
+
// (PULSE_DESIGN_v3 §8). The worker spawn seam is the existing guarded
|
|
14
|
+
// herdr-lifecycle boundary — native confirmation, trusted repository,
|
|
15
|
+
// installed model roll, fixed argv, shell:false — never raw pane management.
|
|
16
|
+
|
|
17
|
+
import { executeHerdrSpawnWorker } from "../scripts/enforcement/herdr_lifecycle_pi.js";
|
|
18
|
+
import { resolveBoardPath, registerPulseTools, createPulseTimer, pulseTick, pulseWorkerSpawnSeam } from "../scripts/enforcement/pulse_scheduler_pi.js";
|
|
19
|
+
import { prepareRouterRuntimeWithHealth, closeCachedRouterStores } from "../scripts/enforcement/router_runtime_pi.js";
|
|
20
|
+
|
|
21
|
+
export default function pulsePi(pi) {
|
|
22
|
+
|
|
23
|
+
// Guarded worker-creation seam (§2.5): every Pulse spawn goes through
|
|
24
|
+
// pulseWorkerSpawnSeam, which is placement-aware and fails closed — host
|
|
25
|
+
// placements route to executeHerdrSpawnWorker (native confirmation,
|
|
26
|
+
// verification); container/microvm placements are denied before any host
|
|
27
|
+
// worker is ever started. No other creation path exists.
|
|
28
|
+
const spawnWorker = pulseWorkerSpawnSeam({ executeHerdrSpawnWorker });
|
|
29
|
+
|
|
30
|
+
// The runtime is rebuilt per tool call and per automated tick (W3): a
|
|
31
|
+
// snapshot frozen at session setup would leave every subscription seat
|
|
32
|
+
// stale after the first observation expiry and freeze the prior-reservation
|
|
33
|
+
// term. The localHealth probe adapter (W2) is attached here, producing
|
|
34
|
+
// endpoint-keyed fresh health observations for local seats. `check`
|
|
35
|
+
// assembles the runtime read-only (W4): no store writes, no store creation.
|
|
36
|
+
const routerRuntimeFor = async (ctx, boardPath, { readOnly = false } = {}) => {
|
|
37
|
+
const runtime = await prepareRouterRuntimeWithHealth({
|
|
38
|
+
repoRoot: ctx?.cwd || process.cwd(), boardPath,
|
|
39
|
+
defaultsPath: ctx?.routerDefaultsPath ?? null, profilePath: ctx?.routerProfilePath ?? null,
|
|
40
|
+
dbPath: ctx?.routerDbPath ?? null, cacheRoot: ctx?.routerCacheRoot ?? null,
|
|
41
|
+
consumptionReceipts: ctx?.consumptionReceipts ?? [], readOnly,
|
|
42
|
+
fetchFn: ctx?.routerHealthFetch ?? null,
|
|
43
|
+
});
|
|
44
|
+
const installed = new Set(runtime.routerConfig.seats.map((seat) => seat.model).filter((model) => {
|
|
45
|
+
try { return ctx?.modelRegistry?.get?.(model) != null; } catch { return false; }
|
|
46
|
+
}));
|
|
47
|
+
runtime.routerSnapshot.modelInstalled = installed;
|
|
48
|
+
return { ...runtime, activeSessions: ctx?.activeSessions ?? [], providerLimit: ctx?.providerLimit ?? null };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const result = registerPulseTools(pi, {
|
|
52
|
+
resolveBoardPath: (ctx) => resolveBoardPath(typeof ctx === "string" ? ctx : ctx?.cwd || process.cwd()),
|
|
53
|
+
spawnWorker,
|
|
54
|
+
routerRuntimeFor,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Optional timer (§8): created only after session_start, only when the
|
|
58
|
+
// resolved workspace policy enables Pulse in automated mode with a valid
|
|
59
|
+
// interval. fillOnStart queues one tick after startup; it is not catch-up.
|
|
60
|
+
// Ticks never overlap and missed ticks are never replayed. Reload/new/
|
|
61
|
+
// resume/fork emit session_shutdown first, so exactly one fresh runtime
|
|
62
|
+
// exists at a time and no in-memory single-flight state is inherited.
|
|
63
|
+
let timer = null;
|
|
64
|
+
const clearTimer = () => {
|
|
65
|
+
if (timer) {
|
|
66
|
+
timer.clear();
|
|
67
|
+
timer = null;
|
|
68
|
+
}
|
|
69
|
+
// Release the cached per-dbPath store handles with the session so the
|
|
70
|
+
// runtime never accumulates DatabaseSync handles (W5).
|
|
71
|
+
closeCachedRouterStores();
|
|
72
|
+
};
|
|
73
|
+
const setupTimer = async (_event, ctx) => {
|
|
74
|
+
clearTimer();
|
|
75
|
+
try {
|
|
76
|
+
const boardPath = resolveBoardPath(ctx?.cwd || process.cwd());
|
|
77
|
+
if (!boardPath) return;
|
|
78
|
+
const { readAutomationPolicy, checkAutomationPolicy } = await import(new URL("../scripts/enforcement/task_board_core_pi.js", import.meta.url).href);
|
|
79
|
+
const policy = readAutomationPolicy(boardPath);
|
|
80
|
+
const check = checkAutomationPolicy(policy, { boardPath });
|
|
81
|
+
const pulse = check.ok ? check.policy.pulse : null;
|
|
82
|
+
if (!pulse || pulse.enabled !== true || pulse.mode !== "automated") return;
|
|
83
|
+
// W3: the tick asks for a FRESH runtime every tick instead of reusing a
|
|
84
|
+
// setup-time snapshot. The factory re-reads collector caches, health
|
|
85
|
+
// probes, and the prior-reservation term under the read-time freshness
|
|
86
|
+
// rules; a factory failure fails that tick closed.
|
|
87
|
+
timer = createPulseTimer({
|
|
88
|
+
intervalSeconds: pulse.intervalSeconds,
|
|
89
|
+
fillOnStart: pulse.fillOnStart === true,
|
|
90
|
+
tick: () => pulseTick({ boardPath, spawnWorker, context: ctx,
|
|
91
|
+
routerRuntimeFor: () => routerRuntimeFor(ctx, boardPath, { readOnly: false }) }),
|
|
92
|
+
});
|
|
93
|
+
timer.start();
|
|
94
|
+
} catch {
|
|
95
|
+
// No-board/no-policy/disabled policy produce zero scheduling effects.
|
|
96
|
+
clearTimer();
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
if (typeof pi?.on === "function") {
|
|
100
|
+
pi.on("session_start", setupTimer);
|
|
101
|
+
pi.on("session_shutdown", clearTimer);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return result;
|
|
105
|
+
}
|
package/extensions/task-board.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
4
|
// BOARD-1 provider extension. Both tools register at startup; the board is
|
|
5
5
|
// resolved per tool call from the calling session's working directory. A
|
package/lib/code-phage-core.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Julen Gamboa <j.a.r.gamboa@gmail.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
3
|
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evoclock/pi-agentic-driver",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Guardrail extensions for Agentic Driver: advisory review, bounded Herdr communication, and guarded worker lifecycle.",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"license": "AGPL-3.0-
|
|
6
|
+
"license": "AGPL-3.0-only",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22.5.0"
|
|
9
|
+
},
|
|
7
10
|
"keywords": [
|
|
8
11
|
"pi-package",
|
|
9
12
|
"pi-extension",
|
|
@@ -40,6 +43,7 @@
|
|
|
40
43
|
"extensions/herdr-communication.ts",
|
|
41
44
|
"extensions/herdr-dispatch.ts",
|
|
42
45
|
"extensions/task-board.ts",
|
|
46
|
+
"extensions/pulse.ts",
|
|
43
47
|
"lib/adapters/diff-scope.mjs",
|
|
44
48
|
"lib/adapters/evidence.mjs",
|
|
45
49
|
"lib/adapters/narrative.mjs",
|
|
@@ -66,7 +70,17 @@
|
|
|
66
70
|
"extensions/aidr.ts",
|
|
67
71
|
"scripts/aidr_writing_review.js",
|
|
68
72
|
"templates/AGENTS.md",
|
|
69
|
-
"scripts/enforcement/task_board_core_pi.js"
|
|
73
|
+
"scripts/enforcement/task_board_core_pi.js",
|
|
74
|
+
"scripts/enforcement/pulse_core_pi.js",
|
|
75
|
+
"scripts/enforcement/pulse_scheduler_pi.js",
|
|
76
|
+
"scripts/enforcement/router_engine_pi.js",
|
|
77
|
+
"scripts/enforcement/router_schemas_pi.js",
|
|
78
|
+
"scripts/enforcement/router_ranking_pi.js",
|
|
79
|
+
"scripts/enforcement/router_store_pi.js",
|
|
80
|
+
"scripts/enforcement/router_replacement_pi.js",
|
|
81
|
+
"scripts/enforcement/router_runtime_pi.js",
|
|
82
|
+
".agentic-driver/router.defaults.json",
|
|
83
|
+
"skills/pulse/SKILL.md"
|
|
70
84
|
],
|
|
71
85
|
"pi": {
|
|
72
86
|
"extensions": [
|