@event4u/agent-config 2.18.0 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/.agent-src/commands/agent-status.md +29 -0
  2. package/.agent-src/commands/onboard.md +221 -81
  3. package/.agent-src/commands/refine-ticket.md +3 -0
  4. package/.agent-src/packs/README.md +49 -0
  5. package/.agent-src/packs/agency-delivery.yml +63 -0
  6. package/.agent-src/packs/content-engine.yml +53 -0
  7. package/.agent-src/packs/founder-mvp.yml +51 -0
  8. package/.agent-src/personas/README.md +8 -0
  9. package/.agent-src/presets/README.md +26 -0
  10. package/.agent-src/presets/balanced.yml +34 -0
  11. package/.agent-src/presets/fast.yml +31 -0
  12. package/.agent-src/presets/strict.yml +38 -0
  13. package/.agent-src/profiles/README.md +29 -0
  14. package/.agent-src/profiles/agency.yml +27 -0
  15. package/.agent-src/profiles/content_creator.yml +25 -0
  16. package/.agent-src/profiles/developer.yml +26 -0
  17. package/.agent-src/profiles/finance.yml +24 -0
  18. package/.agent-src/profiles/founder.yml +25 -0
  19. package/.agent-src/profiles/ops.yml +25 -0
  20. package/.agent-src/rules/no-cheap-questions.md +25 -17
  21. package/.agent-src/skills/adr-create/SKILL.md +78 -68
  22. package/.agent-src/skills/refine-ticket/SKILL.md +3 -0
  23. package/.agent-src/skills/subagent-orchestration/SKILL.md +33 -0
  24. package/.agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  25. package/.agent-src/templates/skill-archive-note.md +101 -0
  26. package/.agent-src/user-types/README.md +124 -0
  27. package/.agent-src/user-types/_template/user-type.md +95 -0
  28. package/.agent-src/user-types/galabau-field-crew.md +100 -0
  29. package/.agent-src/user-types/metalworking-shop.md +105 -0
  30. package/.agent-src/user-types/truck-driver.md +113 -0
  31. package/.claude-plugin/marketplace.json +1 -1
  32. package/CHANGELOG.md +91 -30
  33. package/README.md +68 -72
  34. package/config/agent-settings.template.yml +22 -0
  35. package/docs/adrs/caveman/0001-default-off-until-bench.md +93 -0
  36. package/docs/adrs/caveman/README.md +9 -0
  37. package/docs/adrs/cost/0001-hard-stop-hook.md +114 -0
  38. package/docs/adrs/cost/README.md +9 -0
  39. package/docs/adrs/memory/0001-consumer-side-snapshot.md +111 -0
  40. package/docs/adrs/memory/README.md +9 -0
  41. package/docs/adrs/router/0001-three-tier-routing.md +119 -0
  42. package/docs/adrs/router/README.md +9 -0
  43. package/docs/adrs/schema/0001-json-schema-frontmatter.md +102 -0
  44. package/docs/adrs/schema/README.md +9 -0
  45. package/docs/adrs/smoke/0001-per-tier-smoke-scripts.md +99 -0
  46. package/docs/adrs/smoke/README.md +9 -0
  47. package/docs/architecture/current-onboard-baseline.md +126 -0
  48. package/docs/architecture/current-safety-behavior.md +137 -0
  49. package/docs/archive/CHANGELOG-pre-2.16.0.md +48 -0
  50. package/docs/contracts/adr-layout.md +108 -0
  51. package/docs/contracts/adr-mcp-runtime.md +128 -0
  52. package/docs/contracts/adr-user-types-axis.md +127 -0
  53. package/docs/contracts/benchmark-corpus-spec.md +97 -0
  54. package/docs/contracts/benchmark-report-schema.md +111 -0
  55. package/docs/contracts/command-clusters.md +1 -0
  56. package/docs/contracts/command-taxonomy.md +137 -0
  57. package/docs/contracts/compression-default-kill-criterion.md +69 -0
  58. package/docs/contracts/config-presets.md +144 -0
  59. package/docs/contracts/cost-dashboard.md +143 -0
  60. package/docs/contracts/cost-enforcement.md +134 -0
  61. package/docs/contracts/file-ownership-matrix.json +0 -7
  62. package/docs/contracts/mcp-tool-inventory.md +53 -0
  63. package/docs/contracts/measurement-baseline.md +102 -0
  64. package/docs/contracts/namespace.md +125 -0
  65. package/docs/contracts/profile-system.md +142 -0
  66. package/docs/contracts/safety-model.md +129 -0
  67. package/docs/contracts/smoke-contracts.md +144 -0
  68. package/docs/contracts/user-type-schema.md +146 -0
  69. package/docs/contracts/workflow-packs.md +121 -0
  70. package/docs/decisions/ADR-010-profile-pack-preset-boundary.md +132 -0
  71. package/docs/decisions/INDEX.md +1 -0
  72. package/docs/featured-commands.md +27 -0
  73. package/docs/parity/bench-ruflo.json +58 -0
  74. package/docs/parity/bench.json +41 -0
  75. package/docs/parity/ruflo.md +46 -0
  76. package/docs/profiles.md +91 -0
  77. package/docs/recruits/_template.md +81 -0
  78. package/package.json +1 -1
  79. package/scripts/_cli/cmd_explain.py +250 -0
  80. package/scripts/_lib/bench_cost.py +138 -0
  81. package/scripts/_lib/bench_quality.py +118 -0
  82. package/scripts/_lib/bench_report.py +150 -0
  83. package/scripts/agent-config +13 -0
  84. package/scripts/audit_adr_coverage.py +175 -0
  85. package/scripts/audit_mcp_tools.py +146 -0
  86. package/scripts/bench_baseline_ready.py +108 -0
  87. package/scripts/bench_drift_check.py +151 -0
  88. package/scripts/bench_per_tool.py +216 -0
  89. package/scripts/bench_run.py +155 -0
  90. package/scripts/compress.py +48 -2
  91. package/scripts/config/__init__.py +9 -0
  92. package/scripts/config/presets.py +206 -0
  93. package/scripts/config/profiles.py +173 -0
  94. package/scripts/cost/budget.mjs +73 -12
  95. package/scripts/cost/preflight.mjs +89 -0
  96. package/scripts/lint_archived_skills.py +143 -0
  97. package/scripts/lint_bench_corpus.py +161 -0
  98. package/scripts/lint_namespace.py +135 -0
  99. package/scripts/schemas/user-type.schema.json +35 -0
  100. package/scripts/skill_linter.py +139 -4
  101. package/scripts/skill_overlap.py +204 -0
  102. package/scripts/skill_tools/audit_user_type_coverage.py +148 -0
  103. package/scripts/skill_usage_collect.py +191 -0
  104. package/scripts/skill_usage_report.py +162 -0
  105. package/scripts/smoke/kernel.sh +101 -0
  106. package/scripts/smoke/router.sh +129 -0
  107. package/scripts/smoke/schema.sh +71 -0
  108. package/scripts/smoke/skills.sh +101 -0
@@ -0,0 +1,114 @@
1
+ # ADR 0001 — Hard-stop hook surface
2
+
3
+ > Area: `cost` · Status: accepted · Date: 2026-05-16 · Type: retrospective
4
+ > Roadmap: `agents/roadmaps/step-11-ruflo-parity.md` Phase 2 Step 3
5
+
6
+ ## Context
7
+
8
+ `step-11-measurement-governance-parity` Phase 2 lands a 5-tier budget
9
+ ladder (`OK / INFO / WARNING / CRITICAL / HARD_STOP`) evaluated by
10
+ [`scripts/cost/budget.mjs`](../../../scripts/cost/budget.mjs). The
11
+ roadmap requires that the `HARD_STOP` tier fail closed when the user
12
+ opts into `cost.enforcement: hard-stop` — without changing the
13
+ default-on advisory experience.
14
+
15
+ This package is a governance layer, not a runtime orchestrator (see
16
+ [`step-11`](../../../agents/roadmaps/step-11-ruflo-parity.md) scope
17
+ boundary). The hook must therefore live at a **process-entry seam**,
18
+ not inside the rule-loader, agent dispatcher, or per-tool-call
19
+ interceptor — none of those exist in this codebase by design.
20
+
21
+ ## Decision
22
+
23
+ Land a single shell-entry preflight script:
24
+ [`scripts/cost/preflight.mjs`](../../../scripts/cost/preflight.mjs).
25
+
26
+ ### Surface
27
+
28
+ - **Where it fires:** any shell or CI wrapper that opts in by calling
29
+ `task cost:preflight` (or `node scripts/cost/preflight.mjs`) before
30
+ composing a turn. Not auto-injected anywhere.
31
+ - **What it does:** wraps `budget.mjs check`. Reads `cost.enforcement`
32
+ from `.agent-settings.yml`. Exits non-zero **only** when
33
+ `enforcement: hard-stop` **and** `level: HARD_STOP`.
34
+ - **Refusal output:** human-readable refusal block citing
35
+ [`docs/contracts/cost-enforcement.md`](../../contracts/cost-enforcement.md)
36
+ with the three bypass paths (raise budget · reset ledger · disable
37
+ enforcement). Machine-readable equivalent on `PREFLIGHT_QUIET=1`.
38
+
39
+ ### Default behaviour without a budget
40
+
41
+ When `cost.budgets.{daily,weekly,monthly}` are all `0`:
42
+
43
+ - `preflight.mjs` exits `0`. Always.
44
+ - This is the **fail-open default**. Unconfigured projects never get
45
+ blocked.
46
+
47
+ ### Bypass
48
+
49
+ Three options, all documented in the refusal block and the contract:
50
+
51
+ 1. **Raise the budget** — edit `.agent-settings.yml § cost.budgets`.
52
+ 2. **Reset the ledger** — `node scripts/cost/track.mjs reset` (drops
53
+ historical spend from utilization).
54
+ 3. **Disable enforcement** — set `cost.enforcement: advisory`.
55
+
56
+ No env-var override. Bypass is durable and auditable.
57
+
58
+ ## Considered alternatives
59
+
60
+ ### Alt 1 — Rule-loader hook (rejected)
61
+
62
+ Refuse to compose the turn-start preamble in the kernel-rule loader.
63
+
64
+ **Why rejected:** the kernel-rule loader is a static-projection step
65
+ (`scripts/sync.py` writes `.agent-src/rules/` from
66
+ `.agent-src.uncompressed/`). There is no live loader at turn-start to
67
+ hook — Claude / Augment / etc. read the projected files directly. A
68
+ "refusal" would have to be baked into the file content, which mixes
69
+ policy enforcement with documentation. Out of scope.
70
+
71
+ ### Alt 2 — `/onboard` boot path (rejected)
72
+
73
+ Block `/onboard` when over budget.
74
+
75
+ **Why rejected:** `/onboard` is a one-shot install path. Blocking it
76
+ when the **historical** spend exceeds the **new** budget creates a
77
+ chicken-and-egg lock-out. Onboarding must never fail-closed.
78
+
79
+ ### Alt 3 — Per-tool-call interceptor (rejected)
80
+
81
+ Wrap every tool call with a budget check.
82
+
83
+ **Why rejected:** this package doesn't intercept tool calls. Building
84
+ that would require a runtime engine — the explicit Non-goal of
85
+ `step-11` (see scope boundary). This is the Ruflo-style runtime
86
+ absorption we ruled out.
87
+
88
+ ### Alt 4 — Single-shell-entry preflight (accepted)
89
+
90
+ The chosen surface. Opt-in by wrapper invocation; predictable; no
91
+ runtime, no projection coupling, no chicken-and-egg edges. Matches the
92
+ governance-layer charter.
93
+
94
+ ## Consequences
95
+
96
+ - **Positive:** consumers who want fail-closed behaviour get it with
97
+ one settings flip + one task invocation. The default-on experience
98
+ is unchanged. No runtime is introduced. The hook composes with `task
99
+ ci`, `task work:*`, or any shell wrapper the consumer chooses.
100
+ - **Negative:** the hook is **opt-in by wrapper**. A consumer who sets
101
+ `enforcement: hard-stop` but never invokes `task cost:preflight`
102
+ gets no enforcement. Documented as a known limitation; mitigated by
103
+ surfacing the gap in `agent-status`.
104
+ - **Reversal cost:** flip `cost.enforcement: advisory` globally, or
105
+ remove the `task cost:preflight` call from wrappers. Hook becomes
106
+ inert with no code change.
107
+
108
+ ## References
109
+
110
+ - [`docs/contracts/cost-enforcement.md`](../../contracts/cost-enforcement.md) — contract surface.
111
+ - [`scripts/cost/budget.mjs`](../../../scripts/cost/budget.mjs) — evaluator.
112
+ - [`scripts/cost/preflight.mjs`](../../../scripts/cost/preflight.mjs) — this hook.
113
+ - [`agents/roadmaps/step-11-ruflo-parity.md`](../../../agents/roadmaps/step-11-ruflo-parity.md) Phase 2 Step 3 — origin.
114
+ - [`agents/audit-2026-05-14-north-star/external-findings.md`](../../../agents/audit-2026-05-14-north-star/external-findings.md) § 2 row "hard stop" — upstream Ruflo pattern this absorbs.
@@ -0,0 +1,9 @@
1
+ # ADRs — `cost`
2
+
3
+ > Budget ladder, hard-stop hook, cost reporting and dashboards.
4
+
5
+ Contract: [`docs/contracts/cost-enforcement.md`](../../../docs/contracts/cost-enforcement.md).
6
+
7
+ | # | Title | Status | Date | Supersedes |
8
+ |---|---|---|---|---|
9
+ | [0001](0001-hard-stop-hook.md) | Hard Stop Hook | — | — | — |
@@ -0,0 +1,111 @@
1
+ # ADR 0001 — Consumer-side snapshot of the agent-memory contract
2
+
3
+ > Area: `memory` · Status: accepted · Date: 2026-05-16 · Type: retrospective
4
+ > Roadmap: `agents/roadmaps/step-11-ruflo-parity.md` Phase 4 Step 3
5
+ > Supersedes: —
6
+
7
+ ## Context
8
+
9
+ `@event4u/agent-memory` is a sibling package owned by this team. It
10
+ provides MCP-server semantic-retrieval plus a v1 retrieval envelope
11
+ (`id`, `type`, `source`, `confidence`, `body`, …). The spec-side
12
+ source-of-truth lives in
13
+ [`agents/roadmaps/archive/agent-memory/`](../../../agents/roadmaps/archive/agent-memory/);
14
+ the implementation lives in the sibling repo.
15
+
16
+ The question this ADR records is: **what surface does `agent-config`
17
+ freeze internally**, given the package ships independently and the
18
+ two repos can drift between releases?
19
+
20
+ ## Decision
21
+
22
+ **Maintain a consumer-side snapshot at
23
+ [`docs/contracts/agent-memory-contract.md`](../../contracts/agent-memory-contract.md)** —
24
+ a point-in-time pin of the interface `agent-config`'s wired code
25
+ **currently assumes**.
26
+
27
+ ### Three expected backend states
28
+
29
+ Probed by [`scripts/memory_status.py`](../../../scripts/memory_status.py):
30
+
31
+ | Status | Meaning | Agent-config behaviour |
32
+ |---|---|---|
33
+ | `absent` | Package not installed / CLI not on PATH | File fallback only |
34
+ | `misconfigured` | Installed; `health()` fails within 2 s | Warn once per session, fall back to file |
35
+ | `present` | Installed; healthy within 2 s | Route retrieval through package |
36
+
37
+ Detection is **bounded** (≤ 2 s cold probe), **cached per process**,
38
+ **non-raising** on probe failure.
39
+
40
+ ### CLI candidates
41
+
42
+ Probed in `_CLI_CANDIDATES`: `memory` (canonical, v1.1+) ·
43
+ `agent-memory` (planned alias) · `agentmem` (legacy). If the released
44
+ package diverges from these names, this file updates — never the
45
+ other way round.
46
+
47
+ ### Retrieval envelope (v1)
48
+
49
+ Mandatory per entry: `id`, `type`, `source ∈ {repo, operational}`,
50
+ `confidence`, `body`. Optional: `trust`, `last_validated`,
51
+ `shadowed_by`. Envelope: `contract_version`, `status ∈ {ok, partial,
52
+ error}`, `entries`, `slices`, `errors`. Source-of-truth:
53
+ [`scripts/memory_lookup.py`](../../../scripts/memory_lookup.py)
54
+ lines 320–345.
55
+
56
+ ### Refresh policy
57
+
58
+ The snapshot doc carries a `Last refreshed:` line. On every sibling
59
+ package release that touches the CLI or envelope shape, the
60
+ maintainer:
61
+
62
+ 1. Runs the sibling package's CLI against `agent-config`'s test
63
+ fixtures.
64
+ 2. Updates this contract doc with the new shape, bumps
65
+ `Last refreshed:`, files the diff as a PR.
66
+ 3. Updates `_CLI_CANDIDATES` and any consumer skills only if the
67
+ shape diff is breaking.
68
+
69
+ ## Considered alternatives
70
+
71
+ ### Alt 1 — No internal pin; trust the sibling spec (rejected)
72
+
73
+ Read the sibling package's spec at runtime / docs time.
74
+
75
+ **Why rejected:** the two repos release on independent cadences. A
76
+ mid-iteration sibling-package change would silently break consumer
77
+ code. The internal pin makes the divergence point a diffable doc.
78
+
79
+ ### Alt 2 — Submodule the sibling spec (rejected)
80
+
81
+ Git submodule pulls `agent-memory/docs/` into `agent-config/`.
82
+
83
+ **Why rejected:** submodules complicate consumer installs (npx /
84
+ shell installer must handle nested clones); the spec is fast-moving
85
+ and submodule churn dwarfs the consumer-side surface this package
86
+ actually wires.
87
+
88
+ ### Alt 3 — Consumer-side snapshot (accepted)
89
+
90
+ The chosen path. One readable doc, refreshed on sibling-package
91
+ release, citable from every consumer skill that touches memory.
92
+
93
+ ## Consequences
94
+
95
+ - **Positive:** drift between sibling spec and consumer wiring lands
96
+ in one diffable file; the `present` / `misconfigured` / `absent`
97
+ contract is one citation away; new consumer skills don't have to
98
+ re-derive the envelope shape.
99
+ - **Negative:** the snapshot can lag the sibling package. Mitigated
100
+ by the explicit `Last refreshed:` line and the refresh policy in §
101
+ "Refresh policy" above.
102
+ - **Reversal cost:** delete the contract doc; consumers fall back to
103
+ reading the sibling spec directly. No code change required.
104
+
105
+ ## References
106
+
107
+ - [`docs/contracts/agent-memory-contract.md`](../../contracts/agent-memory-contract.md) — the consumer-side snapshot.
108
+ - [`scripts/memory_status.py`](../../../scripts/memory_status.py) — three-state probe.
109
+ - [`scripts/memory_lookup.py`](../../../scripts/memory_lookup.py) — retrieval envelope source.
110
+ - [`agents/roadmaps/archive/agent-memory/`](../../../agents/roadmaps/archive/agent-memory/) — sibling-package spec.
111
+ - [`agents/roadmaps/step-11-ruflo-parity.md`](../../../agents/roadmaps/step-11-ruflo-parity.md) Phase 4 Step 3 — origin.
@@ -0,0 +1,9 @@
1
+ # ADRs — `memory`
2
+
3
+ > Memory MCP, propose / promote / poison flow, runtime-trust scoring.
4
+
5
+ Contract: [`docs/contracts/agent-memory-contract.md`](../../../docs/contracts/agent-memory-contract.md).
6
+
7
+ | # | Title | Status | Date | Supersedes |
8
+ |---|---|---|---|---|
9
+ | [0001](0001-consumer-side-snapshot.md) | Consumer Side Snapshot | — | — | — |
@@ -0,0 +1,119 @@
1
+ # ADR 0001 — Three-tier rule router (kernel · tier-1 · tier-2)
2
+
3
+ > Area: `router` · Status: accepted · Date: 2026-05-16 · Type: retrospective
4
+ > Roadmap: `agents/roadmaps/step-11-ruflo-parity.md` Phase 4 Step 3
5
+ > Supersedes: —
6
+
7
+ ## Context
8
+
9
+ Every rule in `.agent-src.uncompressed/rules/` loads into a host
10
+ agent's system prompt. Loading them all is wasteful (the workspace
11
+ budget is finite) and noisy (irrelevant rules degrade attention).
12
+ The kernel-membership work
13
+ ([`docs/contracts/kernel-membership.md`](../../contracts/kernel-membership.md))
14
+ proved 9 rules are unconditionally relevant; the rest are
15
+ situational.
16
+
17
+ The router question is: **how does a non-kernel rule declare when it
18
+ fires, what artefacts carry its body, and how does the host agent
19
+ look that up cheaply at session start**.
20
+
21
+ ## Decision
22
+
23
+ **Three tiers, declared in rule frontmatter, compiled into a single
24
+ [`router.json`](../../../router.json) at the repo root.** Host agents
25
+ read `router.json` once per session.
26
+
27
+ ### Tier semantics
28
+
29
+ | Tier | Load behaviour | Workspace cost |
30
+ |---|---|---|
31
+ | `kernel` | Body injected verbatim every turn | High (capped per ADR-002 · ≤ 26k chars) |
32
+ | `tier-1` | Description stub injected; body loaded on trigger | Low (stub only) |
33
+ | `tier-2` | No injection; loaded only on explicit trigger match | Zero (until activated) |
34
+
35
+ The tier value sits in the rule's `tier:` frontmatter key; the
36
+ schema enforces the enum (`scripts/schemas/rule.schema.json`).
37
+
38
+ ### Trigger vocabulary
39
+
40
+ Six match kinds, OR-combined across entries, AND-combined within an
41
+ entry's qualifier object (full grammar:
42
+ [`rule-router.md`](../../contracts/rule-router.md) § `triggers:` shape):
43
+
44
+ `keyword` · `phrase` · `intent` · `file_pattern` · `path_prefix` ·
45
+ `command`. Kernel rules **forbid** `triggers:` — they are
46
+ unconditional by definition.
47
+
48
+ ### Compilation pipeline
49
+
50
+ 1. `scripts/sync.py` projects `.agent-src.uncompressed/` → `.agent-src/`.
51
+ 2. `scripts/compile_router.py` walks rule frontmatter, validates the
52
+ `routes_to:` targets exist on disk, writes `router.json`.
53
+ 3. `scripts/skill_linter.py` runs the bidirectional check: every
54
+ `routes_to:` target has a matching `triggered_by:` back-ref.
55
+
56
+ ### `routes_to:` resolution
57
+
58
+ Plain `<kind>:<id>` strings; kinds are `skill`, `guideline`,
59
+ `command`, `contract`. Resolution paths are pinned in
60
+ [`rule-router.md`](../../contracts/rule-router.md) lines 73–77 and
61
+ enforced by the linter.
62
+
63
+ ## Considered alternatives
64
+
65
+ ### Alt 1 — Single flat list (rejected)
66
+
67
+ All rules `always`-load.
68
+
69
+ **Why rejected:** the rules tree is ~70 entries; even with caveman
70
+ compression the workspace budget blows past the kernel cap. Static
71
+ loading wastes attention on rules irrelevant to the current turn.
72
+
73
+ ### Alt 2 — Pure-runtime semantic search (rejected)
74
+
75
+ Embed every rule, semantic-match the turn against the index, load
76
+ top-k.
77
+
78
+ **Why rejected:** introduces a runtime (this package is a governance
79
+ layer, not a runtime — see step-11 scope boundary); index drift adds
80
+ a non-trivial maintenance surface; first-turn cold-start is slow.
81
+
82
+ ### Alt 3 — Two tiers (kernel + load-on-trigger, rejected)
83
+
84
+ Skip the `tier-1` description-stub layer.
85
+
86
+ **Why rejected:** the stub layer carries 70 % of the "does this turn
87
+ need this rule?" signal at < 5 % of the body cost. Removing it
88
+ forces the host agent to either over-load (cost spike) or
89
+ mis-trigger (correctness loss).
90
+
91
+ ### Alt 4 — Three-tier with frontmatter declaration (accepted)
92
+
93
+ The chosen path. Kernel + tier-1 stubs (balanced + full profiles) +
94
+ tier-2 (full profile only). Cost stays bounded; trigger declarations
95
+ diff cleanly in PRs.
96
+
97
+ ## Consequences
98
+
99
+ - **Positive:** every rule declares its activation cost; the kernel
100
+ cap is enforceable; the host agent's session-start cost is one
101
+ JSON read; the `routes_to:` link makes "where does this rule's
102
+ body live?" answerable without grep.
103
+ - **Negative:** two layers of indirection (rule → stub → body)
104
+ raise the bar for new contributors. Mitigated by
105
+ [`rule-router.md`](../../contracts/rule-router.md) being the
106
+ single citable contract and the linter catching shape errors.
107
+ - **Reversal cost:** flatten by removing tier-1 / tier-2 distinction
108
+ in the compiler — `router.json` becomes a list of all rules. The
109
+ rule frontmatter stays valid (extra fields are tolerated by
110
+ Draft-07 once `additionalProperties` is relaxed).
111
+
112
+ ## References
113
+
114
+ - [`docs/contracts/rule-router.md`](../../contracts/rule-router.md) — frontmatter contract.
115
+ - [`docs/contracts/kernel-membership.md`](../../contracts/kernel-membership.md) — kernel cap.
116
+ - [`router.json`](../../../router.json) — compiled output.
117
+ - [`scripts/compile_router.py`](../../../scripts/compile_router.py) — compiler.
118
+ - [`scripts/schemas/rule.schema.json`](../../../scripts/schemas/rule.schema.json) — schema.
119
+ - [`agents/roadmaps/step-11-ruflo-parity.md`](../../../agents/roadmaps/step-11-ruflo-parity.md) Phase 4 Step 3 — origin.
@@ -0,0 +1,9 @@
1
+ # ADRs — `router`
2
+
3
+ > router.json shape, tier semantics, dispatch precedence.
4
+
5
+ Contract: [`docs/contracts/rule-router.md`](../../../docs/contracts/rule-router.md).
6
+
7
+ | # | Title | Status | Date | Supersedes |
8
+ |---|---|---|---|---|
9
+ | [0001](0001-three-tier-routing.md) | Three Tier Routing | — | — | — |
@@ -0,0 +1,102 @@
1
+ # ADR 0001 — JSON Schema as the frontmatter source of truth
2
+
3
+ > Area: `schema` · Status: accepted · Date: 2026-05-16 · Type: retrospective
4
+ > Roadmap: `agents/roadmaps/step-11-ruflo-parity.md` Phase 4 Step 3
5
+ > Supersedes: —
6
+
7
+ ## Context
8
+
9
+ Skills, rules, commands, and personas all declare YAML frontmatter
10
+ with required and optional keys. Validation needs to be:
11
+
12
+ 1. Machine-checkable on every PR (no "guideline" enforcement).
13
+ 2. Diff-readable so the contract drift is visible.
14
+ 3. Tool-agnostic — the same artefacts ship to Claude, Cursor, Cline,
15
+ Windsurf, and Augment, all of which parse the same YAML.
16
+
17
+ The contract is documented for humans in
18
+ [`agents/docs/frontmatter-contract.md`](../../../agents/docs/frontmatter-contract.md);
19
+ the question this ADR records is **how that contract is enforced**.
20
+
21
+ ## Decision
22
+
23
+ **JSON Schema (Draft-07) files in
24
+ [`scripts/schemas/`](../../../scripts/schemas/) are the
25
+ machine-readable source of truth.** The human contract document
26
+ defers to the schema (`$comment` in each schema file pins
27
+ `agents/docs/frontmatter-contract.md` as the source).
28
+
29
+ ### Schema files
30
+
31
+ | Type | Schema | Validator entry-point |
32
+ |---|---|---|
33
+ | Skill | `scripts/schemas/skill.schema.json` | `scripts/skill_linter.py` |
34
+ | Rule | `scripts/schemas/rule.schema.json` | `scripts/skill_linter.py` |
35
+ | Command | `scripts/schemas/command.schema.json` | `scripts/validate_frontmatter.py` |
36
+ | Persona | `scripts/schemas/persona.schema.json` | `scripts/validate_frontmatter.py` |
37
+
38
+ ### Required-key threshold
39
+
40
+ A key is **required** (in the schema's `required:` array) if ≥ 95 %
41
+ of files in the type declare it. Everything else is optional. The
42
+ threshold is documented inline in
43
+ [`frontmatter-contract.md`](../../../agents/docs/frontmatter-contract.md)
44
+ § "Definition of required". Re-derive counts with
45
+ `python3 scripts/inventory_frontmatter.py`.
46
+
47
+ ### Validation hooks
48
+
49
+ - `task lint-skills` — runs `skill_linter.py` against all skills + rules.
50
+ - `task ci` — wraps `lint-skills` plus router + smoke smokes.
51
+ - Smoke contract `scripts/smoke/schema.sh` — fast random-sample check
52
+ for PRs touching `.agent-src.uncompressed/**` (see
53
+ [`docs/contracts/smoke-contracts.md`](../../contracts/smoke-contracts.md)).
54
+
55
+ ## Considered alternatives
56
+
57
+ ### Alt 1 — Inline regex in the linter (rejected)
58
+
59
+ Hard-code shape checks in `skill_linter.py`.
60
+
61
+ **Why rejected:** the linter becomes the contract, the contract is
62
+ hidden in Python, and the artefacts can't be validated by external
63
+ tools (CI, editors, IDE plugins). Cross-tool portability is the
64
+ whole point of YAML frontmatter — the schema must be portable too.
65
+
66
+ ### Alt 2 — Pydantic / dataclass models (rejected)
67
+
68
+ Validate via typed Python models.
69
+
70
+ **Why rejected:** ties validation to Python runtime, prevents
71
+ JS/TS / Node tooling from reusing the same contract, and forces a
72
+ non-trivial dependency on every consumer that wants to validate
73
+ their own artefacts. JSON Schema is the lingua franca.
74
+
75
+ ### Alt 3 — JSON Schema Draft-07 (accepted)
76
+
77
+ The chosen path. One source-of-truth file per artefact type,
78
+ referenced by Python linter today, reusable by Node / VS Code /
79
+ JetBrains / any JSON-Schema-aware tool tomorrow.
80
+
81
+ ## Consequences
82
+
83
+ - **Positive:** schemas are diffable; new keys land via PR with
84
+ reviewable shape changes; non-Python tools can validate the same
85
+ contract; the linter stays thin.
86
+ - **Negative:** Draft-07 is older than Draft-2020-12; some keyword
87
+ niceties (`unevaluatedProperties`, conditional `then`/`else`) are
88
+ awkward. Mitigated by `additionalProperties: false` plus
89
+ `oneOf` / `if`-then composition where needed.
90
+ - **Reversal cost:** the linter is the only consumer today; replacing
91
+ the schema with Pydantic models would be a one-PR swap. The choice
92
+ is reversible without contract churn.
93
+
94
+ ## References
95
+
96
+ - [`scripts/schemas/skill.schema.json`](../../../scripts/schemas/skill.schema.json) — skill contract.
97
+ - [`scripts/schemas/rule.schema.json`](../../../scripts/schemas/rule.schema.json) — rule contract.
98
+ - [`scripts/schemas/command.schema.json`](../../../scripts/schemas/command.schema.json) — command contract.
99
+ - [`scripts/schemas/persona.schema.json`](../../../scripts/schemas/persona.schema.json) — persona contract.
100
+ - [`agents/docs/frontmatter-contract.md`](../../../agents/docs/frontmatter-contract.md) — human-readable contract.
101
+ - [`scripts/skill_linter.py`](../../../scripts/skill_linter.py) — primary validator.
102
+ - [`agents/roadmaps/step-11-ruflo-parity.md`](../../../agents/roadmaps/step-11-ruflo-parity.md) Phase 4 Step 3 — origin.
@@ -0,0 +1,9 @@
1
+ # ADRs — `schema`
2
+
3
+ > Frontmatter schemas, v2 rigor, lint behaviour for skills / rules / commands.
4
+
5
+ Contract: [`agents/docs/frontmatter-contract.md`](../../../agents/docs/frontmatter-contract.md).
6
+
7
+ | # | Title | Status | Date | Supersedes |
8
+ |---|---|---|---|---|
9
+ | [0001](0001-json-schema-frontmatter.md) | Json Schema Frontmatter | — | — | — |
@@ -0,0 +1,99 @@
1
+ # ADR 0001 — Per-tier smoke scripts (kernel · router · schema · skills)
2
+
3
+ > Area: `smoke` · Status: accepted · Date: 2026-05-16 · Type: retrospective
4
+ > Roadmap: `agents/roadmaps/step-11-ruflo-parity.md` Phase 4 Step 3
5
+ > Supersedes: —
6
+
7
+ ## Context
8
+
9
+ The North-Star audit
10
+ ([`external-findings.md § 5`](../../../agents/audit-2026-05-14-north-star/external-findings.md))
11
+ flagged "smoke contracts" as an absorbed Ruflo pattern: every
12
+ high-traffic tier needs a fast, deterministic, measurable check that
13
+ runs in CI and surfaces regressions before they reach the rules /
14
+ router / schema / skill linter pipelines.
15
+
16
+ The full `task ci` run is ≥ 90 s and exercises every linter. That's
17
+ fine for merge gates; it's too slow for path-change feedback on PRs
18
+ that touch one tier in isolation.
19
+
20
+ ## Decision
21
+
22
+ **One smoke script per tier, each ≤ 30 s, each emitting a baseline
23
+ declaration as its last stdout line.** Scripts live under
24
+ [`scripts/smoke/`](../../../scripts/smoke/):
25
+
26
+ | Tier | Script | Validates | Path-trigger globs |
27
+ |---|---|---|---|
28
+ | Kernel | [`kernel.sh`](../../../scripts/smoke/kernel.sh) | 9 kernel rules present, char-budget respected | `.agent-src.uncompressed/rules/**`, `docs/contracts/kernel-membership.md` |
29
+ | Router | [`router.sh`](../../../scripts/smoke/router.sh) | `router.json` compiles, all `routes_to:` resolve | `router.json`, `.agent-src.uncompressed/rules/**` |
30
+ | Schema | [`schema.sh`](../../../scripts/smoke/schema.sh) | Random skill / rule sample validates against JSON Schema | `scripts/schemas/**`, `.agent-src.uncompressed/{rules,skills}/**` |
31
+ | Skills | [`skills.sh`](../../../scripts/smoke/skills.sh) | 5 random skills pass frontmatter + `name == dir` | `.agent-src.uncompressed/skills/**` |
32
+
33
+ ### Runtime contract
34
+
35
+ Per [`smoke-contracts.md`](../../contracts/smoke-contracts.md) § 1:
36
+
37
+ | Limit | Value |
38
+ |---|---:|
39
+ | Wall time | ≤ 30 s |
40
+ | External I/O | filesystem only — no network, no MCP |
41
+ | Output | last stdout line = baseline declaration |
42
+ | Exit code | non-zero on baseline regression |
43
+
44
+ ### CI wiring
45
+
46
+ [`.github/workflows/smoke.yml`](../../../.github/workflows/smoke.yml)
47
+ dispatches each smoke independently on path-trigger match. Local
48
+ aggregator: `task smoke` (sub-tasks `task smoke:{kernel,router,schema,skills}`)
49
+ wired in [`taskfiles/engine.yml`](../../../taskfiles/engine.yml).
50
+
51
+ ### Baseline declarations (lock-in 2026-05-16)
52
+
53
+ - Kernel: `9 rules · 23 / 26 kB used (88 %) · 0 fence breaches`.
54
+ - Router: `tier_1: N · tier_2: M · 0 unresolved routes`.
55
+ - Schema: deterministic seed = epoch day · 10 random files validated.
56
+ - Skills: deterministic seed = epoch day · `210 skills · 5/5 pass`.
57
+
58
+ ## Considered alternatives
59
+
60
+ ### Alt 1 — One monolithic smoke (rejected)
61
+
62
+ Single `task smoke` running every check.
63
+
64
+ **Why rejected:** path-change PRs pay the full cost every time;
65
+ flaky tier-X regression masks tier-Y signal; output is harder to
66
+ diff. The per-tier split costs four files and saves CI minutes.
67
+
68
+ ### Alt 2 — Inline-in-`task ci` only (rejected)
69
+
70
+ Skip the smoke layer; rely on `task ci` for everything.
71
+
72
+ **Why rejected:** `task ci` is the merge gate, not the feedback
73
+ loop. Smokes are the cheap-and-fast layer between push and review.
74
+
75
+ ### Alt 3 — Per-tier, ≤ 30 s budget, baseline-declaring (accepted)
76
+
77
+ The chosen path. One script per tier, declared budget, declared
78
+ baseline, CI-dispatched on path-trigger.
79
+
80
+ ## Consequences
81
+
82
+ - **Positive:** PRs touching one tier get tier-specific feedback in
83
+ ≤ 30 s; baseline declarations are diff-readable so regressions
84
+ surface in PR descriptions; the `task ci` merge gate stays the
85
+ authoritative full-run.
86
+ - **Negative:** four scripts to maintain, one workflow file, one
87
+ taskfile entry. Mitigated by the runtime contract — a smoke that
88
+ approaches 30 s gets split, not optimised in place.
89
+ - **Reversal cost:** delete `smoke.yml`; the scripts stay as opt-in
90
+ local checks (`task smoke:*`). No contract churn.
91
+
92
+ ## References
93
+
94
+ - [`docs/contracts/smoke-contracts.md`](../../contracts/smoke-contracts.md) — runtime + path-trigger contract.
95
+ - [`scripts/smoke/`](../../../scripts/smoke/) — four scripts.
96
+ - [`.github/workflows/smoke.yml`](../../../.github/workflows/smoke.yml) — CI dispatch.
97
+ - [`taskfiles/engine.yml`](../../../taskfiles/engine.yml) — local aggregator.
98
+ - [`agents/audit-2026-05-14-north-star/external-findings.md`](../../../agents/audit-2026-05-14-north-star/external-findings.md) § 5 — origin pattern.
99
+ - [`agents/roadmaps/step-11-ruflo-parity.md`](../../../agents/roadmaps/step-11-ruflo-parity.md) Phase 3 (delivery) + Phase 4 Step 3 (this ADR).
@@ -0,0 +1,9 @@
1
+ # ADRs — `smoke`
2
+
3
+ > Per-tier smoke contracts, baseline locks, regression gates.
4
+
5
+ Contract: [`docs/contracts/smoke-contracts.md`](../../../docs/contracts/smoke-contracts.md).
6
+
7
+ | # | Title | Status | Date | Supersedes |
8
+ |---|---|---|---|---|
9
+ | [0001](0001-per-tier-smoke-scripts.md) | Per Tier Smoke Scripts | — | — | — |