@plainconceptsplatform/agent-harness 2.4.1 → 2.5.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/README.md +435 -437
- package/cli/fragments/archive/az.md +97 -95
- package/cli/fragments/archive/gh.md +96 -94
- package/cli/fragments/archive/gl.md +96 -94
- package/cli/fragments/archive/none.md +75 -73
- package/cli/fragments/guardrails/codegraph.md +5 -7
- package/cli/fragments/guardrails/humanizer.md +4 -4
- package/cli/fragments/guardrails/memory.md +4 -4
- package/cli/fragments/guardrails/rtk.md +3 -3
- package/cli/fragments/guardrails/simple-english.md +4 -4
- package/cli/fragments/ops-backlog/az.md +1 -1
- package/cli/fragments/ops-backlog/gh.md +1 -1
- package/cli/fragments/ops-backlog/jira.md +1 -1
- package/cli/fragments/ops-evidence/az.md +44 -41
- package/cli/fragments/ops-evidence/gh.md +54 -53
- package/cli/fragments/ops-evidence/jira.md +42 -38
- package/cli/fragments/ops-review/az.md +1 -1
- package/cli/fragments/ops-review/gh.md +1 -1
- package/cli/fragments/ops-review/gl.md +1 -1
- package/cli/fragments/ops-ship/az.md +81 -80
- package/cli/fragments/ops-ship/gh.md +68 -68
- package/cli/fragments/ops-ship/gl.md +85 -85
- package/cli/presets/agents-content.json +34 -53
- package/cli/steps/copy/agents.js +18 -17
- package/cli/steps/copy/opencode-json.js +5 -1
- package/cli/steps/copy/skills.js +98 -5
- package/cli/steps/optimization/patch-guardrails.js +5 -3
- package/cli/utils/copy.js +8 -3
- package/cli/utils/update-manifest.js +28 -2
- package/harness/.agents/skills/pc-guardrails-generic/SKILL.md +47 -68
- package/harness/.agents/skills/pc-make-architecture/SKILL.md +31 -51
- package/harness/.agents/skills/pc-make-design/SKILL.md +45 -68
- package/harness/.agents/skills/pc-make-engineer/SKILL.md +59 -219
- package/harness/.agents/skills/pc-make-engineer/signal-mapping.md +53 -68
- package/harness/.agents/skills/pc-make-engineer/template.md +42 -80
- package/harness/.agents/skills/pc-make-evidence-scaffold/SKILL.md +18 -18
- package/harness/.agents/skills/pc-make-evidence-scaffold/evidence-contract.md +29 -29
- package/harness/.agents/skills/pc-make-guardrails/SKILL.md +43 -74
- package/harness/.agents/skills/pc-make-guardrails/category-reference.md +10 -5
- package/harness/.agents/skills/pc-make-merge-risk-assess/category-reference.md +26 -7
- package/harness/.agents/skills/pc-make-user-model/SKILL.md +56 -66
- package/harness/.agents/skills/pc-ops-evidence/SKILL.md +133 -127
- package/harness/.agents/skills/pc-plan-apply/SKILL.md +14 -5
- package/harness/.agents/skills/pc-plan-apply/simple-mode.md +21 -21
- package/harness/.agents/skills/pc-plan-archive/SKILL.md +66 -66
- package/harness/.agents/skills/pc-plan-explore/SKILL.md +19 -2
- package/harness/.agents/skills/pc-plan-goal/SKILL.md +7 -5
- package/harness/.agents/skills/pc-plan-goal/output-mode.md +1 -0
- package/harness/.agents/skills/pc-plan-goal/output.md +71 -65
- package/harness/.agents/skills/pc-plan-propose/SKILL.md +1 -1
- package/harness/.agents/skills/pc-plan-quick/SKILL.md +46 -62
- package/harness/.agents/skills/pc-plan-story/SKILL.md +48 -149
- package/harness/.agents/skills/pc-repo-help/SKILL.md +89 -91
- package/harness/.agents/skills/pc-repo-initialize/SKILL.md +112 -130
- package/harness/.agents/skills/pc-repo-onboard/SKILL.md +32 -87
- package/harness/.agents/skills/pc-repo-verify/SKILL.md +2 -0
- package/harness/.agents/skills/pc-userstory-az/SKILL.md +71 -157
- package/harness/.agents/skills/pc-userstory-browser/SKILL.md +50 -122
- package/harness/.agents/skills/pc-userstory-gh/SKILL.md +63 -120
- package/harness/.agents/skills/pc-userstory-jira/SKILL.md +74 -131
- package/harness/.opencode/commands/init.md +5 -5
- package/harness/.opencode/commands/make-architecture.md +5 -5
- package/harness/.opencode/commands/make-design.md +5 -5
- package/harness/.opencode/commands/make-engineer.md +5 -5
- package/harness/.opencode/commands/make-evidence-scaffold.md +5 -5
- package/harness/.opencode/commands/make-guardrails.md +5 -5
- package/harness/.opencode/commands/make-user-model.md +5 -5
- package/harness/.opencode/commands/plan-apply.md +9 -9
- package/harness/.opencode/commands/plan-goal.md +5 -5
- package/harness/.opencode/commands/plan-quick.md +5 -5
- package/harness/.opencode/commands/plan-story.md +9 -9
- package/harness/.opencode/commands/repo-audit.md +5 -5
- package/harness/.opencode/commands/repo-initialize.md +5 -5
- package/harness/.opencode/commands/repo-onboard.md +5 -5
- package/harness/.opencode/commands/repo-verify.md +5 -5
- package/harness/.opencode/plugins/pc-subagent-monitor.js +82 -2
- package/harness/.opencode/plugins/pc-subagent-tiers.js +9 -6
- package/harness/.opencode/plugins/pc-system-reminders.js +312 -3
- package/harness/AGENTS.md +49 -71
- package/harness/opencode.jsonc +1 -1
- package/package.json +1 -1
|
@@ -1,131 +1,74 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pc-userstory
|
|
3
|
-
description: Parse a Jira work item and create an OpenSpec change. Use when the user provides a Jira URL or a bare issue key (e.g. PROJ-123).
|
|
4
|
-
license: MIT
|
|
5
|
-
compatibility: Requires openspec CLI and Atlassian CLI (acli).
|
|
6
|
-
metadata:
|
|
7
|
-
author: copilots
|
|
8
|
-
version: "1.0"
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
4. **Create OpenSpec Change**
|
|
76
|
-
```bash
|
|
77
|
-
openspec new change "{slug-from-summary}"
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Write `proposal.md` with:
|
|
81
|
-
- Title: the Jira issue summary
|
|
82
|
-
- Context: mention this is Jira issue `{KEY}`, link back to the URL
|
|
83
|
-
- Requirements: extracted from description and acceptance criteria
|
|
84
|
-
- Scope: what's in/out based on the issue
|
|
85
|
-
|
|
86
|
-
5. **Hand off to proposal.** Load the `pc-plan-propose` skill (interactive mode) to generate the proposal, specs, and tasks. After it completes, call the `question` tool:
|
|
87
|
-
|
|
88
|
-
```json
|
|
89
|
-
{
|
|
90
|
-
"questions": [
|
|
91
|
-
{
|
|
92
|
-
"header": "Ready to implement",
|
|
93
|
-
"question": "Ready to implement?",
|
|
94
|
-
"options": [
|
|
95
|
-
{ "label": "yes", "description": "Load the pc-plan-apply skill to start implementation." },
|
|
96
|
-
{ "label": "no", "description": "Stop here. You can run /plan-apply later." }
|
|
97
|
-
]
|
|
98
|
-
}
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
Wait for confirmation before loading `pc-plan-apply`.
|
|
104
|
-
|
|
105
|
-
## Jira URL Patterns
|
|
106
|
-
|
|
107
|
-
| URL format | Example |
|
|
108
|
-
|------------|---------|
|
|
109
|
-
| Browse URL | `https://yoursite.atlassian.net/browse/PROJ-123` |
|
|
110
|
-
| Issue URL | `https://yoursite.atlassian.net/jira/core/projects/PROJ/issues/PROJ-123` |
|
|
111
|
-
| Board URL | `https://yoursite.atlassian.net/jira/software/c/projects/PROJ/boards/1?selectedIssue=PROJ-123` |
|
|
112
|
-
| Direct key | `PROJ-123` |
|
|
113
|
-
|
|
114
|
-
## Useful Commands
|
|
115
|
-
|
|
116
|
-
```bash
|
|
117
|
-
# View work item
|
|
118
|
-
acli jira workitem view --key "PROJ-123"
|
|
119
|
-
|
|
120
|
-
# Transition work item
|
|
121
|
-
acli jira workitem transition --key "PROJ-123" --status "In Progress"
|
|
122
|
-
acli jira workitem transition --key "PROJ-123" --status "Done"
|
|
123
|
-
|
|
124
|
-
# Search with JQL
|
|
125
|
-
acli jira workitem search --jql "project = PROJ AND status = 'To Do' ORDER BY priority DESC"
|
|
126
|
-
|
|
127
|
-
# Add a comment
|
|
128
|
-
acli jira workitem comment create --key "PROJ-123" --body "Implementation started"
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Jira is a backlog-only platform: it has no code repos or PRs. PR creation and code review use the repo platform (GitHub or Azure DevOps) configured separately.
|
|
1
|
+
---
|
|
2
|
+
name: pc-userstory
|
|
3
|
+
description: Parse a Jira work item and create an OpenSpec change. Use when the user provides a Jira URL or a bare issue key (e.g. PROJ-123).
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires openspec CLI and Atlassian CLI (acli).
|
|
6
|
+
metadata:
|
|
7
|
+
author: copilots
|
|
8
|
+
version: "1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Turn a Jira issue into an OpenSpec change, then hand the change to `pc-plan-propose`. Jira is backlog-only: it has no repositories and no pull requests, so shipping runs on whichever repo platform the project configured.
|
|
12
|
+
|
|
13
|
+
## Rules
|
|
14
|
+
|
|
15
|
+
- Issue data comes from `acli`, never from a page fetch or a browser (denied by `pc-system-reminders`). An `acli` that cannot authenticate is a blocker to report; install and login are documented at https://developer.atlassian.com/cloud/acli/guides/install-acli/.
|
|
16
|
+
- Never transition the work item without asking, and never transition one that is not in `To Do` or `Backlog`. Moving somebody's ticket is visible to their whole team.
|
|
17
|
+
- In an unattended run, skip the question and the transition rather than resolving it yes.
|
|
18
|
+
- Never load `pc-plan-apply` until the user has said yes.
|
|
19
|
+
|
|
20
|
+
## Contracts
|
|
21
|
+
|
|
22
|
+
The key is `PROJ-123`, taken from `/browse/PROJ-123`, `/jira/core/projects/PROJ/issues/PROJ-123`, `?selectedIssue=PROJ-123`, or given bare.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
acli jira workitem view --key "PROJ-123"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
From the output take the summary (title), the description (context), acceptance criteria wherever they live (spec requirements), labels, status, assignee and priority.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
acli jira workitem transition --key "PROJ-123" --status "In Progress"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Ask before that one:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"questions": [
|
|
39
|
+
{
|
|
40
|
+
"header": "Transition work item",
|
|
41
|
+
"question": "Move {KEY} to In Progress?",
|
|
42
|
+
"options": [
|
|
43
|
+
{ "label": "yes", "description": "Transition the work item to In Progress." },
|
|
44
|
+
{ "label": "no", "description": "Skip the transition." }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then create the change, whose `proposal.md` names the Jira key and links back to it:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
openspec new change "{slug-from-summary}"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Load `pc-plan-propose` (interactive) and, once it returns, ask:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"questions": [
|
|
62
|
+
{
|
|
63
|
+
"header": "Ready to implement",
|
|
64
|
+
"question": "Ready to implement?",
|
|
65
|
+
"options": [
|
|
66
|
+
{ "label": "yes", "description": "Load the pc-plan-apply skill to start implementation." },
|
|
67
|
+
{ "label": "no", "description": "Stop here. You can run /plan-apply later." }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Also available: `acli jira workitem search --jql "..."` and `acli jira workitem comment create --key "PROJ-123" --body "..."`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-initialize` skill
|
|
1
|
+
---
|
|
2
|
+
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-initialize` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update ARCHITECTURE.md by analyzing the codebase structure. Safe to run at any time.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-architecture` skill
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update ARCHITECTURE.md by analyzing the codebase structure. Safe to run at any time.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-architecture` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update DESIGN.md by analyzing the codebase design system. Safe to run at any time.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-design` skill
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update DESIGN.md by analyzing the codebase design system. Safe to run at any time.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-design` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Create a custom engineer agent via persona-driven interactive design
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-engineer` skill
|
|
1
|
+
---
|
|
2
|
+
description: Create a custom engineer agent via persona-driven interactive design
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-engineer` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description:
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-evidence-scaffold` skill
|
|
1
|
+
---
|
|
2
|
+
description: DEPRECATED. Per-project evidence scaffolds are gone; run /ops-evidence instead.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-evidence-scaffold` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Generate or update a pc-guardrails-project skill from ARCHITECTURE.md and relevant project files.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-guardrails` skill
|
|
1
|
+
---
|
|
2
|
+
description: Generate or update a pc-guardrails-project skill from ARCHITECTURE.md and relevant project files.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-guardrails` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Set the model for a tier (plan, build, or fast). Team-wide or user-local override.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-make-user-model` skill
|
|
1
|
+
---
|
|
2
|
+
description: Set the model for a tier (plan, build, or fast). Team-wide or user-local override.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-make-user-model` skill.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Implement tasks from a plan: works with OpenSpec proposals and in-conversation plans.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-apply` skill and execute it in **interactive mode** with `start_from: branch
|
|
6
|
-
|
|
7
|
-
Input:
|
|
8
|
-
|
|
9
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: "Implement tasks from a plan: works with OpenSpec proposals and in-conversation plans."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-apply` skill and execute it in **interactive mode** with `start_from: branch`.
|
|
6
|
+
|
|
7
|
+
Input:
|
|
8
|
+
|
|
9
|
+
$ARGUMENTS
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Autonomous pipeline: explore, propose, apply, archive, then merge/PR/push. For loop-engineering.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-goal` skill
|
|
1
|
+
---
|
|
2
|
+
description: "Autonomous pipeline: explore, propose, apply, archive, then merge/PR/push. For loop-engineering."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-goal` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-quick` skill
|
|
1
|
+
---
|
|
2
|
+
description: "Quick plan: analyze the codebase and create a task checklist using the Todo pane. No files, no OpenSpec."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-quick` skill.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Write a detailed, repo-aware user story from a feature idea or need.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-plan-story` skill
|
|
6
|
-
|
|
7
|
-
Input:
|
|
8
|
-
|
|
9
|
-
$ARGUMENTS
|
|
1
|
+
---
|
|
2
|
+
description: Write a detailed, repo-aware user story from a feature idea or need.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-plan-story` skill.
|
|
6
|
+
|
|
7
|
+
Input:
|
|
8
|
+
|
|
9
|
+
$ARGUMENTS
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Audit every configured source root against the fullstack engineer's guardrails and abilities. Read-only.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-audit` skill
|
|
1
|
+
---
|
|
2
|
+
description: Audit every configured source root against the fullstack engineer's guardrails and abilities. Read-only.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-audit` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-initialize` skill
|
|
1
|
+
---
|
|
2
|
+
description: Initialize the project. Presents a single form with all setup questions, then executes selected steps.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-initialize` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Walk the user through the project and its agentic infrastructure. Explains what exists, how agents work, and how to use the system.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-onboard` skill
|
|
1
|
+
---
|
|
2
|
+
description: Walk the user through the project and its agentic infrastructure. Explains what exists, how agents work, and how to use the system.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-onboard` skill.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Verify current-branch changes, plus immutable dependency installs, builds, and tests for every discovered project.
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
Load the `pc-repo-verify` skill
|
|
1
|
+
---
|
|
2
|
+
description: Verify current-branch changes, plus immutable dependency installs, builds, and tests for every discovered project.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Load the `pc-repo-verify` skill.
|
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
// pc-subagent-monitor: tracks spawned subagents in .opencode/harness-run.json for
|
|
2
|
-
// live TUI display and crash recovery
|
|
3
|
-
//
|
|
2
|
+
// live TUI display and crash recovery, and holds a wave to agents.maxConcurrent.
|
|
3
|
+
//
|
|
4
|
+
// It throws in exactly one case: to deny a spawn over the cap. Every other
|
|
5
|
+
// failure, including its own bugs, is swallowed — a monitor that breaks the run
|
|
6
|
+
// it is watching is worse than no monitor.
|
|
4
7
|
|
|
5
8
|
import fs from "node:fs/promises"
|
|
6
9
|
import path from "node:path"
|
|
7
10
|
|
|
11
|
+
// A spawn that has been allowed but whose session has not appeared yet. A wave
|
|
12
|
+
// is one assistant turn, and opencode calls tool.execute.before for every
|
|
13
|
+
// task() in that turn before the first child session exists, so counting live
|
|
14
|
+
// sessions alone would let an entire wave through whatever the cap says.
|
|
15
|
+
//
|
|
16
|
+
// The slot is released when the session lands, and expires otherwise:
|
|
17
|
+
// tool.execute.after never fires for a tool that threw, so a failed spawn must
|
|
18
|
+
// not hold a slot for the rest of the run.
|
|
19
|
+
const PENDING_TTL_MS = 15_000
|
|
20
|
+
|
|
8
21
|
export const PcSubagentMonitor = async ({ directory, client }) => {
|
|
9
22
|
const root = directory || process.cwd()
|
|
10
23
|
const statePath = path.join(root, ".opencode", "harness-run.json")
|
|
11
24
|
const state = { updatedAt: null, agents: {} }
|
|
25
|
+
const pending = []
|
|
12
26
|
|
|
13
27
|
try {
|
|
14
28
|
const prev = JSON.parse(await fs.readFile(statePath, "utf-8"))
|
|
@@ -94,7 +108,69 @@ export const PcSubagentMonitor = async ({ directory, client }) => {
|
|
|
94
108
|
}
|
|
95
109
|
}
|
|
96
110
|
|
|
111
|
+
let _capCache = null
|
|
112
|
+
async function maxConcurrent() {
|
|
113
|
+
if (_capCache) return _capCache
|
|
114
|
+
let configured = 3
|
|
115
|
+
try {
|
|
116
|
+
const raw = await fs.readFile(path.join(root, ".opencode", "harness.json"), "utf-8")
|
|
117
|
+
const value = JSON.parse(raw)?.agents?.maxConcurrent
|
|
118
|
+
if (Number.isFinite(value)) configured = value
|
|
119
|
+
} catch {
|
|
120
|
+
// no config yet; the CLI's own default is 3
|
|
121
|
+
}
|
|
122
|
+
_capCache = Math.min(5, Math.max(1, Math.trunc(configured)))
|
|
123
|
+
return _capCache
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function runningFor(parentID) {
|
|
127
|
+
return Object.values(state.agents)
|
|
128
|
+
.filter(entry => entry?.status === "running" && !entry.stale && entry.parentID === parentID)
|
|
129
|
+
.length
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function livePending(parentID) {
|
|
133
|
+
const now = Date.now()
|
|
134
|
+
for (let i = pending.length - 1; i >= 0; i--) {
|
|
135
|
+
if (now - pending[i].at > PENDING_TTL_MS) pending.splice(i, 1)
|
|
136
|
+
}
|
|
137
|
+
return pending.filter(entry => entry.parentID === parentID).length
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function releasePending(parentID) {
|
|
141
|
+
const index = pending.findIndex(entry => entry.parentID === parentID)
|
|
142
|
+
if (index !== -1) pending.splice(index, 1)
|
|
143
|
+
}
|
|
144
|
+
|
|
97
145
|
return {
|
|
146
|
+
// The cap was prose in pc-plan-apply ("you enforce the cap"), which asked
|
|
147
|
+
// the lead to count its own parallel calls. Six disjoint groups and a cap
|
|
148
|
+
// of three is exactly the moment a model stops counting.
|
|
149
|
+
"tool.execute.before": async (input) => {
|
|
150
|
+
if (input?.tool !== "task") return
|
|
151
|
+
|
|
152
|
+
let cap
|
|
153
|
+
let live
|
|
154
|
+
try {
|
|
155
|
+
pruneStale()
|
|
156
|
+
cap = await maxConcurrent()
|
|
157
|
+
live = runningFor(input.sessionID) + livePending(input.sessionID)
|
|
158
|
+
if (live < cap) {
|
|
159
|
+
pending.push({ parentID: input.sessionID, at: Date.now() })
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
// Compute inside the try, deny outside it, so this catch can never
|
|
164
|
+
// swallow the one exception the hook is meant to raise.
|
|
165
|
+
console.error(`[harness] concurrency check failed open: ${error?.message}`)
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
throw new Error(
|
|
170
|
+
`[harness] ${live} subagents are already in flight and agents.maxConcurrent is ${cap}.\n` +
|
|
171
|
+
"Collect a running worker before spawning another. A denied spawn is not a failed task: re-issue it in the next wave.",
|
|
172
|
+
)
|
|
173
|
+
},
|
|
98
174
|
event: async ({ event }) => {
|
|
99
175
|
try {
|
|
100
176
|
if (!event?.type?.startsWith("session.")) return
|
|
@@ -103,9 +179,13 @@ export const PcSubagentMonitor = async ({ directory, client }) => {
|
|
|
103
179
|
|
|
104
180
|
if (event.type === "session.created" && info.parentID) {
|
|
105
181
|
pruneStale()
|
|
182
|
+
// The spawn this session came from no longer needs its pending slot;
|
|
183
|
+
// the session itself is now what the cap counts.
|
|
184
|
+
releasePending(info.parentID)
|
|
106
185
|
|
|
107
186
|
state.agents[info.id] = {
|
|
108
187
|
agent: info.agent ?? null,
|
|
188
|
+
parentID: info.parentID,
|
|
109
189
|
model: await modelForAgent(info.agent),
|
|
110
190
|
tasks: parseTasks(info.title),
|
|
111
191
|
title: info.title ?? null,
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
// Agent topology:
|
|
7
7
|
// build.md / plan.md mode: primary the only agents a human selects.
|
|
8
8
|
// Both are fullstack-engineer with a
|
|
9
|
-
// tier model; plan
|
|
9
|
+
// tier model; plan can neither edit
|
|
10
|
+
// nor spawn.
|
|
10
11
|
// fullstack-engineer.md mode: subagent the shared body of build and plan,
|
|
11
12
|
// and the fallback worker.
|
|
12
13
|
// *-engineer.md mode: subagent specialists, spawned by task().
|
|
@@ -22,8 +23,10 @@ import path from "node:path"
|
|
|
22
23
|
const TIERS = ["build", "fast", "plan"]
|
|
23
24
|
|
|
24
25
|
// The two primaries, and the tier each takes its model from. plan denies edit
|
|
25
|
-
//
|
|
26
|
-
//
|
|
26
|
+
// and task: a planning session cannot mutate the tree itself, and it cannot
|
|
27
|
+
// spawn a worker that would do it on its behalf. bash stays allowed because the
|
|
28
|
+
// planning skills shell out to git and openspec to read state, and
|
|
29
|
+
// pc-system-reminders holds it to inspection commands.
|
|
27
30
|
//
|
|
28
31
|
// Their colours are theme keywords rather than derived hexes, and they are
|
|
29
32
|
// fixed: these are the two agents a human picks, so they should look the same
|
|
@@ -39,7 +42,7 @@ const PRIMARIES = {
|
|
|
39
42
|
tier: "plan",
|
|
40
43
|
color: "warning",
|
|
41
44
|
description: "Explore and plan without touching the tree. Read-only: proposes work for build to carry out.",
|
|
42
|
-
permission: { edit: "deny" },
|
|
45
|
+
permission: { edit: "deny", task: "deny" },
|
|
43
46
|
},
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -228,8 +231,8 @@ export const PcSubagentTiers = async ({ directory }) => {
|
|
|
228
231
|
if (model) lines.push(`model: ${model}`)
|
|
229
232
|
lines.push(`color: ${yamlColor(spec.color)}`)
|
|
230
233
|
lines.push('permission:')
|
|
231
|
-
// plan denies edit;
|
|
232
|
-
// still read the tree
|
|
234
|
+
// plan denies edit and task; the rest stays allowed so the planning skills
|
|
235
|
+
// can still read the tree and shell out to git and openspec.
|
|
233
236
|
lines.push(` edit: ${spec.permission?.edit ?? 'allow'}`)
|
|
234
237
|
for (const key of ['bash', 'read', 'glob', 'grep', 'question', 'todowrite', 'task', 'skill']) {
|
|
235
238
|
lines.push(` ${key}: ${spec.permission?.[key] ?? 'allow'}`)
|