@hecer/yoke 1.15.0 → 1.15.1
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +7 -5
- package/canon/AGENTS.md +7 -0
- package/canon/manifest.yaml +1 -1
- package/canon/skills/executing-plans/SKILL.md +1 -1
- package/canon/skills/requesting-code-review/SKILL.md +2 -2
- package/canon/skills/requesting-code-review/code-reviewer.md +12 -0
- package/canon/skills/subagent-driven-development/SKILL.md +7 -3
- package/canon/skills/subagent-driven-development/code-quality-reviewer-prompt.md +7 -0
- package/canon/skills/subagent-driven-development/implementer-prompt.md +7 -0
- package/canon/skills/subagent-driven-development/spec-reviewer-prompt.md +7 -0
- package/canon/skills/systematic-debugging/SKILL.md +7 -11
- package/canon/skills/systematic-debugging/condition-based-waiting.md +7 -0
- package/canon/skills/systematic-debugging/defense-in-depth.md +7 -0
- package/canon/skills/systematic-debugging/root-cause-tracing.md +9 -0
- package/canon/skills/tdd/SKILL.md +1 -1
- package/canon/skills/tdd/testing-anti-patterns.md +9 -0
- package/dist/agents/pi-telemetry.js +53 -0
- package/dist/agents/process-streams.js +13 -0
- package/dist/agents/providers.js +4 -1
- package/dist/agents/supervision.js +2 -0
- package/dist/agents/telemetry.js +22 -25
- package/dist/estimation/schedule.js +40 -26
- package/dist/retrofit/planners/pi.js +1 -1
- package/dist/retrofit/skill-actions.js +1 -1
- package/docs/AGENT-HARDENING-2026-09-16.md +32 -0
- package/docs/HARNESSES.md +6 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "yoke",
|
|
4
4
|
"displayName": "Yoke",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.15.1",
|
|
6
6
|
"description": "Cross-agent coding harness for Claude, Codex, Gemini, Qwen, OpenCode, Kilo and Pi: one curated skill canon plus mechanical safety gates and an autonomous loop via the yoke CLI.",
|
|
7
7
|
"author": { "name": "HECer", "url": "https://github.com/HECer" },
|
|
8
8
|
"homepage": "https://github.com/HECer/yoke#readme",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.15.1 — 2026-09-16
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- Sum finalized Pi assistant-turn usage without counting streamed snapshots or replayed transcripts twice; preserve missing measurements and multiple model identities.
|
|
7
|
+
- Recognize successful Pi/OpenCode/Kilo tool events as watchdog progress without relaxing execution budgets.
|
|
8
|
+
- Reject structured verdicts followed by terminal provider errors, reject errored/aborted Pi verdicts, and exclude Claude child-agent verdicts/usage from parent results.
|
|
9
|
+
- Validate OpenCode/Kilo effort aliases consistently; emit a single variant flag.
|
|
10
|
+
- Correct Pi settings-relative skill discovery and enforce manual-only skill invocation using Pi's native frontmatter.
|
|
11
|
+
- Estimate schedule ranges from per-story scenarios and retain low confidence for sparse task-specific evidence.
|
|
12
|
+
- Ship eight missing delegation/review/debugging/testing resources and clarify host capability, worker-budget and verification rules in the shared skills; remove unsupported quality/speed claims.
|
|
13
|
+
- Keep coordinator unit tests offline by stubbing the separate preview backend; verify actual isolated edits and preservation of the source project.
|
|
14
|
+
- Synchronize previously stale Claude/Codex plugin, Gemini extension and Canon versions with the npm package.
|
|
15
|
+
|
|
16
|
+
### Migration and validation limits
|
|
17
|
+
- Refresh generated skills with a reviewed `yoke retrofit . --agent=all` (or the selected agent). Current Pi requires explicit project trust to load project-local resources; Yoke does not grant it automatically. See [harness setup](docs/HARNESSES.md).
|
|
18
|
+
- Existing custom configuration remains authoritative. No timeout or acceptance-gate defaults were weakened. Time ranges remain empirical, not guaranteed deadlines.
|
|
19
|
+
- See the [audit and validation limits](docs/AGENT-HARDENING-2026-09-16.md). No authenticated seven-agent benchmark or guaranteed speed/quality improvement is claimed.
|
|
20
|
+
- Local verification: 1,281 tests passed, two platform-specific tests skipped; TypeScript lint/build, Canon validation, documentation metadata, package dry run and dependency audit passed.
|
|
21
|
+
|
|
3
22
|
## 1.15.0 — 2026-09-09
|
|
4
23
|
|
|
5
24
|
### Added
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<h1><img src="https://raw.githubusercontent.com/HECer/yoke/v1.15.
|
|
3
|
+
<h1><img src="https://raw.githubusercontent.com/HECer/yoke/v1.15.1/docs/assets/yoke-logo.png" alt="Yoke" width="100" height="63"></h1>
|
|
4
4
|
|
|
5
|
-
<!-- yoke:version:start -->1.15.
|
|
6
|
-
<!-- yoke:tests:start -->
|
|
5
|
+
<!-- yoke:version:start -->1.15.1<!-- yoke:version:end -->
|
|
6
|
+
<!-- yoke:tests:start -->1283<!-- yoke:tests:end -->
|
|
7
7
|
<!-- yoke:skills:start -->34<!-- yoke:skills:end -->
|
|
8
8
|
<!-- yoke:agents:start -->Claude | Codex | Gemini | Qwen | OpenCode | Kilo | Pi<!-- yoke:agents:end -->
|
|
9
9
|
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
[](#-license)
|
|
18
18
|

|
|
19
19
|

|
|
20
|
-

|
|
21
21
|

|
|
22
22
|

|
|
23
23
|
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
|
|
32
32
|
OpenCode, Kilo and Pi are real CLI integrations, not bundled runtimes or credentials. OpenCode/Kilo use their JSON headless modes and local MCP configuration; Pi uses JSONL and explicit tool allowlists, but has no native MCP, sub-agent or plan layer. Read the [integration guide](docs/HARNESSES.md) before selecting a permission profile.
|
|
33
33
|
|
|
34
|
+
**Fixed in 1.15.1:** multi-turn Pi usage accounting, provider error/progress handling, task-specific time ranges and missing skill resources. Pi has been supported since **1.13.0**; current Pi versions require explicit project trust for project-local skills in headless runs. The [agent/skill hardening audit](docs/AGENT-HARDENING-2026-09-16.md) documents the fixes, migration notes and validation limits.
|
|
35
|
+
|
|
34
36
|
### One dashboard, multiple projects
|
|
35
37
|
|
|
36
38
|
```sh
|
|
@@ -929,7 +931,7 @@ release provenance.
|
|
|
929
931
|
## 🧪 Development
|
|
930
932
|
|
|
931
933
|
```bash
|
|
932
|
-
npm test # vitest (
|
|
934
|
+
npm test # vitest (1283 tests)
|
|
933
935
|
npm run build # tsc, no emit errors
|
|
934
936
|
npm run yoke -- validate canon
|
|
935
937
|
```
|
package/canon/AGENTS.md
CHANGED
|
@@ -9,6 +9,13 @@ You are operating in a project retrofitted by Yoke. Follow these always:
|
|
|
9
9
|
|
|
10
10
|
This file is the portable baseline. Agent-specific instructions are generated alongside it (CLAUDE.md, GEMINI.md).
|
|
11
11
|
|
|
12
|
+
## Host capabilities and execution budgets
|
|
13
|
+
|
|
14
|
+
- Use only tools and skills actually installed in the host. Legacy `superpowers:` references in adapted skills refer to the corresponding local skill; `test-driven-development` maps to `tdd`. Do not install another plugin just to resolve a namespace.
|
|
15
|
+
- When Yoke owns the loop, worker concurrency, verification, and integration remain under its control. Do not start nested loops or native subagents from a worker. Without native delegation, work serially and expose missing independent-review evidence.
|
|
16
|
+
- Run focused checks for quick feedback, but never skip required acceptance, protected, integration, or release gates. Cache evidence only when code, configuration, and environment still match.
|
|
17
|
+
- Distinguish observed durations from future estimates. Report the sample count, empirical range, and unknown waiting time; a timeout is a budget, not a promised completion time. Do not reduce reasoning or test scope merely to meet an estimate.
|
|
18
|
+
|
|
12
19
|
## Skill routing & precedence
|
|
13
20
|
|
|
14
21
|
When several skills could match the same task, resolve deterministically:
|
package/canon/manifest.yaml
CHANGED
|
@@ -11,7 +11,7 @@ Load plan, review critically, execute all tasks, report when complete.
|
|
|
11
11
|
|
|
12
12
|
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Use `subagent-driven-development` only when the host exposes delegation and the current run permits it. Inside a Yoke worker, execute the assigned task without launching nested workers; Yoke owns concurrency and independent review. Without delegation, execute serially and report any unavailable independent review explicitly. Subagents alone do not guarantee better quality or faster completion.
|
|
15
15
|
|
|
16
16
|
## The Process
|
|
17
17
|
|
|
@@ -31,7 +31,7 @@ HEAD_SHA=$(git rev-parse HEAD)
|
|
|
31
31
|
|
|
32
32
|
**2. Dispatch code-reviewer subagent:**
|
|
33
33
|
|
|
34
|
-
Use
|
|
34
|
+
Use the host's available read-only reviewer mechanism and fill the [review template](code-reviewer.md). Do not assume a `Task` tool exists. Inside a Yoke worker, hand evidence to Yoke's configured reviewer instead of launching nested agents. If independent review is unavailable, report that limitation; self-review is not an equivalent substitute.
|
|
35
35
|
|
|
36
36
|
**Placeholders:**
|
|
37
37
|
- `{WHAT_WAS_IMPLEMENTED}` - What you just built
|
|
@@ -102,4 +102,4 @@ You: [Fix progress indicators]
|
|
|
102
102
|
- Show code/tests that prove it works
|
|
103
103
|
- Request clarification
|
|
104
104
|
|
|
105
|
-
See
|
|
105
|
+
See the [review template](code-reviewer.md).
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Code review request
|
|
2
|
+
|
|
3
|
+
- Implementation: {WHAT_WAS_IMPLEMENTED}
|
|
4
|
+
- Acceptance criteria and requirements: {PLAN_OR_REQUIREMENTS}
|
|
5
|
+
- Base commit: {BASE_SHA}
|
|
6
|
+
- Candidate commit: {HEAD_SHA}
|
|
7
|
+
- Context and constraints: {DESCRIPTION}
|
|
8
|
+
- Permitted read scope, available checks, artifacts and known validation gaps: fill explicitly.
|
|
9
|
+
|
|
10
|
+
Independently inspect the actual candidate against requirements. Check correctness, failure handling, security, concurrency, maintainability and meaningful regression tests. Do not edit the candidate, weaken tests, merge or publish.
|
|
11
|
+
|
|
12
|
+
Return evidence-backed critical/important findings separately from minor suggestions. Each finding needs a location, failure scenario and validation approach. Distinguish verified, failed and unverified criteria. State limitations and whether unresolved blockers prevent acceptance; a test summary alone is insufficient.
|
|
@@ -5,6 +5,10 @@ description: Use when executing implementation plans with independent tasks in t
|
|
|
5
5
|
|
|
6
6
|
# Subagent-Driven Development
|
|
7
7
|
|
|
8
|
+
## Host capability and budget check
|
|
9
|
+
|
|
10
|
+
Use this workflow only if native delegation is available and authorized. Do not invent a `Task` or `TodoWrite` tool on hosts that lack it. Pi has no built-in subagents; use Yoke's scheduler or `executing-plans` instead. When running inside an existing Yoke worker, do not start nested agents or another loop: return evidence to the controlling runner. Independent review must not be replaced by claiming a self-review was independent.
|
|
11
|
+
|
|
8
12
|
Execute plan by dispatching fresh subagent per task, with two-stage review after each: spec compliance review first, then code quality review.
|
|
9
13
|
|
|
10
14
|
**Why subagents:** You delegate tasks to specialized agents with isolated context. By precisely crafting their instructions and context, you ensure they stay focused and succeed at their task. They should never inherit your session's context or history — you construct exactly what they need. This also preserves your own context for coordination work.
|
|
@@ -119,9 +123,9 @@ Implementer subagents report one of four statuses. Handle each appropriately:
|
|
|
119
123
|
|
|
120
124
|
## Prompt Templates
|
|
121
125
|
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
-
|
|
126
|
+
- [Implementer prompt](./implementer-prompt.md) - Dispatch implementer subagent
|
|
127
|
+
- [Spec reviewer prompt](./spec-reviewer-prompt.md) - Dispatch spec compliance reviewer subagent
|
|
128
|
+
- [Code quality reviewer prompt](./code-quality-reviewer-prompt.md) - Dispatch code quality reviewer subagent
|
|
125
129
|
|
|
126
130
|
## Example Workflow
|
|
127
131
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Code quality reviewer handoff
|
|
2
|
+
|
|
3
|
+
Supply the task, Acceptance criteria, base and candidate commits, architecture constraints, test evidence, and known risks. Review with read-only permissions after the specification review.
|
|
4
|
+
|
|
5
|
+
Inspect correctness, error paths, concurrency, resource cleanup, security boundaries, compatibility, and regression coverage. Prioritize reproducible defects over stylistic preferences. Check that optimizations preserve required gates and that unknown usage or timing evidence is not reported as zero or certainty.
|
|
6
|
+
|
|
7
|
+
Return severity-ranked findings with precise locations, failure scenarios, and suggested regression tests. Separate required fixes from optional improvements. State validation limits even when no defects are found. Never edit the candidate, self-merge, or infer release readiness solely from a green test summary.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Implementer handoff
|
|
2
|
+
|
|
3
|
+
Supply the task, repository/worktree path, base commit, allowed write scope, relevant interfaces, and Acceptance criteria with their required checks. Include only relevant context and previous failure evidence.
|
|
4
|
+
|
|
5
|
+
Implement only the assigned task. Preserve unrelated changes. Reproduce defects with a failing test before fixing them; do not weaken protected tests or acceptance checks. Run focused checks during iteration and all required gates before handoff. Do not spawn nested workers, publish, merge, or expand permissions. Commit only if the controller explicitly delegates that responsibility.
|
|
6
|
+
|
|
7
|
+
Return: outcome, changed files, exact checks and exit results, remaining risks, blockers, and artifact paths. Report incomplete work as incomplete. If blocked by a product decision or missing credentials, retain the work and explain what is needed; do not repeat the same failing action indefinitely.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Specification reviewer handoff
|
|
2
|
+
|
|
3
|
+
Supply the original task, Acceptance criteria, base and candidate commits, allowed read scope, and validation commands. Review independently from the implementer, with read-only permissions.
|
|
4
|
+
|
|
5
|
+
Compare the actual diff and observable behavior to each criterion. Check omissions, unauthorized additions, weakened tests, and whether evidence applies to the candidate being reviewed. Do not rely on the implementer's completion claim. Run permitted non-mutating checks where feasible; mark unavailable checks as unverified.
|
|
6
|
+
|
|
7
|
+
Return one disposition per criterion: verified, failed, or unverified, with file/line or command evidence. Give actionable defects and distinguish blockers from optional suggestions. Do not modify files, approve an unverified requirement, merge, or publish.
|
|
@@ -111,7 +111,7 @@ You MUST complete each phase before proceeding to the next.
|
|
|
111
111
|
|
|
112
112
|
**WHEN error is deep in call stack:**
|
|
113
113
|
|
|
114
|
-
See
|
|
114
|
+
See [root-cause tracing](root-cause-tracing.md) for the backward tracing technique.
|
|
115
115
|
|
|
116
116
|
**Quick version:**
|
|
117
117
|
- Where does bad value originate?
|
|
@@ -273,24 +273,20 @@ If systematic investigation reveals issue is truly environmental, timing-depende
|
|
|
273
273
|
3. Implement appropriate handling (retry, timeout, error message)
|
|
274
274
|
4. Add monitoring/logging for future investigation
|
|
275
275
|
|
|
276
|
-
|
|
276
|
+
Before declaring the cause unknowable, record what was ruled out and which observations are still missing.
|
|
277
277
|
|
|
278
278
|
## Supporting Techniques
|
|
279
279
|
|
|
280
280
|
These techniques are part of systematic debugging and available in this directory:
|
|
281
281
|
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
282
|
+
- [Root-cause tracing](root-cause-tracing.md) - Trace bugs backward to the original trigger
|
|
283
|
+
- [Defense in depth](defense-in-depth.md) - Validate relevant trust boundaries after finding the cause
|
|
284
|
+
- [Condition-based waiting](condition-based-waiting.md) - Replace arbitrary sleeps with bounded condition waits
|
|
285
285
|
|
|
286
286
|
**Related skills:**
|
|
287
287
|
- **superpowers:test-driven-development** - For creating failing test case (Phase 4, Step 1)
|
|
288
288
|
- **superpowers:verification-before-completion** - Verify fix worked before claiming success
|
|
289
289
|
|
|
290
|
-
##
|
|
290
|
+
## Measuring impact
|
|
291
291
|
|
|
292
|
-
|
|
293
|
-
- Systematic approach: 15-30 minutes to fix
|
|
294
|
-
- Random fixes approach: 2-3 hours of thrashing
|
|
295
|
-
- First-time fix rate: 95% vs 40%
|
|
296
|
-
- New bugs introduced: Near zero vs common
|
|
292
|
+
Record time to reproduce, time to a verified fix, retries and escaped regressions for the actual project. No fixed speedup, success rate or absence of new bugs is guaranteed by this workflow.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Condition-based waiting
|
|
2
|
+
|
|
3
|
+
Prefer a completion event or promise over sleeping for an assumed duration. Subscribe before starting work so a fast completion is not missed. Handle success, failure, cancellation and timeout, and remove listeners/timers in every terminal path.
|
|
4
|
+
|
|
5
|
+
If polling is unavoidable, choose a measurable condition, bounded deadline and modest interval. Preserve the last observed state in the timeout error. Do not treat repeated log output as successful progress.
|
|
6
|
+
|
|
7
|
+
Tests should control time or use an explicit readiness signal. Keep one real process integration test where needed. A larger timeout is justified only by measured runtime and does not repair a race or an unintended network call.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Defense in depth
|
|
2
|
+
|
|
3
|
+
Fix the originating contract violation first. Then identify independent trust boundaries where malformed or stale data could enter again: configuration, external process output, persisted state and public interfaces.
|
|
4
|
+
|
|
5
|
+
Validate at those boundaries with explicit errors and preserve unknown values. Avoid scattering duplicate checks through code that already has a validated type. Do not catch every exception and return success or zero.
|
|
6
|
+
|
|
7
|
+
Test malformed input, missing evidence, stale state, cancellation and cleanup. For destructive operations verify target scope and authority independently of the requesting model. Protection layers must not weaken acceptance tests or convert a blocked action into an automatic permission bypass.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Root-cause tracing
|
|
2
|
+
|
|
3
|
+
Capture the smallest failing command, inputs, expected/actual behavior, environment and code revision. Reproduce before changing code.
|
|
4
|
+
|
|
5
|
+
Trace backward from the first observed invalid value or state transition to its producer. At each boundary, record the input, output and contract without logging credentials. Distinguish a downstream symptom from the earliest violated invariant.
|
|
6
|
+
|
|
7
|
+
Form one falsifiable hypothesis and choose an observation that separates it from alternatives. Change one factor at a time. If reproduction depends on concurrency, preserve scheduling and cancellation evidence rather than adding arbitrary delays.
|
|
8
|
+
|
|
9
|
+
Write a regression test at the violated boundary, demonstrate its failure, fix the cause and run dependent checks. Document remaining uncertainty instead of attributing an intermittent pass to a fix without evidence.
|
|
@@ -356,7 +356,7 @@ Never fix bugs without a test.
|
|
|
356
356
|
|
|
357
357
|
## Testing Anti-Patterns
|
|
358
358
|
|
|
359
|
-
When adding mocks or test utilities, read
|
|
359
|
+
When adding mocks or test utilities, read [testing anti-patterns](testing-anti-patterns.md) to avoid common pitfalls:
|
|
360
360
|
- Testing mock behavior instead of real behavior
|
|
361
361
|
- Adding test-only methods to production classes
|
|
362
362
|
- Mocking without understanding dependencies
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Testing anti-patterns
|
|
2
|
+
|
|
3
|
+
- Test observable behavior, not that a mock returned the value you supplied. Assert resulting state and failure behavior as well as calls.
|
|
4
|
+
- Mock external boundaries deliberately. If production constructs a second client for an isolated workspace, replace that constructor too; a unit test must not silently invoke a real network backend.
|
|
5
|
+
- Do not mock the implementation under test or delete assertions to make a change pass. Keep at least one contract/integration check for important boundaries.
|
|
6
|
+
- Demonstrate that the regression test fails for the original defect and passes after the fix. A new green test alone does not establish that it detects the bug.
|
|
7
|
+
- Avoid arbitrary sleeps and broad timeout increases. Use readiness events, controlled clocks and bounded cancellation.
|
|
8
|
+
- Preserve protected acceptance tests and required gates. Focused tests speed feedback but do not replace release validation.
|
|
9
|
+
- Report skipped tests, unavailable platforms and missing credentials separately from passing checks. Never convert absent measurements into measured zero.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const record = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2
|
+
const finite = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0;
|
|
3
|
+
/** Pi usage is per assistant message, not cumulative across a run. */
|
|
4
|
+
export function createPiTelemetry() {
|
|
5
|
+
const totals = {};
|
|
6
|
+
const counts = {};
|
|
7
|
+
const models = new Set();
|
|
8
|
+
let turns = 0;
|
|
9
|
+
let legacyUsage;
|
|
10
|
+
const add = (usage) => {
|
|
11
|
+
turns++;
|
|
12
|
+
const fields = {
|
|
13
|
+
inputTokens: usage?.input, outputTokens: usage?.output,
|
|
14
|
+
cachedInputTokens: usage?.cacheRead, cacheWriteInputTokens: usage?.cacheWrite,
|
|
15
|
+
reasoningOutputTokens: usage?.reasoning,
|
|
16
|
+
totalCostUsd: record(usage?.cost) ? usage.cost.total : undefined,
|
|
17
|
+
};
|
|
18
|
+
for (const [key, value] of Object.entries(fields))
|
|
19
|
+
if (finite(value)) {
|
|
20
|
+
totals[key] = (totals[key] ?? 0) + value;
|
|
21
|
+
counts[key] = (counts[key] ?? 0) + 1;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
return {
|
|
25
|
+
consume(event) {
|
|
26
|
+
// Compatibility with earlier top-level snapshots; never override a final usage.
|
|
27
|
+
if (event.type === 'message_update' && record(event.usage))
|
|
28
|
+
legacyUsage = event.usage;
|
|
29
|
+
if (event.type !== 'message_end' || !record(event.message) || event.message.role !== 'assistant')
|
|
30
|
+
return;
|
|
31
|
+
if (typeof event.message.model === 'string' && event.message.model)
|
|
32
|
+
models.add(event.message.model);
|
|
33
|
+
add(record(event.message.usage) ? event.message.usage : legacyUsage);
|
|
34
|
+
legacyUsage = undefined;
|
|
35
|
+
},
|
|
36
|
+
finish() {
|
|
37
|
+
const reportedModels = [...models];
|
|
38
|
+
const complete = turns > 0 && counts.inputTokens === turns && counts.outputTokens === turns;
|
|
39
|
+
if (complete) {
|
|
40
|
+
// Optional totals must also cover every turn; omitted is not measured zero.
|
|
41
|
+
const measured = Object.fromEntries(Object.entries(totals).filter(([key]) => counts[key] === turns));
|
|
42
|
+
return { usageAvailable: true, tokens: {
|
|
43
|
+
...measured, inputTokens: totals.inputTokens, outputTokens: totals.outputTokens,
|
|
44
|
+
...(reportedModels.length === 1 ? { model: reportedModels[0] } : {}),
|
|
45
|
+
}, ...(reportedModels.length > 1 ? { reportedModels } : {}) };
|
|
46
|
+
}
|
|
47
|
+
return { usageAvailable: false,
|
|
48
|
+
...(Object.keys(totals).length ? { partialUsage: { ...totals } } : {}),
|
|
49
|
+
...(reportedModels.length ? { reportedModels } : {}),
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { parseProviderTelemetry } from './telemetry.js';
|
|
2
|
+
import { createPiTelemetry } from './pi-telemetry.js';
|
|
2
3
|
export function createBoundedOutput(limitBytes) {
|
|
3
4
|
let text = '';
|
|
4
5
|
let truncated = false;
|
|
@@ -17,6 +18,7 @@ export function createBoundedOutput(limitBytes) {
|
|
|
17
18
|
};
|
|
18
19
|
}
|
|
19
20
|
export function createTelemetryAccumulator(agent) {
|
|
21
|
+
const pi = agent === 'pi' ? createPiTelemetry() : undefined;
|
|
20
22
|
let trailing = '';
|
|
21
23
|
let telemetry = { usageAvailable: false };
|
|
22
24
|
let reportedModels = [];
|
|
@@ -25,6 +27,15 @@ export function createTelemetryAccumulator(agent) {
|
|
|
25
27
|
: undefined;
|
|
26
28
|
const update = (lines) => {
|
|
27
29
|
for (const line of lines) {
|
|
30
|
+
if (pi) {
|
|
31
|
+
try {
|
|
32
|
+
const event = JSON.parse(line);
|
|
33
|
+
if (event && typeof event === 'object' && !Array.isArray(event))
|
|
34
|
+
pi.consume(event);
|
|
35
|
+
}
|
|
36
|
+
catch { /* non-JSON diagnostics carry no usage */ }
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
28
39
|
const next = parseProviderTelemetry(agent, [line]);
|
|
29
40
|
if (next.reportedModels)
|
|
30
41
|
reportedModels = next.reportedModels;
|
|
@@ -75,6 +86,8 @@ export function createTelemetryAccumulator(agent) {
|
|
|
75
86
|
if (trailing)
|
|
76
87
|
update([trailing]);
|
|
77
88
|
trailing = '';
|
|
89
|
+
if (pi)
|
|
90
|
+
return pi.finish();
|
|
78
91
|
if (stepTotals && (stepTotals.hasInput || stepTotals.hasOutput)) {
|
|
79
92
|
const latest = telemetry.tokens;
|
|
80
93
|
const inputTokens = stepTotals.hasInput ? stepTotals.input : latest?.inputTokens;
|
package/dist/agents/providers.js
CHANGED
|
@@ -45,6 +45,9 @@ const argsFor = (agent, permissions) => {
|
|
|
45
45
|
};
|
|
46
46
|
export function buildProviderInvocation(agent, prompt, cwd, permissions = 'safe', selection = {}, output = {}) {
|
|
47
47
|
const parsedSelection = ModelSelectionSchema.parse(selection);
|
|
48
|
+
if (['opencode', 'kilo', 'pi'].includes(agent) && parsedSelection.reasoningEffort && parsedSelection.variant && parsedSelection.reasoningEffort !== parsedSelection.variant) {
|
|
49
|
+
throw new Error(`${agent} reasoningEffort and variant selections must match`);
|
|
50
|
+
}
|
|
48
51
|
if (agent === 'gemini' && parsedSelection.bare)
|
|
49
52
|
throw new Error('Gemini does not support the bare startup selection');
|
|
50
53
|
if (agent === 'gemini' && parsedSelection.reasoningEffort)
|
|
@@ -106,7 +109,7 @@ export function buildProviderInvocation(agent, prompt, cwd, permissions = 'safe'
|
|
|
106
109
|
args.push('--thinking', parsedSelection.reasoningEffort);
|
|
107
110
|
}
|
|
108
111
|
if (parsedSelection.variant) {
|
|
109
|
-
if (agent === 'opencode' || agent === 'kilo')
|
|
112
|
+
if ((agent === 'opencode' || agent === 'kilo') && !parsedSelection.reasoningEffort)
|
|
110
113
|
args.push('--variant', parsedSelection.variant);
|
|
111
114
|
else if (agent === 'pi') {
|
|
112
115
|
if (parsedSelection.reasoningEffort && parsedSelection.reasoningEffort !== parsedSelection.variant)
|
|
@@ -36,6 +36,8 @@ export function inspectProviderEvent(line) {
|
|
|
36
36
|
return { failure: 'provider-terminal-error' };
|
|
37
37
|
}
|
|
38
38
|
return { progress: (event.type === 'item.completed' && ((item?.type === 'command_execution' && item.exit_code === 0) || (item?.type === 'file_change' && item.status === 'completed')))
|
|
39
|
+
|| (event.type === 'tool_execution_end' && event.isError === false)
|
|
40
|
+
|| (event.type === 'tool_use' && event.part?.type === 'tool' && event.part.state?.status === 'completed')
|
|
39
41
|
|| (event.type === 'tool_result' && event.status === 'success')
|
|
40
42
|
|| (event.type === 'user' && Array.isArray(event.message?.content) && event.message.content.some((part) => part.type === 'tool_result' && part.is_error === false)) };
|
|
41
43
|
}
|
package/dist/agents/telemetry.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createPiTelemetry } from './pi-telemetry.js';
|
|
1
2
|
const finite = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : undefined;
|
|
2
3
|
function parseJson(value) {
|
|
3
4
|
try {
|
|
@@ -32,15 +33,21 @@ export function parseProviderResult(agent, output) {
|
|
|
32
33
|
if (agent === 'qwen')
|
|
33
34
|
return parseQwenResult(output);
|
|
34
35
|
const fragments = [];
|
|
36
|
+
let structuredResult;
|
|
35
37
|
for (const line of output.split(/\r?\n/u)) {
|
|
36
38
|
const parsed = parseJson(line);
|
|
37
39
|
if (!parsed.ok || !isRecord(parsed.value))
|
|
38
40
|
continue;
|
|
39
41
|
const event = parsed.value;
|
|
42
|
+
if (agent === 'claude' && event.parent_tool_use_id != null)
|
|
43
|
+
continue;
|
|
44
|
+
if (event.type === 'error' || event.type === 'turn.failed' ||
|
|
45
|
+
(event.type === 'result' && (event.is_error === true || event.status === 'error')))
|
|
46
|
+
return null;
|
|
40
47
|
switch (agent) {
|
|
41
48
|
case 'claude':
|
|
42
49
|
if (event.type === 'result' && directMachineResult(event.structured_output) !== undefined)
|
|
43
|
-
|
|
50
|
+
structuredResult = event.structured_output;
|
|
44
51
|
if (event.type === 'result' && typeof event.result === 'string')
|
|
45
52
|
fragments.push(event.result);
|
|
46
53
|
break;
|
|
@@ -63,6 +70,8 @@ export function parseProviderResult(agent, output) {
|
|
|
63
70
|
}
|
|
64
71
|
case 'pi':
|
|
65
72
|
if (event.type === 'message_end' && isRecord(event.message) && event.message.role === 'assistant') {
|
|
73
|
+
if (event.message.stopReason === 'error' || event.message.stopReason === 'aborted')
|
|
74
|
+
return null;
|
|
66
75
|
const text = textContent(event.message.content);
|
|
67
76
|
if (text)
|
|
68
77
|
fragments.push(text);
|
|
@@ -70,6 +79,8 @@ export function parseProviderResult(agent, output) {
|
|
|
70
79
|
break;
|
|
71
80
|
}
|
|
72
81
|
}
|
|
82
|
+
if (structuredResult !== undefined)
|
|
83
|
+
return structuredResult;
|
|
73
84
|
const joined = parseJson(fragments.join(''));
|
|
74
85
|
if (joined.ok) {
|
|
75
86
|
const direct = directMachineResult(joined.value);
|
|
@@ -115,6 +126,15 @@ function parseQwenResult(output) {
|
|
|
115
126
|
return candidate;
|
|
116
127
|
}
|
|
117
128
|
export function parseProviderTelemetry(agent, lines) {
|
|
129
|
+
if (agent === 'pi') {
|
|
130
|
+
const accumulator = createPiTelemetry();
|
|
131
|
+
for (const line of lines) {
|
|
132
|
+
const parsed = parseJson(line);
|
|
133
|
+
if (parsed.ok && isRecord(parsed.value))
|
|
134
|
+
accumulator.consume(parsed.value);
|
|
135
|
+
}
|
|
136
|
+
return accumulator.finish();
|
|
137
|
+
}
|
|
118
138
|
let inputTokens;
|
|
119
139
|
let cachedInputTokens;
|
|
120
140
|
let cacheWriteInputTokens;
|
|
@@ -126,7 +146,6 @@ export function parseProviderTelemetry(agent, lines) {
|
|
|
126
146
|
const harnessTotals = agent === 'opencode' || agent === 'kilo'
|
|
127
147
|
? { input: 0, output: 0, cached: 0, cacheWrite: 0, reasoning: 0, cost: 0, hasInput: false, hasOutput: false, hasCached: false, hasCacheWrite: false, hasReasoning: false, hasCost: false }
|
|
128
148
|
: undefined;
|
|
129
|
-
let piUsage;
|
|
130
149
|
for (const line of lines) {
|
|
131
150
|
let parsed;
|
|
132
151
|
try {
|
|
@@ -138,7 +157,7 @@ export function parseProviderTelemetry(agent, lines) {
|
|
|
138
157
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
139
158
|
continue;
|
|
140
159
|
const event = parsed;
|
|
141
|
-
if (agent === 'qwen' && event.parent_tool_use_id != null)
|
|
160
|
+
if ((agent === 'qwen' || agent === 'claude') && event.parent_tool_use_id != null)
|
|
142
161
|
continue;
|
|
143
162
|
const message = event.message && typeof event.message === 'object' ? event.message : undefined;
|
|
144
163
|
const stats = event.stats && typeof event.stats === 'object' ? event.stats : undefined;
|
|
@@ -177,8 +196,6 @@ export function parseProviderTelemetry(agent, lines) {
|
|
|
177
196
|
harnessTotals.hasCost = true;
|
|
178
197
|
}
|
|
179
198
|
}
|
|
180
|
-
if (agent === 'pi' && event.type === 'message_update' && event.usage && typeof event.usage === 'object')
|
|
181
|
-
piUsage = event.usage;
|
|
182
199
|
const usage = (event.usage && typeof event.usage === 'object'
|
|
183
200
|
? event.usage
|
|
184
201
|
: message?.usage && typeof message.usage === 'object'
|
|
@@ -247,26 +264,6 @@ export function parseProviderTelemetry(agent, lines) {
|
|
|
247
264
|
if (typeof eventModel === 'string' && eventModel && reportedModels.length <= 1)
|
|
248
265
|
model = eventModel;
|
|
249
266
|
}
|
|
250
|
-
if (piUsage) {
|
|
251
|
-
const piInput = finite(piUsage.input);
|
|
252
|
-
const piOutput = finite(piUsage.output);
|
|
253
|
-
const piCached = finite(piUsage.cacheRead);
|
|
254
|
-
const piCacheWrite = finite(piUsage.cacheWrite);
|
|
255
|
-
const piReasoning = finite(piUsage.reasoning);
|
|
256
|
-
const piCost = isRecord(piUsage.cost) ? finite(piUsage.cost.total) : undefined;
|
|
257
|
-
if (piInput !== undefined)
|
|
258
|
-
inputTokens = piInput;
|
|
259
|
-
if (piOutput !== undefined)
|
|
260
|
-
outputTokens = piOutput;
|
|
261
|
-
if (piCached !== undefined)
|
|
262
|
-
cachedInputTokens = piCached;
|
|
263
|
-
if (piCacheWrite !== undefined)
|
|
264
|
-
cacheWriteInputTokens = piCacheWrite;
|
|
265
|
-
if (piReasoning !== undefined)
|
|
266
|
-
reasoningOutputTokens = piReasoning;
|
|
267
|
-
if (piCost !== undefined)
|
|
268
|
-
totalCostUsd = piCost;
|
|
269
|
-
}
|
|
270
267
|
if (harnessTotals) {
|
|
271
268
|
if (harnessTotals.hasInput)
|
|
272
269
|
inputTokens = harnessTotals.input;
|
|
@@ -10,32 +10,46 @@ export function estimateSchedule(stories, maxConcurrency, history) {
|
|
|
10
10
|
if (!estimate)
|
|
11
11
|
return { available: false, reason: 'No measured duration history' };
|
|
12
12
|
const ranks = criticalPathRanks(stories);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
const durations = new Map(stories.filter(story => !story.passes).map(story => [story.id,
|
|
14
|
+
estimateDurations(history.filter(item => item.storyId === story.id).map(item => item.ms)) ?? estimate,
|
|
15
|
+
]));
|
|
16
|
+
const simulate = (field) => {
|
|
17
|
+
const pending = stories.filter(story => !story.passes).sort((a, b) => (a.priority ?? 0) - (b.priority ?? 0) || (ranks.get(b.id) ?? 0) - (ranks.get(a.id) ?? 0) || a.id.localeCompare(b.id));
|
|
18
|
+
const complete = new Set(stories.filter(story => story.passes).map(story => story.id));
|
|
19
|
+
const active = [];
|
|
20
|
+
const tasks = [];
|
|
21
|
+
let time = 0;
|
|
22
|
+
while (pending.length || active.length) {
|
|
23
|
+
for (let index = 0; index < pending.length && active.length < maxConcurrency;) {
|
|
24
|
+
const story = pending[index];
|
|
25
|
+
if ((story.needs ?? []).every(id => complete.has(id)) && (!story.area || !active.some(item => item.story.area === story.area)) && !active.some(item => writeScopesOverlap(story.writes, item.story.writes))) {
|
|
26
|
+
const end = time + durations.get(story.id)[field];
|
|
27
|
+
active.push({ story, end });
|
|
28
|
+
tasks.push({ storyId: story.id, startMs: time, endMs: end });
|
|
29
|
+
pending.splice(index, 1);
|
|
30
|
+
}
|
|
31
|
+
else
|
|
32
|
+
index++;
|
|
27
33
|
}
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
if (!active.length)
|
|
35
|
+
return undefined;
|
|
36
|
+
time = Math.min(...active.map(item => item.end));
|
|
37
|
+
for (let index = active.length - 1; index >= 0; index--)
|
|
38
|
+
if (active[index].end === time) {
|
|
39
|
+
complete.add(active[index].story.id);
|
|
40
|
+
active.splice(index, 1);
|
|
41
|
+
}
|
|
30
42
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
return { time, tasks };
|
|
44
|
+
};
|
|
45
|
+
const typical = simulate('typicalMs'), lower = simulate('lowerMs'), upper = simulate('upperMs');
|
|
46
|
+
if (!typical || !lower || !upper)
|
|
47
|
+
return { available: false, reason: 'Cyclic or missing dependencies' };
|
|
48
|
+
// Different durations can change a greedy schedule's ordering. Keep the
|
|
49
|
+
// empirical scenario envelope ordered; this is not a calibrated interval.
|
|
50
|
+
return { available: true, etaMs: typical.time,
|
|
51
|
+
lowerMs: Math.min(lower.time, typical.time, upper.time), upperMs: Math.max(lower.time, typical.time, upper.time),
|
|
52
|
+
sampleCount: estimate.sampleCount,
|
|
53
|
+
confidence: [...durations.values()].some(duration => duration.confidence === 'low') ? 'low' : estimate.confidence,
|
|
54
|
+
tasks: typical.tasks };
|
|
41
55
|
}
|
|
@@ -17,7 +17,7 @@ export function planPi(canonDir, _targetDir, _codeGraph = 'graphify', _codeIntel
|
|
|
17
17
|
kind: 'write',
|
|
18
18
|
target: '.pi/settings.json',
|
|
19
19
|
merge: true,
|
|
20
|
-
content: JSON.stringify({ skills: ['
|
|
20
|
+
content: JSON.stringify({ skills: ['./skills'] }, null, 2) + '\n',
|
|
21
21
|
reason: 'Pi project skill discovery',
|
|
22
22
|
});
|
|
23
23
|
return actions;
|
|
@@ -52,7 +52,7 @@ export function skillPackageActions(canonDir, skill, provider) {
|
|
|
52
52
|
.map(file => ({
|
|
53
53
|
kind: 'write',
|
|
54
54
|
target: `${roots[provider]}/${skill.id}/${file.relativePath}`,
|
|
55
|
-
content: (provider === 'claude' || provider === 'qwen') && skill.invocation === 'manual' && file.relativePath === 'SKILL.md'
|
|
55
|
+
content: (provider === 'claude' || provider === 'qwen' || provider === 'pi') && skill.invocation === 'manual' && file.relativePath === 'SKILL.md'
|
|
56
56
|
? manualClaudeSkill(file.content, skill)
|
|
57
57
|
: portableContent(file),
|
|
58
58
|
executable: file.executable,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Agent and skill hardening — 2026-09-16
|
|
2
|
+
|
|
3
|
+
This is a bounded source/contract audit, not a guarantee of defect-free operation or a seven-provider model benchmark. Pi was already supported in 1.13.0. The npm release observed at the start of this audit was 1.15.0; the fixes below are included in the 1.15.1 release changeset.
|
|
4
|
+
|
|
5
|
+
## Implemented fixes
|
|
6
|
+
|
|
7
|
+
- Pi telemetry now sums finalized assistant messages across tool turns. Streaming snapshots, turn-end echoes and agent-end transcript replays are not double-counted. Model switches remain visible; missing turn measurements produce partial usage, not a complete total. Optional cost/cache fields are reported as full totals only when every finalized turn measures them. An interrupted unfinalized turn remains unknown.
|
|
8
|
+
- Pi successful tool completions and OpenCode/Kilo completed tool envelopes reset the progress watchdog. Failed tools and streaming updates do not. Total, idle and progress budgets remain enforced; no timeout defaults were relaxed.
|
|
9
|
+
- Structured results from Claude, Codex, Gemini, OpenCode and Kilo are rejected when followed by a terminal error. Pi errored/aborted assistant messages cannot supply a verdict. Claude child-agent events cannot masquerade as parent verdicts or parent usage. Qwen's existing parent/result handling remains in place.
|
|
10
|
+
- OpenCode/Kilo conflicting effort/variant aliases fail before process launch; matching aliases produce one flag.
|
|
11
|
+
- Pi settings use a skill path relative to `.pi/settings.json`. Manual-only skills receive Pi's native `disable-model-invocation` marker, just as Claude/Qwen already did.
|
|
12
|
+
- Schedule estimation simulates typical/lower/upper per-story durations with dependency and write-conflict constraints. A sparse per-story sample no longer inherits stronger confidence from unrelated pooled samples. These are empirical scenarios, not calibrated probabilities or deadlines.
|
|
13
|
+
- Eight missing supporting files are now packaged and linked: three delegation templates, a review template, three debugging guides and a testing anti-pattern guide. Shared instructions prohibit nested orchestration inside Yoke workers, explain host capability fallbacks, preserve acceptance/review gates, and distinguish budgets from time estimates. Removed unsupported claims about guaranteed subagent quality and fixed debugging speed/success rates.
|
|
14
|
+
- The Code Intelligence coordinator unit test now replaces the separate sandbox adapter too, avoiding accidental real Serena startup. It checks an actual rename in the isolated transaction output, approval gating, and that the source project remains untouched (apply does not merge).
|
|
15
|
+
|
|
16
|
+
## Compatibility and operation
|
|
17
|
+
|
|
18
|
+
Existing projects can refresh the canonical skills with `yoke retrofit . --agent=all`, or select one harness. Inspect the merge-aware retrofit diff and backups. Existing custom skill paths remain user-owned; remove an obsolete `.pi/skills` settings entry only after confirming it is the old Yoke-generated entry. The correct settings-relative entry is `./skills`.
|
|
19
|
+
|
|
20
|
+
Current Pi also requires project trust before loading project-local skills in headless runs. Trust is an explicit user decision, not something Yoke grants automatically. See [the harness guide](HARNESSES.md). Tool allowlists are not an OS sandbox: extensions and native configuration still require review.
|
|
21
|
+
|
|
22
|
+
## Evidence and limits
|
|
23
|
+
|
|
24
|
+
Final local validation: 1,281 tests passed, two platform-specific tests skipped, 140 test files passed. TypeScript lint/build, Canon validation, README metadata check and npm package dry run passed; npm audit reported zero vulnerabilities. A follow-up Canon run after the supporting-document additions passed (36 passed, one platform-specific skip). The subsequent release request targets 1.15.1; publication status is recorded by the matching GitHub release and npm registry, not inferred from these local checks.
|
|
25
|
+
|
|
26
|
+
Regression cases were observed failing before their fixes, then passing in targeted runs. Coverage includes multi-turn/chunked Pi usage, missing measurements, model changes, terminal errors, effort conflicts, sparse timing samples, manual invocation and packaged templates. Canon validation scans all registered skill packages; the content audit focused on orchestration, execution and verification instructions, not a formal proof of every skill's behavior.
|
|
27
|
+
|
|
28
|
+
The local Pi 0.85.1 CLI help confirms JSON mode, tool allowlists, provider/model/thinking selection and project-trust controls. Qwen and Kilo were not found on this machine's PATH. No paid/authenticated seven-agent task matrix, cross-platform native sandbox comparison, measured speedup or quality benchmark was performed. Faster feedback is a workflow recommendation, not a measured improvement claim. Existing full verification gates remain required.
|
|
29
|
+
|
|
30
|
+
A read-only README provenance scan found no supported C2PA structure and completed the supported scan. Cryptographic verification and signer trust remain unknown because no conforming verifier/trust policy was supplied. Metadata privacy was unsupported for this text format. Proprietary keyed watermark detection was unavailable; no authorship conclusion follows. No marks were removed.
|
|
31
|
+
|
|
32
|
+
Primary references: [Pi JSON mode](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/json.md), [Pi event types](https://github.com/earendil-works/pi/blob/main/packages/agent/src/types.ts), [Pi skills](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/skills.md), [OpenCode run implementation](https://github.com/anomalyco/opencode/blob/dev/packages/opencode/src/cli/cmd/run.ts).
|
package/docs/HARNESSES.md
CHANGED
|
@@ -4,6 +4,10 @@ Yoke 1.13.0 adds first-class adapters for OpenCode, Kilo and Pi coding agent. Th
|
|
|
4
4
|
|
|
5
5
|
This is a CLI integration, not an authentication bundle. Install the selected harness, log in or configure its API provider, and verify it independently before starting a Yoke loop.
|
|
6
6
|
|
|
7
|
+
For current Pi installations, the official package is `@earendil-works/pi-coding-agent` (the executable remains `pi`). Pi support has existed since Yoke 1.13.0; no additional adapter is required.
|
|
8
|
+
|
|
9
|
+
Pi project trust is separate from Yoke's permission profile. Current Pi ignores project-local settings and skills in headless mode unless the project is trusted. Review the project resources, open Pi interactively, use `/trust`, then restart before running Yoke. Yoke does not silently grant project trust or enable arbitrary project extensions. For isolated worktrees, review the applicable trust scope as well. See [Pi project trust](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/README.md#project-trust).
|
|
10
|
+
|
|
7
11
|
## Setup and retrofit
|
|
8
12
|
|
|
9
13
|
Select one of the new harnesses explicitly:
|
|
@@ -58,6 +62,8 @@ runner:
|
|
|
58
62
|
|
|
59
63
|
This becomes `--provider openai --model gpt-5.6 --thinking high`. Pi calls `variant` and `reasoningEffort` the same underlying thinking-level selection; configuring both with different values is rejected.
|
|
60
64
|
|
|
65
|
+
OpenCode and Kilo likewise map these two fields to a single `--variant`: matching values are emitted once and conflicting values are rejected before spawning a process.
|
|
66
|
+
|
|
61
67
|
The same fields are available on routing workers and quality critic/repair roles. Routing evidence is keyed by harness, provider, model, reasoning effort and variant, so a model profile does not inherit another profile's success history.
|
|
62
68
|
|
|
63
69
|
## Permission profiles and honest limits
|
package/gemini-extension.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yoke",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"description": "Cross-agent coding harness for seven supported CLIs: curated skill canon, mechanical safety gates, autonomous loop with proof artifacts. CLI: npm i -g @hecer/yoke",
|
|
5
5
|
"contextFileName": "GEMINI-EXTENSION.md"
|
|
6
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hecer/yoke",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.1",
|
|
4
4
|
"description": "One harness, seven agents, zero trust in \"done\" — cross-agent coding harness for Claude Code, Codex CLI, Gemini CLI, Qwen Code, OpenCode, Kilo and Pi: one skill canon, mechanical safety gates, an autonomous loop with screenshot/video proofs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|