@alphazede/bearing-lite 0.1.10 → 0.1.11
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/README.md +43 -25
- package/hooks/closeout.cjs +64 -15
- package/hooks/com.anthropic.claude-code/host.cjs +8 -11
- package/hooks/com.anthropic.claude-code/mapping.md +16 -2
- package/hooks/planning-review.cjs +99 -0
- package/hooks/transition-order.cjs +13 -0
- package/package.json +6 -3
- package/plugin.json +1 -1
- package/skills/bearing-lite/SKILL.md +39 -46
- package/skills/bearing-lite/agents/openai.yaml +1 -1
- package/skills/bearing-lite/references/peer-synthesis.md +1 -1
- package/skills/bearing-lite/references/review-policy.md +37 -0
- package/skills/bearing-lite/references/role-routing.mmd +9 -9
- package/skills/bearing-lite/references/task-state.md +2 -2
- package/skills/bearing-lite/templates/default-role-lineup.md +4 -2
- package/skills/bearing-lite/templates/task.md +64 -16
- package/skills/crewmate/SKILL.md +23 -17
- package/skills/explorer/SKILL.md +34 -34
- package/skills/gather-supplies/SKILL.md +2 -1
- package/skills/map-the-route/SKILL.md +47 -36
- package/skills/map-the-route/references/artifact-grammar.md +52 -11
- package/skills/navigator/SKILL.md +18 -41
- package/skills/park-ranger/SKILL.md +14 -11
- package/skills/surveyor/SKILL.md +14 -13
- package/skills/validator/SKILL.md +14 -12
package/README.md
CHANGED
|
@@ -8,10 +8,11 @@ planning, routing, bounded execution, and independent review of repository work.
|
|
|
8
8
|
It ships portable skills, references, templates, and optional client hooks.
|
|
9
9
|
|
|
10
10
|
An agent cannot certify its own work. The stateful Router owns the planning
|
|
11
|
-
conversation
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
verified deterministically without another review. Owner
|
|
11
|
+
conversation, visible Journey state, and Expedition sequencing. Crewmate and
|
|
12
|
+
Explorer may continue in-wave when the envelope is unchanged. Independent
|
|
13
|
+
assurance runs once at the end on the final integrated candidate. One repair
|
|
14
|
+
may follow; it is verified deterministically without another review. Owner
|
|
15
|
+
Authority remains human-only.
|
|
15
16
|
|
|
16
17
|
Bearing Lite was created by William Rumph.
|
|
17
18
|
|
|
@@ -28,9 +29,10 @@ Then give your agent a real task:
|
|
|
28
29
|
> Use Bearing Lite to add rate limiting to this API without changing its public
|
|
29
30
|
> responses. Require one independent review at the end.
|
|
30
31
|
|
|
31
|
-
Bearing Lite
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
Bearing Lite fills missing planning stages, then Map the Route creates the
|
|
33
|
+
complete five-artifact package with proposed route, lineup, role states,
|
|
34
|
+
reasoning, and at-end cadence. One integrated owner review approves or changes
|
|
35
|
+
that package before bounded sessions dispatch with visible Markdown state.
|
|
34
36
|
|
|
35
37
|
If Bearing Lite helps keep a long agent task scoped and reviewable,
|
|
36
38
|
[star the repository](https://github.com/alphazede/bearing-lite). It helps other
|
|
@@ -66,13 +68,25 @@ agy plugin install /path/to/bearing-lite/.agy
|
|
|
66
68
|
|
|
67
69
|
# Pi — skills package, no command hooks
|
|
68
70
|
pi install npm:@alphazede/bearing-lite
|
|
71
|
+
|
|
72
|
+
# DeepCode — discover the packaged skills through ~/.deepcode/skills or ~/.agents/skills;
|
|
73
|
+
# DeepCode has no plugin-install or command-hook surface
|
|
69
74
|
```
|
|
70
75
|
|
|
71
76
|
Claude Code, Codex, Grok Build, Cursor, and Kimi Code are **partial** hook
|
|
72
77
|
clients: session start runs the activation advisory and stop runs the closeout
|
|
73
|
-
advisory. AGY and
|
|
74
|
-
checks stay in the skills on every host. Node.js must be on
|
|
75
|
-
hook adapters.
|
|
78
|
+
advisory. AGY, Pi, and DeepCode are **skills-only**. Transition-order and
|
|
79
|
+
protected-action checks stay in the skills on every host. Node.js must be on
|
|
80
|
+
`PATH` for the hook adapters.
|
|
81
|
+
|
|
82
|
+
Planning-review constraints live only in
|
|
83
|
+
[`skills/bearing-lite/references/review-policy.md`](skills/bearing-lite/references/review-policy.md);
|
|
84
|
+
the shared evaluator is `hooks/planning-review.cjs`. Journey-specific abstract
|
|
85
|
+
slot IDs and owner-selected primary/ordered fallback route references belong
|
|
86
|
+
only in the approved `lineup_snapshot`. Existing host mappings cannot safely
|
|
87
|
+
derive the nested record from session events, so they preserve partial or
|
|
88
|
+
skills-only coverage and apply this gate procedurally. Planning review is a
|
|
89
|
+
pre-dispatch plan gate; implementation `max_assurance_rounds` remains separate.
|
|
76
90
|
|
|
77
91
|
**Skills-only copy** of `skills/` into a host skills directory does not
|
|
78
92
|
register hooks. That path remains first-class. See
|
|
@@ -80,11 +94,14 @@ register hooks. That path remains first-class. See
|
|
|
80
94
|
|
|
81
95
|
## What it does
|
|
82
96
|
|
|
83
|
-
1. **
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
1. **Fill only missing planning stages:** Repository Fit → Set Bearings → Gather
|
|
98
|
+
Supplies.
|
|
99
|
+
2. **Invoke Map the Route** after material intent is settled. It creates
|
|
100
|
+
specification, design, SEIT, implementation, and `review.html` together.
|
|
101
|
+
3. **Review once:** approve or change the proposed route, user-owned
|
|
102
|
+
primary/fallback lineup, role states, reasoning, at-end cadence, and plan.
|
|
103
|
+
4. **Dispatch bounded sessions** with compact receipts. Crewmate and Explorer may
|
|
104
|
+
continue in-wave; assurance always starts fresh at the end.
|
|
88
105
|
5. **Record state visibly** in human-readable Markdown artifacts only.
|
|
89
106
|
|
|
90
107
|
Bearing Lite never selects models, providers, credentials, or launchers. The
|
|
@@ -97,11 +114,11 @@ the applicable Journey snapshot before implementation.
|
|
|
97
114
|
| Route | When | Cost |
|
|
98
115
|
|---|---|---|
|
|
99
116
|
| **Explorer Journey** | One bounded packet or one wave | Direct Crewmate or one Explorer |
|
|
100
|
-
| **Expedition** | Multi-phase or concurrent independent lanes |
|
|
117
|
+
| **Expedition** | Multi-phase or concurrent independent lanes | Router sequences; Explorer owns waves |
|
|
101
118
|
|
|
102
119
|
An **Explorer Journey** uses a direct Crewmate for one ready packet or one
|
|
103
120
|
Explorer over a compact/sequential wave.
|
|
104
|
-
**Expedition**
|
|
121
|
+
**Expedition** lets the Router sequence waves so independent lanes
|
|
105
122
|
stay small and sharp instead of degrading in one long context. Either shape can
|
|
106
123
|
use substantial tokens; the product does not impose a default budget ceiling.
|
|
107
124
|
|
|
@@ -112,19 +129,20 @@ The text below remains authoritative for clients that do not render Mermaid.
|
|
|
112
129
|
|
|
113
130
|
**Authoritative text (vision optional):** Owner Authority remains human-only. The
|
|
114
131
|
Bearing Lite Router is the stateful planning controller, not a work role. It
|
|
115
|
-
invokes only missing planning stages
|
|
116
|
-
|
|
132
|
+
invokes only missing planning stages, has Map the Route generate all five
|
|
133
|
+
artifacts with proposed lineup and `review_cadence: at-end`, then presents one
|
|
134
|
+
integrated owner review before dispatching an Explorer Journey or Expedition. Explorer
|
|
117
135
|
coordinates proven-independent in-wave lanes without a nested coordinator.
|
|
118
|
-
Validator, Park Ranger, and Surveyor appear only when declared and
|
|
119
|
-
|
|
136
|
+
Validator, Park Ranger, and Surveyor appear only when declared and only at the
|
|
137
|
+
end on the final integrated candidate. Diagrams
|
|
120
138
|
explain orientation; they never authorize a transition.
|
|
121
139
|
|
|
122
140
|
## Roles and authority
|
|
123
141
|
|
|
124
142
|
| Role | What it is | Executes | Notes |
|
|
125
143
|
|---|---|---|---|
|
|
126
|
-
| **Router** | Stateful planning controller | no | User-facing; planning-state writer |
|
|
127
|
-
| **Navigator** |
|
|
144
|
+
| **Router** | Stateful planning controller | no | User-facing; planning-state writer; Expedition sequencing |
|
|
145
|
+
| **Navigator** | Compatibility diagnostic | no | Not a normal role; existing plans reroute to Router |
|
|
128
146
|
| **Explorer** | One-wave controller | no | Dispatches Crewmates; owns proven-independent lanes |
|
|
129
147
|
| **Crewmate** | Bounded implementer | yes | Most hands-on work; exact write set |
|
|
130
148
|
| **Validator** | Evidence sufficiency | no | Independent of the author |
|
|
@@ -141,7 +159,7 @@ Failure escalates to the nearest role whose scope can see it:
|
|
|
141
159
|
|---|---|
|
|
142
160
|
| Within one slice or packet | Explorer or nearest parent |
|
|
143
161
|
| Across slices in a wave | Explorer |
|
|
144
|
-
| Across waves or phases |
|
|
162
|
+
| Across waves or phases | Router |
|
|
145
163
|
| Contract, security, or authority change | Owner Authority |
|
|
146
164
|
|
|
147
165
|
## Task state (explanatory)
|
|
@@ -162,7 +180,7 @@ no second review. Diagrams never create state or authorize transitions.
|
|
|
162
180
|
## Implementation process (explanatory)
|
|
163
181
|
|
|
164
182
|
Default packet completion is author self-check plus coordinator confirmation.
|
|
165
|
-
Declared independent assurance runs once at the
|
|
183
|
+
Declared independent assurance runs once at the end. A repairable
|
|
166
184
|
verdict permits one repair; deterministic coordinator verification then closes
|
|
167
185
|
the gate without another review. Once the Journey is `COMPLETE`, an already
|
|
168
186
|
authorized deployment proceeds with operational checks and rollback readiness,
|
package/hooks/closeout.cjs
CHANGED
|
@@ -10,25 +10,42 @@
|
|
|
10
10
|
const HOOK_CLASS = "closeout";
|
|
11
11
|
const OUTCOMES = Object.freeze(["ADVISE", "REROUTE", "BLOCK", "UNAVAILABLE"]);
|
|
12
12
|
const ENFORCEMENT = "procedural";
|
|
13
|
+
const { evaluatePlanningReview } = require("./planning-review.cjs");
|
|
13
14
|
|
|
14
15
|
const HANDOFF_FIELDS = Object.freeze([
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"authority",
|
|
21
|
-
"outcome",
|
|
22
|
-
"evidence",
|
|
16
|
+
"verdict",
|
|
17
|
+
"candidate_ref",
|
|
18
|
+
"changed_paths",
|
|
19
|
+
"tests",
|
|
20
|
+
"findings",
|
|
23
21
|
"blocker",
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
]);
|
|
23
|
+
|
|
24
|
+
/** Closed role-return tokens. Task-block `outcome` is intent and cannot satisfy this. */
|
|
25
|
+
const VERDICT_VALUES = new Set([
|
|
26
|
+
"ACCEPT",
|
|
27
|
+
"ACCEPT_WITH_FINDINGS",
|
|
28
|
+
"BLOCK",
|
|
29
|
+
"CANDIDATE_READY",
|
|
30
|
+
"FAIL",
|
|
31
|
+
"GAPS",
|
|
32
|
+
"NEEDS_MORE_EVIDENCE",
|
|
33
|
+
"OWNER_DECISION_REQUIRED",
|
|
34
|
+
"PARTIAL",
|
|
35
|
+
"PASS",
|
|
36
|
+
"READY",
|
|
37
|
+
"REPAIR_REQUIRED",
|
|
38
|
+
"REROUTED",
|
|
39
|
+
"WAITING_ON",
|
|
26
40
|
]);
|
|
27
41
|
|
|
28
42
|
const RECOVERY_UNAVAILABLE =
|
|
29
43
|
"Report UNAVAILABLE, complete the handoff checklist manually, and do not request protected completion until required fields and assurance are present";
|
|
30
44
|
const RECOVERY_HANDOFF =
|
|
31
|
-
"Complete the
|
|
45
|
+
"Complete the compact receipt (verdict, candidate_ref, changed_paths, tests, findings, blocker) in the project plan";
|
|
46
|
+
const RECOVERY_INVALID_VERDICT =
|
|
47
|
+
"Replace verdict with a closed role-return token: " +
|
|
48
|
+
[...VERDICT_VALUES].join(", ");
|
|
32
49
|
const RECOVERY_COMPLETE =
|
|
33
50
|
"Handoff is complete; parent coordinator may advance using the project plan only";
|
|
34
51
|
const RECOVERY_BLOCK_COMPLETION =
|
|
@@ -75,9 +92,10 @@ function normalizeAssurance(value) {
|
|
|
75
92
|
return [String(value)].filter((s) => s && s !== "none");
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
function
|
|
95
|
+
function inspectHandoffFields(input) {
|
|
79
96
|
const handoff = isPlainObject(input.handoff) ? input.handoff : input;
|
|
80
97
|
const missing = [];
|
|
98
|
+
const invalid = [];
|
|
81
99
|
for (const field of HANDOFF_FIELDS) {
|
|
82
100
|
const value = handoff[field];
|
|
83
101
|
if (value === undefined || value === null) {
|
|
@@ -86,10 +104,14 @@ function missingHandoffFields(input) {
|
|
|
86
104
|
}
|
|
87
105
|
if (typeof value === "string" && value.trim() === "") {
|
|
88
106
|
missing.push(field);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (field === "verdict" && (typeof value !== "string" || !VERDICT_VALUES.has(value.trim()))) {
|
|
110
|
+
invalid.push(field);
|
|
89
111
|
}
|
|
90
112
|
}
|
|
91
113
|
// blocker may be the string "none"; that is present and valid.
|
|
92
|
-
return missing;
|
|
114
|
+
return { missing, invalid };
|
|
93
115
|
}
|
|
94
116
|
|
|
95
117
|
/**
|
|
@@ -124,7 +146,11 @@ function evaluate(input) {
|
|
|
124
146
|
? "protected_completion"
|
|
125
147
|
: "advisory";
|
|
126
148
|
|
|
127
|
-
const
|
|
149
|
+
const planningVerdict = input.planning_review
|
|
150
|
+
? evaluatePlanningReview(input.planning_review)
|
|
151
|
+
: null;
|
|
152
|
+
|
|
153
|
+
const { missing, invalid } = inspectHandoffFields(input);
|
|
128
154
|
const required = normalizeAssurance(input.required_assurance);
|
|
129
155
|
const accepted = Array.isArray(input.assurance_accepted)
|
|
130
156
|
? input.assurance_accepted.map(String)
|
|
@@ -141,12 +167,16 @@ function evaluate(input) {
|
|
|
141
167
|
|
|
142
168
|
if (mode === "protected_completion") {
|
|
143
169
|
const blockers = [];
|
|
144
|
-
|
|
170
|
+
const handoffProblems = [...missing, ...invalid];
|
|
171
|
+
if (handoffProblems.length > 0) blockers.push("handoff:" + handoffProblems.join(","));
|
|
145
172
|
if (missingAssurance.length > 0) {
|
|
146
173
|
blockers.push("assurance:" + missingAssurance.join(","));
|
|
147
174
|
}
|
|
148
175
|
if (!candidateMatched) blockers.push("candidate_mismatch");
|
|
149
176
|
if (unresolvedBlocker) blockers.push("unresolved_blocker");
|
|
177
|
+
if (planningVerdict && planningVerdict.outcome !== "PASS") {
|
|
178
|
+
blockers.push("planning_review:" + planningVerdict.outcome);
|
|
179
|
+
}
|
|
150
180
|
|
|
151
181
|
if (blockers.length > 0) {
|
|
152
182
|
return result(
|
|
@@ -165,6 +195,16 @@ function evaluate(input) {
|
|
|
165
195
|
);
|
|
166
196
|
}
|
|
167
197
|
|
|
198
|
+
if (planningVerdict) {
|
|
199
|
+
return result(
|
|
200
|
+
planningVerdict.outcome === "PASS" ? "ADVISE" : "REROUTE",
|
|
201
|
+
"planning_review:" + planningVerdict.outcome + ":" + planningVerdict.reason,
|
|
202
|
+
planningVerdict.outcome === "PASS"
|
|
203
|
+
? "Planning-review record is complete; continue to the integrated owner gate"
|
|
204
|
+
: "Keep dispatch closed and complete, repair, or amend the planning-review record"
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
168
208
|
// Advisory closeout: never BLOCK.
|
|
169
209
|
if (missing.length > 0) {
|
|
170
210
|
return result(
|
|
@@ -174,6 +214,14 @@ function evaluate(input) {
|
|
|
174
214
|
);
|
|
175
215
|
}
|
|
176
216
|
|
|
217
|
+
if (invalid.length > 0) {
|
|
218
|
+
return result(
|
|
219
|
+
"ADVISE",
|
|
220
|
+
"handoff_invalid:" + invalid.join(","),
|
|
221
|
+
RECOVERY_INVALID_VERDICT
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
177
225
|
if (missingAssurance.length > 0) {
|
|
178
226
|
return result(
|
|
179
227
|
"ADVISE",
|
|
@@ -234,6 +282,7 @@ module.exports = {
|
|
|
234
282
|
OUTCOMES,
|
|
235
283
|
ENFORCEMENT,
|
|
236
284
|
HANDOFF_FIELDS,
|
|
285
|
+
VERDICT_VALUES,
|
|
237
286
|
evaluate,
|
|
238
287
|
};
|
|
239
288
|
|
|
@@ -52,7 +52,9 @@ const SKIP_DIRS = new Set([
|
|
|
52
52
|
const TASK_MARK = /(?:^|\n)###\s*task_id:\s*\S+/;
|
|
53
53
|
const TASK_LINE = /^###\s*task_id:\s*(\S+)\s*$/;
|
|
54
54
|
const FIELD_LINE =
|
|
55
|
-
/^-\s*(assigned_role|next_action|status|required_assurance|blocker|evidence|candidate_ref|scope|authority|outcome|depends_on|receiving_role|plan_ref|role|subject):\s*(.*)$/;
|
|
55
|
+
/^-\s*(assigned_role|next_action|status|required_assurance|blocker|evidence|candidate_ref|scope|authority|outcome|verdict|depends_on|receiving_role|plan_ref|role|subject|changed_paths|tests|findings):\s*(.*)$/;
|
|
56
|
+
// Matches both the plan-level Journey type and the lease-nested Journey
|
|
57
|
+
// identity; either non-placeholder value marks the Router as invoked.
|
|
56
58
|
const JOURNEY_LINE = /^\s*-\s*journey:\s*(.+)$/i;
|
|
57
59
|
const LEASE_MARK = /^\s*-\s*checkout_lease:/m;
|
|
58
60
|
|
|
@@ -325,17 +327,12 @@ function evaluateForHost(eventName, derived) {
|
|
|
325
327
|
if (classForEvent(eventName) === "closeout") {
|
|
326
328
|
const task = derived.active_task || {};
|
|
327
329
|
return closeout.evaluate({
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
authority: presentString(task.authority),
|
|
334
|
-
outcome: presentString(task.outcome),
|
|
335
|
-
evidence: presentString(task.evidence),
|
|
330
|
+
verdict: presentString(task.verdict),
|
|
331
|
+
candidate_ref: presentString(task.candidate_ref),
|
|
332
|
+
changed_paths: presentString(task.changed_paths),
|
|
333
|
+
tests: presentString(task.tests),
|
|
334
|
+
findings: presentString(task.findings),
|
|
336
335
|
blocker: presentString(task.blocker) || "none",
|
|
337
|
-
next_action: presentString(task.next_action),
|
|
338
|
-
receiving_role: presentString(task.receiving_role),
|
|
339
336
|
required_assurance: task.required_assurance,
|
|
340
337
|
});
|
|
341
338
|
}
|
|
@@ -16,6 +16,7 @@ procedural.
|
|
|
16
16
|
| Kimi Code | `.kimi-plugin/plugin.json` | manifest `hooks` array | partial |
|
|
17
17
|
| AGY | `.agy/` (strict `plugin.json`) | none | skills-only |
|
|
18
18
|
| Pi | `package.json` `"pi"` + `pi-package` | none (TypeScript extensions, not command hooks) | skills-only |
|
|
19
|
+
| DeepCode | `.deepcode/skills` or interoperable `.agents/skills` discovery | none | skills-only |
|
|
19
20
|
|
|
20
21
|
Do **not** set `hooks` on Claude, Codex, or Grok host manifests. Those hosts
|
|
21
22
|
auto-load `hooks/hooks.json`; declaring both is a duplicate-file error.
|
|
@@ -32,6 +33,14 @@ adapters into global hook configuration.
|
|
|
32
33
|
| `Stop`, `stop` | closeout | yes, advisory only |
|
|
33
34
|
| any other host event | none | unmapped; fail open as `UNAVAILABLE` |
|
|
34
35
|
|
|
36
|
+
The shared planning-review evaluator is used by transition and closeout when a
|
|
37
|
+
client supplies a structured `planning_review` record. Current session-start /
|
|
38
|
+
stop mappings cannot derive that nested record safely, so Claude Code, Codex,
|
|
39
|
+
Grok Build, Cursor, and Kimi remain partial and the check is procedural there.
|
|
40
|
+
AGY, Pi, and DeepCode remain skills-only. Do not claim full planning-review
|
|
41
|
+
enforcement for any of these hosts until a native event supplies the complete
|
|
42
|
+
record.
|
|
43
|
+
|
|
35
44
|
The adapter accepts snake_case and camelCase (`hook_event_name` /
|
|
36
45
|
`hookEventName`, `cwd` / `workspaceRoot`).
|
|
37
46
|
|
|
@@ -44,15 +53,20 @@ trees) and sets only:
|
|
|
44
53
|
| Bearing field | Source |
|
|
45
54
|
|---|---|
|
|
46
55
|
| `plan_present` | a Markdown file contains a `task_id`, `assigned_role`, non-placeholder journey marker, or `checkout_lease` block |
|
|
47
|
-
| `router_invoked` | a `- journey:` setting is present
|
|
56
|
+
| `router_invoked` | a non-placeholder `- journey:` setting is present, including the Journey identity nested inside the `checkout_lease` block |
|
|
48
57
|
| `assigned_role` | active task `assigned_role` when not `unassigned` or `<…>` |
|
|
49
58
|
| `next_action` / `next_action_known` | active task `next_action` when not a placeholder |
|
|
50
|
-
| closeout handoff fields | matching task-record keys when present |
|
|
59
|
+
| closeout handoff fields | matching task-record keys when present. Receipt `verdict` is a closed role-return token; task `outcome` is approved intent and is not mapped into the receipt |
|
|
51
60
|
|
|
52
61
|
`assigned_role` and `router_invoked` are **not** inferred from the tool-call
|
|
53
62
|
payload. Missing values stay missing, so activation advises the router instead
|
|
54
63
|
of inventing context.
|
|
55
64
|
|
|
65
|
+
The Router writes the visible `checkout_lease` before any planning write or
|
|
66
|
+
dispatch; its nested non-placeholder Journey identity is the Router-invoked
|
|
67
|
+
signal during planning. The plan-level Explorer-versus-Expedition value is
|
|
68
|
+
recorded later at the route review.
|
|
69
|
+
|
|
56
70
|
## Outcome translation
|
|
57
71
|
|
|
58
72
|
| Outcome | Host JSON | Process exit |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const POLICY = Object.freeze({
|
|
4
|
+
reviewer_slots_min: 2,
|
|
5
|
+
reviewer_slots_max: 2,
|
|
6
|
+
independence_required: true,
|
|
7
|
+
isolated_findings_until_aggregation: true,
|
|
8
|
+
candidate_fields: ["candidate_ref", "candidate_revision", "candidate_digest"],
|
|
9
|
+
shared_candidate_required: true,
|
|
10
|
+
review_rounds: 1,
|
|
11
|
+
aggregated_repairs_max: 1,
|
|
12
|
+
post_repair_gate: "deterministic_PASS",
|
|
13
|
+
automatic_rereview: "prohibited",
|
|
14
|
+
slot_exhaustion_outcome: "FAIL_ROUND",
|
|
15
|
+
terminal_outcomes: ["HALT", "OWNER_AMENDMENT_REQUIRED"],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const sameCandidate = (a, b) =>
|
|
19
|
+
POLICY.candidate_fields.every(
|
|
20
|
+
(key) => typeof a?.[key] === "string" && a[key] && a[key] === b?.[key]
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
function evaluatePlanningReview(input) {
|
|
24
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
25
|
+
return { outcome: "NEEDS_MORE_EVIDENCE", reason: "planning_review_missing" };
|
|
26
|
+
}
|
|
27
|
+
const slots = Array.isArray(input.reviewer_slots) ? input.reviewer_slots : [];
|
|
28
|
+
const ids = slots.map((slot) => slot?.slot_id);
|
|
29
|
+
const primaryRoutes = slots.map((slot) => slot?.primary_route_ref);
|
|
30
|
+
if (
|
|
31
|
+
slots.length < POLICY.reviewer_slots_min ||
|
|
32
|
+
slots.length > POLICY.reviewer_slots_max ||
|
|
33
|
+
ids.some((id) => typeof id !== "string" || !id) ||
|
|
34
|
+
new Set(ids).size !== ids.length ||
|
|
35
|
+
new Set(primaryRoutes).size !== primaryRoutes.length ||
|
|
36
|
+
slots.some(
|
|
37
|
+
(slot) =>
|
|
38
|
+
typeof slot.primary_route_ref !== "string" ||
|
|
39
|
+
!slot.primary_route_ref ||
|
|
40
|
+
!Array.isArray(slot.fallback_route_refs)
|
|
41
|
+
)
|
|
42
|
+
) {
|
|
43
|
+
return { outcome: "OWNER_AMENDMENT_REQUIRED", reason: "slot_binding_invalid" };
|
|
44
|
+
}
|
|
45
|
+
if (slots.some((slot) => slot.exhausted === true)) {
|
|
46
|
+
return { outcome: POLICY.slot_exhaustion_outcome, reason: "reviewer_slot_exhausted" };
|
|
47
|
+
}
|
|
48
|
+
if (input.round_number !== 1 || input.completed_rounds > POLICY.review_rounds) {
|
|
49
|
+
return { outcome: "HALT", reason: "review_round_limit" };
|
|
50
|
+
}
|
|
51
|
+
if (input.completed_rounds === 0) {
|
|
52
|
+
return { outcome: "NEEDS_MORE_EVIDENCE", reason: "review_round_pending" };
|
|
53
|
+
}
|
|
54
|
+
if (input.completed_rounds !== POLICY.review_rounds) {
|
|
55
|
+
return { outcome: "OWNER_AMENDMENT_REQUIRED", reason: "review_round_invalid" };
|
|
56
|
+
}
|
|
57
|
+
if (
|
|
58
|
+
POLICY.automatic_rereview === "prohibited" &&
|
|
59
|
+
(input.automatic_rereview_requested === true || input.review_after_repair === true)
|
|
60
|
+
) {
|
|
61
|
+
return { outcome: "OWNER_AMENDMENT_REQUIRED", reason: "automatic_rereview_prohibited" };
|
|
62
|
+
}
|
|
63
|
+
const receipts = Array.isArray(input.receipts) ? input.receipts : [];
|
|
64
|
+
const receiptIds = receipts.map((receipt) => receipt?.slot_id);
|
|
65
|
+
const selectedRoutes = receipts.map((receipt) => receipt?.selected_route_ref);
|
|
66
|
+
if (
|
|
67
|
+
receipts.length !== slots.length ||
|
|
68
|
+
new Set(receiptIds).size !== receiptIds.length ||
|
|
69
|
+
new Set(selectedRoutes).size !== selectedRoutes.length ||
|
|
70
|
+
!input.candidate ||
|
|
71
|
+
receipts.some(
|
|
72
|
+
(receipt) => {
|
|
73
|
+
const slot = slots.find((item) => item.slot_id === receipt?.slot_id);
|
|
74
|
+
return (
|
|
75
|
+
!slot ||
|
|
76
|
+
![slot.primary_route_ref, ...slot.fallback_route_refs].includes(receipt.selected_route_ref) ||
|
|
77
|
+
receipt.independent !== POLICY.independence_required ||
|
|
78
|
+
receipt.findings_isolated !== POLICY.isolated_findings_until_aggregation ||
|
|
79
|
+
!sameCandidate(receipt, input.candidate)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
) {
|
|
84
|
+
return { outcome: "HALT", reason: "candidate_or_independence_mismatch" };
|
|
85
|
+
}
|
|
86
|
+
if (input.aggregation_complete !== true) {
|
|
87
|
+
return { outcome: "NEEDS_MORE_EVIDENCE", reason: "aggregation_pending" };
|
|
88
|
+
}
|
|
89
|
+
const repairs = Number(input.aggregated_repairs || 0);
|
|
90
|
+
if (!Number.isInteger(repairs) || repairs < 0 || repairs > POLICY.aggregated_repairs_max) {
|
|
91
|
+
return { outcome: "HALT", reason: "aggregated_repair_limit" };
|
|
92
|
+
}
|
|
93
|
+
if (repairs === 1 && input.deterministic_gate !== POLICY.post_repair_gate.split("_")[1]) {
|
|
94
|
+
return { outcome: "HALT", reason: "deterministic_post_repair_gate_required" };
|
|
95
|
+
}
|
|
96
|
+
return { outcome: "PASS", reason: repairs ? "repair_gate_passed" : "review_aggregated" };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = { POLICY, evaluatePlanningReview };
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
const HOOK_CLASS = "transition";
|
|
11
11
|
const OUTCOMES = Object.freeze(["ADVISE", "REROUTE", "BLOCK", "UNAVAILABLE"]);
|
|
12
12
|
const ENFORCEMENT = "procedural";
|
|
13
|
+
const { evaluatePlanningReview } = require("./planning-review.cjs");
|
|
13
14
|
|
|
14
15
|
const RECOVERY_UNAVAILABLE =
|
|
15
16
|
"Keep the current state, run the transition checklist procedurally, and record the result before retrying";
|
|
@@ -125,6 +126,18 @@ function evaluate(input) {
|
|
|
125
126
|
return result("ADVISE", "channel_open", RECOVERY_CHANNEL);
|
|
126
127
|
}
|
|
127
128
|
|
|
129
|
+
if (input.action_kind === "planning_review_transition") {
|
|
130
|
+
const verdict = evaluatePlanningReview(input.planning_review);
|
|
131
|
+
if (verdict.outcome === "PASS") {
|
|
132
|
+
return result("ADVISE", "planning_review:PASS", RECOVERY_ALLOW);
|
|
133
|
+
}
|
|
134
|
+
return result(
|
|
135
|
+
verdict.outcome === "NEEDS_MORE_EVIDENCE" ? "REROUTE" : "BLOCK",
|
|
136
|
+
"planning_review:" + verdict.outcome + ":" + verdict.reason,
|
|
137
|
+
"Keep dispatch closed and repair or amend the planning-review record"
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
128
141
|
const from = typeof input.from_state === "string" ? input.from_state.trim() : "";
|
|
129
142
|
const to = typeof input.to_state === "string" ? input.to_state.trim() : "";
|
|
130
143
|
if (!from || !to) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alphazede/bearing-lite",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "Skills-first Agent Plugin for planning, routing, bounded execution, and independent review of repository work—without CLI, MCP, server, or hidden runtime state.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-plugins",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"pi-package"
|
|
16
16
|
],
|
|
17
17
|
"pi": {
|
|
18
|
-
"skills": [
|
|
18
|
+
"skills": [
|
|
19
|
+
"./skills"
|
|
20
|
+
]
|
|
19
21
|
},
|
|
20
22
|
"author": "William Rumph / AlphaZede",
|
|
21
23
|
"license": "Apache-2.0",
|
|
@@ -36,5 +38,6 @@
|
|
|
36
38
|
"CONTRIBUTING.md",
|
|
37
39
|
"SECURITY.md",
|
|
38
40
|
"LICENSE-APACHE"
|
|
39
|
-
]
|
|
41
|
+
],
|
|
42
|
+
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
|
|
40
43
|
}
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "bearing-lite",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.11",
|
|
5
5
|
"description": "Skills-first portable plugin that routes repository work through the smallest valid planning stages and agent roles, using project Markdown as the only task record.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "William Rumph / AlphaZede",
|
|
@@ -3,51 +3,44 @@ name: bearing-lite
|
|
|
3
3
|
description: Bearing Lite Router for Journeys. Not for ordinary work, assigned packets, implementation, or publication.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
The Router alone writes Journey planning state and owns
|
|
7
|
-
planning nodes return owner questions.
|
|
8
|
-
or hidden ledger. plugin hosts are partial; skill-copy is skills-only.
|
|
6
|
+
The Router alone writes Journey planning state, owns owner conversation, and owns Expedition sequencing;
|
|
7
|
+
planning nodes return owner questions. Plugin hosts are partial; skill-copy is skills-only.
|
|
9
8
|
|
|
10
|
-
1. Say `Preparing this Journey.`
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
4.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
review run—after a slice, after an integrated round, or at the end?`
|
|
34
|
-
7. Record route, lineup, and cadence before task mapping; if declined, record the named default explicitly.
|
|
35
|
-
The recorded snapshot is authoritative for this Journey. Later edits to
|
|
36
|
-
`~/.agents/bearing-lite/default-role-lineup.md` have no effect on it. Replace
|
|
37
|
-
only through an explicit owner-confirmed dated visible amendment. Invoke Map the Route with the snapshot.
|
|
38
|
-
8. Every ready node gets a fresh session with lineup identity from the recorded snapshot.
|
|
9
|
+
1. Say `Preparing this Journey.` Acquire or resume a generation-bound checkout lease before
|
|
10
|
+
planning or dispatch. A live same-checkout competitor returns `WAITING_ON` with sanitized identity.
|
|
11
|
+
2. Resume the next incomplete stage in the same generation; refresh `candidate_revision`.
|
|
12
|
+
Never replay accepted stages or duplicate dispatch. Invalid leases fail closed.
|
|
13
|
+
3. If `~/.agents/bearing-lite/default-role-lineup.md` is absent, create a proposed copy
|
|
14
|
+
from `templates/default-role-lineup.md`;
|
|
15
|
+
never infer identity values. The recorded snapshot is authoritative for this Journey.
|
|
16
|
+
Later edits to
|
|
17
|
+
`~/.agents/bearing-lite/default-role-lineup.md` have no effect on it except through an
|
|
18
|
+
explicit owner-confirmed dated visible amendment. Dispatch uses lineup identity from the recorded snapshot.
|
|
19
|
+
4. Run Repository Fit → Set Bearings → Gather Supplies; unresolved material intent blocks Map the Route.
|
|
20
|
+
5. Invoke Map the Route after settled intent. Do not ask for lineup or route
|
|
21
|
+
before it; carry owner-supplied lineup and `review_cadence: at-end` as proposals.
|
|
22
|
+
6. On `PLAN_REVIEW_READY`, enforce `references/review-policy.md`: one candidate,
|
|
23
|
+
unique independent slots, one round and aggregated repair, deterministic PASS,
|
|
24
|
+
no rereview. Journey snapshots bind slots; validation never dispatches. Show one integrated
|
|
25
|
+
approval-or-change gate for outcome, design, route, lineup, role states,
|
|
26
|
+
reasoning, cadence, and plan. Record the approved Journey type and snapshot; regenerate changes.
|
|
27
|
+
Never add a staged lineup or route-review gate.
|
|
28
|
+
Dispatch only after approval.
|
|
29
|
+
7. Dispatch from the snapshot. Crewmate and Explorer may continue in-wave unchanged.
|
|
30
|
+
Validate the lease at wave start, after drift, and before commit; use the visible wave receipt
|
|
31
|
+
and update implementation and review once per wave.
|
|
39
32
|
|
|
40
|
-
Return `READY`, `WAITING_ON`, `OWNER_DECISION_REQUIRED`, or `COMPLETE`.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
self-assure, select models, or publish.
|
|
33
|
+
Return `READY`, `WAITING_ON`, `OWNER_DECISION_REQUIRED`, or `COMPLETE`. Three
|
|
34
|
+
evidence-changing corrections outside assurance.
|
|
35
|
+
`max_assurance_rounds` is 1 per Journey; Direct route checks `assurance_rounds`, never
|
|
36
|
+
dispatch Navigator, and one review may authorize one repair. Verify repair
|
|
37
|
+
deterministically without another review; failed repair/scope change returns
|
|
38
|
+
`OWNER_DECISION_REQUIRED` naming the candidate and count. Only a separately scoped,
|
|
39
|
+
materially changed new Journey resets review allowance. `COMPLETE` ends Bearing assurance.
|
|
40
|
+
Authorized deployment keeps checks without reopening review.
|
|
41
|
+
Planning review is a separate pre-dispatch gate; it never consumes implementation
|
|
42
|
+
`required_assurance`, `assurance_rounds`, or `max_assurance_rounds`.
|
|
43
|
+
Release the lease once: release the checkout lease exactly once on `COMPLETE` or `CANCELLED`;
|
|
44
|
+
recovery needs explicit recorded generation increment.
|
|
45
|
+
Recovery cannot steal a live lease.
|
|
46
|
+
Never implement, self-assure, select models, or publish.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
interface:
|
|
2
2
|
display_name: "Bearing Lite"
|
|
3
3
|
short_description: "Route a stateful repository Journey"
|
|
4
|
-
default_prompt: "Use $bearing-lite to start or resume this Journey, resolve planning one stage at a time, confirm the lineup
|
|
4
|
+
default_prompt: "Use $bearing-lite to start or resume this Journey, resolve planning one stage at a time, confirm the lineup, record at-end review, then dispatch bounded sessions."
|
|
5
5
|
|
|
6
6
|
policy:
|
|
7
7
|
allow_implicit_invocation: false
|