@plainconceptsplatform/agent-harness 3.4.1 → 3.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.
Files changed (50) hide show
  1. package/cli/commands/update.js +121 -121
  2. package/cli/fragments/archive/az.md +97 -97
  3. package/cli/fragments/archive/gh.md +96 -96
  4. package/cli/fragments/archive/gl.md +96 -96
  5. package/cli/fragments/archive/none.md +75 -75
  6. package/cli/fragments/guardrails/codegraph.md +5 -5
  7. package/cli/fragments/guardrails/humanizer.md +4 -4
  8. package/cli/fragments/guardrails/memory.md +4 -4
  9. package/cli/fragments/guardrails/rtk.md +3 -3
  10. package/cli/fragments/guardrails/simple-english.md +4 -4
  11. package/cli/fragments/ops-ship/az.md +81 -81
  12. package/cli/presets/agents-content.json +34 -34
  13. package/cli/presets/browser.json +10 -10
  14. package/cli/steps/browser/index.js +48 -48
  15. package/cli/steps/copy/commands.js +79 -79
  16. package/cli/steps/copy/index.js +88 -88
  17. package/cli/steps/metadata/index.js +115 -115
  18. package/cli/steps/models/write.js +38 -38
  19. package/harness/.opencode/commands/init.md +5 -5
  20. package/harness/.opencode/commands/make-architecture.md +5 -5
  21. package/harness/.opencode/commands/make-design.md +5 -5
  22. package/harness/.opencode/commands/make-engineer.md +5 -5
  23. package/harness/.opencode/commands/make-guardrails.md +5 -5
  24. package/harness/.opencode/commands/make-user-model.md +5 -5
  25. package/harness/.opencode/commands/plan-apply.md +9 -9
  26. package/harness/.opencode/commands/plan-goal.md +5 -5
  27. package/harness/.opencode/commands/repo-initialize.md +5 -5
  28. package/harness/.opencode/commands/repo-onboard.md +5 -5
  29. package/harness/.opencode/commands/repo-verify.md +5 -5
  30. package/harness/.opencode/scripts/check-diff.mjs +9 -1
  31. package/harness/AGENTS.md +49 -49
  32. package/package.json +1 -1
  33. package/skills/README.md +18 -18
  34. package/skills/browser-automation/SKILL.md +72 -72
  35. package/skills/pc-make-architecture/SKILL.md +32 -32
  36. package/skills/pc-make-design/SKILL.md +45 -45
  37. package/skills/pc-make-engineer/signal-mapping.md +53 -53
  38. package/skills/pc-make-guardrails/SKILL.md +44 -44
  39. package/skills/pc-make-user-model/SKILL.md +56 -56
  40. package/skills/pc-plan-apply/SKILL.md +2 -0
  41. package/skills/pc-plan-archive/SKILL.md +66 -66
  42. package/skills/pc-plan-goal/branching.md +39 -39
  43. package/skills/pc-plan-goal/output.md +71 -71
  44. package/skills/pc-plan-story/SKILL.md +93 -93
  45. package/skills/pc-repo-initialize/SKILL.md +119 -119
  46. package/skills/pc-repo-onboard/SKILL.md +32 -32
  47. package/skills/pc-userstory-az/SKILL.md +71 -71
  48. package/skills/pc-userstory-browser/SKILL.md +64 -64
  49. package/skills/pc-userstory-gh/SKILL.md +63 -63
  50. package/skills/pc-userstory-jira/SKILL.md +74 -74
@@ -1,115 +1,115 @@
1
- import { execa } from 'execa'
2
- import fse from 'fs-extra'
3
- import path from 'path'
4
- import { createRequire } from 'node:module'
5
- import { header, success, warn } from '../../utils/exec.js'
6
- import { configPath } from '../../utils/paths.js'
7
-
8
- const require = createRequire(import.meta.url)
9
- const { version: harnessVersion } = require('../../../package.json')
10
-
11
- function clampConcurrency(n) {
12
- const v = Number(n)
13
- if (!Number.isFinite(v)) return 3
14
- return Math.min(5, Math.max(1, Math.round(v)))
15
- }
16
-
17
- async function detectOpencodeVersion() {
18
- try {
19
- const result = await execa('opencode', ['--version'], { reject: false })
20
- if (result.exitCode !== 0) return null
21
- // `opencode --version` prints "opencode v2.0.22" on some builds and "2.0.22" on others;
22
- // record the bare version so the field does not churn between machines.
23
- const output = (result.stdout || result.stderr || '').trim()
24
- return output.match(/\d+\.\d+\.\d+[\w.-]*/)?.[0] ?? (output || null)
25
- } catch {
26
- return null
27
- }
28
- }
29
-
30
- export async function writeHarnessConfig(data) {
31
- header('Step 10, Writing onboarding metadata')
32
-
33
- const opencodeVersion = await detectOpencodeVersion()
34
- const cwd = data.cwd ?? process.cwd()
35
- const target = configPath(cwd)
36
-
37
- // Read the existing file so load-bearing config (models, maxConcurrent)
38
- // is preserved across metadata refreshes when not explicitly provided.
39
- const existing = await fse.readJson(target).catch(() => null)
40
-
41
- const selectedModels = Object.fromEntries(
42
- Object.entries({
43
- plan: data.planModel,
44
- build: data.buildModel,
45
- fast: data.fastModel,
46
- }).filter(([, value]) => value)
47
- )
48
- const models = Object.keys(selectedModels).length > 0
49
- ? { ...existing?.models, ...selectedModels }
50
- : existing?.models ?? null
51
- const maxConcurrent = clampConcurrency(data.maxConcurrentAgents ?? existing?.agents?.maxConcurrent ?? 3)
52
-
53
- const optionalTools = data.optionalTools ?? existing?.tools ?? {}
54
- const { caveman: _caveman, ...existingTools } = existing?.tools ?? {}
55
- const tools = {
56
- rtk: !!(optionalTools.rtk?.optedIn ?? optionalTools.rtk),
57
- quota: !!(optionalTools.quota?.optedIn ?? optionalTools.quota),
58
- simpleEnglish: !!(
59
- optionalTools.simpleEnglish?.optedIn ?? optionalTools.simpleEnglish ??
60
- optionalTools.caveman?.optedIn ?? optionalTools.caveman
61
- ),
62
- codegraph: !!(optionalTools.codegraph?.optedIn ?? optionalTools.codegraph),
63
- memory: !!(optionalTools.memory?.optedIn ?? optionalTools.memory),
64
- // humanizer was missing here, so a selection never survived a metadata
65
- // write and patchGuardrails always saw it as off, leaving its marker
66
- // section empty however the project was actually set up.
67
- humanizer: !!(optionalTools.humanizer?.optedIn ?? optionalTools.humanizer),
68
- }
69
-
70
- const payload = {
71
- ...existing,
72
- // Never lower a schema version a repository already records.
73
- version: Math.max(2, Number(existing?.version) || 0),
74
- generatedAt: new Date().toISOString(),
75
- harnessVersion,
76
- opencodeVersion,
77
-
78
- platform: {
79
- ...existing?.platform,
80
- backlog: data.backlogPlatform ?? 'none',
81
- repo: data.repoPlatform ?? 'none',
82
- },
83
-
84
- ...(models ? { models } : {}),
85
-
86
- agents: {
87
- ...existing?.agents,
88
- maxConcurrent,
89
- },
90
-
91
- source: {
92
- ...existing?.source,
93
- mode: data.sourceMode ?? 'current',
94
- roots: data.sourceRoots ?? [],
95
- },
96
-
97
- tools: { ...existingTools, ...tools },
98
-
99
- preexisting: {
100
- ...existing?.preexisting,
101
- design: !!data.hasDesign,
102
- architecture: !!data.hasArchitecture,
103
- openspec: !!data.hasOpenspec,
104
- },
105
- }
106
-
107
- try {
108
- await fse.ensureDir(path.dirname(target))
109
- await fse.writeJson(target, payload, { spaces: 2 })
110
- success('Wrote .opencode/harness.json')
111
- if (!opencodeVersion) warn('Could not detect opencode version, saved as null')
112
- } catch (err) {
113
- warn(`Could not write onboarding metadata: ${err.message}`)
114
- }
115
- }
1
+ import { execa } from 'execa'
2
+ import fse from 'fs-extra'
3
+ import path from 'path'
4
+ import { createRequire } from 'node:module'
5
+ import { header, success, warn } from '../../utils/exec.js'
6
+ import { configPath } from '../../utils/paths.js'
7
+
8
+ const require = createRequire(import.meta.url)
9
+ const { version: harnessVersion } = require('../../../package.json')
10
+
11
+ function clampConcurrency(n) {
12
+ const v = Number(n)
13
+ if (!Number.isFinite(v)) return 3
14
+ return Math.min(5, Math.max(1, Math.round(v)))
15
+ }
16
+
17
+ async function detectOpencodeVersion() {
18
+ try {
19
+ const result = await execa('opencode', ['--version'], { reject: false })
20
+ if (result.exitCode !== 0) return null
21
+ // `opencode --version` prints "opencode v2.0.22" on some builds and "2.0.22" on others;
22
+ // record the bare version so the field does not churn between machines.
23
+ const output = (result.stdout || result.stderr || '').trim()
24
+ return output.match(/\d+\.\d+\.\d+[\w.-]*/)?.[0] ?? (output || null)
25
+ } catch {
26
+ return null
27
+ }
28
+ }
29
+
30
+ export async function writeHarnessConfig(data) {
31
+ header('Step 10, Writing onboarding metadata')
32
+
33
+ const opencodeVersion = await detectOpencodeVersion()
34
+ const cwd = data.cwd ?? process.cwd()
35
+ const target = configPath(cwd)
36
+
37
+ // Read the existing file so load-bearing config (models, maxConcurrent)
38
+ // is preserved across metadata refreshes when not explicitly provided.
39
+ const existing = await fse.readJson(target).catch(() => null)
40
+
41
+ const selectedModels = Object.fromEntries(
42
+ Object.entries({
43
+ plan: data.planModel,
44
+ build: data.buildModel,
45
+ fast: data.fastModel,
46
+ }).filter(([, value]) => value)
47
+ )
48
+ const models = Object.keys(selectedModels).length > 0
49
+ ? { ...existing?.models, ...selectedModels }
50
+ : existing?.models ?? null
51
+ const maxConcurrent = clampConcurrency(data.maxConcurrentAgents ?? existing?.agents?.maxConcurrent ?? 3)
52
+
53
+ const optionalTools = data.optionalTools ?? existing?.tools ?? {}
54
+ const { caveman: _caveman, ...existingTools } = existing?.tools ?? {}
55
+ const tools = {
56
+ rtk: !!(optionalTools.rtk?.optedIn ?? optionalTools.rtk),
57
+ quota: !!(optionalTools.quota?.optedIn ?? optionalTools.quota),
58
+ simpleEnglish: !!(
59
+ optionalTools.simpleEnglish?.optedIn ?? optionalTools.simpleEnglish ??
60
+ optionalTools.caveman?.optedIn ?? optionalTools.caveman
61
+ ),
62
+ codegraph: !!(optionalTools.codegraph?.optedIn ?? optionalTools.codegraph),
63
+ memory: !!(optionalTools.memory?.optedIn ?? optionalTools.memory),
64
+ // humanizer was missing here, so a selection never survived a metadata
65
+ // write and patchGuardrails always saw it as off, leaving its marker
66
+ // section empty however the project was actually set up.
67
+ humanizer: !!(optionalTools.humanizer?.optedIn ?? optionalTools.humanizer),
68
+ }
69
+
70
+ const payload = {
71
+ ...existing,
72
+ // Never lower a schema version a repository already records.
73
+ version: Math.max(2, Number(existing?.version) || 0),
74
+ generatedAt: new Date().toISOString(),
75
+ harnessVersion,
76
+ opencodeVersion,
77
+
78
+ platform: {
79
+ ...existing?.platform,
80
+ backlog: data.backlogPlatform ?? 'none',
81
+ repo: data.repoPlatform ?? 'none',
82
+ },
83
+
84
+ ...(models ? { models } : {}),
85
+
86
+ agents: {
87
+ ...existing?.agents,
88
+ maxConcurrent,
89
+ },
90
+
91
+ source: {
92
+ ...existing?.source,
93
+ mode: data.sourceMode ?? 'current',
94
+ roots: data.sourceRoots ?? [],
95
+ },
96
+
97
+ tools: { ...existingTools, ...tools },
98
+
99
+ preexisting: {
100
+ ...existing?.preexisting,
101
+ design: !!data.hasDesign,
102
+ architecture: !!data.hasArchitecture,
103
+ openspec: !!data.hasOpenspec,
104
+ },
105
+ }
106
+
107
+ try {
108
+ await fse.ensureDir(path.dirname(target))
109
+ await fse.writeJson(target, payload, { spaces: 2 })
110
+ success('Wrote .opencode/harness.json')
111
+ if (!opencodeVersion) warn('Could not detect opencode version, saved as null')
112
+ } catch (err) {
113
+ warn(`Could not write onboarding metadata: ${err.message}`)
114
+ }
115
+ }
@@ -1,38 +1,38 @@
1
- import fse from 'fs-extra'
2
- import { applyEdits, modify, parse } from 'jsonc-parser'
3
- import path from 'path'
4
- import { success, warn } from '../../utils/exec.js'
5
-
6
- /**
7
- * Writes the selected build model as the default model in opencode.jsonc.
8
- * Per-tier models (plan/build/fast) are recorded in harness.json (models)
9
- * by the metadata step, then consumed by the agent-variant generator and /plan-apply.
10
- *
11
- * opencode tolerates JSONC (comments, trailing commas) in its config, so this
12
- * must not use readJson/writeJson: a strict parse crashes on valid configs and
13
- * a strict rewrite deletes user comments. jsonc-parser edits only the `model`
14
- * key and preserves the rest of the file byte-for-byte.
15
- */
16
- export async function writeModelsToConfigs({ buildModel, keepExisting = false, cwd = process.cwd() }) {
17
- const opencodeJsonPath = path.join(cwd, 'opencode.jsonc')
18
- if (!await fse.pathExists(opencodeJsonPath)) return
19
-
20
- const text = await fse.readFile(opencodeJsonPath, 'utf-8')
21
- const errors = []
22
- parse(text, errors)
23
- if (errors.length > 0) {
24
- warn('opencode.jsonc could not be parsed: leaving it untouched. Set "model" manually.')
25
- return
26
- }
27
-
28
- // A model the repository already chose is its decision, not the wizard's: `update` used to
29
- // reset a deliberately pinned default to the build tier in every consumer it ran in.
30
- if (keepExisting && typeof parse(text)?.model === 'string') return
31
-
32
- // `undefined` removes the key; a string value sets it.
33
- const edits = modify(text, ['model'], buildModel || undefined, {
34
- formattingOptions: { insertSpaces: true, tabSize: 2 },
35
- })
36
- await fse.writeFile(opencodeJsonPath, applyEdits(text, edits), 'utf-8')
37
- if (buildModel) success(`default model -> ${buildModel} (written to opencode.jsonc)`)
38
- }
1
+ import fse from 'fs-extra'
2
+ import { applyEdits, modify, parse } from 'jsonc-parser'
3
+ import path from 'path'
4
+ import { success, warn } from '../../utils/exec.js'
5
+
6
+ /**
7
+ * Writes the selected build model as the default model in opencode.jsonc.
8
+ * Per-tier models (plan/build/fast) are recorded in harness.json (models)
9
+ * by the metadata step, then consumed by the agent-variant generator and /plan-apply.
10
+ *
11
+ * opencode tolerates JSONC (comments, trailing commas) in its config, so this
12
+ * must not use readJson/writeJson: a strict parse crashes on valid configs and
13
+ * a strict rewrite deletes user comments. jsonc-parser edits only the `model`
14
+ * key and preserves the rest of the file byte-for-byte.
15
+ */
16
+ export async function writeModelsToConfigs({ buildModel, keepExisting = false, cwd = process.cwd() }) {
17
+ const opencodeJsonPath = path.join(cwd, 'opencode.jsonc')
18
+ if (!await fse.pathExists(opencodeJsonPath)) return
19
+
20
+ const text = await fse.readFile(opencodeJsonPath, 'utf-8')
21
+ const errors = []
22
+ parse(text, errors)
23
+ if (errors.length > 0) {
24
+ warn('opencode.jsonc could not be parsed: leaving it untouched. Set "model" manually.')
25
+ return
26
+ }
27
+
28
+ // A model the repository already chose is its decision, not the wizard's: `update` used to
29
+ // reset a deliberately pinned default to the build tier in every consumer it ran in.
30
+ if (keepExisting && typeof parse(text)?.model === 'string') return
31
+
32
+ // `undefined` removes the key; a string value sets it.
33
+ const edits = modify(text, ['model'], buildModel || undefined, {
34
+ formattingOptions: { insertSpaces: true, tabSize: 2 },
35
+ })
36
+ await fse.writeFile(opencodeJsonPath, applyEdits(text, edits), 'utf-8')
37
+ if (buildModel) success(`default model -> ${buildModel} (written to opencode.jsonc)`)
38
+ }
@@ -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: 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: 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.
@@ -182,6 +182,13 @@ export function collect(root, base) {
182
182
  return files
183
183
  }
184
184
 
185
+ // A subagent checks only the files it owns while others edit the same tree: the budgets then fit its share.
186
+ export function scope(files, paths) {
187
+ if (!paths?.length) return files
188
+ const norm = paths.map(p => p.replace(/\\/g, '/').replace(/^\.\//, ''))
189
+ return files.filter(f => norm.some(p => f.path === p || f.path.startsWith(p.endsWith('/') ? p : `${p}/`)))
190
+ }
191
+
185
192
  // Paths of the files a complexity gate tracks, from its baseline keyed `path::method`.
186
193
  export function trackedFiles(root, baseline) {
187
194
  try {
@@ -236,7 +243,8 @@ function main(argv) {
236
243
  return 2
237
244
  }
238
245
  const limits = readLimits(root)
239
- const result = evaluate(collect(root, base.base), limits, trackedFiles(root, limits.complexityBaseline))
246
+ const paths = option('paths')?.split(',').map(p => p.trim()).filter(Boolean)
247
+ const result = evaluate(scope(collect(root, base.base), paths), limits, trackedFiles(root, limits.complexityBaseline))
240
248
  console.log(argv.includes('--json') ? JSON.stringify({ base, ...result }, null, 2) : report(result, base))
241
249
  return result.violations.length === 0 ? 0 : 1
242
250
  }
package/harness/AGENTS.md CHANGED
@@ -1,49 +1,49 @@
1
- # AGENTS.md
2
-
3
- <!-- PC-NOT-INITIALIZED -->
4
-
5
- # Agent operating guide
6
-
7
- The operating contract for AI agents in this repository. Agent-agnostic: OpenCode, Claude Code, Codex, Gemini and others.
8
-
9
- ## Session context
10
-
11
- Before a non-trivial change, read `AGENTS.md` for workflow rules, `ARCHITECTURE.md` for boundaries and component interactions, `DESIGN.md` for UI and design-system work, and the active OpenSpec change or the specification covering the area you are changing.
12
-
13
- Command aliases: OpenSpec skills may reference `/opsx-propose`, `/opsx-apply`, `/opsx-archive`, or `/opsx-explore`. Always substitute them with the `pc-plan-propose`, `pc-plan-apply`, `pc-plan-archive`, and `pc-plan-explore` skills respectively. User-facing command names are `/plan-propose`, `/plan-apply`, `/plan-archive`, and `/plan-explore`. Never mention the `opsx-` names to the user.
14
-
15
- ## Workflow ownership
16
-
17
- <!-- PC-PLATFORM-WORKFLOW-START -->
18
- <!-- PC-PLATFORM-WORKFLOW-END -->
19
-
20
- ## Planning and execution
21
-
22
- - Never combine an unrelated refactor with the work you were asked to do. It arrives under a message that does not mention it, and the reviewer approves both.
23
- - Never introduce a new convention where the repository already has one, and never guess when requirements, architecture or a security constraint are unclear. Ask.
24
-
25
- ## Engineer selection
26
-
27
- Inspect `.opencode/agents/*.md` before spawning. Prefer the most specialized custom engineer. `build` and `plan` are the only primaries and are never spawned; `fullstack-engineer` is the body they share and the fallback worker, so prefer a specialist over it. If no specialist matches, tell the user to create one with `/make-engineer`. Spawn only engineers present in that directory.
28
-
29
- The `pc-plan-apply` skill is authoritative for subagent waves, dependency ordering, retries, and concurrency. A spawn past `agents.maxConcurrent` is denied (`pc-subagent-monitor`); a denied spawn is not a failed task, so re-issue it in the next wave.
30
-
31
- ## Tool and repository safety
32
-
33
- - Never expose or commit secrets, credentials, tokens, or production data.
34
- - Never overwrite a generated file, or uncommitted changes you did not make. The tree may be shared with a person and another agent.
35
- - Never bypass a check, weaken a test, or silence a lint rule to reach a green result. A green run that was arranged is worse than a red one, because nobody looks again.
36
- - Commit, push, open a pull request, change dependencies, or touch deployment configuration only with the user's explicit approval and the repository's stated process.
37
-
38
- ## Verification and completion
39
-
40
- - Never call a bug fixed without a test that would have caught it, where one is practical.
41
- - Never leave a specification, `ARCHITECTURE.md` or `DESIGN.md` asserting something this change made false.
42
- - Never end on a blocker without naming it and the decision it needs. An unattended run that stops quietly looks like one that finished.
43
-
44
- ## Skills
45
-
46
- Skills live in `.agents/skills/`. Always installed: `@pc-guardrails-generic`, `@pc-guardrails-project`, and `@browser-automation`. An entry under `## Abilities` is not a passive reference: call the `skill` tool once per `@skill-name`, guardrails first. Editing, shell and spawning stay blocked until you have (`pc-system-reminders`), and a loaded skill can require further loads.
47
-
48
- <!-- PC-PLATFORM-SKILLS-GUIDE-START -->
49
- <!-- PC-PLATFORM-SKILLS-GUIDE-END -->
1
+ # AGENTS.md
2
+
3
+ <!-- PC-NOT-INITIALIZED -->
4
+
5
+ # Agent operating guide
6
+
7
+ The operating contract for AI agents in this repository. Agent-agnostic: OpenCode, Claude Code, Codex, Gemini and others.
8
+
9
+ ## Session context
10
+
11
+ Before a non-trivial change, read `AGENTS.md` for workflow rules, `ARCHITECTURE.md` for boundaries and component interactions, `DESIGN.md` for UI and design-system work, and the active OpenSpec change or the specification covering the area you are changing.
12
+
13
+ Command aliases: OpenSpec skills may reference `/opsx-propose`, `/opsx-apply`, `/opsx-archive`, or `/opsx-explore`. Always substitute them with the `pc-plan-propose`, `pc-plan-apply`, `pc-plan-archive`, and `pc-plan-explore` skills respectively. User-facing command names are `/plan-propose`, `/plan-apply`, `/plan-archive`, and `/plan-explore`. Never mention the `opsx-` names to the user.
14
+
15
+ ## Workflow ownership
16
+
17
+ <!-- PC-PLATFORM-WORKFLOW-START -->
18
+ <!-- PC-PLATFORM-WORKFLOW-END -->
19
+
20
+ ## Planning and execution
21
+
22
+ - Never combine an unrelated refactor with the work you were asked to do. It arrives under a message that does not mention it, and the reviewer approves both.
23
+ - Never introduce a new convention where the repository already has one, and never guess when requirements, architecture or a security constraint are unclear. Ask.
24
+
25
+ ## Engineer selection
26
+
27
+ Inspect `.opencode/agents/*.md` before spawning. Prefer the most specialized custom engineer. `build` and `plan` are the only primaries and are never spawned; `fullstack-engineer` is the body they share and the fallback worker, so prefer a specialist over it. If no specialist matches, tell the user to create one with `/make-engineer`. Spawn only engineers present in that directory.
28
+
29
+ The `pc-plan-apply` skill is authoritative for subagent waves, dependency ordering, retries, and concurrency. A spawn past `agents.maxConcurrent` is denied (`pc-subagent-monitor`); a denied spawn is not a failed task, so re-issue it in the next wave.
30
+
31
+ ## Tool and repository safety
32
+
33
+ - Never expose or commit secrets, credentials, tokens, or production data.
34
+ - Never overwrite a generated file, or uncommitted changes you did not make. The tree may be shared with a person and another agent.
35
+ - Never bypass a check, weaken a test, or silence a lint rule to reach a green result. A green run that was arranged is worse than a red one, because nobody looks again.
36
+ - Commit, push, open a pull request, change dependencies, or touch deployment configuration only with the user's explicit approval and the repository's stated process.
37
+
38
+ ## Verification and completion
39
+
40
+ - Never call a bug fixed without a test that would have caught it, where one is practical.
41
+ - Never leave a specification, `ARCHITECTURE.md` or `DESIGN.md` asserting something this change made false.
42
+ - Never end on a blocker without naming it and the decision it needs. An unattended run that stops quietly looks like one that finished.
43
+
44
+ ## Skills
45
+
46
+ Skills live in `.agents/skills/`. Always installed: `@pc-guardrails-generic`, `@pc-guardrails-project`, and `@browser-automation`. An entry under `## Abilities` is not a passive reference: call the `skill` tool once per `@skill-name`, guardrails first. Editing, shell and spawning stay blocked until you have (`pc-system-reminders`), and a loaded skill can require further loads.
47
+
48
+ <!-- PC-PLATFORM-SKILLS-GUIDE-START -->
49
+ <!-- PC-PLATFORM-SKILLS-GUIDE-END -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plainconceptsplatform/agent-harness",
3
- "version": "3.4.1",
3
+ "version": "3.5.0",
4
4
  "description": "Installs the Plain Concepts Platform Harness into any codebase, and keeps it up to date. Wires OpenCode, OpenSpec, codegraph, and agentmemory into a multi-agent workflow that runs on native parallel subagents.",
5
5
  "keywords": [
6
6
  "opencode",
package/skills/README.md CHANGED
@@ -1,18 +1,18 @@
1
- # skills/
2
-
3
- Two kinds of skills live here, both discoverable by `npx skills`:
4
-
5
- | Kind | Directories | Purpose |
6
- | --- | --- | --- |
7
- | Installable `pc-*` + `browser-automation` | `pc-*`, `browser-automation` | What the CLI copies into a target project under `.agents/skills/` during onboarding. Plain Concepts' own skills. |
8
- | CLI-self | `agent-harness-cli` | Skills for agents working on THIS CLI repo (driving `npx @plainconceptsplatform/agent-harness`). Never copied into target projects. |
9
-
10
- Discoverability: any `SKILL.md` in a subdirectory here is auto-discovered by OpenCode, Claude Code, and `npx skills` (which scans `./skills/` as a recognized project-skill location).
11
-
12
- ## Using one
13
-
14
- Point your agent at the directory, or copy a skill into wherever your tool discovers skills:
15
-
16
- ```bash
17
- cp -r skills/agent-harness-cli ~/.claude/skills/
18
- ```
1
+ # skills/
2
+
3
+ Two kinds of skills live here, both discoverable by `npx skills`:
4
+
5
+ | Kind | Directories | Purpose |
6
+ | --- | --- | --- |
7
+ | Installable `pc-*` + `browser-automation` | `pc-*`, `browser-automation` | What the CLI copies into a target project under `.agents/skills/` during onboarding. Plain Concepts' own skills. |
8
+ | CLI-self | `agent-harness-cli` | Skills for agents working on THIS CLI repo (driving `npx @plainconceptsplatform/agent-harness`). Never copied into target projects. |
9
+
10
+ Discoverability: any `SKILL.md` in a subdirectory here is auto-discovered by OpenCode, Claude Code, and `npx skills` (which scans `./skills/` as a recognized project-skill location).
11
+
12
+ ## Using one
13
+
14
+ Point your agent at the directory, or copy a skill into wherever your tool discovers skills:
15
+
16
+ ```bash
17
+ cp -r skills/agent-harness-cli ~/.claude/skills/
18
+ ```