geneseed 4.2.0 → 4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +2 -2
- package/SHIPPED.md +2 -2
- package/adapters/opencode/plugins/geneseed-context.js +25 -1
- package/adapters/opencode/plugins/geneseed-guard.js +25 -1
- package/adapters/opencode/plugins/geneseed-learn.js +25 -1
- package/docs/concepts/agents.md +1 -0
- package/docs/concepts/exclusions.md +2 -0
- package/docs/concepts/host-matrix.md +2 -1
- package/docs/reference/opencode-plugins.md +1 -1
- package/harness.config.json +1 -1
- package/js/hosts/gitref.mjs +25 -1
- package/js/hosts/hosts.mjs +14 -4
- package/js/inspect/excludes.mjs +33 -2
- package/package.json +1 -1
- package/registry.json +7 -0
- package/src/AGENT.md.tmpl +1 -0
- package/src/agents/performance.md +72 -0
- package/src/laws/universal.md +7 -5
- package/src/skills/council.md +1 -1
- package/themes/_TEMPLATE.json +1 -0
- package/themes/biker.json +1 -0
- package/themes/commentator.json +1 -0
- package/themes/cyberpunk.json +1 -0
- package/themes/gamer.json +1 -0
- package/themes/imperial.json +1 -0
- package/themes/joker.json +1 -0
- package/themes/marvin.json +1 -0
- package/themes/mean.json +1 -0
- package/themes/military.json +1 -0
- package/themes/neutral.json +1 -0
- package/themes/pirate.json +1 -0
- package/themes/sports.json +1 -0
- package/themes/verstappen.json +1 -0
- package/themes/wizard.json +1 -0
- package/web/dist/assets/{Activity-ClEuDk9q.js → Activity-UiGvYgEl.js} +1 -1
- package/web/dist/assets/{ActivityDetail-CS9IuJlw.js → ActivityDetail-COXCSeXn.js} +1 -1
- package/web/dist/assets/{Dashboard-BiRFjkBS.js → Dashboard-DkdOUpke.js} +2 -2
- package/web/dist/assets/{Docs-CD20mrVv.js → Docs-TtVyc_Dy.js} +1 -1
- package/web/dist/assets/{GreenhouseView-CL3PubNb.js → GreenhouseView-Bh0xq6Up.js} +1 -1
- package/web/dist/assets/{Installs-BFLOVV0r.js → Installs-J3IoSqk6.js} +1 -1
- package/web/dist/assets/{JournalView-BvsSkjSn.js → JournalView-BrD33V35.js} +1 -1
- package/web/dist/assets/{Laws-BVoYOkVW.js → Laws-Cjkenizx.js} +1 -1
- package/web/dist/assets/Library-CKyeB096.js +1 -0
- package/web/dist/assets/{Loops-Cnpep8FX.js → Loops-D15LDhZO.js} +1 -1
- package/web/dist/assets/Markdown-DrXLM6TA.js +65 -0
- package/web/dist/assets/{OperatorHudView-B0AMVmtV.js → OperatorHudView-B5CcWoJ6.js} +1 -1
- package/web/dist/assets/{Personal-CBg_x2kA.js → Personal-BBdGbJn6.js} +1 -1
- package/web/dist/assets/{Tabs-2gX8I69E.js → Tabs-s8T501po.js} +1 -1
- package/web/dist/assets/{drawable-KPn0rKI7.js → drawable-DALqyS4l.js} +1 -1
- package/web/dist/assets/index-BP4foUp0.js +2 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/Library-Bl7xqOlh.js +0 -1
- package/web/dist/assets/Markdown-C6fRd4A4.js +0 -67
- package/web/dist/assets/index-DoD_g2CM.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,30 @@ label. For the capability ↔ spec map, see [SHIPPED.md](SHIPPED.md).
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [4.3.1] — 2026-10-15
|
|
12
|
+
|
|
13
|
+
Patch: a folder excluded from the global harness now stays excluded in its git worktrees.
|
|
14
|
+
|
|
15
|
+
### Upgrade notes
|
|
16
|
+
- Run `geneseed rebuild-all` once after updating so installed hooks and OpenCode plugins carry the fix.
|
|
17
|
+
- On Claude Code and OpenClaude, a worktree still loads the global `CLAUDE.md` until you commit the `claudeMdExcludes` snippet that `geneseed exclude list` prints into the repo's tracked settings file.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Exclusions cover git worktrees.** A session in a linked worktree of an excluded repo (`git worktree add`, or a tool that keeps worktrees elsewhere on disk) got the whole global harness, because the bypass only matched the working directory's path. The hooks and the three OpenCode plugins now follow the worktree's `.git` file back to the main repository, reading files only. `exclude add` and `exclude list` warn that `settings.local.json` never reaches a worktree and print the snippet to commit; Geneseed writes no tracked file. (#280)
|
|
21
|
+
|
|
22
|
+
## [4.3.0] — 2026-10-15
|
|
23
|
+
|
|
24
|
+
Minor: a performance agent, and Deletion Is Deliberate says what counts as recoverable.
|
|
25
|
+
|
|
26
|
+
### Upgrade notes
|
|
27
|
+
- Run `geneseed rebuild-all` once after updating so installed harnesses carry the new agent and the amended law.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **performance agent.** Measures where time is spent before it names a bottleneck, and answers "cannot measure" rather than guess. Read-only with a shell, so it can run benchmarks and profilers; it reports and leaves the fix to the developer. Dispatched on a reported slowdown, a change on a hot path, or as a council seat. Registered as experimental.
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
- **Deletion Is Deliberate** defines recoverable: deleting work committed and pushed to a branch runs freely; deleting uncommitted, unpushed or untracked work asks. History-rewriting git verbs (force-push, `reset --hard`, `clean -f`) stay gated.
|
|
34
|
+
|
|
11
35
|
## [4.2.0] — 2026-10-14
|
|
12
36
|
|
|
13
37
|
Minor: the web console's Overview becomes a control panel over every installed harness, rebuild, prune and uninstall keep owned files you edited, and skill and subagent calls are counted.
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](package.json)
|
|
13
13
|
[](themes/)
|
|
14
14
|
[](src/skills/)
|
|
15
|
-
[](src/agents/)
|
|
16
16
|
[](src/doctrines/)
|
|
17
17
|
[](adapters/opencode/plugins/)
|
|
18
18
|
[](#-supported-harnesses)
|
|
@@ -178,7 +178,7 @@ The harness ships as a small set of layers, and the web console's rail is the sa
|
|
|
178
178
|
| **🧭 Ethos** (`ontology/`) | the mind the rules govern, in four prose sections — **Telos** (the Pact: three ranked laws — protect the user, serve their intent, keep your own honesty), **Evidence** (every claim graded by how it was obtained), **Decisions** (classify and tier by reversibility, show the real forks), **Conduct** (answer what was asked, once). Always in force, never toggleable |
|
|
179
179
|
| **🛡️ Rules** (`laws/`) | 9 universal laws — always in force, never toggleable: sealed-secrets, one-intent-one-act, verify-before-asserting, deletion-is-deliberate, surface-failures, data-not-orders, least-privilege, cure-the-cause, echo-the-intent. Each rule has a permanent id; its number is only its position, and the harness cites rules by name |
|
|
180
180
|
| **📐 Doctrines** (`doctrines/`) | practice packs, chosen per install at build time: **craft** (how code is written), **rigor** (how work is proven), **ops** (how the machine is operated), **process** (how a task is run), **comms** (how answers are presented). A doctrine rule may tighten a Rule, never repeal one, and the user's own `user-rules.md` outranks it. Pick with `geneseed-build --doctrines craft,rigor` (or `none`), a single rule with `--exclude-rules "process 7"`, in the setup wizard, or through the switches on the console's Constitution page; all five pack files ship on disk either way, so a citation into a pack you left out still resolves |
|
|
181
|
-
| **🤖 Agents** (
|
|
181
|
+
| **🤖 Agents** (19) | capability specialists: `reviewer`, `tester`, `architect`, `docs`, `security`, `performance`, `explorer`, `researcher`, `developer` — plus a debate **council** the `council` skill convenes: `advocate`, `skeptic`, `pragmatist`, `steward`, `visionary`, `user-advocate`, `framer`, `empiricist`, `operator`, `historian` |
|
|
182
182
|
| **🛠 Skills** (46) | repeatable workflows: brainstorm · plan · **codebase-design** · **wayfinder** · **develop** · **worktree** · debug · **prototype** · refactor · **ponytail** · **forge-mcp** · **bruno** · geneseed-code-review · **fresh-eyes** · **security-audit** · **dependencies** · **review-response** · commit · **ship** · **release** · **git-history** · document-project · **frontend-design** · **prose** · **ingest** · **research** · **teach** · **quiz** · **learn-mode** · handoff · roast-me · **council** · parallel-agents · **workflow** · **wiki** · **geneseed** · **rule** · **profile** · **skill-forge** · **pipeline** · **loop** · **brick-forge** · **daydream** · **react-view-transitions** · **token-report** · **explain-changes** |
|
|
183
183
|
| **🔌 Plugins** (OpenCode) | `geneseed-context` injects project docs *and your machine wiki* every session (and across compaction); `geneseed-learn` distils memory at session end; `geneseed-guard` enforces the safety Laws and protected wiki folders at the tool boundary; `geneseed-workflow` registers the `workflow` tool that runs saved orchestration scripts; `geneseed-notify` sends a native OS notification when a long run finishes; `geneseed-ponytail` holds a minimal-code mode (`/ponytail lite\|full\|ultra\|off`), opt-in, injecting the laziest-that-works ruleset every turn so it doesn't drift; `geneseed-activity` streams what each session is doing to the web console's Activity view |
|
|
184
184
|
| **🧠 Memory** (`memory/`) | one-fact-per-file durable knowledge, indexed by `MEMORY.md` (git-ignored, personal) |
|
package/SHIPPED.md
CHANGED
|
@@ -20,7 +20,7 @@ historical references, not files distributed with the repo.
|
|
|
20
20
|
> **On version numbers.** [`harness.config.json`](harness.config.json)'s `version` is a
|
|
21
21
|
> human-readable label only. The canonical identity of an installed harness is the
|
|
22
22
|
> **source fingerprint** stamped in `.geneseed-version` (see `geneseed version`), not the
|
|
23
|
-
> string. Current label: **4.
|
|
23
|
+
> string. Current label: **4.3.1**.
|
|
24
24
|
|
|
25
25
|
## Capabilities
|
|
26
26
|
|
|
@@ -29,7 +29,7 @@ Every row below is present in the tree today; "Spec" names the design record.
|
|
|
29
29
|
| Capability | What it is | Spec |
|
|
30
30
|
| --- | --- | --- |
|
|
31
31
|
| **Themed generator** | One neutral `src/` → 14 themed bundles via `geneseed-build` (zero dependencies); structure stays theme-independent | [DESIGN.md](DESIGN.md) |
|
|
32
|
-
| **Laws / Agents / Skills / Memory / Notebook** | 9 laws,
|
|
32
|
+
| **Laws / Agents / Skills / Memory / Notebook** | 9 laws, 19 agents, 46 skills, the memory convention, and the agent's sovereign notebook | `2026-06-11-notebook-sovereign-space` · `2026-06-10-notebook-agent-own-space` |
|
|
33
33
|
| **Three-tier constitution** | The governance surface splits into an always-on **Ontology** (Telos, Evidence, Decisions, Conduct — the Pact absorbed into Telos), the nine always-on **Invariants**, and five toggleable **Doctrine** packs (craft, rigor, ops, process, comms) addressed `<pack> <n>`. Every rule carries a permanent id; its number is its position, computed at render time, and a citation renders as the rule's principle name. Packs are chosen at build time with `--doctrines` or the setup wizard; the whole catalogue ships on disk either way, so a citation into an inactive pack still resolves. Precedence, in order: Ontology + Invariants, then the user's `user-rules.md`, then the active Doctrines, then `PROFILE.md`. `doctor`'s `constitutionProblems` gates rule ids (declared, unique, never a retired one), the per-rule Principle column, every `{{LAW:<id>}}` / `{{DOCTRINE:<id>}}` citation in `src/`, and the rule that an always-on tier may never cite a toggleable one | `2026-08-19-three-tier-constitution-design` |
|
|
34
34
|
| **`doctor`** | One check: unresolved tokens, dead/non-hermetic links, theme-key parity, authoring gates, rendered-bundle drift | `2026-06-07-theme-aware-doctor-diff` |
|
|
35
35
|
| **`diff` + improvements export** | Deployed-vs-source drift report; export an `improvements.md` back-port | `2026-06-12-improvements-export` |
|
|
@@ -85,17 +85,41 @@ const norm = (p) => {
|
|
|
85
85
|
}
|
|
86
86
|
return process.platform === "win32" ? s.toLowerCase() : s
|
|
87
87
|
}
|
|
88
|
+
// A linked git worktree of an excluded repo is excluded too, wherever it sits on disk — twin of
|
|
89
|
+
// js/hosts/gitref.mjs `mainWorktreeOf`: the worktree's `.git` FILE names its gitdir, whose
|
|
90
|
+
// `commondir` names the shared `.git`; that directory's parent is the main worktree. null for
|
|
91
|
+
// a main worktree, a submodule, a bare repo's worktree, or anything malformed.
|
|
92
|
+
async function mainWorktreeOf(dir) {
|
|
93
|
+
try {
|
|
94
|
+
let root = path.resolve(dir)
|
|
95
|
+
for (;;) {
|
|
96
|
+
try { await fs.stat(path.join(root, ".git")); break } catch { /* walk up */ }
|
|
97
|
+
const up = path.dirname(root)
|
|
98
|
+
if (up === root) return null
|
|
99
|
+
root = up
|
|
100
|
+
}
|
|
101
|
+
const dotgit = path.join(root, ".git")
|
|
102
|
+
if (!(await fs.stat(dotgit)).isFile()) return null
|
|
103
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(await fs.readFile(dotgit, "utf8"))
|
|
104
|
+
if (!m) return null
|
|
105
|
+
const gitdir = path.resolve(root, m[1])
|
|
106
|
+
const common = path.resolve(gitdir, (await fs.readFile(path.join(gitdir, "commondir"), "utf8")).trim())
|
|
107
|
+
return path.basename(common) === ".git" ? path.dirname(common) : null
|
|
108
|
+
} catch { return null }
|
|
109
|
+
}
|
|
88
110
|
async function sovereignBypass(cwd) {
|
|
89
111
|
try {
|
|
90
112
|
const cfg = path.dirname(PLUGIN_DIR) // plugins/ sits directly in <cfg>
|
|
91
113
|
const raw = await fs.readFile(path.join(cfg, "excludes.json"), "utf8")
|
|
92
114
|
const entries = (JSON.parse(raw).excludes) || []
|
|
93
115
|
const here = norm(cwd || process.cwd())
|
|
116
|
+
const main = await mainWorktreeOf(cwd || process.cwd())
|
|
117
|
+
const heres = main ? [here, norm(main)] : [here]
|
|
94
118
|
for (const e of entries) {
|
|
95
119
|
const p = typeof e === "string" ? e : e && e.path
|
|
96
120
|
if (typeof p !== "string" || !p.trim()) continue
|
|
97
121
|
const base = norm(p.trim()).replace(/[\\/]+$/, "")
|
|
98
|
-
if (
|
|
122
|
+
if (heres.some((h) => h === base || h.startsWith(base + path.sep))) return true
|
|
99
123
|
}
|
|
100
124
|
} catch { /* degrade to active */ }
|
|
101
125
|
return false
|
|
@@ -72,17 +72,41 @@ const norm = (p) => {
|
|
|
72
72
|
}
|
|
73
73
|
return process.platform === "win32" ? s.toLowerCase() : s
|
|
74
74
|
}
|
|
75
|
+
// A linked git worktree of an excluded repo is excluded too, wherever it sits on disk — twin of
|
|
76
|
+
// js/hosts/gitref.mjs `mainWorktreeOf`: the worktree's `.git` FILE names its gitdir, whose
|
|
77
|
+
// `commondir` names the shared `.git`; that directory's parent is the main worktree. null for
|
|
78
|
+
// a main worktree, a submodule, a bare repo's worktree, or anything malformed.
|
|
79
|
+
async function mainWorktreeOf(dir) {
|
|
80
|
+
try {
|
|
81
|
+
let root = path.resolve(dir)
|
|
82
|
+
for (;;) {
|
|
83
|
+
try { await fs.stat(path.join(root, ".git")); break } catch { /* walk up */ }
|
|
84
|
+
const up = path.dirname(root)
|
|
85
|
+
if (up === root) return null
|
|
86
|
+
root = up
|
|
87
|
+
}
|
|
88
|
+
const dotgit = path.join(root, ".git")
|
|
89
|
+
if (!(await fs.stat(dotgit)).isFile()) return null
|
|
90
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(await fs.readFile(dotgit, "utf8"))
|
|
91
|
+
if (!m) return null
|
|
92
|
+
const gitdir = path.resolve(root, m[1])
|
|
93
|
+
const common = path.resolve(gitdir, (await fs.readFile(path.join(gitdir, "commondir"), "utf8")).trim())
|
|
94
|
+
return path.basename(common) === ".git" ? path.dirname(common) : null
|
|
95
|
+
} catch { return null }
|
|
96
|
+
}
|
|
75
97
|
async function sovereignBypass(cwd) {
|
|
76
98
|
try {
|
|
77
99
|
const cfg = path.dirname(PLUGIN_DIR) // plugins/ sits directly in <cfg>
|
|
78
100
|
const raw = await fs.readFile(path.join(cfg, "excludes.json"), "utf8")
|
|
79
101
|
const entries = (JSON.parse(raw).excludes) || []
|
|
80
102
|
const here = norm(cwd || process.cwd())
|
|
103
|
+
const main = await mainWorktreeOf(cwd || process.cwd())
|
|
104
|
+
const heres = main ? [here, norm(main)] : [here]
|
|
81
105
|
for (const e of entries) {
|
|
82
106
|
const p = typeof e === "string" ? e : e && e.path
|
|
83
107
|
if (typeof p !== "string" || !p.trim()) continue
|
|
84
108
|
const base = norm(p.trim()).replace(/[\\/]+$/, "")
|
|
85
|
-
if (
|
|
109
|
+
if (heres.some((h) => h === base || h.startsWith(base + path.sep))) return true
|
|
86
110
|
}
|
|
87
111
|
} catch { /* degrade to active */ }
|
|
88
112
|
return false
|
|
@@ -67,17 +67,41 @@ const norm = (p) => {
|
|
|
67
67
|
}
|
|
68
68
|
return process.platform === "win32" ? s.toLowerCase() : s
|
|
69
69
|
}
|
|
70
|
+
// A linked git worktree of an excluded repo is excluded too, wherever it sits on disk — twin of
|
|
71
|
+
// js/hosts/gitref.mjs `mainWorktreeOf`: the worktree's `.git` FILE names its gitdir, whose
|
|
72
|
+
// `commondir` names the shared `.git`; that directory's parent is the main worktree. null for
|
|
73
|
+
// a main worktree, a submodule, a bare repo's worktree, or anything malformed.
|
|
74
|
+
async function mainWorktreeOf(dir) {
|
|
75
|
+
try {
|
|
76
|
+
let root = path.resolve(dir)
|
|
77
|
+
for (;;) {
|
|
78
|
+
try { await fs.stat(path.join(root, ".git")); break } catch { /* walk up */ }
|
|
79
|
+
const up = path.dirname(root)
|
|
80
|
+
if (up === root) return null
|
|
81
|
+
root = up
|
|
82
|
+
}
|
|
83
|
+
const dotgit = path.join(root, ".git")
|
|
84
|
+
if (!(await fs.stat(dotgit)).isFile()) return null
|
|
85
|
+
const m = /^gitdir:\s*(.+?)\s*$/m.exec(await fs.readFile(dotgit, "utf8"))
|
|
86
|
+
if (!m) return null
|
|
87
|
+
const gitdir = path.resolve(root, m[1])
|
|
88
|
+
const common = path.resolve(gitdir, (await fs.readFile(path.join(gitdir, "commondir"), "utf8")).trim())
|
|
89
|
+
return path.basename(common) === ".git" ? path.dirname(common) : null
|
|
90
|
+
} catch { return null }
|
|
91
|
+
}
|
|
70
92
|
async function sovereignBypass(cwd) {
|
|
71
93
|
try {
|
|
72
94
|
const cfg = path.dirname(PLUGIN_DIR) // plugins/ sits directly in <cfg>
|
|
73
95
|
const raw = await fs.readFile(path.join(cfg, "excludes.json"), "utf8")
|
|
74
96
|
const entries = (JSON.parse(raw).excludes) || []
|
|
75
97
|
const here = norm(cwd || process.cwd())
|
|
98
|
+
const main = await mainWorktreeOf(cwd || process.cwd())
|
|
99
|
+
const heres = main ? [here, norm(main)] : [here]
|
|
76
100
|
for (const e of entries) {
|
|
77
101
|
const p = typeof e === "string" ? e : e && e.path
|
|
78
102
|
if (typeof p !== "string" || !p.trim()) continue
|
|
79
103
|
const base = norm(p.trim()).replace(/[\\/]+$/, "")
|
|
80
|
-
if (
|
|
104
|
+
if (heres.some((h) => h === base || h.startsWith(base + path.sep))) return true
|
|
81
105
|
}
|
|
82
106
|
} catch { /* degrade to active */ }
|
|
83
107
|
return false
|
package/docs/concepts/agents.md
CHANGED
|
@@ -24,6 +24,7 @@ An **agent** is a specialist the main session can hand a piece of work to. Each
|
|
|
24
24
|
| `tester` | writes, runs and diagnoses tests |
|
|
25
25
|
| `reviewer` | reviews a change for correctness and quality before it merges |
|
|
26
26
|
| `security` | audits changes that touch the security surface |
|
|
27
|
+
| `performance` | measures where time and memory go, names the bottleneck with numbers, proposes the fix |
|
|
27
28
|
| `docs` | writes and updates user-facing documentation after code lands |
|
|
28
29
|
|
|
29
30
|
### The council
|
|
@@ -42,6 +42,8 @@ What "dormant" means per host:
|
|
|
42
42
|
|
|
43
43
|
`geneseed exclude remove` undoes all of it.
|
|
44
44
|
|
|
45
|
+
**Git worktrees.** A linked worktree of an excluded repo (`git worktree add`) is excluded too, wherever it sits on disk: the hooks and plugins follow its `.git` file back to the main repository. The global `CLAUDE.md` is the exception on Claude Code and OpenClaude: `settings.local.json` is gitignored, so a worktree never gets it. Geneseed writes no tracked file in a repo you told it to leave alone, so `exclude add` and `exclude list` print the snippet to commit yourself in the repo's tracked `.claude/settings.json` (`.openclaude/` for OpenClaude): `"claudeMdExcludes": ["<path to the global CLAUDE.md>"]`.
|
|
46
|
+
|
|
45
47
|
**Limits.** Globally installed skills and agents stay *listed* by the host — no host offers a per-repo switch for them. And a global install created *after* you added exclusions starts with an empty list: run `geneseed exclude add` again (`geneseed exclude list` flags installs whose lists differ).
|
|
46
48
|
|
|
47
49
|
The web console has the same controls in the **Excluded folders** card on the Harness page, shown once a global install exists.
|
|
@@ -19,7 +19,7 @@ Every [host](hosts.md) gets the same content. This table is what each one lets G
|
|
|
19
19
|
| Consent before every commit and push | 🔒 permission ask | 🪝 ask | 🪝 warning¹ | 🪝 ask² |
|
|
20
20
|
| Rule-or-memory write needs your call | ⚙️ speed bump³ | 🪝 ask | 🪝 warning¹ | 🪝 ask² |
|
|
21
21
|
| User-only skills hidden from the model | 🔒 `permission.skill` deny | ✅ `disable-model-invocation` | ✅ `/`-command, no skill | ✅ `disable-model-invocation` |
|
|
22
|
-
| Sovereign-repo exclusions | ⚙️ plugins stand down | ✅ `claudeMdExcludes` | ✅ rules shadow stub | ✅ `claudeMdExcludes` |
|
|
22
|
+
| Sovereign-repo exclusions⁵ | ⚙️ plugins stand down | ✅ `claudeMdExcludes` | ✅ rules shadow stub | ✅ `claudeMdExcludes` |
|
|
23
23
|
| MCP server wiring | ✅ `mcp` | ✅ `mcpServers` | ✅ `mcp.json` | ✅ `mcpServers` |
|
|
24
24
|
| Colour themes · LSP · workflow runner · primary agent · `/`-commands | ✅ | ➖ | ➖ | ➖ |
|
|
25
25
|
|
|
@@ -29,6 +29,7 @@ Every [host](hosts.md) gets the same content. This table is what each one lets G
|
|
|
29
29
|
² **OpenClaude** is a Claude Code fork and gets Claude's hooks and verdicts verbatim, in `~/.openclaude/settings.json` (global) or `.openclaude/settings.local.json` (per repo). **Unverified live** for the same reason.
|
|
30
30
|
³ OpenCode's plugin hook can only allow or throw — there is no "ask the user" — so this check stops the first such write once rather than prompting.
|
|
31
31
|
⁴ The checks differ in shape: OpenCode's guard plugin blocks writes *to* private-key and credential files by path; the Claude-shaped hook looks at the *content* being written for credential-shaped strings (cloud keys, tokens, private-key blocks) and asks. A `.env` file is exempt on the hook side — that is where a secret is allowed to live.
|
|
32
|
+
⁵ A linked git worktree of an excluded repo is excluded too: the hooks and plugins follow its `.git` file back to the main repository. `claudeMdExcludes` is the exception — it lives in the gitignored `settings.local.json`, which a worktree never gets — so `geneseed exclude add` and `exclude list` print the snippet to commit yourself. See [Exclusions](exclusions.md).
|
|
32
33
|
|
|
33
34
|
## The one conditional row
|
|
34
35
|
|
|
@@ -35,4 +35,4 @@ If a plugin seems silent on OpenCode 2, check that `~/.config/opencode/plugins/`
|
|
|
35
35
|
|
|
36
36
|
## Excluded folders
|
|
37
37
|
|
|
38
|
-
`geneseed-context`, `geneseed-guard` and `geneseed-learn` go dormant inside a folder listed in the global install's `excludes.json` (managed by `geneseed exclude`). See [Exclusions](../concepts/exclusions.md).
|
|
38
|
+
`geneseed-context`, `geneseed-guard` and `geneseed-learn` go dormant inside a folder listed in the global install's `excludes.json` (managed by `geneseed exclude`), and inside any linked git worktree of such a folder. See [Exclusions](../concepts/exclusions.md).
|
package/harness.config.json
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
"_comment": "version is a human-readable release label only; the canonical identity of an installed harness is the source fingerprint stamped in .geneseed-version (see `harness version`), not this string.",
|
|
3
3
|
"theme": "neutral",
|
|
4
4
|
"product": "Geneseed",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.3.1"
|
|
6
6
|
}
|
package/js/hosts/gitref.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* launched-loop evidence reader were duplicated in `js/hosts/hooks.mjs` (the hook's
|
|
7
7
|
* `loopExempt`) and `js/loop/cli.mjs` (the CLI's commit-message writer) — two copies of the
|
|
8
8
|
* same worktree-following walk that could silently drift apart. Both now import this one.
|
|
9
|
-
* `js/hosts/hooks.mjs` is NOT a safe shared home for it: it pulls in `
|
|
9
|
+
* `js/hosts/hooks.mjs` is NOT a safe shared home for it: it pulls in `child_process`
|
|
10
10
|
* (`spawnSync`, for the destructive-act guard's own concerns) and the hook-dispatch
|
|
11
11
|
* machinery (`jsonDumpsCompact`, the ledger), none of which `js/loop/cli.mjs` — under a hard
|
|
12
12
|
* `child_process` ban like every other closure that feeds `bin/geneseed-cli.mjs` — may ever
|
|
@@ -54,6 +54,30 @@ export function gitDirOf(root) {
|
|
|
54
54
|
return dotgit;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* The MAIN worktree's root when `cwd` stands in a LINKED worktree (`git worktree add`), else
|
|
59
|
+
* null — a main worktree, a submodule (its gitdir has no `commondir`), a bare repository's
|
|
60
|
+
* worktree, no repo, or a malformed link. Never throws.
|
|
61
|
+
*
|
|
62
|
+
* WHY: a linked worktree can live anywhere on disk (Orca puts them under its own workspaces
|
|
63
|
+
* folder), so a path-prefix test against the repo the user EXCLUDED never matches it, and the
|
|
64
|
+
* global harness woke up inside a sovereign repo's worktree. The worktree's `.git` FILE names
|
|
65
|
+
* `<common>/.git/worktrees/<n>`, whose `commondir` (relative to it, usually `../..`) names the
|
|
66
|
+
* shared `.git`; that directory's parent is the main worktree. Read off disk, never by
|
|
67
|
+
* spawning git: `sovereignBypass` runs on every hook call and feeds the CLI's `child_process` ban.
|
|
68
|
+
*/
|
|
69
|
+
export function mainWorktreeOf(cwd) {
|
|
70
|
+
try {
|
|
71
|
+
const root = gitRootOf(cwd);
|
|
72
|
+
if (!root || !statSync(path.join(root, '.git')).isFile()) return null;
|
|
73
|
+
const gitdir = gitDirOf(root);
|
|
74
|
+
const common = path.resolve(gitdir, readFileSync(path.join(gitdir, 'commondir'), 'utf8').trim());
|
|
75
|
+
return path.basename(common) === '.git' ? path.dirname(common) : null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
57
81
|
/**
|
|
58
82
|
* The branch checked out in `cwd`, read from .git/HEAD without spawning git. null on
|
|
59
83
|
* anything unexpected (detached HEAD, no repo, a malformed worktree link, unreadable) — the
|
package/js/hosts/hosts.mjs
CHANGED
|
@@ -19,6 +19,7 @@ import path from 'node:path';
|
|
|
19
19
|
import os from 'node:os';
|
|
20
20
|
import { printErr, withDiscardableStderr, isDir, isFile, readText } from '../lib/fs.mjs';
|
|
21
21
|
import { toPlatformPath, normcase } from '../lib/paths.mjs';
|
|
22
|
+
import { mainWorktreeOf } from './gitref.mjs';
|
|
22
23
|
|
|
23
24
|
/** `_build_global.GLOBAL_MANIFEST` — the file whose presence means "a global install". */
|
|
24
25
|
export const GLOBAL_MANIFEST = '.geneseed-manifest.json';
|
|
@@ -39,6 +40,11 @@ export const GATE_LEDGER = path.join('notebook', 'gates.jsonl');
|
|
|
39
40
|
* under the transitive `child_process` ban that `hooks.mjs`'s `learn` verb breaks). A
|
|
40
41
|
* second copy in `js/inspect/` was the alternative, and a copy is what let the `~user`
|
|
41
42
|
* refusal diverge between the two CLIs once already (see `hooks.mjs`'s header).
|
|
43
|
+
*
|
|
44
|
+
* A LINKED GIT WORKTREE OF AN EXCLUDED REPO IS EXCLUDED TOO, wherever it sits on disk: the
|
|
45
|
+
* cwd matches, or the main worktree `mainWorktreeOf` reads off the `.git` file does. An
|
|
46
|
+
* exclusion names a repository the user keeps sovereign, not a folder; a worktree elsewhere
|
|
47
|
+
* (Orca's workspaces) otherwise woke the full global harness inside it.
|
|
42
48
|
*/
|
|
43
49
|
export function sovereignBypass(root) {
|
|
44
50
|
if (!root) return false;
|
|
@@ -49,12 +55,16 @@ export function sovereignBypass(root) {
|
|
|
49
55
|
} catch {
|
|
50
56
|
return false;
|
|
51
57
|
}
|
|
52
|
-
let
|
|
58
|
+
let heres;
|
|
53
59
|
try {
|
|
54
|
-
|
|
60
|
+
heres = [normcase(resolvePath(process.cwd()))];
|
|
55
61
|
} catch {
|
|
56
62
|
return false;
|
|
57
63
|
}
|
|
64
|
+
try {
|
|
65
|
+
const main = mainWorktreeOf(process.cwd());
|
|
66
|
+
if (main) heres.push(normcase(resolvePath(main)));
|
|
67
|
+
} catch { /* an unresolvable main worktree degrades to the cwd test alone */ }
|
|
58
68
|
for (const entry of entries) {
|
|
59
69
|
const raw = (entry && typeof entry === 'object' ? entry.path : entry) || '';
|
|
60
70
|
if (typeof raw !== 'string' || !raw.trim()) continue;
|
|
@@ -67,7 +77,7 @@ export function sovereignBypass(root) {
|
|
|
67
77
|
// and this caller catches: the reference prints nothing here, so replaying the
|
|
68
78
|
// message would be a stderr divergence on every hook call for one bad entry.
|
|
69
79
|
//
|
|
70
|
-
// `resolvePath`, the same resolution as `
|
|
80
|
+
// `resolvePath`, the same resolution as `heres` above: symlinks and junctions are followed on
|
|
71
81
|
// BOTH sides, so an entry spelled through a link matches the real directory the session
|
|
72
82
|
// stands in (and the OpenCode plugins' `norm` applies the identical rule).
|
|
73
83
|
base = withDiscardableStderr(
|
|
@@ -79,7 +89,7 @@ export function sovereignBypass(root) {
|
|
|
79
89
|
// Skipping errs toward the gate staying ACTIVE, which is the safe direction.
|
|
80
90
|
continue;
|
|
81
91
|
}
|
|
82
|
-
if (
|
|
92
|
+
if (heres.some((h) => h === base || h.startsWith(base + path.sep))) return true;
|
|
83
93
|
}
|
|
84
94
|
return false;
|
|
85
95
|
}
|
package/js/inspect/excludes.mjs
CHANGED
|
@@ -32,6 +32,28 @@ import { normcase, toPlatformPath } from '../lib/paths.mjs';
|
|
|
32
32
|
const localSettings = (repo, host) =>
|
|
33
33
|
path.join(repo, HOSTS.find((h) => h.host === host).projectMarker, 'settings.local.json');
|
|
34
34
|
|
|
35
|
+
/** The `claudeMdExcludes` entry naming a Claude-family global install's CLAUDE.md, as wired. */
|
|
36
|
+
const claudeMdEntry = (cfg) => resolvePath(path.join(cfg, 'CLAUDE.md')).split(path.sep).join('/');
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The worktree caveat, or null when it does not apply: a Claude-family install and an
|
|
40
|
+
* excluded folder that is a git repository (a `.git` there — no repo, no worktrees).
|
|
41
|
+
*
|
|
42
|
+
* WHY A WARNING AND NOT A WRITE: `settings.local.json` is gitignored, so a `git worktree add`
|
|
43
|
+
* of the excluded repo never carries it and the global CLAUDE.md loads there again (the hooks
|
|
44
|
+
* do stand down — `sovereignBypass` follows the worktree to its main repo). The one durable
|
|
45
|
+
* fix is the repo's TRACKED `settings.json`, and the user decided (2026-10) Geneseed never
|
|
46
|
+
* writes a tracked file in a repo it was told to leave alone — so it prints the snippet.
|
|
47
|
+
*/
|
|
48
|
+
function worktreeNote(host, cfg, repo) {
|
|
49
|
+
if (host !== 'claude' && host !== 'openclaude') return null;
|
|
50
|
+
if (!existsSync(path.join(repo, '.git'))) return null;
|
|
51
|
+
const marker = HOSTS.find((h) => h.host === host).projectMarker;
|
|
52
|
+
return `${host}: git worktrees of this repo do not get the gitignored `
|
|
53
|
+
+ `${marker}/settings.local.json and still load the global CLAUDE.md — to stop that, commit `
|
|
54
|
+
+ `to the repo's ${marker}/settings.json: "claudeMdExcludes": ["${claudeMdEntry(cfg)}"]`;
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
/** `_global_installs` — every host whose GLOBAL config dir carries a Geneseed manifest. */
|
|
36
58
|
function globalInstalls() {
|
|
37
59
|
const out = [];
|
|
@@ -112,8 +134,7 @@ export function excludeAdd(target) {
|
|
|
112
134
|
const priorWired = (isDict(prior) ? get(prior, 'wired') : null) || {};
|
|
113
135
|
const wired = {};
|
|
114
136
|
if ((host === 'claude' || host === 'openclaude') && isDir(repo)) {
|
|
115
|
-
const
|
|
116
|
-
const added = wireClaudeExcludes(localSettings(repo, host), [entry]);
|
|
137
|
+
const added = wireClaudeExcludes(localSettings(repo, host), [claudeMdEntry(cfg)]);
|
|
117
138
|
if (added.length) {
|
|
118
139
|
wired.claude_md_excludes = added;
|
|
119
140
|
} else if (get(priorWired, 'claude_md_excludes')) {
|
|
@@ -126,6 +147,8 @@ export function excludeAdd(target) {
|
|
|
126
147
|
// own project-bypasses-global wiring, or a bailed write) — do NOT fabricate ownership,
|
|
127
148
|
// or a later excludeRemove would strip wiring we never created.
|
|
128
149
|
if (!added.length) messages.push(`${host}: claudeMdExcludes already present (kept)`);
|
|
150
|
+
const note = worktreeNote(host, cfg, repo);
|
|
151
|
+
if (note) messages.push(note);
|
|
129
152
|
}
|
|
130
153
|
if (host === 'bob' && isDir(repo)) {
|
|
131
154
|
const stub = path.join(repo, '.bob', 'rules', 'geneseed.md');
|
|
@@ -249,6 +272,14 @@ export function cmdExclude(args) {
|
|
|
249
272
|
const flag = missing.length
|
|
250
273
|
? ` (MISSING from: ${missing.join(', ')} — re-run \`geneseed exclude add\`)` : '';
|
|
251
274
|
printOut(` ${rec.path} [${rec.hosts.slice().sort().join(', ')}]${flag}\n`);
|
|
275
|
+
for (const { host, cfg } of snap.installs) {
|
|
276
|
+
if (!rec.hosts.includes(host)) continue;
|
|
277
|
+
let note = null;
|
|
278
|
+
try {
|
|
279
|
+
note = worktreeNote(host, cfg, toPlatformPath(rec.path));
|
|
280
|
+
} catch { /* a broken resolver: the listing itself must still print */ }
|
|
281
|
+
if (note) printOut(` note: ${note}\n`);
|
|
282
|
+
}
|
|
252
283
|
}
|
|
253
284
|
return 0;
|
|
254
285
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"//": "Every field here is argued and gated in tests/unit/package_manifest.test.mjs. `files`, `bin` and `engines` each have a test that fails when reality drifts from this file; `version` mirrors harness.config.json and is gated too. Read that docblock before editing this one.",
|
|
3
3
|
"name": "geneseed",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.3.1",
|
|
5
5
|
"description": "A portable, theme-able harness you implant once and use everywhere to grow a disciplined AI coding agent.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ai",
|
package/registry.json
CHANGED
|
@@ -85,6 +85,13 @@
|
|
|
85
85
|
"added": "2026-06-01",
|
|
86
86
|
"last_verified": ""
|
|
87
87
|
},
|
|
88
|
+
"agents/performance": {
|
|
89
|
+
"status": "experimental",
|
|
90
|
+
"version": "1.0.0",
|
|
91
|
+
"owner": "Guillaume Lemer",
|
|
92
|
+
"added": "2026-10-14",
|
|
93
|
+
"last_verified": ""
|
|
94
|
+
},
|
|
88
95
|
"agents/security": {
|
|
89
96
|
"status": "approved",
|
|
90
97
|
"version": "1.0.0",
|
package/src/AGENT.md.tmpl
CHANGED
|
@@ -163,6 +163,7 @@ Active packs: {{DOCTRINES_LIST}}{{EXCLUDED_RULES_LINE}}
|
|
|
163
163
|
| [architect]({{DIR_AGENTS}}/architect.md) | a task needs a design/plan before any code is written |
|
|
164
164
|
| [docs]({{DIR_AGENTS}}/docs.md) | code is done and user-facing docs/READMEs must follow |
|
|
165
165
|
| [security]({{DIR_AGENTS}}/security.md) | a change touches auth, input handling, secrets, or dependencies — or anything outward-facing is about to ship |
|
|
166
|
+
| [performance]({{DIR_AGENTS}}/performance.md) | something is reported slow or heavy, or a diff touches a hot path — measured, never guessed |
|
|
166
167
|
| [explorer]({{DIR_AGENTS}}/explorer.md) | you must sweep many files for an answer but only want the conclusion |
|
|
167
168
|
| [researcher]({{DIR_AGENTS}}/researcher.md) | a question needs the open web — fetched, cross-checked, and returned as sourced findings, not pages |
|
|
168
169
|
| [advocate]({{DIR_AGENTS}}/advocate.md) | a council debate needs the strongest case **for** the motion argued in isolation |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# {{AGENT}}: performance
|
|
2
|
+
|
|
3
|
+
> {{DESC_PERFORMANCE}}
|
|
4
|
+
|
|
5
|
+
## When to dispatch
|
|
6
|
+
- The user reports something slow, heavy or timing out — a latency, throughput,
|
|
7
|
+
memory or startup complaint, or a regression against an earlier version.
|
|
8
|
+
- A diff touches a hot path: a loop over unbounded data, a query inside a loop,
|
|
9
|
+
synchronous I/O on a request or render path, startup, or code run on every call.
|
|
10
|
+
- A council debate turns on a performance trade-off and needs one seat that
|
|
11
|
+
speaks only from measurements.
|
|
12
|
+
|
|
13
|
+
## When NOT to dispatch
|
|
14
|
+
- No one has measured anything and nothing is slow — speculative tuning is the
|
|
15
|
+
waste this {{AGENT}} exists to refuse.
|
|
16
|
+
- The code is wrong, not slow — that is the debug {{SKILL}}.
|
|
17
|
+
|
|
18
|
+
## Inputs
|
|
19
|
+
- The symptom or the diff, the workload it runs under (data size, call rate,
|
|
20
|
+
environment), and the command that reproduces it, if known.
|
|
21
|
+
|
|
22
|
+
## Allowed tools
|
|
23
|
+
- **Read-only.** May run the code, benchmarks and profilers to measure. Reports;
|
|
24
|
+
does not patch — the fix goes to the [developer](developer.md).
|
|
25
|
+
<!-- bash: allow -->
|
|
26
|
+
|
|
27
|
+
## Procedure
|
|
28
|
+
0. If `{{DIR_MEMORY}}/agents/<your-name>.md` exists, read it first — your durable lessons from prior dispatches ({{DOCTRINE:persist-insight}}).
|
|
29
|
+
1. Pin the question: which metric (wall time, p95 latency, peak memory, allocations,
|
|
30
|
+
query count), under which workload, and what number would count as fixed.
|
|
31
|
+
2. Take a baseline with the project's own tooling where it has some, run several
|
|
32
|
+
times, and report the spread — one run is an anecdote ({{LAW:verify-before-asserting}}).
|
|
33
|
+
3. Profile before naming a cause: a CPU or memory profile, a query log, a flame
|
|
34
|
+
graph, or timing at each layer boundary to find which layer owns the time.
|
|
35
|
+
4. Name the bottleneck with its share of the total. A cost under a few percent is
|
|
36
|
+
not the bottleneck, however ugly the code.
|
|
37
|
+
5. For a diff, check the usual shapes against the real data size: work inside a
|
|
38
|
+
loop that belongs outside it, N+1 queries, quadratic scans, unbounded caches or
|
|
39
|
+
buffers, blocking I/O on a hot path, repeated parsing or allocation.
|
|
40
|
+
6. Propose the smallest fix that removes the measured cost, with the expected gain
|
|
41
|
+
and how to re-measure it; when a fix was tried, report before/after on the same
|
|
42
|
+
workload.
|
|
43
|
+
|
|
44
|
+
## Output contract
|
|
45
|
+
- Findings as `metric — location — measured cost — proposed fix — expected gain`,
|
|
46
|
+
largest cost first, each with the command that produced its number. End with:
|
|
47
|
+
within budget / fix-recommended / cannot-measure.
|
|
48
|
+
- If the code could not be run, the workload is unknown, or the measurements are
|
|
49
|
+
noisier than the effect, report `cannot-measure` and what is missing — a
|
|
50
|
+
bottleneck named without a measurement is the one finding this {{AGENT}} must
|
|
51
|
+
never return.
|
|
52
|
+
|
|
53
|
+
## Pipeline role
|
|
54
|
+
|
|
55
|
+
*(Ignored outside pipelines — this section only tells pipeline orchestration who
|
|
56
|
+
to recruit; it changes nothing about how this {{AGENT}} behaves when dispatched
|
|
57
|
+
independently.)*
|
|
58
|
+
|
|
59
|
+
- **Seat(s):** specialist add-on — recruited above the floor when the task is a
|
|
60
|
+
performance complaint or the diff touches a hot path.
|
|
61
|
+
- **Receives:** the crew's diff, the workload, and the reproduce command.
|
|
62
|
+
- **Delivers:** measured findings and a verdict, same shape as its own output
|
|
63
|
+
contract above.
|
|
64
|
+
|
|
65
|
+
## Self-improvement
|
|
66
|
+
|
|
67
|
+
If this spec misled you — an input you needed but were not given, a boundary
|
|
68
|
+
that proved wrong, a step you could not execute — end your report with one line:
|
|
69
|
+
`spec-feedback: <what failed — the one-line fix>`. Omit it when there is no
|
|
70
|
+
friction. The caller weighs the feedback, folds a real flaw back into this file
|
|
71
|
+
with the user's assent, and records it to {{MEMORY}} only if it clears
|
|
72
|
+
{{DOCTRINE:persist-insight}}'s bar — most reports carry no feedback at all.
|
package/src/laws/universal.md
CHANGED
|
@@ -75,16 +75,18 @@ requires explicit confirmation bound to that specific act, or a durable
|
|
|
75
75
|
authorization the user gave that already covers it; a yes to one act is never
|
|
76
76
|
stretched to the next. Classify every action as Create, Read, Update, or Delete
|
|
77
77
|
before acting, and tier it by reversibility: a read-only or easily-reversible
|
|
78
|
-
action — an edit or a delete
|
|
79
|
-
irreversible, financial, externally-visible, or
|
|
80
|
-
that confirmation.
|
|
78
|
+
action — an edit, or a delete of what is committed and pushed to a branch —
|
|
79
|
+
runs freely; an irreversible, financial, externally-visible, or
|
|
80
|
+
privilege-changing one needs that confirmation. Uncommitted, unpushed, or
|
|
81
|
+
untracked work is not recoverable.
|
|
81
82
|
<!-- LEAN:else -->
|
|
82
83
|
Deleting what version control cannot restore, and any irreversible or
|
|
83
84
|
outward-facing act — publishing, force-push, sending data to a third party —
|
|
84
85
|
needs explicit confirmation bound to that act, or a durable authorization that
|
|
85
86
|
covers it; one yes never stretches to the next act. A read-only or
|
|
86
|
-
easily-reversed action runs freely; an
|
|
87
|
-
externally-visible, or privilege-changing one asks.
|
|
87
|
+
easily-reversed action — deleting work pushed to a branch — runs freely; an
|
|
88
|
+
irreversible, financial, externally-visible, or privilege-changing one asks.
|
|
89
|
+
Deleting unpushed work asks.
|
|
88
90
|
<!-- LEAN:end -->
|
|
89
91
|
|
|
90
92
|
### {{LAW:surface-failures}} Surface Failures
|
package/src/skills/council.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- [visionary](../{{DIR_AGENTS}}/visionary.md) — the bold, transformative version; [framer](../{{DIR_AGENTS}}/framer.md) — whether it's even the right problem; [empiricist](../{{DIR_AGENTS}}/empiricist.md) — every claim held to evidence; [historian](../{{DIR_AGENTS}}/historian.md) — what was tried before.
|
|
13
13
|
- [user-advocate](../{{DIR_AGENTS}}/user-advocate.md) — whoever consumes the outcome.
|
|
14
14
|
|
|
15
|
-
Hand each chosen seat the motion and a one-line charter scoped to this topic; skip the seats with nothing to say here, and add an ad-hoc seat (e.g. the [security](../{{DIR_AGENTS}}/security.md) surface) only when the topic plainly demands a voice the roster doesn't cover.
|
|
15
|
+
Hand each chosen seat the motion and a one-line charter scoped to this topic; skip the seats with nothing to say here, and add an ad-hoc seat (e.g. the [security](../{{DIR_AGENTS}}/security.md) surface, or [performance](../{{DIR_AGENTS}}/performance.md) for a speed or memory trade-off) only when the topic plainly demands a voice the roster doesn't cover.
|
|
16
16
|
3. Round one — positions: convene the seats by dispatching each stance {{AGENT}} as its own subagent in one batch where the tool supports it (the [parallel-agents {{SKILL}}](parallel-agents.md)), so each argues in an isolated context with no groupthink; where no subagent capability exists, voice each seat in turn as a persona. Each returns its steelmanned brief ({{ONTOLOGY}}: {{ONT_CONDUCT}}) — no hedging, no strawmen.
|
|
17
17
|
4. Round two — clash: put the briefs in front of each other and have the seats rebut only on the points that actually conflict, surfacing the cruxes, the load-bearing assumptions, and where the evidence is thin. Hold to a fixed number of rounds so the debate converges instead of looping; the skeptic already pairs every objection with what would resolve it (the [roast-me {{SKILL}}](roast-me.md) discipline).
|
|
18
18
|
5. The chair synthesises in neutral voice: state the verdict and its reasoning, record the strongest surviving dissent verbatim so it is not lost, list what would change the verdict, and name the single next action. Surface it for the user to decide — the council advises, it does not commit: write no code and push nothing on its own ({{LAW:deletion-is-deliberate}}, {{DOCTRINE:consent-before-push}}).
|
package/themes/_TEMPLATE.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "<one-line description: produces a design/plan before code>",
|
|
21
21
|
"DESC_DOCS": "<one-line description: writes user-facing docs after code lands>",
|
|
22
22
|
"DESC_SECURITY": "<one-line description: audits changes touching the security surface>",
|
|
23
|
+
"DESC_PERFORMANCE": "<one-line description: measures where the time and memory go, names the bottleneck with numbers, never guesses>",
|
|
23
24
|
"DESC_EXPLORER": "<one-line description: reads/searches widely, returns only distilled findings>",
|
|
24
25
|
"DESC_RESEARCHER": "<one-line description: searches and fetches the open web, cross-checks every claim, returns sourced findings>",
|
|
25
26
|
"DESC_ADVOCATE": "<council seat: argues the strongest case FOR the proposal>",
|
package/themes/biker.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "Plans the route before a single line is committed.",
|
|
21
21
|
"DESC_DOCS": "Keeps the roadbook and the notes once the work is done.",
|
|
22
22
|
"DESC_SECURITY": "Goes over anything touching the security surface, bolt by bolt.",
|
|
23
|
+
"DESC_PERFORMANCE": "Puts it on the dyno — measures where the power goes before anyone touches the engine.",
|
|
23
24
|
"DESC_EXPLORER": "Sends the scout ahead — sweeps wide on a throwaway recon run, brings back only the read.",
|
|
24
25
|
"DESC_RESEARCHER": "Rides out past the county line — reads the road signs everyone else skipped, checks each one twice, brings back only what held up.",
|
|
25
26
|
"DESC_ADVOCATE": "Argues for the run — the ground to be gained, the opening, the cost of staying parked.",
|
package/themes/commentator.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "Walks the circuit and plots the strategy before a single line is committed.",
|
|
21
21
|
"DESC_DOCS": "Files the race report and updates the notes once the chequered flag falls.",
|
|
22
22
|
"DESC_SECURITY": "Runs the safety inspection on anything touching the security surface.",
|
|
23
|
+
"DESC_PERFORMANCE": "Brings out the stopwatch — times every lap and names the slow sector with the split.",
|
|
23
24
|
"DESC_EXPLORER": "Sends the track scout — sweeps wide from a throwaway recon lap, returns only the read.",
|
|
24
25
|
"DESC_RESEARCHER": "Sends the pit reporter down the paddock — checks every rumour against two sources before it goes on air.",
|
|
25
26
|
"DESC_ADVOCATE": "Calls for the overtake — the place to be gained, the gap, the cost of staying put.",
|
package/themes/cyberpunk.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "Maps the run before a single line hits the deck.",
|
|
21
21
|
"DESC_DOCS": "Writes the user-facing data once the code goes live.",
|
|
22
22
|
"DESC_SECURITY": "Breaks and checks ICE — audits anything on the security surface.",
|
|
23
|
+
"DESC_PERFORMANCE": "Traces the lag in the net — profiles the run and names the choke point with numbers.",
|
|
23
24
|
"DESC_EXPLORER": "Scouts the net — sweeps wide in a throwaway shell, returns only the intel.",
|
|
24
25
|
"DESC_RESEARCHER": "Jacks into the open net — pulls the intel, cross-checks it against two nodes, returns only what verified.",
|
|
25
26
|
"DESC_ADVOCATE": "Pushes the build — the upside, the opening, the cost of sitting on it.",
|
package/themes/gamer.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "Plans the route before the run starts.",
|
|
21
21
|
"DESC_DOCS": "Writes the wiki and patch notes once the feature ships.",
|
|
22
22
|
"DESC_SECURITY": "Runs the anti-cheat pass on anything touching the security surface.",
|
|
23
|
+
"DESC_PERFORMANCE": "Checks the frame times — profiles the run and names the bottleneck before any tuning.",
|
|
23
24
|
"DESC_EXPLORER": "Scouts the map — sweeps wide in a throwaway scout run, returns only the intel.",
|
|
24
25
|
"DESC_RESEARCHER": "Reads the wiki and the patch notes — cross-checks every claim against two sources before it goes in the build guide.",
|
|
25
26
|
"DESC_ADVOCATE": "Calls for the play — the upside, the opening, the cost of passing it up.",
|
package/themes/imperial.json
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"DESC_ARCHITECT": "Draws the battle-plan before a single line is committed to war.",
|
|
21
21
|
"DESC_DOCS": "Inscribes the records for those who come after, once the work is done.",
|
|
22
22
|
"DESC_SECURITY": "Wards the gates, auditing every change that touches the security surface.",
|
|
23
|
+
"DESC_PERFORMANCE": "Weighs the machine-spirit’s labour — measures where time is spent and names the burden, never guessing.",
|
|
23
24
|
"DESC_EXPLORER": "Ranges far and wide through a throwaway context, returning only the distilled truth.",
|
|
24
25
|
"DESC_RESEARCHER": "Ranges beyond the archives into the wider realm, holding every claim to two witnesses before it is entered as truth.",
|
|
25
26
|
"DESC_ADVOCATE": "Champions the proposal — presses its strongest case, the prize to be won, the cost of staying the hand.",
|