@event4u/agent-config 8.12.0 → 8.13.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +28 -0
- package/README.md +1 -1
- package/dist/agent-src/commands/pr/create.md +26 -0
- package/dist/agent-src/commands/team/adversarial.md +96 -0
- package/dist/agent-src/commands/team/delegate.md +109 -0
- package/dist/agent-src/commands/team/review.md +84 -0
- package/dist/agent-src/commands/team/status.md +92 -0
- package/dist/agent-src/commands/team.md +147 -0
- package/dist/agent-src/rules/improve-before-implement.md +2 -0
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +148 -10
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +3 -3
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +11 -6
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +10 -5
- package/dist/install/install.mjs +38 -0
- package/dist/mcp/registry-manifest.json +2 -2
- package/dist/server/schemas/settings.js +7 -0
- package/dist/server/schemas/settings.js.map +1 -1
- package/docs/CLAIMS.md +1 -1
- package/docs/architecture.md +1 -1
- package/docs/catalog.md +10 -4
- package/docs/command-flows.md +6 -1
- package/docs/contracts/ai-team-config.md +191 -0
- package/docs/contracts/command-clusters.md +1 -0
- package/docs/featured-skills.md +1 -1
- package/docs/getting-started-by-role.md +3 -1
- package/docs/getting-started.md +31 -1
- package/docs/maintainers/branch-protection.md +18 -0
- package/docs/proof.md +1 -1
- package/package.json +1 -1
- package/src/config/agent-settings.template.yml +40 -0
- package/src/scripts/_cli/cmd_doctor.ts +196 -1
- package/src/scripts/_lib/claude_plugin.ts +39 -4
- package/src/scripts/ai_team/config.ts +162 -0
- package/src/scripts/install.ts +39 -0
- package/src/scripts/rule_backlinks.ts +0 -0
- package/src/server/schemas/settings.ts +17 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
keep-beta-until: 2026-10-10
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI-Team Config (`ai_team` block)
|
|
7
|
+
|
|
8
|
+
**Purpose.** Lock the schema, validation, and quota rules for the `/team`
|
|
9
|
+
cross-model review family — one strong external model (via the codex CLI,
|
|
10
|
+
subscription-authed) reviewing inside the repo. Team mode is the **depth**
|
|
11
|
+
complement to the council's **breadth**; this contract is the boundary that
|
|
12
|
+
prevents drift across the settings template, the loader, the `/team`
|
|
13
|
+
wrappers, and the quota counter.
|
|
14
|
+
|
|
15
|
+
**Audience.** Authors of `src/scripts/ai_team/config.ts`, the `/team`
|
|
16
|
+
command family, the doctor `team` section, and the setup wizard. Also
|
|
17
|
+
reviewers checking that new team features keep the schema intact.
|
|
18
|
+
|
|
19
|
+
**Status.** Internal-locked. Changes require a contract version bump and a
|
|
20
|
+
revision entry in the consuming roadmap.
|
|
21
|
+
|
|
22
|
+
## File location
|
|
23
|
+
|
|
24
|
+
Unlike the council (ALWAYS user-global `.ai-council.yml` — see
|
|
25
|
+
[ai-council-config.md](ai-council-config.md)), the `ai_team` block lives in
|
|
26
|
+
the **project settings cascade**:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
<project>/.agent-settings.yml → ai_team: { … }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
read via `load_agent_settings` (`src/scripts/_lib/agent_settings.ts`) and
|
|
33
|
+
validated by `src/scripts/ai_team/config.ts:load_ai_team_config`. Team mode
|
|
34
|
+
is a per-project posture (default-off), not a per-developer credential
|
|
35
|
+
store — the codex CLI carries the subscription auth itself, so there is
|
|
36
|
+
nothing secret to centralize. The shipped defaults live in
|
|
37
|
+
`src/config/agent-settings.template.yml` and are mirrored by the wizard
|
|
38
|
+
schema (`src/server/schemas/settings.ts`, enforced by the schema↔template
|
|
39
|
+
parity test).
|
|
40
|
+
|
|
41
|
+
## Schema
|
|
42
|
+
|
|
43
|
+
```yaml
|
|
44
|
+
ai_team:
|
|
45
|
+
enabled: <bool> # master switch, default false
|
|
46
|
+
model: <string> # default 'auto'
|
|
47
|
+
allow_delegate: <bool> # second opt-in for the write path, default false
|
|
48
|
+
max_calls_per_day: <int >= 0> # default 50; counts into the shared openai bucket
|
|
49
|
+
suppress_setup_hint: <bool> # default false; cosmetic wizard-hint suppression
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
| Key | Type | Default | Semantics |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `enabled` | bool | `false` | Master switch. `false` = `/team` commands are never suggested and every invocation refuses with an enable pointer — byte-identical to pre-feature behavior. `true` = the family is live; per-command gates below still apply. |
|
|
55
|
+
| `model` | string | `'auto'` | Model handed to the codex CLI. `'auto'` = pass **no** `--model` flag; the codex CLI's own default applies. Any other value passes through **verbatim** as `--model <value>`. |
|
|
56
|
+
| `allow_delegate` | bool | `false` | Second opt-in for the **only** wrapper that delegates write access (`/team:delegate`). Refuses with an enable pointer until BOTH `enabled` and `allow_delegate` are `true`. |
|
|
57
|
+
| `max_calls_per_day` | int ≥ 0 | `50` | Per-day ceiling on team calls, read against the **shared** `cli_call_budget` openai bucket (see § Quota). `0` blocks all team calls. |
|
|
58
|
+
| `suppress_setup_hint` | bool | `false` | Suppress the one-line wizard/init recommendation to install the codex plugin on Claude-Code hosts. Cosmetic only. |
|
|
59
|
+
|
|
60
|
+
### Why `model: 'auto'` instead of a pinned ID
|
|
61
|
+
|
|
62
|
+
A hardcoded model ID rots silently (the council's own CLI default is a
|
|
63
|
+
deliberate, documented *pin* — `DEFAULT_OPENAI_CLI_MODEL` in
|
|
64
|
+
`src/scripts/ai_council/clients.ts`, see
|
|
65
|
+
[ai-council-config.md](ai-council-config.md)). Team mode inverts that:
|
|
66
|
+
under a subscription the *strongest* available model is the rational
|
|
67
|
+
default, and only the codex CLI knows what that currently is. `'auto'`
|
|
68
|
+
therefore delegates the choice to the CLI; a set value is a user pin and
|
|
69
|
+
passes through verbatim — the loader never rewrites or "corrects" it.
|
|
70
|
+
|
|
71
|
+
**Future keys:** `review_gate` (managed, loop-bound governance of the
|
|
72
|
+
plugin's Stop-hook Review Gate) is reserved for a later team-mode phase
|
|
73
|
+
(Phase 4). Do not add it — or any other key — ahead of its phase; the
|
|
74
|
+
loader rejects unknown keys today by design.
|
|
75
|
+
|
|
76
|
+
## Role semantics — the council-verdict design constraint
|
|
77
|
+
|
|
78
|
+
Verbatim from the consuming roadmap's council verdict, binding on every
|
|
79
|
+
team-mode phase:
|
|
80
|
+
|
|
81
|
+
> **Council verdict on team-mode frontmatter (claude-sonnet-4-5 + gpt-4o,
|
|
82
|
+
> 2026-07-12, unanimous REJECT):** skills/commands get NO `team_mode` /
|
|
83
|
+
> role frontmatter. Role semantics belong in the `ai_team` config block +
|
|
84
|
+
> prompt library (reusing subagent-orchestration's implementer/judge frame
|
|
85
|
+
> and status envelope), not smeared across 271 skill files while the
|
|
86
|
+
> feature's role model does not operationally exist. Revisit-if: Phase 2
|
|
87
|
+
> execution turns out to be blocked SPECIFICALLY on artefact-level role
|
|
88
|
+
> metadata — then re-open via decision-revisit-gate, not by silently
|
|
89
|
+
> adding the key.
|
|
90
|
+
|
|
91
|
+
Operationally: ALL role semantics (builder/reviewer/verifier selection,
|
|
92
|
+
eligibility) live HERE — in this `ai_team` block — plus the prompt
|
|
93
|
+
library, reusing `subagent-orchestration`'s implementer/judge frame and
|
|
94
|
+
its `subagent-status.json` envelope. **No `team_mode`/role frontmatter key
|
|
95
|
+
is added to skill/command/rule schemas.**
|
|
96
|
+
|
|
97
|
+
## Quota — one subscription, one counter
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
TEAM CALLS COUNT INTO THE EXISTING cli_call_budget OPENAI BUCKET.
|
|
101
|
+
ONE SUBSCRIPTION, ONE COUNTER. NEVER A PARALLEL COUNTER.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The daily CLI-call counter is already **generic per-provider** — no
|
|
105
|
+
team-specific counting system exists or may be built:
|
|
106
|
+
|
|
107
|
+
- **State file:** `~/.event4u/agent-config/cli-calls.json`
|
|
108
|
+
(`CLI_CALLS_FILENAME`, `src/scripts/ai_council/clients.ts:716`), shape
|
|
109
|
+
`{ date: "YYYY-MM-DD", counts: { <provider>: <int> } }`, resets on UTC
|
|
110
|
+
date rollover.
|
|
111
|
+
- **Read:** `load_cli_call_counts(path?)` —
|
|
112
|
+
`src/scripts/ai_council/clients.ts:738`. Returns today's per-provider
|
|
113
|
+
counts; empty on rollover.
|
|
114
|
+
- **Increment:** `record_cli_call(provider, path?)` —
|
|
115
|
+
`src/scripts/ai_council/clients.ts:774`. Returns the new total.
|
|
116
|
+
- **Gate + increment on the transport itself:** `CliClient.ask()` checks
|
|
117
|
+
the counter *before* spawning (`clients.ts` § quota gate, returns
|
|
118
|
+
`error: 'cli_quota_exhausted'` + a `block_quota` events-log line when
|
|
119
|
+
exhausted) and records the call *after* — even failed calls count, so a
|
|
120
|
+
broken CLI cannot burn the budget in a tight loop.
|
|
121
|
+
- **The openai bucket:** `OpenAICliClient` (`clients.ts:1275`) has
|
|
122
|
+
`name = 'openai'`; council CLI calls and team calls land on the **same**
|
|
123
|
+
`counts.openai` entry.
|
|
124
|
+
|
|
125
|
+
A `/team` invocation therefore reuses the existing seams, in preference
|
|
126
|
+
order:
|
|
127
|
+
|
|
128
|
+
1. **Through the transport** — construct `OpenAICliClient` with
|
|
129
|
+
`max_calls_per_day: <ai_team.max_calls_per_day>`; the gate, the
|
|
130
|
+
exhausted-error, the events-log line, and the increment all come for
|
|
131
|
+
free.
|
|
132
|
+
2. **Direct** (for `/team:status` rendering or a pre-flight check) —
|
|
133
|
+
`load_cli_call_counts()['openai'] ?? 0` to read,
|
|
134
|
+
`record_cli_call('openai')` to count. No new helper exists because
|
|
135
|
+
none is needed; adding a team-side duplicate of this counter is a
|
|
136
|
+
contract violation.
|
|
137
|
+
|
|
138
|
+
`ai_team.max_calls_per_day` and the council's
|
|
139
|
+
`cli_call_budget.max_calls_per_day.openai` are two *ceilings* over the
|
|
140
|
+
same *counter*: whichever path a call takes, it increments the one shared
|
|
141
|
+
bucket, and each surface enforces its own configured cap against that
|
|
142
|
+
shared count.
|
|
143
|
+
|
|
144
|
+
## Validation rules (fail-closed)
|
|
145
|
+
|
|
146
|
+
`load_ai_team_config` / `build_ai_team_config`
|
|
147
|
+
(`src/scripts/ai_team/config.ts`) raise `TeamConfigError` when:
|
|
148
|
+
|
|
149
|
+
1. `ai_team` is present but not a mapping,
|
|
150
|
+
2. any **unknown key** appears under `ai_team` (a typo must never
|
|
151
|
+
silently disable a gate),
|
|
152
|
+
3. `enabled` / `allow_delegate` / `suppress_setup_hint` is not a boolean,
|
|
153
|
+
4. `model` is not a non-empty string,
|
|
154
|
+
5. `max_calls_per_day` is not a non-negative integer (booleans rejected).
|
|
155
|
+
|
|
156
|
+
An **absent** `ai_team` block is not an error — it yields the defaults
|
|
157
|
+
(`AI_TEAM_DEFAULTS`) and the feature stays off.
|
|
158
|
+
|
|
159
|
+
## Default-off posture
|
|
160
|
+
|
|
161
|
+
Every team-mode capability is default-off. With the block absent or
|
|
162
|
+
`enabled: false`, all paths are byte-identical to pre-feature behavior:
|
|
163
|
+
no command suggestions, no wrapper execution, no quota consumption, no
|
|
164
|
+
wizard nagging beyond the single suppressible setup hint.
|
|
165
|
+
`/team:delegate` is doubly gated (`enabled` AND `allow_delegate`).
|
|
166
|
+
|
|
167
|
+
## No-claims constraint
|
|
168
|
+
|
|
169
|
+
No public claim about cross-model review quality ("a second model finds
|
|
170
|
+
errors the first never sees", "two strongest models catch each other's
|
|
171
|
+
errors", or any review-lift assertion) may exist anywhere in the tree
|
|
172
|
+
until the pre-registered three-arm defect-finding benchmark has produced
|
|
173
|
+
a verdict bound in CLAIMS.md. Workflow-value prose is allowed; lift
|
|
174
|
+
claims are not. An honest null keeps the feature documented as workflow
|
|
175
|
+
value only.
|
|
176
|
+
|
|
177
|
+
## Boundary vs. the council
|
|
178
|
+
|
|
179
|
+
Team mode and the council are complements, not variants — the council's
|
|
180
|
+
neutrality contract is untouched by team mode:
|
|
181
|
+
|
|
182
|
+
| Axis | Council ([ai-council-config.md](ai-council-config.md)) | Team (`ai_team`) |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| Shape | N members, breadth | One strong reviewer, depth |
|
|
185
|
+
| Repo access | NEVER (artefact text + neutral preamble only) | Full (reviewer runs inside the working tree) |
|
|
186
|
+
| Config location | User-global `.ai-council.yml` (ADR-104) | Project `.agent-settings.yml` cascade |
|
|
187
|
+
| Default models | Mid-tier, cost-conscious | Subscription's strongest (`model: 'auto'`) |
|
|
188
|
+
| Quota | `cli_call_budget` per provider | Same counter — shared openai bucket |
|
|
189
|
+
|
|
190
|
+
This link is deliberately one-directional (team → council); the council
|
|
191
|
+
contract does not reference team mode.
|
|
@@ -45,6 +45,7 @@ column 1 of this table.
|
|
|
45
45
|
| `council` | 3 | `default` · `pr` · `design` · `optimize` · `analysis` | `council` (legacy default lens) · `council-pr` · `council-design` · `council-optimize`; `analysis` added 2026-05-14 — wrapper for local analysis outputs with a Top-N consensus tail block consumed by `/roadmap create` |
|
|
46
46
|
| `challenge-me` | — | `vision` · `with-docs` | new — Pocock-inspired one-question-at-a-time interview; `vision` is the standard 95%-confidence variant, `with-docs` adds doc/glossary awareness with a session-scoped glossary and load-bearing claim-vs-code verification |
|
|
47
47
|
| `research` | 2 | `deep` · `report` | preliminary-research scaffolder ported from `Weizhena/Deep-Research-skills` (cluster head emits `outline.yaml` + `fields.yaml` against the `research-schema` contract). `:deep` populates per-item JSON in batches with native web-search + JSON-Schema self-validation (no Python runtime); `:report` renders `report.md` directly + optionally emits a `jq` template for deterministic regeneration. `add-items` / `add-fields` intentionally **not** ported — re-run `/research <topic>` to extend the field framework. |
|
|
48
|
+
| `team` | 2 | `review` · `adversarial` · `delegate` · `status` | new 2026-07-12 (road-to-team-mode Phase 2) — cross-model depth review: thin fail-closed delegations to the official codex plugin on Claude-Code hosts under `ai_team` governance ([`ai-team-config`](ai-team-config.md)); default-off (`ai_team.enabled: false`), `delegate` behind the second opt-in `allow_delegate`; internal visibility until the ADR promotion gate |
|
|
48
49
|
| `orchestrate` | — | _(none yet — cluster head only)_ | new — runtime executor for YAML pipelines under `.agent-config/orchestrations/` per the [`orchestration-dsl-v1`](orchestration-dsl-v1.md) contract; chains personas / skills / commands / sub-agents deterministically. Single cluster head; sub-commands deferred until a second verb is needed. |
|
|
49
50
|
| `sync` | 4 | `agent-settings` · `gitignore` · `gitignore-fix` | new cluster 2026-07-08 — absorbs the former single-sub `sync-gitignore` cluster (slug-neutral nests: `sync-agent-settings`, `sync-gitignore`, `sync-gitignore-fix` keep their slugs; the gitignore node keeps its own `fix` sub-dir, mirroring the `agents/user` deep-nest precedent). Bare `/sync` shows the menu. |
|
|
50
51
|
| `ghostwriter` | — | `fetch` · `write` · `list` · `show` · `delete` | new cluster 2026-05-15 — third voice primitive for AI-assisted writing in the public voice of a public figure. Hybrid storage: real-person profiles live consumer-side under `agents/reference/ghostwriter/<slug>.md` (gitignored by default); package source ships only `fictional: true` fixtures. Zero network code in the package — `:fetch` delegates web-fetch / web-search to the host agent. Mandatory disclosure footer on every `:write` output (no opt-out). Schema: [`ghostwriter-schema`](ghostwriter-schema.md). |
|
package/docs/featured-skills.md
CHANGED
|
@@ -92,4 +92,4 @@ task lint-featured-skills
|
|
|
92
92
|
|
|
93
93
|
CI runs this in `taskfiles/ci-fast.yml`. Stale entries (renamed / removed skill or command) fail the build. See [`scripts/lint_featured_skills.py`](../src/scripts/lint_featured_skills.py) for the matcher.
|
|
94
94
|
|
|
95
|
-
→ Browse all 271 skills: [`dist/agent-src/skills/`](../dist/agent-src/skills/) · all
|
|
95
|
+
→ Browse all 271 skills: [`dist/agent-src/skills/`](../dist/agent-src/skills/) · all 183 commands: [`dist/agent-src/commands/`](../dist/agent-src/commands/)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Pick the entry that matches what you do day-to-day. Each section names the three skills you will reach for first and shows whether MCP (no terminal) or CLI (terminal) is the simpler install path for that role.
|
|
4
4
|
|
|
5
|
-
`agent-config` ships 271 skills, 104 governed rules, and
|
|
5
|
+
`agent-config` ships 271 skills, 104 governed rules, and 183 commands. You do not need all of them. Each role below filters to the slice that pays back in week one; the rest stays available and shows up on demand when a task references it.
|
|
6
6
|
|
|
7
7
|
> **Taglines at a glance →** [`docs/role-experiences.md`](role-experiences.md) — the one-line pitch per role experience, in one table.
|
|
8
8
|
|
|
@@ -73,6 +73,8 @@ Cinematic-blueprint approach: the agent expands your script into a 12-block scen
|
|
|
73
73
|
- [`nextjs-patterns`](../dist/agent-src/skills/nextjs-patterns/SKILL.md) — App Router, Server Components, Server Actions, caching.
|
|
74
74
|
- [`quality-tools`](../dist/agent-src/skills/quality-tools/SKILL.md) — PHPStan, Rector, ECS error triage and fix loop.
|
|
75
75
|
|
|
76
|
+
Cross-model review of the real diff (**team mode**, default off) is documented in [Getting Started § Team mode](getting-started.md#team-mode--cross-model-review-default-off).
|
|
77
|
+
|
|
76
78
|
**Install path:** **CLI.** Run `npx @event4u/agent-config init --tools=claude-code,cursor` in the project root. MCP works too but loses git / file-system tooling that the IDE-integrated path gives you.
|
|
77
79
|
|
|
78
80
|
---
|
package/docs/getting-started.md
CHANGED
|
@@ -174,7 +174,37 @@ Your agent now understands slash commands:
|
|
|
174
174
|
| `/fix quality` | Run and fix all quality checks |
|
|
175
175
|
| `/chat-history import` | Pull a prior session into the current chat (resume) |
|
|
176
176
|
|
|
177
|
-
→ [Browse all
|
|
177
|
+
→ [Browse all 183 active commands](../dist/agent-src/commands/)
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Team mode — cross-model review (default off)
|
|
182
|
+
|
|
183
|
+
Team mode pairs two strong models on one change: one model builds, a
|
|
184
|
+
second reviews the **real diff** in your working tree and hands the
|
|
185
|
+
findings back for a fix round. It is the depth complement to the
|
|
186
|
+
[AI council](../dist/agent-src/skills/ai-council/SKILL.md): the council
|
|
187
|
+
collects many cheap, neutral opinions on an artefact's *text*; team mode
|
|
188
|
+
puts one strong, opinionated reviewer *inside the repo*.
|
|
189
|
+
|
|
190
|
+
| Axis | Council | Team mode |
|
|
191
|
+
|---|---|---|
|
|
192
|
+
| Repo access | none — members see only the artefact text | full — the reviewer reads the real diff and git state |
|
|
193
|
+
| Shape | breadth — N neutral opinions, one round | depth — one strong reviewer, build→review→fix iteration |
|
|
194
|
+
| Cost model | API-billed members (per-token) | subscription-authed `codex` CLI (runs under your existing plan) |
|
|
195
|
+
|
|
196
|
+
**Setup.** Run `agent-config doctor --check team` — it verifies the
|
|
197
|
+
`codex` binary + auth and, on Claude Code hosts, the Codex plugin, and
|
|
198
|
+
prints the exact remediation command for anything missing.
|
|
199
|
+
|
|
200
|
+
**Default off.** Team mode ships disabled (`ai_team.enabled: false` in
|
|
201
|
+
`.agent-settings.yml`); no team command runs and no cross-model call is
|
|
202
|
+
made until you opt in.
|
|
203
|
+
|
|
204
|
+
**No lift claim.** Whether cross-model team review catches more real
|
|
205
|
+
defects than single-model adversarial self-review is **unproven** — the
|
|
206
|
+
package makes no review-quality claim until the pre-registered benchmark
|
|
207
|
+
has run and its verdict is recorded.
|
|
178
208
|
|
|
179
209
|
---
|
|
180
210
|
|
|
@@ -71,6 +71,24 @@ second-writer race to protect against; flip to `true` when there are
|
|
|
71
71
|
concurrent mergers. `required_pull_request_reviews: null` per the
|
|
72
72
|
bus-factor reality above.
|
|
73
73
|
|
|
74
|
+
## Operating conditions under `strict: false`
|
|
75
|
+
|
|
76
|
+
`strict: false` drops the branches-up-to-date requirement, so three
|
|
77
|
+
conditions become merge-time habits the config cannot enforce:
|
|
78
|
+
|
|
79
|
+
- **The checked commit must not change after green CI.** No post-CI
|
|
80
|
+
amend or force-push on the PR branch — the config already blocks
|
|
81
|
+
force-pushes to `main`; the same discipline applies to the head that
|
|
82
|
+
CI checked: what went green is what merges.
|
|
83
|
+
- **Critical checks must have run on the final head before merge.** A
|
|
84
|
+
human glance at the checks tab on the PR's latest commit — with
|
|
85
|
+
`strict: false` GitHub does not re-run required checks when the base
|
|
86
|
+
moves, so the green you see is only as fresh as the head it ran on.
|
|
87
|
+
- **Auto-merge must not be enabled in a way that merges with pending or
|
|
88
|
+
failed required checks.** Enable auto-merge only once the required
|
|
89
|
+
list is complete and green on the final head — never as a
|
|
90
|
+
fire-and-forget while checks are still queued.
|
|
91
|
+
|
|
74
92
|
## Rollback
|
|
75
93
|
|
|
76
94
|
```bash
|
package/docs/proof.md
CHANGED
|
@@ -27,7 +27,7 @@ evidence pointer, or `task check-claims` fails the build.
|
|
|
27
27
|
| Claim | Kind | Evidence | Resolves |
|
|
28
28
|
|---|---|---|---|
|
|
29
29
|
| The release process is documented as an inheritable runbook + succession doc, and the project's bus-factor (trailing-90-day distinct human reviewers) is tracked and reported truthfully — currently 1, not implied to be more. | qual | `docs/succession.md#trailing 90 days` | ✅ |
|
|
30
|
-
|
|
|
30
|
+
| 183 commands. | quant | `src/scripts/check_artefact_count_messaging.ts#Artefact-count messaging gate` | ✅ |
|
|
31
31
|
| A MEASURED-BUT-NOT-SHIPPED experiment — the thin rule projection reduced eager rule load 78,513 → 13,881 GPT-tokens (whole always-loaded projection 98,529 → 33,897, ~65.6%), but FAILED the quality gate (thin win-rate 36.2% vs required 48%) and does not ship; it un-defers only behind `discipline_profile: essential`. Shipped behavior does NOT include this reduction. Method: `agent-config benchmark` over the pinned token baseline; the baseline is the honest "what the user pays if everything loads eagerly", NOT a synthetic full-corpus strawman (council Q4); quality gate per the Phase-0 paired judge run. | quant | `internal/bench/reports/token-baseline.json#eager_rule_load` | ✅ |
|
|
32
32
|
| On a weak host (claude-haiku-4-5) the package produces a significant, placebo-controlled discipline lift on scope/downstream traps; on a strong host the same measurement is a published null — the package transplants discipline a weak model lacks, not model intelligence. | quant | `docs/benchmark.md#weak-host-specific` | ✅ |
|
|
33
33
|
| The non-coding domain skills (finance/founder/ops/content) are forged on TS/PHP and labeled unvalidated until they pass a sourced domain-truth fixture; no public prose implies proven domain correctness, and the validated count is CI-ratcheted. | qual | `src/scripts/domain_soundness_status.ts#checkRatchet` | ✅ |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@event4u/agent-config",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.13.0",
|
|
4
4
|
"description": "Universal AI Agent OS — audited skills, governance rules, commands, and templates for AI coding tools (Claude Code, Cursor, Windsurf, Copilot).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -629,6 +629,46 @@ worktrees:
|
|
|
629
629
|
#
|
|
630
630
|
# See `docs/contracts/ai-council-config.md` for the schema.
|
|
631
631
|
|
|
632
|
+
# --- AI Team (cross-model strong-pair review — /team family) ---
|
|
633
|
+
#
|
|
634
|
+
# Governs the default-off `/team` capability family: one strong external
|
|
635
|
+
# model (via the codex CLI, subscription-authed) reviews inside the repo —
|
|
636
|
+
# the depth complement to the council's breadth. Schema + validation
|
|
637
|
+
# contract: `docs/contracts/ai-team-config.md`. The loader
|
|
638
|
+
# (`src/scripts/ai_team/config.ts`) rejects unknown keys fail-closed.
|
|
639
|
+
ai_team:
|
|
640
|
+
# Master switch. false (default) = /team commands are never suggested
|
|
641
|
+
# and every invocation refuses with an enable pointer; true = the
|
|
642
|
+
# family is live (individual gates below still apply).
|
|
643
|
+
enabled: false
|
|
644
|
+
|
|
645
|
+
# Model handed to the codex CLI. 'auto' (default) = pass NO --model
|
|
646
|
+
# flag, the codex CLI's own default applies — this tracks the
|
|
647
|
+
# subscription's current strongest model instead of pinning a stale
|
|
648
|
+
# ID. Any other value passes through verbatim as `--model <value>`.
|
|
649
|
+
model: auto
|
|
650
|
+
|
|
651
|
+
# Second opt-in for the ONLY wrapper that delegates write access
|
|
652
|
+
# (/team:delegate → the plugin's native-Codex worker). false (default)
|
|
653
|
+
# = delegate refuses with an enable pointer even when ai_team.enabled
|
|
654
|
+
# is true. Both keys must be true before delegation is reachable.
|
|
655
|
+
allow_delegate: false
|
|
656
|
+
|
|
657
|
+
# Per-day cap on team calls. Team calls count into the EXISTING
|
|
658
|
+
# cli_call_budget openai bucket (~/.event4u/agent-config/cli-calls.json,
|
|
659
|
+
# daily UTC reset) — one subscription, one counter, never a parallel
|
|
660
|
+
# count. This key is the team-side ceiling read against that shared
|
|
661
|
+
# bucket. 0 = block all team calls; raise if you review heavily.
|
|
662
|
+
max_calls_per_day: 50
|
|
663
|
+
|
|
664
|
+
# Suppress the one-line wizard/init recommendation to set up the codex
|
|
665
|
+
# plugin on Claude-Code hosts. Cosmetic only — never changes behavior.
|
|
666
|
+
suppress_setup_hint: false
|
|
667
|
+
|
|
668
|
+
# NOTE for future keys: `review_gate` (managed loop-bound governance of
|
|
669
|
+
# the plugin's Stop-hook Review Gate) lands in a later team-mode phase
|
|
670
|
+
# (Phase 4) — do not add it here ahead of that phase.
|
|
671
|
+
|
|
632
672
|
# --- Onboarding ---
|
|
633
673
|
#
|
|
634
674
|
# Tracks whether the initial setup flow (/onboard) has been completed
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
* scope · global-binary · claude-plugin · stale-orphans · manifest-integrity ·
|
|
30
30
|
* lockfile-freshness · bridge-drift · mcp-mode · mcp-beta-readiness ·
|
|
31
31
|
* offline-readiness · python-runtime · humanizer-runtime · tier-usage-readiness ·
|
|
32
|
-
* council-cli ·
|
|
32
|
+
* council-cli · team ·
|
|
33
33
|
* unsupported-combos · wizard-state.
|
|
34
34
|
* Each emits a structured `{id, status, message, remedy}` record with
|
|
35
35
|
* `status` ∈ `ok` / `warn` / `fail` / `skipped` (rendered
|
|
@@ -747,6 +747,7 @@ const CHECK_IDS = [
|
|
|
747
747
|
'humanizer-runtime',
|
|
748
748
|
'tier-usage-readiness',
|
|
749
749
|
'council-cli',
|
|
750
|
+
'team',
|
|
750
751
|
'unsupported-combos',
|
|
751
752
|
'wizard-state',
|
|
752
753
|
'settings-review-pending',
|
|
@@ -769,6 +770,7 @@ const GLOBAL_CHECK_IDS: ReadonlySet<string> = new Set([
|
|
|
769
770
|
'humanizer-runtime',
|
|
770
771
|
'tier-usage-readiness',
|
|
771
772
|
'council-cli',
|
|
773
|
+
'team',
|
|
772
774
|
'wizard-state',
|
|
773
775
|
'settings-review-pending',
|
|
774
776
|
]);
|
|
@@ -1975,6 +1977,196 @@ function pyFloat(value: number): string {
|
|
|
1975
1977
|
return String(value);
|
|
1976
1978
|
}
|
|
1977
1979
|
|
|
1980
|
+
// ---------------------------------------------------------------------------
|
|
1981
|
+
// team check (road-to-team-mode Phase 1) — codex binary + auth, official
|
|
1982
|
+
// codex plugin on Claude-Code hosts, Review-Gate consistency.
|
|
1983
|
+
// ---------------------------------------------------------------------------
|
|
1984
|
+
|
|
1985
|
+
/**
|
|
1986
|
+
* Codex CLI home — `CODEX_HOME` env override (the codex CLI's own
|
|
1987
|
+
* convention), else `~/.codex`.
|
|
1988
|
+
*/
|
|
1989
|
+
function _codex_home(): string {
|
|
1990
|
+
const env = (process.env['CODEX_HOME'] ?? '').trim();
|
|
1991
|
+
return env !== '' ? env : path.join(os.homedir(), '.codex');
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/**
|
|
1995
|
+
* Codex binary name for the team check — REUSES the council probe's binary
|
|
1996
|
+
* discovery: when a council config exists and declares an enabled cli-mode
|
|
1997
|
+
* `openai` member with a `binary` override, honour it; else the provider
|
|
1998
|
+
* default from `_CLI_PROVIDER_META` (`codex`). Never throws — an unreadable
|
|
1999
|
+
* or invalid council config falls back to the default binary (the council-cli
|
|
2000
|
+
* check owns reporting that problem).
|
|
2001
|
+
*/
|
|
2002
|
+
function _team_codex_binary_name(project_root: string): string {
|
|
2003
|
+
const default_bin = (_CLI_PROVIDER_META['openai'] as [string, boolean])[0];
|
|
2004
|
+
const { load_council_config, resolve_config_path } = ai_council_config;
|
|
2005
|
+
const council_path = resolve_config_path(project_root);
|
|
2006
|
+
if (!pathExists(String(council_path))) {
|
|
2007
|
+
return default_bin;
|
|
2008
|
+
}
|
|
2009
|
+
let cfg: ai_council_config.CouncilConfig;
|
|
2010
|
+
try {
|
|
2011
|
+
cfg = load_council_config(council_path);
|
|
2012
|
+
} catch {
|
|
2013
|
+
return default_bin;
|
|
2014
|
+
}
|
|
2015
|
+
const member = cfg.members.get('openai');
|
|
2016
|
+
if (member && member.enabled && member.mode === 'cli' && member.binary) {
|
|
2017
|
+
return member.binary;
|
|
2018
|
+
}
|
|
2019
|
+
return default_bin;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
/** Settings-flag coercion shared with the tier-usage check (bool or string). */
|
|
2023
|
+
function _settings_flag(val: unknown): boolean {
|
|
2024
|
+
if (typeof val === 'boolean') return val;
|
|
2025
|
+
if (typeof val === 'string') {
|
|
2026
|
+
return ['true', 'yes', 'on', '1'].includes(val.trim().toLowerCase());
|
|
2027
|
+
}
|
|
2028
|
+
return false;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
/** The `ai_team` block from `.agent-settings.yml` — lenient, `{}` when absent. */
|
|
2032
|
+
function _read_ai_team_block(project_root: string): Dict {
|
|
2033
|
+
const settings_file = project_settings_path(project_root);
|
|
2034
|
+
if (!isFile(settings_file)) return {};
|
|
2035
|
+
let content: string;
|
|
2036
|
+
try {
|
|
2037
|
+
content = readText0(settings_file);
|
|
2038
|
+
} catch {
|
|
2039
|
+
return {};
|
|
2040
|
+
}
|
|
2041
|
+
const loaded = yamlSafeLoad(content);
|
|
2042
|
+
if (typeof loaded !== 'object' || loaded === null || Array.isArray(loaded)) return {};
|
|
2043
|
+
const raw = (loaded as Dict)['ai_team'];
|
|
2044
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return {};
|
|
2045
|
+
return raw as Dict;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
/**
|
|
2049
|
+
* `team` health check — three sub-signals folded into one result:
|
|
2050
|
+
*
|
|
2051
|
+
* (a) codex binary present (council-probe binary discovery reused) AND
|
|
2052
|
+
* auth present. Auth is a READ-ONLY presence probe of
|
|
2053
|
+
* `$CODEX_HOME/auth.json` (default `~/.codex/auth.json`) — token
|
|
2054
|
+
* expiry cannot be validated without a billable call; runtime expiry
|
|
2055
|
+
* is caught by `OpenAICliClient._AUTH_FAILURE_PATTERNS`.
|
|
2056
|
+
* (b) on Claude-Code hosts (claude binary on PATH or the Claude config dir
|
|
2057
|
+
* present): the official codex plugin recorded in
|
|
2058
|
+
* `plugins/installed_plugins.json`. Detection is read-only — doctor
|
|
2059
|
+
* never writes under `~/.claude/`.
|
|
2060
|
+
* (c) Review-Gate consistency: `ai_team.review_gate.managed` on while the
|
|
2061
|
+
* loop bound (`max_consecutive_blocks`, Phase 4 — unbuilt) is absent
|
|
2062
|
+
* → WARN.
|
|
2063
|
+
*
|
|
2064
|
+
* Absent feature ≠ broken feature: with `ai_team` absent or disabled the
|
|
2065
|
+
* check reports ok ("team mode not configured (default-off)"); WARN fires
|
|
2066
|
+
* only on failing sub-signals or inconsistent half-configured states.
|
|
2067
|
+
*/
|
|
2068
|
+
function _check_team(project_root: string): Dict {
|
|
2069
|
+
const ai_team = _read_ai_team_block(project_root);
|
|
2070
|
+
const enabled = _settings_flag(ai_team['enabled']);
|
|
2071
|
+
const gateRaw = ai_team['review_gate'];
|
|
2072
|
+
const gate =
|
|
2073
|
+
typeof gateRaw === 'object' && gateRaw !== null && !Array.isArray(gateRaw)
|
|
2074
|
+
? (gateRaw as Dict)
|
|
2075
|
+
: {};
|
|
2076
|
+
const gate_managed = _settings_flag(gate['managed']);
|
|
2077
|
+
const bound = gate['max_consecutive_blocks'];
|
|
2078
|
+
const bound_present = typeof bound === 'number' && Number.isInteger(bound) && bound > 0;
|
|
2079
|
+
|
|
2080
|
+
if (!enabled) {
|
|
2081
|
+
if (gate_managed) {
|
|
2082
|
+
return {
|
|
2083
|
+
id: 'team',
|
|
2084
|
+
status: 'warn',
|
|
2085
|
+
message:
|
|
2086
|
+
'half-configured: ai_team.review_gate.managed is on but ' +
|
|
2087
|
+
'ai_team.enabled is false — the gate never runs',
|
|
2088
|
+
remedy:
|
|
2089
|
+
'set `ai_team.enabled: true` in .agent-settings.yml, or ' +
|
|
2090
|
+
'remove `ai_team.review_gate.managed`',
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
return {
|
|
2094
|
+
id: 'team',
|
|
2095
|
+
status: 'ok',
|
|
2096
|
+
message: 'team mode not configured (default-off)',
|
|
2097
|
+
remedy:
|
|
2098
|
+
'opt in via `ai_team.enabled: true` in .agent-settings.yml, ' +
|
|
2099
|
+
'then re-run `agent-config doctor --check team`',
|
|
2100
|
+
};
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
const remedies: string[] = [];
|
|
2104
|
+
|
|
2105
|
+
// (a) codex binary — council-probe discovery reused.
|
|
2106
|
+
const binary_name = _team_codex_binary_name(project_root);
|
|
2107
|
+
const binary_resolved = shutilWhich(binary_name);
|
|
2108
|
+
const binary_glyph = binary_resolved !== null ? '✅' : '❌';
|
|
2109
|
+
if (binary_resolved === null) {
|
|
2110
|
+
remedies.push('install the codex CLI: `npm install -g @openai/codex`');
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
// (a, cont.) codex auth — presence probe of $CODEX_HOME/auth.json.
|
|
2114
|
+
const auth_path = path.join(_codex_home(), 'auth.json');
|
|
2115
|
+
const authed = pathExists(auth_path);
|
|
2116
|
+
const auth_glyph = authed ? '✅' : '❌';
|
|
2117
|
+
if (!authed) {
|
|
2118
|
+
remedies.push('run `codex login`');
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// (b) official codex plugin — Claude-Code hosts only.
|
|
2122
|
+
const is_claude_host =
|
|
2123
|
+
shutilWhich('claude') !== null || pathExists(claude_plugin.claude_config_dir());
|
|
2124
|
+
let plugin_str: string;
|
|
2125
|
+
if (is_claude_host) {
|
|
2126
|
+
const plugin_present = claude_plugin.codex_plugin_installed();
|
|
2127
|
+
plugin_str = `codex plugin ${plugin_present ? '✅' : '❌'}`;
|
|
2128
|
+
if (!plugin_present) {
|
|
2129
|
+
remedies.push(
|
|
2130
|
+
'install the official codex plugin: ' +
|
|
2131
|
+
claude_plugin.CODEX_PLUGIN_INSTALL_HINT.map((c) => `\`${c}\``).join(' then '),
|
|
2132
|
+
);
|
|
2133
|
+
}
|
|
2134
|
+
} else {
|
|
2135
|
+
plugin_str = 'codex plugin — (not a Claude Code host; fallback path applies)';
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
// (c) Review-Gate consistency.
|
|
2139
|
+
let gate_str: string;
|
|
2140
|
+
if (gate_managed && !bound_present) {
|
|
2141
|
+
gate_str = 'review-gate ⚠️ on, loop bound absent';
|
|
2142
|
+
remedies.push(
|
|
2143
|
+
'set `ai_team.review_gate.max_consecutive_blocks` (loop bound; ' +
|
|
2144
|
+
'ships with the Review-Gate governance phase) or set ' +
|
|
2145
|
+
'`ai_team.review_gate.managed: false`',
|
|
2146
|
+
);
|
|
2147
|
+
} else {
|
|
2148
|
+
gate_str = `review-gate ${gate_managed ? 'on' : 'off'}`;
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
const detail =
|
|
2152
|
+
`codex binary ${binary_glyph} (${binary_name}) · ` +
|
|
2153
|
+
`codex auth ${auth_glyph} (${auth_path}) · ${plugin_str} · ${gate_str}`;
|
|
2154
|
+
if (remedies.length > 0) {
|
|
2155
|
+
return {
|
|
2156
|
+
id: 'team',
|
|
2157
|
+
status: 'warn',
|
|
2158
|
+
message: `${remedies.length} team sub-signal(s) failing · ${detail}`,
|
|
2159
|
+
remedy: remedies.join('; '),
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
return {
|
|
2163
|
+
id: 'team',
|
|
2164
|
+
status: 'ok',
|
|
2165
|
+
message: `team mode enabled · ${detail}`,
|
|
2166
|
+
remedy: '',
|
|
2167
|
+
};
|
|
2168
|
+
}
|
|
2169
|
+
|
|
1978
2170
|
function _check_unsupported_combos(manifest: Dict): Dict {
|
|
1979
2171
|
const global_only = new Set(['droid', 'qoder']);
|
|
1980
2172
|
const bad: string[] = [];
|
|
@@ -2257,6 +2449,7 @@ function _run_checks(
|
|
|
2257
2449
|
'humanizer-runtime': () => _check_humanizer_runtime(),
|
|
2258
2450
|
'tier-usage-readiness': () => _check_tier_usage_readiness(project_root),
|
|
2259
2451
|
'council-cli': () => _check_council_cli(project_root),
|
|
2452
|
+
team: () => _check_team(project_root),
|
|
2260
2453
|
'unsupported-combos': () => _check_unsupported_combos(manifest),
|
|
2261
2454
|
'wizard-state': _check_wizard_state,
|
|
2262
2455
|
'settings-review-pending': _check_settings_review_pending,
|
|
@@ -2329,6 +2522,7 @@ function _run_checks_no_manifest(
|
|
|
2329
2522
|
'humanizer-runtime': () => _check_humanizer_runtime(),
|
|
2330
2523
|
'tier-usage-readiness': () => _check_tier_usage_readiness(project_root),
|
|
2331
2524
|
'council-cli': () => _check_council_cli(project_root),
|
|
2525
|
+
team: () => _check_team(project_root),
|
|
2332
2526
|
'unsupported-combos': () => _skipped_manifest_check('unsupported-combos'),
|
|
2333
2527
|
'wizard-state': _check_wizard_state,
|
|
2334
2528
|
'settings-review-pending': _check_settings_review_pending,
|
|
@@ -2818,6 +3012,7 @@ export {
|
|
|
2818
3012
|
_check_mcp_beta_readiness,
|
|
2819
3013
|
_check_tier_usage_readiness,
|
|
2820
3014
|
_check_council_cli,
|
|
3015
|
+
_check_team,
|
|
2821
3016
|
_check_unsupported_combos,
|
|
2822
3017
|
_check_wizard_state,
|
|
2823
3018
|
_check_settings_review_pending,
|