@event4u/agent-config 2.10.0 → 2.12.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/.agent-src/commands/agents.md +1 -0
- package/.agent-src/commands/challenge-me.md +1 -0
- package/.agent-src/commands/chat-history.md +1 -0
- package/.agent-src/commands/context.md +1 -0
- package/.agent-src/commands/council.md +1 -0
- package/.agent-src/commands/feature.md +1 -0
- package/.agent-src/commands/fix.md +1 -0
- package/.agent-src/commands/grill-me.md +1 -0
- package/.agent-src/commands/judge.md +1 -0
- package/.agent-src/commands/memory.md +1 -0
- package/.agent-src/commands/module.md +1 -0
- package/.agent-src/commands/onboard.md +32 -4
- package/.agent-src/commands/optimize.md +1 -0
- package/.agent-src/commands/override.md +1 -0
- package/.agent-src/commands/roadmap.md +1 -0
- package/.agent-src/commands/tests.md +1 -0
- package/.agent-src/skills/canvas-design/SKILL.md +132 -0
- package/.agent-src/skills/canvas-design/evals/triggers.json +16 -0
- package/.agent-src/skills/doc-coauthoring/SKILL.md +129 -0
- package/.agent-src/skills/doc-coauthoring/evals/triggers.json +16 -0
- package/.agent-src/skills/nextjs-patterns/SKILL.md +203 -0
- package/.agent-src/skills/skill-writing/SKILL.md +101 -16
- package/.agent-src/skills/sql-writing/SKILL.md +1 -1
- package/.agent-src/skills/symfony-workflow/SKILL.md +173 -0
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +4 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/__init__.py +3 -0
- package/.agent-src/templates/scripts/work_engine/hooks/builtin/decision_gate.py +162 -0
- package/.agent-src/templates/scripts/work_engine/hooks/settings.py +24 -6
- package/.agent-src/templates/scripts/work_engine/scoring/decision_engine.py +351 -0
- package/.claude-plugin/marketplace.json +5 -1
- package/CHANGELOG.md +68 -0
- package/README.md +37 -8
- package/config/agent-settings.template.yml +66 -0
- package/docs/architecture.md +1 -1
- package/docs/contracts/STABILITY.md +16 -0
- package/docs/contracts/adr-chat-history-split.md +1 -0
- package/docs/contracts/adr-forecast-construction-shape.md +1 -0
- package/docs/contracts/adr-gtm-context-spine.md +1 -0
- package/docs/contracts/adr-level-6-productization.md +147 -0
- package/docs/contracts/adr-settings-sync-engine.md +1 -0
- package/docs/contracts/adr-wing4-context-spine.md +1 -0
- package/docs/contracts/agent-memory-contract.md +1 -0
- package/docs/contracts/agents-md-tech-stack.md +1 -0
- package/docs/contracts/audit-log-v1.md +1 -0
- package/docs/contracts/command-clusters.md +1 -0
- package/docs/contracts/command-surface-tiers.md +1 -0
- package/docs/contracts/context-paths.md +1 -0
- package/docs/contracts/cost-profile-defaults.md +105 -0
- package/docs/contracts/cross-wing-handoff.md +1 -0
- package/docs/contracts/decision-engine-gates.md +115 -0
- package/docs/contracts/decision-trace-v1.md +1 -0
- package/docs/contracts/file-ownership-matrix.md +1 -0
- package/docs/contracts/hook-architecture-v1.md +1 -0
- package/docs/contracts/implement-ticket-flow.md +1 -0
- package/docs/contracts/installed-tools-lockfile.md +1 -0
- package/docs/contracts/kernel-membership.md +1 -0
- package/docs/contracts/linear-ai-rules-inclusion.md +1 -0
- package/docs/contracts/linear-ai-three-layers.md +1 -0
- package/docs/contracts/linter-structural-model.md +1 -0
- package/docs/contracts/load-context-budget-model.md +1 -0
- package/docs/contracts/load-context-schema.md +1 -0
- package/docs/contracts/memory-visibility-v1.md +1 -0
- package/docs/contracts/one-off-script-lifecycle.md +1 -0
- package/docs/contracts/orchestration-dsl-v1.md +1 -0
- package/docs/contracts/package-self-orientation.md +1 -0
- package/docs/contracts/persona-schema.md +1 -0
- package/docs/contracts/release-trunk-sync.md +104 -0
- package/docs/contracts/roadmap-complexity-standard.md +1 -0
- package/docs/contracts/rule-classification.md +1 -0
- package/docs/contracts/rule-interactions.md +26 -0
- package/docs/contracts/rule-priority-hierarchy.md +1 -0
- package/docs/contracts/rule-router.md +1 -0
- package/docs/contracts/settings-sync-yaml-subset.md +1 -0
- package/docs/contracts/skill-domains.md +1 -0
- package/docs/contracts/tier-3-contrib-plugin.md +1 -0
- package/docs/contracts/ui-stack-extension.md +1 -0
- package/docs/contracts/ui-track-flow.md +1 -0
- package/docs/customization.md +1 -1
- package/docs/getting-started.md +3 -1
- package/docs/installation.md +8 -6
- package/package.json +1 -1
- package/scripts/ai_council/clients.py +17 -4
- package/scripts/ai_council/orchestrator.py +6 -2
- package/scripts/check_beta_review_markers.py +127 -0
- package/scripts/check_references.py +25 -0
- package/scripts/check_release_trunk_sync.py +152 -0
- package/scripts/council_cli.py +36 -5
- package/scripts/install.py +3 -3
- package/scripts/run_skill_evals.py +185 -0
- package/scripts/schemas/command.schema.json +5 -0
- package/scripts/schemas/skill.schema.json +4 -0
- package/scripts/skill_linter.py +82 -3
- package/scripts/smoke_quickstart.py +134 -0
- package/scripts/validate_decision_engine.py +124 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Decision-engine gates (v1)
|
|
2
|
+
|
|
3
|
+
**Status:** beta — landed 2026-05-14 via `road-to-productization.md` Phase 2.
|
|
4
|
+
**Owners:** `work_engine` maintainers.
|
|
5
|
+
**Scope:** the optional `decision_engine:` block in `.agent-settings.yml`.
|
|
6
|
+
|
|
7
|
+
## Purpose
|
|
8
|
+
|
|
9
|
+
Cross the package from **observable** (Level-5) to **controllable**
|
|
10
|
+
(Level-6). The engine has scored confidence-bands, risk-classes, and
|
|
11
|
+
memory-hits since Phase 4 of `road-to-decision-trace`; this contract
|
|
12
|
+
turns those signals into refusal gates the user opts into.
|
|
13
|
+
|
|
14
|
+
Absent block = unchanged behaviour. Enforcement is opt-in only; the
|
|
15
|
+
engine never silently halts on a signal the user did not configure.
|
|
16
|
+
|
|
17
|
+
## Schema
|
|
18
|
+
|
|
19
|
+
All keys optional. Unknown keys are rejected hard by
|
|
20
|
+
`scripts/validate_decision_engine.py` and by
|
|
21
|
+
`work_engine.scoring.decision_engine.parse`.
|
|
22
|
+
|
|
23
|
+
| Key | Type | Default | Notes |
|
|
24
|
+
|------------------------|-----------------|---------|-------|
|
|
25
|
+
| `surface_traces` | bool | `false` | Mirrored to `DecisionTraceHook`. Predates the gates; lives here so the block has one schema. |
|
|
26
|
+
| `min_confidence` | enum | `off` | `low` \| `medium` \| `high` \| `off`. Phase=Plan floor. |
|
|
27
|
+
| `block_on_risk` | enum | `off` | `low` \| `medium` \| `high` \| `off`. Phase=Implement ceiling. |
|
|
28
|
+
| `require_memory_hits` | bool | `false` | Phase=Refine demands `memory_hits >= 1`. |
|
|
29
|
+
| `on_block` | enum | `stop` | `stop` \| `ask` \| `warn`. Action when a gate fires. |
|
|
30
|
+
| `ask_timeout_seconds` | int (>= 0) | `30` | Non-TTY wait before applying `on_block_fallback`. |
|
|
31
|
+
| `on_block_fallback` | enum | `stop` | `stop` \| `warn`. Resolution after `ask_timeout`. |
|
|
32
|
+
|
|
33
|
+
## Gate-to-phase mapping
|
|
34
|
+
|
|
35
|
+
Each gate fires on exactly one phase. The dispatcher emits gate
|
|
36
|
+
decisions on `AFTER_STEP` for that phase only.
|
|
37
|
+
|
|
38
|
+
| Gate | Phase | Signal compared | Fires when |
|
|
39
|
+
|-----------------------|-----------|-----------------------------|-------------------------------------|
|
|
40
|
+
| `min_confidence` | Plan | `confidence_band` | actual < floor |
|
|
41
|
+
| `require_memory_hits` | Refine | `state.memory.hits` | hits < 1 |
|
|
42
|
+
| `block_on_risk` | Implement | `risk_class` | actual >= ceiling |
|
|
43
|
+
|
|
44
|
+
`low` < `medium` < `high` for both confidence and risk. `off` disables
|
|
45
|
+
the gate.
|
|
46
|
+
|
|
47
|
+
## Conflict matrix
|
|
48
|
+
|
|
49
|
+
Only one gate fires per phase, so cross-phase conflicts are impossible
|
|
50
|
+
by construction. Within a phase, **only the highest-impact gate
|
|
51
|
+
applies**; downstream gates are evaluated against the same phase but
|
|
52
|
+
skipped if a higher-priority gate already fired.
|
|
53
|
+
|
|
54
|
+
Priority (highest → lowest):
|
|
55
|
+
|
|
56
|
+
1. `block_on_risk` (Implement)
|
|
57
|
+
2. `require_memory_hits` (Refine)
|
|
58
|
+
3. `min_confidence` (Plan)
|
|
59
|
+
|
|
60
|
+
This priority surfaces only when a future schema adds gates that
|
|
61
|
+
overlap on the same phase; today each gate owns a unique phase and the
|
|
62
|
+
priority is documentary. The order is locked so future additions
|
|
63
|
+
inherit the contract.
|
|
64
|
+
|
|
65
|
+
### Worked examples
|
|
66
|
+
|
|
67
|
+
| Config | Phase | confidence | risk | hits | Outcome |
|
|
68
|
+
|---------------------------------------------------------------------------------------|-----------|------------|----------|------|----------------------------------|
|
|
69
|
+
| `min_confidence: medium` | Plan | `low` | - | - | `min_confidence` fires, action=stop |
|
|
70
|
+
| `min_confidence: medium` | Plan | `high` | - | - | no fire — band at/above floor |
|
|
71
|
+
| `block_on_risk: medium` | Implement | - | `high` | - | `block_on_risk` fires, action=stop |
|
|
72
|
+
| `block_on_risk: high` | Implement | - | `medium` | - | no fire — below ceiling |
|
|
73
|
+
| `require_memory_hits: true` | Refine | - | - | 0 | `require_memory_hits` fires |
|
|
74
|
+
| `require_memory_hits: true` | Refine | - | - | 2 | no fire |
|
|
75
|
+
| `min_confidence: high, block_on_risk: low, require_memory_hits: true` (all on) | Plan | `low` | `low` | 0 | `min_confidence` fires (Plan-owning gate) — Refine/Implement gates inert this phase |
|
|
76
|
+
|
|
77
|
+
## Non-TTY timeout protocol
|
|
78
|
+
|
|
79
|
+
`on_block=ask` is interactive. In a non-interactive context the
|
|
80
|
+
engine cannot block waiting for keystrokes that will never arrive.
|
|
81
|
+
Detection follows two signals (either disables interactivity):
|
|
82
|
+
|
|
83
|
+
- environment variable `CI` set to `1`, `true`, `yes` (case-insensitive)
|
|
84
|
+
- `sys.stdin.isatty()` or `sys.stdout.isatty()` returns false
|
|
85
|
+
|
|
86
|
+
When non-interactive, `on_block=ask` collapses to action `ask_timeout`.
|
|
87
|
+
The consumer (CLI / dispatcher) is expected to:
|
|
88
|
+
|
|
89
|
+
1. wait `ask_timeout_seconds` for a stdin response;
|
|
90
|
+
2. apply `on_block_fallback` (`stop` or `warn`) when the timeout
|
|
91
|
+
elapses or stdin is closed;
|
|
92
|
+
3. surface `block_reason=ask_timeout` on the decision trace so the
|
|
93
|
+
reason is replay-visible.
|
|
94
|
+
|
|
95
|
+
Default fallback is `stop` (fail-safe). Flip to `warn` only when CI
|
|
96
|
+
explicitly wants advisory gates.
|
|
97
|
+
|
|
98
|
+
## Rollback
|
|
99
|
+
|
|
100
|
+
The block is config-only. Remove the `decision_engine:` block and
|
|
101
|
+
the engine reverts to observe-only behaviour — no migration, no DB
|
|
102
|
+
state, no schema lock. Per-key removal also works (each key has a
|
|
103
|
+
safe default).
|
|
104
|
+
|
|
105
|
+
## Test surface
|
|
106
|
+
|
|
107
|
+
Coverage lives in `tests/work_engine/scoring/test_decision_engine.py`:
|
|
108
|
+
|
|
109
|
+
- schema parser: defaults, unknown-key rejection, bad-type rejection;
|
|
110
|
+
- gate evaluation: per-phase, per-signal, conflict isolation;
|
|
111
|
+
- TTY detection: env-var detection, fallback to `ask_timeout`;
|
|
112
|
+
- action resolution: `stop` / `warn` short-circuit interactivity.
|
|
113
|
+
|
|
114
|
+
Wiring tests (dispatcher + hook) live in
|
|
115
|
+
`tests/work_engine/test_decision_gate_hook.py`.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
keep-beta-until: 2026-08-12
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ADR — Release-trunk sync: main fast-forwards on every tag
|
|
7
|
+
|
|
8
|
+
> **Status:** Decided · 2026-05-14
|
|
9
|
+
> **Context:** PR #43 feedback (Level-5/6 product rating) and PR #143
|
|
10
|
+
> revealed `main` lagging the latest tag by N skills + rules at multiple
|
|
11
|
+
> points across the 2.x cycle. External readers landing on `main`
|
|
12
|
+
> consistently saw stale README counts and missing skill catalogues
|
|
13
|
+
> relative to the npm/Packagist artefact.
|
|
14
|
+
> **Closes:** [Road to Productization](../../agents/roadmaps/road-to-productization.md) § P1.2.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
Every tagged release (`X.Y.Z`) **fast-forwards `main` to the tag's
|
|
19
|
+
commit as the final step of the release pipeline**. No exceptions. No
|
|
20
|
+
grace period.
|
|
21
|
+
|
|
22
|
+
The fast-forward is owned by [`scripts/release.py`](../../scripts/release.py)
|
|
23
|
+
and runs after the GitHub Release is published. The release pipeline
|
|
24
|
+
is **not green** until `main == <new-tag>` at the remote.
|
|
25
|
+
|
|
26
|
+
`main` is therefore a **moving stable trunk pointer**, not a feature
|
|
27
|
+
branch. External readers (README, AGENTS.md, marketplace metadata, npm
|
|
28
|
+
tarball provenance) reading `main` see the artefact that was last
|
|
29
|
+
published, not work-in-progress.
|
|
30
|
+
|
|
31
|
+
## Protocol
|
|
32
|
+
|
|
33
|
+
1. `scripts/release.py` cuts `release/X.Y.Z`, bumps version files,
|
|
34
|
+
opens a release PR against `main`, waits for CI, merges.
|
|
35
|
+
2. The merge commit on `main` becomes the tag's commit; the tag is
|
|
36
|
+
pushed.
|
|
37
|
+
3. `publish-npm.yml` and the marketplace flow trigger on the tag.
|
|
38
|
+
4. The release pipeline asserts `git rev-parse origin/main ==
|
|
39
|
+
git rev-parse refs/tags/X.Y.Z` before exit-0.
|
|
40
|
+
5. If a hotfix lands on `release/X.Y.Z` after step 1 but before step 4,
|
|
41
|
+
the FF still happens — release-branch commits are part of the
|
|
42
|
+
release, not a separate trunk.
|
|
43
|
+
|
|
44
|
+
### Why fast-forward, not merge
|
|
45
|
+
|
|
46
|
+
Fast-forward keeps `main` linear with the tag history. A merge-commit
|
|
47
|
+
on top of the tag would put `main` at a SHA that is **not** the tag's
|
|
48
|
+
SHA, re-introducing the exact divergence this contract closes.
|
|
49
|
+
|
|
50
|
+
If a fast-forward is impossible (force-push to `main`, divergent
|
|
51
|
+
history, abandoned release-prep), the pipeline **fails loudly**; the
|
|
52
|
+
operator either resets `main` manually with an audit trail or aborts
|
|
53
|
+
the release.
|
|
54
|
+
|
|
55
|
+
## CI Gate (P1.3)
|
|
56
|
+
|
|
57
|
+
[`scripts/check_release_trunk_sync.py`](../../scripts/check_release_trunk_sync.py)
|
|
58
|
+
runs on every `release/X.Y.Z` branch (detected by `git rev-parse
|
|
59
|
+
--abbrev-ref HEAD` matching `^release/\d+\.\d+\.\d+$`).
|
|
60
|
+
|
|
61
|
+
It enforces: **`main` is at most ONE tagged release behind the
|
|
62
|
+
release-prep branch's target version.**
|
|
63
|
+
|
|
64
|
+
- On `release/2.11.0`: `main` may be at `2.10.0` or `2.11.0`. `2.9.0`
|
|
65
|
+
or older → **hard fail**.
|
|
66
|
+
- On any other branch class (feature, fix, chore, docs, the agent's
|
|
67
|
+
own `feat/road-to-productization` branch): the check is a **no-op**
|
|
68
|
+
exit-0 — feature branches never trip the gate.
|
|
69
|
+
- Wired into `task ci` as `check-release-trunk-sync`. No warning-only
|
|
70
|
+
mode; the exit code is the gate.
|
|
71
|
+
|
|
72
|
+
### Bootstrap mode
|
|
73
|
+
|
|
74
|
+
When the repo state does not yet match the gate (transitional first
|
|
75
|
+
run after this contract lands), the check reads
|
|
76
|
+
`docs/contracts/release-trunk-sync.bootstrap` for an opt-out window
|
|
77
|
+
keyed by current version. The bootstrap file is purged at the next
|
|
78
|
+
release. Absence of the file = gate is live.
|
|
79
|
+
|
|
80
|
+
## Rollback
|
|
81
|
+
|
|
82
|
+
Revertible by removing `check-release-trunk-sync` from `Taskfile.yml`
|
|
83
|
+
and deleting `scripts/check_release_trunk_sync.py`. No state, no
|
|
84
|
+
schema, no migration. Branch-detection key (`release/X.Y.Z`) is
|
|
85
|
+
already used by `scripts/release.py` so removing this contract does
|
|
86
|
+
not orphan the convention.
|
|
87
|
+
|
|
88
|
+
## Risks
|
|
89
|
+
|
|
90
|
+
| # | Risk | Mitigation |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| 1 | Gate fires on feature branches mid-PR | Branch-name regex; non-`release/` branches no-op exit-0 |
|
|
93
|
+
| 2 | Hotfix release leaves `main` behind | FF runs **after** hotfix commits land on the release branch |
|
|
94
|
+
| 3 | Manual tag (no `scripts/release.py`) skips the FF | Out of scope of this contract — covered by `release-guard.yml` which fails on tag/version mismatch; manual tags already break the pipeline |
|
|
95
|
+
| 4 | Detached HEAD or shallow checkout breaks detection | Check gracefully exits-0 with a `::warning::` line when `git rev-parse --abbrev-ref HEAD == HEAD` (detached) |
|
|
96
|
+
|
|
97
|
+
## See also
|
|
98
|
+
|
|
99
|
+
- [`scripts/release.py`](../../scripts/release.py) — release pipeline owner.
|
|
100
|
+
- [`.github/workflows/release-guard.yml`](../../.github/workflows/release-guard.yml)
|
|
101
|
+
— tag/version-file integrity gate (orthogonal: this contract handles
|
|
102
|
+
trunk position, release-guard handles version-string integrity).
|
|
103
|
+
- [`agents/roadmaps/road-to-productization.md`](../../agents/roadmaps/road-to-productization.md)
|
|
104
|
+
§ Phase 1.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
stability: beta
|
|
3
|
+
keep-beta-until: 2026-08-12
|
|
3
4
|
---
|
|
4
5
|
|
|
5
6
|
# Rule-Interaction Matrix
|
|
@@ -99,6 +100,31 @@ junior (yields). For `complements`, ordering is documentary only.
|
|
|
99
100
|
in the rule files.
|
|
100
101
|
- Skill ↔ rule interactions — the matrix is rule-only. Skills are
|
|
101
102
|
invoked, not always-active.
|
|
103
|
+
- **Orchestration-layer surfaces** (AI Council, Memory, Work-Engine /
|
|
104
|
+
Decision-Engine): these are runtime systems, not `always`-rules.
|
|
105
|
+
Their interactions are governed by their own contracts and stay
|
|
106
|
+
out of this matrix by design — see "Out of scope" below.
|
|
107
|
+
|
|
108
|
+
## Out of scope — orchestration surfaces (Council × Memory × Work-Engine)
|
|
109
|
+
|
|
110
|
+
The matrix is **rule-only**. The orchestration layer is governed by
|
|
111
|
+
dedicated contracts; cross-referencing them here would duplicate the
|
|
112
|
+
source of truth and weaken it. Canonical contracts:
|
|
113
|
+
|
|
114
|
+
| Surface | Canonical contract |
|
|
115
|
+
|---|---|
|
|
116
|
+
| Decision-Engine gates (`min_confidence`, `block_on_risk`, `require_memory_hits`, `on_block`) | [`decision-engine-gates.md`](decision-engine-gates.md) |
|
|
117
|
+
| Decision-trace shape (what the engine emits per phase) | [`decision-trace-v1.md`](decision-trace-v1.md) |
|
|
118
|
+
| Memory contract (entries, scopes, retention) | [`agent-memory-contract.md`](agent-memory-contract.md) |
|
|
119
|
+
| Memory visibility in the trace (`affected` keys) | [`memory-visibility-v1.md`](memory-visibility-v1.md) |
|
|
120
|
+
| AI-Council consultation flow | [`../skills/ai-council/SKILL.md`](../../.agent-src.uncompressed/skills/ai-council/SKILL.md) |
|
|
121
|
+
|
|
122
|
+
Where an `always`-rule **does** interact with one of these surfaces
|
|
123
|
+
(e.g. `non-destructive-by-default` gating a memory-driven action), the
|
|
124
|
+
gate lives in the rule and the precedence is captured in this matrix
|
|
125
|
+
as a rule-pair (the orchestration surface is the *occasion*, not a
|
|
126
|
+
participant). For Council ↔ Memory ↔ Work-Engine interactions among
|
|
127
|
+
themselves, the dedicated contracts above are authoritative.
|
|
102
128
|
|
|
103
129
|
## See also
|
|
104
130
|
|
package/docs/customization.md
CHANGED
|
@@ -139,7 +139,7 @@ Rules:
|
|
|
139
139
|
| Setting | Default | Description |
|
|
140
140
|
|---|---|---|
|
|
141
141
|
| `agent_config_version` | *(empty)* | Exact semver pin of the agent-config release (see above). Empty = unpinned. |
|
|
142
|
-
| `cost_profile` | `
|
|
142
|
+
| `cost_profile` | `balanced` | Token budget (`minimal`, `balanced`, `full`, `custom`) — rationale: [`docs/contracts/cost-profile-defaults.md`](contracts/cost-profile-defaults.md) |
|
|
143
143
|
| `personal.user_name` | *(empty)* | User's first name for personalized responses |
|
|
144
144
|
| `personal.minimal_output` | `true` | Suppress intermediate output |
|
|
145
145
|
| `personal.play_by_play` | `false` | Share intermediate findings during analysis |
|
package/docs/getting-started.md
CHANGED
|
@@ -123,9 +123,11 @@ The system supports four configuration profiles:
|
|
|
123
123
|
Set your profile in `.agent-settings.yml`:
|
|
124
124
|
|
|
125
125
|
```yaml
|
|
126
|
-
cost_profile:
|
|
126
|
+
cost_profile: balanced
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
`balanced` is the default — kernel + tier-1 auto-rules. Rationale:
|
|
130
|
+
[`docs/contracts/cost-profile-defaults.md`](contracts/cost-profile-defaults.md).
|
|
129
131
|
You can override any individual setting. See [Customization](customization.md) for details.
|
|
130
132
|
|
|
131
133
|
---
|
package/docs/installation.md
CHANGED
|
@@ -240,8 +240,8 @@ wrapper (`./agent-config`) can fall through to it when no
|
|
|
240
240
|
The orchestrator chains payload sync and bridge generation:
|
|
241
241
|
|
|
242
242
|
```bash
|
|
243
|
-
bash scripts/install # defaults to cost_profile=
|
|
244
|
-
bash scripts/install --profile=
|
|
243
|
+
bash scripts/install # defaults to cost_profile=balanced
|
|
244
|
+
bash scripts/install --profile=minimal
|
|
245
245
|
bash scripts/install --force # overwrite existing bridges
|
|
246
246
|
bash scripts/install --skip-bridges # payload only
|
|
247
247
|
bash scripts/install --skip-sync # bridges only
|
|
@@ -287,7 +287,7 @@ regardless of which AI tool they use.** No per-developer plugin installation nee
|
|
|
287
287
|
After initial setup, commit these files:
|
|
288
288
|
|
|
289
289
|
```
|
|
290
|
-
.agent-settings.yml ← shared profile (e.g., cost_profile:
|
|
290
|
+
.agent-settings.yml ← shared profile (e.g., cost_profile: balanced)
|
|
291
291
|
agents/installed-tools.lock ← AI bill of materials (ADR-008, Phase 3)
|
|
292
292
|
.augment/ ← rules, skills, commands (symlinks)
|
|
293
293
|
.cursor/rules/ ← Cursor rules (symlinks)
|
|
@@ -517,16 +517,18 @@ The system works immediately with sensible defaults. Optionally, create `.agent-
|
|
|
517
517
|
to choose a profile:
|
|
518
518
|
|
|
519
519
|
```yaml
|
|
520
|
-
cost_profile:
|
|
520
|
+
cost_profile: balanced
|
|
521
521
|
```
|
|
522
522
|
|
|
523
523
|
| Profile | What's active | For whom |
|
|
524
524
|
|---|---|---|
|
|
525
|
-
| `minimal`
|
|
525
|
+
| `minimal` | Kernel only — Iron-Law floor, zero router | Token-constrained agents |
|
|
526
526
|
| `balanced` | + Runtime dispatcher + shell handler | Most teams |
|
|
527
527
|
| `full` | + Tool adapters (GitHub, Jira) | Platform teams |
|
|
528
528
|
|
|
529
|
-
No profile configured = `
|
|
529
|
+
No profile configured = `balanced` behavior (default). Rationale:
|
|
530
|
+
[`docs/contracts/cost-profile-defaults.md`](contracts/cost-profile-defaults.md).
|
|
531
|
+
→ [Full profile details](customization.md)
|
|
530
532
|
|
|
531
533
|
---
|
|
532
534
|
|
package/package.json
CHANGED
|
@@ -53,6 +53,19 @@ def _resolve_key_path(filename: str) -> Path:
|
|
|
53
53
|
DEFAULT_ANTHROPIC_MODEL = "claude-sonnet-4-5"
|
|
54
54
|
DEFAULT_OPENAI_MODEL = "gpt-4o"
|
|
55
55
|
|
|
56
|
+
#: Per-call output budget when no caller-supplied value reaches `ask()`.
|
|
57
|
+
#: The CLI resolves the live default from `ai_council.max_output_tokens`
|
|
58
|
+
#: in `.agent-settings.yml`; this constant is only the abstract-base /
|
|
59
|
+
#: direct-API fallback when nothing else is wired up.
|
|
60
|
+
DEFAULT_MAX_TOKENS = 2048
|
|
61
|
+
|
|
62
|
+
#: Expansion target when the user sets `max_output_tokens: 0` ("unlimited")
|
|
63
|
+
#: in settings. Anthropic requires `max_tokens` to be a positive integer,
|
|
64
|
+
#: so 0 is widened to this safe ceiling before the SDK call. Big enough
|
|
65
|
+
#: for current frontier models (Sonnet/GPT-4o headroom ≥ 16k); raise
|
|
66
|
+
#: explicitly in settings if a larger budget is genuinely needed.
|
|
67
|
+
UNLIMITED_TOKENS_FALLBACK = 16384
|
|
68
|
+
|
|
56
69
|
# OpenAI reasoning models (o1, o3, o4 families) reject `max_tokens` and the
|
|
57
70
|
# `system` role; they require `max_completion_tokens` and accept only `user`
|
|
58
71
|
# (and `developer`) messages.
|
|
@@ -128,7 +141,7 @@ class ExternalAIClient(ABC):
|
|
|
128
141
|
self,
|
|
129
142
|
system_prompt: str,
|
|
130
143
|
user_prompt: str,
|
|
131
|
-
max_tokens: int =
|
|
144
|
+
max_tokens: int = DEFAULT_MAX_TOKENS,
|
|
132
145
|
) -> CouncilResponse:
|
|
133
146
|
"""Send one independent query. Must never raise on network/API
|
|
134
147
|
failure — return a `CouncilResponse` with `error` set instead.
|
|
@@ -162,7 +175,7 @@ class AnthropicClient(ExternalAIClient):
|
|
|
162
175
|
) from exc
|
|
163
176
|
self._client = anthropic.Anthropic(api_key=api_key)
|
|
164
177
|
|
|
165
|
-
def ask(self, system_prompt: str, user_prompt: str, max_tokens: int =
|
|
178
|
+
def ask(self, system_prompt: str, user_prompt: str, max_tokens: int = DEFAULT_MAX_TOKENS) -> CouncilResponse:
|
|
166
179
|
t0 = time.monotonic()
|
|
167
180
|
try:
|
|
168
181
|
response = self._client.messages.create(
|
|
@@ -218,7 +231,7 @@ class OpenAIClient(ExternalAIClient):
|
|
|
218
231
|
) from exc
|
|
219
232
|
self._client = openai.OpenAI(api_key=api_key)
|
|
220
233
|
|
|
221
|
-
def ask(self, system_prompt: str, user_prompt: str, max_tokens: int =
|
|
234
|
+
def ask(self, system_prompt: str, user_prompt: str, max_tokens: int = DEFAULT_MAX_TOKENS) -> CouncilResponse:
|
|
222
235
|
t0 = time.monotonic()
|
|
223
236
|
kwargs: dict[str, object] = {"model": self.model}
|
|
224
237
|
if _is_reasoning_model(self.model):
|
|
@@ -316,7 +329,7 @@ class ManualClient(ExternalAIClient):
|
|
|
316
329
|
self,
|
|
317
330
|
system_prompt: str,
|
|
318
331
|
user_prompt: str,
|
|
319
|
-
max_tokens: int =
|
|
332
|
+
max_tokens: int = DEFAULT_MAX_TOKENS, # noqa: ARG002 — accepted for ABC parity
|
|
320
333
|
) -> CouncilResponse:
|
|
321
334
|
t0 = time.monotonic()
|
|
322
335
|
rounds: list[str] = []
|
|
@@ -27,7 +27,11 @@ from scripts.ai_council.budget_guard import (
|
|
|
27
27
|
today_spend_usd as _today_spend_usd,
|
|
28
28
|
would_exceed as _would_exceed_daily,
|
|
29
29
|
)
|
|
30
|
-
from scripts.ai_council.clients import
|
|
30
|
+
from scripts.ai_council.clients import (
|
|
31
|
+
DEFAULT_MAX_TOKENS,
|
|
32
|
+
CouncilResponse,
|
|
33
|
+
ExternalAIClient,
|
|
34
|
+
)
|
|
31
35
|
from scripts.ai_council.pricing import (
|
|
32
36
|
CostEstimate,
|
|
33
37
|
PriceTable,
|
|
@@ -51,7 +55,7 @@ class CostBudget:
|
|
|
51
55
|
class CouncilQuestion:
|
|
52
56
|
mode: str # one of: prompt, roadmap, diff, files
|
|
53
57
|
user_prompt: str # bundled artefact text
|
|
54
|
-
max_tokens: int =
|
|
58
|
+
max_tokens: int = DEFAULT_MAX_TOKENS
|
|
55
59
|
|
|
56
60
|
|
|
57
61
|
@dataclass
|