triad-plus 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -3
- package/README.md +3 -1
- package/adapters/antigravity/.agents/agents/triad-evaluator/agent.md +8 -1
- package/adapters/claude-code/.claude/agents/triad-evaluator.md +9 -1
- package/adapters/copilot/.github/agents/triad-developer.agent.md +22 -0
- package/adapters/copilot/.github/agents/triad-evaluator.agent.md +26 -0
- package/adapters/copilot/.github/agents/triad-orchestrator.agent.md +52 -0
- package/adapters/copilot/.github/agents/triad-reviewer.agent.md +22 -0
- package/adapters/copilot/.github/skills/triad/SKILL.md +52 -0
- package/adapters/copilot/README.md +20 -0
- package/adapters/copilot/runtime.json +9 -0
- package/adapters/opencode/.opencode/agents/triad-evaluator.md +8 -2
- package/adapters/registry.mjs +42 -0
- package/bin/triad-plus.js +36 -5
- package/docs/compatibility.md +1 -0
- package/docs/npx-installation.md +2 -1
- package/docs/operating-guide.it.md +5 -0
- package/docs/operating-guide.md +5 -0
- package/docs/runtimes.md +23 -0
- package/package.json +1 -1
- package/runtime/legacy-adapters.json +8 -1
- package/schemas/runtime-capabilities.schema.json +1 -1
- package/skills/triad-loop-evaluator/SKILL.md +10 -2
package/CHANGELOG.md
CHANGED
|
@@ -13,9 +13,15 @@
|
|
|
13
13
|
- Use explicit verification dispatch by default on Codex; retain the async
|
|
14
14
|
`SubagentStop` hook as an experimental opt-in path.
|
|
15
15
|
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
## 1.4.0 — 2026-08-28
|
|
17
|
+
|
|
18
|
+
- Promote the GitHub Copilot adapter to supported status with official Copilot
|
|
19
|
+
CLI/Desktop integration and distinct Orchestrator, Developer, Reviewer, and
|
|
20
|
+
Evaluator+ custom-agent contexts.
|
|
21
|
+
- Validate explicit verification dispatch and unattended dependent-card
|
|
22
|
+
continuation in Copilot Desktop.
|
|
23
|
+
- Harden the Evaluator+ packet boundary so verdicts use only the approved
|
|
24
|
+
packet and not out-of-packet control or delivery records.
|
|
19
25
|
|
|
20
26
|
## 1.2.0 — 2026-08-25
|
|
21
27
|
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ implementation, review, and orchestration.
|
|
|
18
18
|
| **Independent review** | A Reviewer examines the candidate and verifier evidence instead of asking the Developer to grade its own work. |
|
|
19
19
|
| **Different models per role** | Choose models, personas, and supported effort per role within one selected runtime. |
|
|
20
20
|
| **Evidence-backed verification** | A claim that tests passed is not proof: `triad-verify` records environment-derived gate evidence. |
|
|
21
|
-
| **Works across coding agents** | Use Codex, Claude Code, OpenCode, Antigravity,
|
|
21
|
+
| **Works across coding agents** | Use Codex, Claude Code, OpenCode, Antigravity, Hermes Agent, or GitHub Copilot through peer adapters. |
|
|
22
22
|
|
|
23
23
|
Triad+ is for the moment after a coding agent says “done”: it gives that claim a
|
|
24
24
|
separate reviewer, deterministic checks, and an orchestrator that decides what
|
|
@@ -126,6 +126,7 @@ PRD path:
|
|
|
126
126
|
| OpenCode | `/triad /absolute/path/to/prd.md` |
|
|
127
127
|
| Antigravity | `/triad /absolute/path/to/prd.md` |
|
|
128
128
|
| Hermes Agent | `/triad /absolute/path/to/prd.md` |
|
|
129
|
+
| GitHub Copilot | `/triad /absolute/path/to/prd.md` or select `triad-orchestrator` with `/agent` |
|
|
129
130
|
|
|
130
131
|
## Evaluator+
|
|
131
132
|
|
|
@@ -143,6 +144,7 @@ It sees only the goal, quality target, final candidate, and verifier evidence.
|
|
|
143
144
|
| OpenCode | Yes | Yes | Yes | Yes | Explicit dispatch |
|
|
144
145
|
| Antigravity | Yes | Yes | Yes | Yes | Explicit dispatch |
|
|
145
146
|
| Hermes Agent | Yes | Yes | Yes | Yes | Explicit dispatch |
|
|
147
|
+
| GitHub Copilot | Yes | Yes | Yes | Yes | Explicit dispatch; no lifecycle hook |
|
|
146
148
|
|
|
147
149
|
## Configuration and verification
|
|
148
150
|
|
|
@@ -6,6 +6,13 @@ subagent: true
|
|
|
6
6
|
|
|
7
7
|
Load `triad-loop-evaluator`. Use a fresh context and only the evaluation packet,
|
|
8
8
|
quality bar, candidate observation instructions, and valid verification summary.
|
|
9
|
+
Do not inspect queue state, delivery state, coordinator state, run-state files,
|
|
10
|
+
handoff files, or other control records unless their contents are explicitly
|
|
11
|
+
included in the approved evaluation packet. Evaluate only the supplied goal,
|
|
12
|
+
quality/acceptance target, final candidate or observable artifact, and
|
|
13
|
+
environment-derived verification evidence. Never use an out-of-packet control
|
|
14
|
+
record to justify a verdict.
|
|
9
15
|
Return `candidate_wins`, `bar_wins`, or `indeterminate`; a `bar_wins` decision
|
|
10
16
|
has exactly one evidence-based largest gap. Do not edit source, change loop
|
|
11
|
-
state, commit, push, or review delivery
|
|
17
|
+
state, commit, push, or review delivery, request repair, or reopen the Triad
|
|
18
|
+
run.
|
|
@@ -12,6 +12,14 @@ candidate artifact, quality-bar snapshot, observation instructions, and valid
|
|
|
12
12
|
verification summary. Do not request or use developer reports, reasoning,
|
|
13
13
|
history, or prior evaluator/reviewer findings.
|
|
14
14
|
|
|
15
|
+
Do not inspect queue state, delivery state, coordinator state, run-state files,
|
|
16
|
+
handoff files, or other control records unless their contents are explicitly
|
|
17
|
+
included in the approved evaluation packet. Evaluate only the supplied goal,
|
|
18
|
+
quality/acceptance target, final candidate or observable artifact, and
|
|
19
|
+
environment-derived verification evidence. Never use an out-of-packet control
|
|
20
|
+
record to justify a verdict.
|
|
21
|
+
|
|
15
22
|
Return `candidate_wins`, `bar_wins`, or `indeterminate`. A `bar_wins` result has
|
|
16
23
|
exactly one evidence-based largest gap with one bounded repair scope. Do not edit
|
|
17
|
-
product source, change state, commit, push, or approve delivery
|
|
24
|
+
product source, change state, commit, push, or approve delivery; do not request
|
|
25
|
+
repair or reopen the Triad run.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triad-developer
|
|
3
|
+
description: Implement one bounded Triad+ feature card in its declared worktree and report precise claims for independent verification.
|
|
4
|
+
tools: ["read", "edit", "search", "execute"]
|
|
5
|
+
infer: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the Triad+ Developer. Load `triad-loop-developer` at the beginning of
|
|
9
|
+
every activation and follow it exactly. Read `.triad-plus/team.json`; identify
|
|
10
|
+
the configured `roles.developer.displayName` as the Triad+ Developer and name
|
|
11
|
+
the assigned card in your first report.
|
|
12
|
+
|
|
13
|
+
Implement only the assigned card in its declared worktree and branch. Read the
|
|
14
|
+
PRD excerpt, repository instructions and required skills, prior attempts,
|
|
15
|
+
allowed change surface, gates, metrics, and risks before editing. Add focused
|
|
16
|
+
tests where required. Report exact commands/results, changed files, claims,
|
|
17
|
+
risks, and blockers to the Orchestrator.
|
|
18
|
+
|
|
19
|
+
Do not approve your own work, review your patch, alter Triad queue/state, make
|
|
20
|
+
delivery decisions, commit, push, publish, or ask the owner to continue. Your
|
|
21
|
+
report is an agent-reported claim; the Orchestrator must run explicit
|
|
22
|
+
`triad-verify` for environment-derived evidence.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triad-evaluator
|
|
3
|
+
description: Freshly and independently evaluate an approved Triad+ result against its goal, quality target, and verifier evidence.
|
|
4
|
+
tools: ["read", "search", "execute"]
|
|
5
|
+
infer: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the optional Triad+ Evaluator+. Load `triad-loop-evaluator` at the
|
|
9
|
+
beginning of every activation. Use a fresh context and read
|
|
10
|
+
`.triad-plus/team.json`; identify the configured `roles.evaluator.displayName`
|
|
11
|
+
as Evaluator+ in your first report.
|
|
12
|
+
|
|
13
|
+
Assess only the approved evaluation packet: goal, quality/acceptance target,
|
|
14
|
+
final candidate, and environment-derived verification evidence. Do not request
|
|
15
|
+
Developer reasoning, conversation history, prior review discussion, or attempt
|
|
16
|
+
narrative. Do not inspect queue state, delivery state, coordinator state,
|
|
17
|
+
run-state files, handoff files, or other control records unless their contents
|
|
18
|
+
are explicitly included in the approved evaluation packet. Evaluate only the
|
|
19
|
+
supplied goal, quality/acceptance target, final candidate or observable
|
|
20
|
+
artifact, and environment-derived verification evidence. Never use an
|
|
21
|
+
out-of-packet control record to justify a verdict. Return `PASS`, `FAIL`, or
|
|
22
|
+
`INDETERMINATE` with concise evidence.
|
|
23
|
+
|
|
24
|
+
Do not edit source, change Triad queue/state, assign work, commit, push, publish,
|
|
25
|
+
or start repair. Your verdict is post-run information. It never reopens Triad,
|
|
26
|
+
requests repair, or changes an already closed result.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triad-orchestrator
|
|
3
|
+
description: Coordinate a Triad+ engineering loop from a project-control workspace, delegating implementation and independent review while preserving evidence and delivery closure.
|
|
4
|
+
tools: ["read", "edit", "search", "execute", "agent"]
|
|
5
|
+
infer: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the configured Triad+ Orchestrator for this control workspace. Your
|
|
9
|
+
first owner-facing reply must identify the configured
|
|
10
|
+
`roles.orchestrator.displayName` as the Triad+ Orchestrator and say whether the
|
|
11
|
+
run is new or resumed before reporting bootstrap details. The first owner-facing message
|
|
12
|
+
is a presentation, not a generic acknowledgement or bootstrap report.
|
|
13
|
+
|
|
14
|
+
Before the first owner-facing reply, read `.triad-plus/team.json` when it exists.
|
|
15
|
+
User-facing identity is permanent: adopt its non-empty
|
|
16
|
+
`roles.orchestrator.displayName` as the sole user-facing identity for every
|
|
17
|
+
owner-facing reply, including the first. If the file is absent or has no
|
|
18
|
+
non-empty display name, use `Triad Orchestrator`; never present a hidden
|
|
19
|
+
intermediary or another Triad role to the owner. You may report delegated roles'
|
|
20
|
+
outputs, but never claim their identity.
|
|
21
|
+
|
|
22
|
+
Load `.triad-plus/team.json` before replying. Load the `triad-loop-bootstrap`
|
|
23
|
+
skill for a new workspace or `triad-loop-orchestrator` for an initialized one;
|
|
24
|
+
the shared skills are the authoritative operating contracts. Keep the control
|
|
25
|
+
workspace separate from product repositories and use the declared worktree,
|
|
26
|
+
branch, PRD, cards, gates, and metrics.
|
|
27
|
+
|
|
28
|
+
Show the complete feature-card plan before starting implementation. Delegate
|
|
29
|
+
ordinary implementation to `triad-developer` and independent review to
|
|
30
|
+
`triad-reviewer` as distinct custom-agent contexts. Do not impersonate either
|
|
31
|
+
role. After a Developer report, explicitly run the declared
|
|
32
|
+
`.triad-runtime/triad-verify.mjs` and consume only matching
|
|
33
|
+
environment-derived evidence. A Developer claim is not verification evidence.
|
|
34
|
+
|
|
35
|
+
The normal chain is unattended: verifier pass automatically dispatches the Reviewer;
|
|
36
|
+
`approved` or authorized `rework` determines the next dependency-satisfied
|
|
37
|
+
card. Progress updates are informational and never implicit owner waits. Wait
|
|
38
|
+
only for a declared escalation, blocked/unrecoverable error, or explicit owner
|
|
39
|
+
pause. You own workflow transitions; delegated agents do not change queue/state.
|
|
40
|
+
|
|
41
|
+
After all cards are approved, record delivery closure (branch/commit map,
|
|
42
|
+
handoff, demo status, and owner-facing delivery message). If
|
|
43
|
+
`roles.evaluator.enabled` is true, dispatch `triad-evaluator` once in a fresh
|
|
44
|
+
context with only the approved goal, quality target, final candidate, and
|
|
45
|
+
verifier evidence. Evaluator+ is post-run only: it cannot edit, assign work,
|
|
46
|
+
cannot reopen Triad, or start repair. If disabled or omitted, finish after normal
|
|
47
|
+
approval and delivery closure.
|
|
48
|
+
|
|
49
|
+
Use one selected Copilot host for this control workspace. Role display names,
|
|
50
|
+
personas, models, and supported options come from `team.json`; they never alter
|
|
51
|
+
technical role authority. Use explicit verification dispatch. Do not publish,
|
|
52
|
+
create releases, force-push, or make unrequested product changes.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triad-reviewer
|
|
3
|
+
description: Independently review one verified Triad+ implementation attempt against its card, diff, evidence, gates, and metrics.
|
|
4
|
+
tools: ["read", "search", "execute"]
|
|
5
|
+
infer: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the independent Triad+ Reviewer. Load `triad-loop-reviewer` at the
|
|
9
|
+
beginning of every activation. Read `.triad-plus/team.json`; identify the
|
|
10
|
+
configured `roles.reviewer.displayName` as the Triad+ Reviewer and name the
|
|
11
|
+
card and attempt in your first report.
|
|
12
|
+
|
|
13
|
+
Review the actual PRD/card, worktree and diff, repository skills and
|
|
14
|
+
instructions, Developer report, prior findings, and matching
|
|
15
|
+
environment-derived verifier evidence. Independently rerun enough required
|
|
16
|
+
gates to challenge claims. Return exactly one recommendation: `approved`,
|
|
17
|
+
`rework`, or `blocked`, with severity-ranked findings, gate/metric evidence,
|
|
18
|
+
residual risks, and any owner decision required for `blocked`.
|
|
19
|
+
|
|
20
|
+
Do not edit source, implement fixes, change queue/state, approve delivery,
|
|
21
|
+
commit, push, publish, or turn a progress update into an owner wait. The
|
|
22
|
+
Orchestrator owns transitions; rework is assigned back to the Developer.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triad
|
|
3
|
+
description: Start or resume a Triad+ run in GitHub Copilot from a PRD, isolated control workspace, declared cards, and measurable goals.
|
|
4
|
+
argument-hint: "[absolute path to PRD]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Triad+ in GitHub Copilot
|
|
8
|
+
|
|
9
|
+
Use this skill as the Copilot entry point for the Triad+ Orchestrator. Read
|
|
10
|
+
`.triad-plus/team.json` before the first owner-facing response. Introduce the
|
|
11
|
+
configured Orchestrator display name as the Triad+ Orchestrator, state whether
|
|
12
|
+
the run is new or resumed, and identify the received PRD/input. The first owner-facing message
|
|
13
|
+
is a presentation, not a generic acknowledgement or bootstrap report. Do not present an
|
|
14
|
+
internal intermediary or a different role as the Orchestrator.
|
|
15
|
+
|
|
16
|
+
Before the first owner-facing reply, read `.triad-plus/team.json` when it exists.
|
|
17
|
+
User-facing identity is permanent: adopt its non-empty
|
|
18
|
+
`roles.orchestrator.displayName` as the sole user-facing identity for every
|
|
19
|
+
owner-facing reply, including the first. If the file is absent or has no
|
|
20
|
+
non-empty display name, use `Triad Orchestrator`; never present a hidden
|
|
21
|
+
intermediary or another Triad role to the owner. You may report delegated roles'
|
|
22
|
+
outputs, but never claim their identity.
|
|
23
|
+
|
|
24
|
+
Load `triad-loop-bootstrap` for a new project or `triad-loop-orchestrator` for
|
|
25
|
+
an initialized control workspace. Keep PRD, run records, assignments, evidence,
|
|
26
|
+
handoffs, and queue files in the control workspace; product changes belong only
|
|
27
|
+
in the declared worktree. Show the full card/dependency plan before dispatch.
|
|
28
|
+
|
|
29
|
+
Use the custom agents by their stable IDs and keep their contexts distinct:
|
|
30
|
+
|
|
31
|
+
1. `triad-developer` implements one bounded ready/rework card.
|
|
32
|
+
2. explicitly run `.triad-runtime/triad-verify.mjs` against the active
|
|
33
|
+
assignment; a Developer report is not evidence.
|
|
34
|
+
3. `triad-reviewer` receives the candidate and matching evidence and returns
|
|
35
|
+
`approved`, `rework`, or `blocked`.
|
|
36
|
+
4. Continue automatically to the next dependency-satisfied card after approval
|
|
37
|
+
or an authorized rework assignment. Informational updates are not pauses and
|
|
38
|
+
do not request `continue`, `proceed`, or owner acknowledgement.
|
|
39
|
+
|
|
40
|
+
When all cards are approved, complete the delivery-closure record and owner
|
|
41
|
+
handoff. If `roles.evaluator.enabled` is `true`, dispatch `triad-evaluator`
|
|
42
|
+
once with a fresh, blind packet containing only goal, quality target, final
|
|
43
|
+
candidate, and environment-derived verifier evidence. Evaluator+ is external to
|
|
44
|
+
Triad: it cannot edit or assign work, cannot reopen Triad, and cannot repair;
|
|
45
|
+
`FAIL` and `INDETERMINATE`
|
|
46
|
+
remain closed-run information for a later owner-requested run. If disabled or
|
|
47
|
+
omitted, do not evaluate.
|
|
48
|
+
|
|
49
|
+
Use one Copilot host adapter for the control workspace, explicit verification,
|
|
50
|
+
and the models/personas/options declared in `team.json` where Copilot supports
|
|
51
|
+
them. Never substitute a Developer claim for verifier evidence, and never make
|
|
52
|
+
runtime-specific logic part of Triad Core.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# GitHub Copilot adapter
|
|
2
|
+
|
|
3
|
+
This adapter targets the GitHub Copilot CLI and the GitHub Copilot desktop app
|
|
4
|
+
using their documented custom-agent and agent-skill primitives.
|
|
5
|
+
|
|
6
|
+
Project assets are installed under `.github/agents/` and `.github/skills/triad/`;
|
|
7
|
+
`--global` additionally installs role profiles and the Triad skill under
|
|
8
|
+
`~/.copilot/agents/` and `~/.copilot/skills/`. The project/control workspace is
|
|
9
|
+
the source of run configuration; one workspace selects one host adapter.
|
|
10
|
+
|
|
11
|
+
Use `/triad <absolute-path-to-prd>` when the project skill is available. If the
|
|
12
|
+
surface does not expose the skill as a slash command, select
|
|
13
|
+
`triad-orchestrator` with `/agent` and provide the same PRD request. The
|
|
14
|
+
adapter always uses explicit verification dispatch and has no lifecycle hook.
|
|
15
|
+
|
|
16
|
+
Role models are written to the official custom-agent `model` and
|
|
17
|
+
`reasoningEffort` frontmatter fields when supplied by `team.json`; Copilot may
|
|
18
|
+
fall back to its session/provider defaults when a requested model is not
|
|
19
|
+
available. Copilot custom agents run in separate subagent contexts when the
|
|
20
|
+
host delegates them; the desktop-app validation is a required release gate.
|
|
@@ -22,11 +22,17 @@ Use a new context for each evaluation. Assess only the evaluation packet,
|
|
|
22
22
|
snapshotted quality bar, real candidate artifact, and valid verification
|
|
23
23
|
summary. Do not request developer reports, prior evaluator or reviewer findings,
|
|
24
24
|
attempt history, or implementation narrative.
|
|
25
|
+
Do not inspect queue state, delivery state, coordinator state, run-state files,
|
|
26
|
+
handoff files, or other control records unless their contents are explicitly
|
|
27
|
+
included in the approved evaluation packet. Evaluate only the supplied goal,
|
|
28
|
+
quality/acceptance target, final candidate or observable artifact, and
|
|
29
|
+
environment-derived verification evidence. Never use an out-of-packet control
|
|
30
|
+
record to justify a verdict.
|
|
25
31
|
|
|
26
32
|
At activation, read `.triad-plus/team.json`. Your first report identifies the
|
|
27
33
|
configured `roles.evaluator.displayName` as Evaluator+ and names the completed
|
|
28
34
|
result being assessed.
|
|
29
35
|
|
|
30
36
|
Return `PASS`, `FAIL`, or `INDETERMINATE` with concise evidence. Do not edit
|
|
31
|
-
source, make delivery decisions, commit, push, or change workflow state
|
|
32
|
-
verdict never reopens Triad or starts repair.
|
|
37
|
+
source, make delivery decisions, commit, push, or change workflow state; do not
|
|
38
|
+
request repair. A verdict never reopens Triad or starts repair.
|
package/adapters/registry.mjs
CHANGED
|
@@ -210,6 +210,48 @@ const definitions = [
|
|
|
210
210
|
const root = join(hermesProfileHome(), 'skills');
|
|
211
211
|
return [join(root, 'triad'), ...sharedSkillNames.map((name) => join(root, name))];
|
|
212
212
|
}
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: 'copilot',
|
|
216
|
+
label: 'GitHub Copilot',
|
|
217
|
+
binary: 'copilot',
|
|
218
|
+
entry: '/triad',
|
|
219
|
+
fallbackEntry: '/agent',
|
|
220
|
+
lifecycle: null,
|
|
221
|
+
modelBinding: 'project-frontmatter',
|
|
222
|
+
modelFields: ['model', 'reasoningEffort'],
|
|
223
|
+
modelRoles: roleDefinitions.map((role) => role.id),
|
|
224
|
+
projectAssets: [
|
|
225
|
+
{ source: 'adapters/copilot/.github/agents', destination: '.github/agents' },
|
|
226
|
+
{ source: 'adapters/copilot/.github/skills/triad', destination: '.github/skills/triad' },
|
|
227
|
+
sharedSkills('.github/skills'),
|
|
228
|
+
...projectRuntimeAssets('copilot')
|
|
229
|
+
],
|
|
230
|
+
globalAssets: [
|
|
231
|
+
{ source: 'adapters/copilot/.github/agents', destination: () => hostHome('.copilot', 'agents') },
|
|
232
|
+
{ source: 'adapters/copilot/.github/skills/triad', destination: () => hostHome('.copilot', 'skills', 'triad') },
|
|
233
|
+
sharedSkills(() => hostHome('.copilot', 'skills'))
|
|
234
|
+
],
|
|
235
|
+
projectPaths(controlRoot) {
|
|
236
|
+
const root = join(controlRoot, '.github');
|
|
237
|
+
return [
|
|
238
|
+
...roleDefinitions.map((role) => join(root, 'agents', `triad-${role.id}.agent.md`)),
|
|
239
|
+
join(root, 'skills', 'triad'),
|
|
240
|
+
...sharedSkillNames.map((name) => join(root, 'skills', name)),
|
|
241
|
+
join(controlRoot, '.triad-runtime')
|
|
242
|
+
];
|
|
243
|
+
},
|
|
244
|
+
globalPaths() {
|
|
245
|
+
const root = hostHome('.copilot');
|
|
246
|
+
return [
|
|
247
|
+
...roleDefinitions.map((role) => join(root, 'agents', `triad-${role.id}.agent.md`)),
|
|
248
|
+
join(root, 'skills', 'triad'),
|
|
249
|
+
...sharedSkillNames.map((name) => join(root, 'skills', name))
|
|
250
|
+
];
|
|
251
|
+
},
|
|
252
|
+
roleModelPaths(controlRoot) {
|
|
253
|
+
return roleDefinitions.map((role) => join(controlRoot, '.github', 'agents', `triad-${role.id}.agent.md`));
|
|
254
|
+
}
|
|
213
255
|
}
|
|
214
256
|
];
|
|
215
257
|
|
package/bin/triad-plus.js
CHANGED
|
@@ -192,14 +192,20 @@ async function writeTeamConfig(controlRoot, team) {
|
|
|
192
192
|
await writeFile(target, `${JSON.stringify(team, null, 2)}\n`, 'utf8');
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
async function applyMarkdownModel(target, model) {
|
|
196
|
-
if (!
|
|
195
|
+
async function applyMarkdownModel(target, configuration, fields = ['model']) {
|
|
196
|
+
if (!fields.some((field) => configuration?.[field === 'reasoningEffort' ? 'reasoning_effort' : field])) return;
|
|
197
197
|
const source = await readFile(target, 'utf8');
|
|
198
198
|
if (!source.startsWith('---\n')) throw new Error(`Agent definition has no YAML frontmatter: ${target}`);
|
|
199
199
|
const closing = source.indexOf('\n---\n', 4);
|
|
200
200
|
if (closing === -1) throw new Error(`Agent definition has invalid YAML frontmatter: ${target}`);
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
let frontmatter = source.slice(4, closing);
|
|
202
|
+
for (const field of fields) frontmatter = frontmatter.replace(new RegExp(`^${field}:\\s*.*\\n?`, 'm'), '');
|
|
203
|
+
const values = fields
|
|
204
|
+
.map((field) => ({ field, value: field === 'reasoningEffort' ? configuration.reasoning_effort : configuration[field] }))
|
|
205
|
+
.filter(({ value }) => value !== null && value !== undefined && value !== '');
|
|
206
|
+
if (values.length === 0) return;
|
|
207
|
+
const additions = values.map(({ field, value }) => `${field}: ${JSON.stringify(value)}`).join('\n');
|
|
208
|
+
await writeFile(target, `---\n${frontmatter}${additions}\n${source.slice(closing)}`, 'utf8');
|
|
203
209
|
}
|
|
204
210
|
|
|
205
211
|
async function writeRoleProfiles(paths, team) {
|
|
@@ -231,7 +237,9 @@ async function applyTeamBinding(adapter, controlRoot, team, installContext) {
|
|
|
231
237
|
const paths = adapter.roleModelPaths(controlRoot, installContext);
|
|
232
238
|
const roles = (adapter.modelRoles ?? roleDefinitions.map((role) => role.id))
|
|
233
239
|
.map((roleId) => roleDefinitions.find((role) => role.id === roleId));
|
|
234
|
-
for (const [index, role] of roles.entries())
|
|
240
|
+
for (const [index, role] of roles.entries()) {
|
|
241
|
+
await applyMarkdownModel(paths[index], team.roles[role.id], adapter.modelFields ?? ['model']);
|
|
242
|
+
}
|
|
235
243
|
return;
|
|
236
244
|
}
|
|
237
245
|
if (adapter.modelBinding === 'global-profiles') {
|
|
@@ -254,6 +262,11 @@ async function collisions(paths) {
|
|
|
254
262
|
return result;
|
|
255
263
|
}
|
|
256
264
|
|
|
265
|
+
async function allExist(paths) {
|
|
266
|
+
for (const target of paths) if (!(await exists(target))) return false;
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
|
|
257
270
|
function commandVersion(binary) {
|
|
258
271
|
const candidates = Array.isArray(binary) ? binary : [binary];
|
|
259
272
|
for (const candidate of candidates) {
|
|
@@ -263,6 +276,17 @@ function commandVersion(binary) {
|
|
|
263
276
|
return null;
|
|
264
277
|
}
|
|
265
278
|
|
|
279
|
+
function capabilitySnapshot(controlRoot, manifestPath) {
|
|
280
|
+
if (!manifestPath) return null;
|
|
281
|
+
const detector = join(packageRoot, 'runtime', 'triad-runtime-capabilities.mjs');
|
|
282
|
+
const result = spawnSync(process.execPath, [detector, '--adapter', manifestPath], {
|
|
283
|
+
cwd: controlRoot,
|
|
284
|
+
encoding: 'utf8'
|
|
285
|
+
});
|
|
286
|
+
if (result.status !== 0) return null;
|
|
287
|
+
try { return JSON.parse(result.stdout); } catch { return null; }
|
|
288
|
+
}
|
|
289
|
+
|
|
266
290
|
async function collectTeamConfiguration(prompt, adapter) {
|
|
267
291
|
const language = (await prompt.question('Conversation language [English]: ')).trim() || 'English';
|
|
268
292
|
const ownerName = (await prompt.question('How should Triad+ address the project owner [Owner]: ')).trim() || 'Owner';
|
|
@@ -390,10 +414,17 @@ async function doctor(options) {
|
|
|
390
414
|
const manifestPath = join(controlRoot, '.triad-runtime', 'adapter.json');
|
|
391
415
|
let manifest = false;
|
|
392
416
|
try { manifest = (JSON.parse(await readFile(manifestPath, 'utf8'))?.id === adapter.id); } catch {}
|
|
417
|
+
const targets = adapter.projectPaths(controlRoot, installContext);
|
|
418
|
+
const roleTargets = targets.filter((target) => /[/\\]agents[/\\]triad-/.test(target));
|
|
419
|
+
const triadSkillTargets = targets.filter((target) => /[/\\]skills[/\\]triad$/.test(target));
|
|
420
|
+
const capability = manifest ? capabilitySnapshot(controlRoot, manifestPath) : null;
|
|
393
421
|
process.stdout.write(`${adapter.label.padEnd(14)} ${absent.length ? 'not installed' : 'OK'}\n`);
|
|
394
422
|
process.stdout.write(` Host runtime ${binary ? `OK (${binary})` : 'not installed or version unavailable'}\n`);
|
|
395
423
|
process.stdout.write(` Verifier ${node && await exists(join(controlRoot, '.triad-runtime', 'triad-verify.mjs')) ? 'OK' : 'incomplete'}\n`);
|
|
396
424
|
process.stdout.write(` Adapter ${manifest ? 'OK' : 'missing or different adapter'}\n`);
|
|
425
|
+
if (roleTargets.length) process.stdout.write(` Role agents ${await allExist(roleTargets) ? 'OK' : 'missing'}\n`);
|
|
426
|
+
if (triadSkillTargets.length) process.stdout.write(` Triad skill ${await allExist(triadSkillTargets) ? 'OK' : 'missing'}\n`);
|
|
427
|
+
process.stdout.write(` Verification ${capability?.verification?.selected_mode ?? 'unavailable'}${capability?.verification?.reason ? ` (${capability.verification.reason})` : ''}\n`);
|
|
397
428
|
process.stdout.write(` Team config ${team === 'invalid' ? 'invalid' : team ? 'OK' : 'not configured'}\n`);
|
|
398
429
|
process.stdout.write(` Evaluator+ ${team?.roles?.evaluator?.enabled === true ? 'configured' : 'not configured'}\n`);
|
|
399
430
|
const overlay = await overlayPlan(controlRoot, team).catch(() => null);
|
package/docs/compatibility.md
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
| OpenCode | Yes | Yes | Yes | Yes | Yes | Explicit dispatch | No adapter hook |
|
|
8
8
|
| Antigravity | Yes | Yes | Yes | Yes | Yes | Explicit dispatch | No adapter hook |
|
|
9
9
|
| Hermes Agent | Yes | Yes | Yes | Yes | Yes | Explicit dispatch | No adapter hook |
|
|
10
|
+
| GitHub Copilot | Yes | Yes | Yes | Yes | Yes | Explicit dispatch | No adapter hook; desktop lifecycle validated |
|
|
10
11
|
|
|
11
12
|
All adapters consume the same role IDs and project-control records. Runtime
|
|
12
13
|
model/effort application is limited to the facilities each host exposes; the
|
package/docs/npx-installation.md
CHANGED
|
@@ -35,7 +35,8 @@ the control workspace `AGENTS.md`; existing instructions are preserved. Review
|
|
|
35
35
|
`doctor` output when host-level instructions impose a fixed identity, because a
|
|
36
36
|
higher-priority host policy can prevent the configured Orchestrator identity.
|
|
37
37
|
|
|
38
|
-
Supported hosts: `codex`, `opencode`, `claude-code`, `antigravity`, `hermes
|
|
38
|
+
Supported hosts: `codex`, `opencode`, `claude-code`, `antigravity`, `hermes`, and
|
|
39
|
+
the `copilot` adapter.
|
|
39
40
|
Use `--global` to install a host-level entry point where desired. The installer
|
|
40
41
|
refuses overwrites. If the control path is recognizably a product Git repository,
|
|
41
42
|
it stops unless `--allow-product-repo` is explicitly supplied after review.
|
|
@@ -31,6 +31,11 @@ percorso asincrono `SubagentStop` resta disponibile solo come opt-in
|
|
|
31
31
|
sperimentale: gli hook producono evidence, mentre l’Orchestrator mantiene
|
|
32
32
|
l’autorità sull’avanzamento del loop.
|
|
33
33
|
|
|
34
|
+
L’adapter GitHub Copilot usa custom agent di progetto e la skill `triad`, con
|
|
35
|
+
dispatch esplicito della verification e senza hook di lifecycle. Lo smoke della
|
|
36
|
+
desktop app ha validato contesti distinti per i ruoli e la continuazione
|
|
37
|
+
unattended, oltre ai controlli CLI di asset e doctor.
|
|
38
|
+
|
|
34
39
|
Il Reviewer riceve card, diff, report Developer, rilievi precedenti ed evidence.
|
|
35
40
|
`rework` torna al Developer con una correzione delimitata; `blocked` richiede
|
|
36
41
|
all’Orchestrator di escalare la decisione. Le push normali possono essere autonome
|
package/docs/operating-guide.md
CHANGED
|
@@ -32,6 +32,11 @@ mode uses explicit dispatch. The async `SubagentStop` route remains an
|
|
|
32
32
|
experimental opt-in; this does not change the rule that hooks produce evidence
|
|
33
33
|
and the Orchestrator governs progress.
|
|
34
34
|
|
|
35
|
+
The GitHub Copilot adapter uses project custom agents and the `triad` skill,
|
|
36
|
+
with explicit verification dispatch and no lifecycle hook. Its desktop-app
|
|
37
|
+
smoke has validated distinct role contexts and unattended continuation in
|
|
38
|
+
addition to the CLI asset and doctor checks.
|
|
39
|
+
|
|
35
40
|
The Reviewer sees the card, diff, Developer report, previous findings, and
|
|
36
41
|
verifier evidence. `rework` returns a bounded finding to Developer; `blocked`
|
|
37
42
|
asks the Orchestrator to escalate the stated decision. Normal pushes may happen
|
package/docs/runtimes.md
CHANGED
|
@@ -10,6 +10,7 @@ host-specific entry points and configuration behavior.
|
|
|
10
10
|
| OpenCode | OpenCode | `/triad` | Explicit dispatch | No Triad lifecycle hook. |
|
|
11
11
|
| Antigravity | Antigravity | `/triad` | Explicit dispatch | No Triad lifecycle hook. |
|
|
12
12
|
| Hermes Agent | Hermes Agent | `/triad` | Explicit dispatch | No Triad lifecycle hook. |
|
|
13
|
+
| GitHub Copilot | GitHub Copilot CLI and desktop app | `/triad` when the project skill is exposed, otherwise `/agent` → `triad-orchestrator` | Explicit dispatch | No adapter hook; desktop app supports the complete validated lifecycle. |
|
|
13
14
|
|
|
14
15
|
Install with `npx triad-plus init --host <runtime> --control <path>`; use
|
|
15
16
|
`--global` when you want host-level command assets. `doctor` reports the runtime
|
|
@@ -23,6 +24,28 @@ See the concise host guides for [Codex](codex-replication.md),
|
|
|
23
24
|
[Claude Code](claude-code-replication.md), [OpenCode](opencode-replication.md),
|
|
24
25
|
and [Antigravity](antigravity-replication.md).
|
|
25
26
|
|
|
27
|
+
## GitHub Copilot
|
|
28
|
+
|
|
29
|
+
The Copilot adapter uses the documented custom-agent and agent-skill primitives.
|
|
30
|
+
Install it with:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx triad-plus init --host copilot --control /absolute/path/to/triad-control --global
|
|
34
|
+
npx triad-plus doctor --host copilot --control /absolute/path/to/triad-control
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Project agents are generated under `.github/agents/` and the Triad skill under
|
|
38
|
+
`.github/skills/triad/`; `--global` also installs the corresponding assets under
|
|
39
|
+
`~/.copilot/`. Open the control workspace in the Copilot desktop app. Use
|
|
40
|
+
`/triad <absolute-prd-path>` when the skill is available as a command; otherwise
|
|
41
|
+
select `triad-orchestrator` through `/agent` and provide the same request.
|
|
42
|
+
Verification is explicit by default and no Copilot lifecycle hook is required.
|
|
43
|
+
|
|
44
|
+
The desktop app has been validated with distinct Orchestrator, Developer, and
|
|
45
|
+
Reviewer contexts through a complete unattended Triad run. The adapter uses
|
|
46
|
+
explicit verification and has no lifecycle hook; the CLI and asset paths are
|
|
47
|
+
validated independently as well.
|
|
48
|
+
|
|
26
49
|
## OpenCode
|
|
27
50
|
|
|
28
51
|
Use the interactive OpenCode TUI for complete multi-step Triad runs. OpenCode
|
package/package.json
CHANGED
|
@@ -14,5 +14,12 @@
|
|
|
14
14
|
"lifecycle": { "kind": "SubagentStop", "agent_type": "triad-developer", "requires_async": false }
|
|
15
15
|
},
|
|
16
16
|
"antigravity": { "schema_version": 1, "id": "antigravity", "binary": "agy", "lifecycle": null },
|
|
17
|
-
"hermes": { "schema_version": 1, "id": "hermes", "binary": "hermes", "lifecycle": null }
|
|
17
|
+
"hermes": { "schema_version": 1, "id": "hermes", "binary": "hermes", "lifecycle": null },
|
|
18
|
+
"copilot": {
|
|
19
|
+
"schema_version": 1,
|
|
20
|
+
"id": "copilot",
|
|
21
|
+
"binary": "copilot",
|
|
22
|
+
"verification": { "default_mode": "explicit_dispatch" },
|
|
23
|
+
"lifecycle": null
|
|
24
|
+
}
|
|
18
25
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"required": ["schema_version", "detected_at", "host", "host_runtime", "verifier_runtime", "lifecycle_async", "verification"],
|
|
7
7
|
"properties": {
|
|
8
8
|
"schema_version": { "const": 1 },
|
|
9
|
-
"host": { "enum": ["codex", "opencode", "claude-code", "antigravity"] },
|
|
9
|
+
"host": { "enum": ["codex", "opencode", "claude-code", "antigravity", "hermes", "copilot"] },
|
|
10
10
|
"host_runtime": { "type": "object", "required": ["binary", "version", "available"] },
|
|
11
11
|
"verifier_runtime": { "type": "object", "required": ["binary", "version", "available"] },
|
|
12
12
|
"lifecycle_async": { "type": "object", "required": ["kind", "minimum_version", "available", "configured", "reason"] },
|
|
@@ -11,6 +11,14 @@ artifact/observation instructions, and current verifier evidence. Do not request
|
|
|
11
11
|
Developer reasoning, conversation history, prior Reviewer discussion, or attempt
|
|
12
12
|
history unless the owner explicitly requires it.
|
|
13
13
|
|
|
14
|
+
The approved evaluation packet is the complete evaluation boundary. Do not
|
|
15
|
+
inspect queue state, delivery state, coordinator state, run-state files,
|
|
16
|
+
handoff files, or other control records unless their contents are explicitly
|
|
17
|
+
included in the approved evaluation packet. Evaluate only the supplied goal,
|
|
18
|
+
quality/acceptance target, final candidate or observable artifact, and
|
|
19
|
+
environment-derived verification evidence. Never use an out-of-packet control
|
|
20
|
+
record to justify a verdict.
|
|
21
|
+
|
|
14
22
|
At the beginning of every activation, read `.triad-plus/team.json` when it
|
|
15
23
|
exists. Your first report must identify you as its configured
|
|
16
24
|
`roles.evaluator.displayName` and Evaluator+, then name the completed result
|
|
@@ -32,5 +40,5 @@ store it separately under `artifacts/evaluator-plus/<evaluation-id>.json`:
|
|
|
32
40
|
|
|
33
41
|
Include concise rationale, direct evidence references, and confidence. Do not
|
|
34
42
|
edit source, change the Triad queue/state, commit, push, approve delivery, or
|
|
35
|
-
request automatic repair
|
|
36
|
-
may inform a new owner-requested run.
|
|
43
|
+
request automatic repair, and never reopen the Triad run. A `FAIL` leaves the
|
|
44
|
+
Triad run approved and closed; it may inform a new owner-requested run.
|