@event4u/agent-config 1.14.0 → 1.15.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/agent-handoff.md +1 -1
- package/.agent-src/commands/bug-fix.md +2 -2
- package/.agent-src/commands/chat-history-checkpoint.md +2 -2
- package/.agent-src/commands/chat-history-clear.md +1 -1
- package/.agent-src/commands/chat-history-resume.md +2 -2
- package/.agent-src/commands/chat-history.md +2 -2
- package/.agent-src/commands/check-current-md.md +43 -32
- package/.agent-src/commands/commit-in-chunks.md +43 -23
- package/.agent-src/commands/compress.md +34 -2
- package/.agent-src/commands/feature-roadmap.md +2 -2
- package/.agent-src/commands/fix-portability.md +2 -2
- package/.agent-src/commands/onboard.md +14 -5
- package/.agent-src/commands/optimize-augmentignore.md +9 -0
- package/.agent-src/commands/refine-ticket.md +9 -7
- package/.agent-src/commands/review-changes.md +35 -8
- package/.agent-src/commands/roadmap-create.md +13 -2
- package/.agent-src/commands/roadmap-execute.md +9 -7
- package/.agent-src/commands/set-cost-profile.md +8 -0
- package/.agent-src/commands/sync-agent-settings.md +9 -0
- package/.agent-src/commands/tests-execute.md +2 -3
- package/.agent-src/rules/artifact-engagement-recording.md +1 -1
- package/.agent-src/rules/augment-portability.md +56 -37
- package/.agent-src/rules/chat-history-cadence.md +109 -0
- package/.agent-src/rules/chat-history-ownership.md +123 -0
- package/.agent-src/rules/chat-history-visibility.md +96 -0
- package/.agent-src/rules/cli-output-handling.md +1 -1
- package/.agent-src/rules/command-suggestion.md +3 -2
- package/.agent-src/rules/commit-policy.md +44 -34
- package/.agent-src/rules/direct-answers.md +1 -1
- package/.agent-src/rules/language-and-tone.md +19 -15
- package/.agent-src/rules/non-destructive-by-default.md +18 -18
- package/.agent-src/rules/roadmap-progress-sync.md +133 -74
- package/.agent-src/rules/role-mode-adherence.md +1 -1
- package/.agent-src/rules/size-enforcement.md +2 -1
- package/.agent-src/rules/user-interaction.md +28 -4
- package/.agent-src/scripts/update_roadmap_progress.py +56 -4
- package/.agent-src/skills/blade-ui/SKILL.md +29 -10
- package/.agent-src/skills/command-writing/SKILL.md +15 -4
- package/.agent-src/skills/existing-ui-audit/SKILL.md +24 -9
- package/.agent-src/skills/fe-design/SKILL.md +20 -15
- package/.agent-src/skills/file-editor/SKILL.md +9 -0
- package/.agent-src/skills/livewire/SKILL.md +26 -7
- package/.agent-src/skills/refine-ticket/SKILL.md +30 -24
- package/.agent-src/skills/roadmap-management/SKILL.md +22 -16
- package/.agent-src/skills/skill-writing/SKILL.md +3 -3
- package/.agent-src/skills/upstream-contribute/SKILL.md +2 -2
- package/.agent-src/templates/agent-settings.md +1 -1
- package/.agent-src/templates/roadmaps.md +9 -8
- package/.agent-src/templates/scripts/memory_lookup.py +1 -1
- package/.agent-src/templates/scripts/work_engine/__init__.py +2 -2
- package/.agent-src/templates/scripts/work_engine/cli.py +64 -461
- package/.agent-src/templates/scripts/work_engine/cli_args.py +116 -0
- package/.agent-src/templates/scripts/work_engine/delivery_state.py +3 -3
- package/.agent-src/templates/scripts/work_engine/directives/backend/__init__.py +1 -1
- package/.agent-src/templates/scripts/work_engine/directives/backend/implement.py +1 -1
- package/.agent-src/templates/scripts/work_engine/directives/backend/memory.py +1 -1
- package/.agent-src/templates/scripts/work_engine/directives/backend/plan.py +1 -1
- package/.agent-src/templates/scripts/work_engine/directives/backend/report.py +1 -1
- package/.agent-src/templates/scripts/work_engine/dispatcher.py +1 -1
- package/.agent-src/templates/scripts/work_engine/emitters.py +43 -0
- package/.agent-src/templates/scripts/work_engine/errors.py +19 -0
- package/.agent-src/templates/scripts/work_engine/hook_bootstrap.py +76 -0
- package/.agent-src/templates/scripts/work_engine/input_builders.py +163 -0
- package/.agent-src/templates/scripts/work_engine/migration/v0_to_v1.py +34 -2
- package/.agent-src/templates/scripts/work_engine/persona_policy.py +1 -1
- package/.agent-src/templates/scripts/work_engine/resolvers/prompt.py +1 -1
- package/.agent-src/templates/scripts/work_engine/state_io.py +202 -0
- package/.claude-plugin/marketplace.json +1 -1
- package/AGENTS.md +6 -4
- package/CHANGELOG.md +83 -8
- package/README.md +24 -23
- package/docs/MIGRATION.md +122 -0
- package/docs/architecture.md +83 -34
- package/docs/contracts/STABILITY.md +95 -0
- package/docs/contracts/adr-chat-history-split.md +132 -0
- package/docs/contracts/adr-command-suggestion.md +146 -0
- package/docs/contracts/adr-implement-ticket-runtime.md +122 -0
- package/docs/contracts/adr-product-ui-track.md +384 -0
- package/docs/contracts/adr-prompt-driven-execution.md +187 -0
- package/docs/contracts/agent-memory-contract.md +149 -0
- package/docs/contracts/artifact-engagement-flow.md +262 -0
- package/docs/contracts/command-clusters.md +126 -0
- package/docs/contracts/command-suggestion-flow.md +148 -0
- package/docs/contracts/implement-ticket-flow.md +628 -0
- package/docs/contracts/linear-ai-rules-inclusion.md +143 -0
- package/docs/contracts/linear-ai-three-layers.md +131 -0
- package/docs/contracts/rule-interactions.md +107 -0
- package/docs/contracts/rule-interactions.yml +142 -0
- package/docs/contracts/ui-stack-extension.md +236 -0
- package/docs/contracts/ui-track-flow.md +338 -0
- package/docs/getting-started.md +2 -2
- package/docs/installation.md +42 -6
- package/docs/migrations/commands-1.15.0.md +112 -0
- package/docs/ui-track-mental-model.md +121 -0
- package/package.json +1 -1
- package/scripts/build_linear_digest.py +4 -4
- package/scripts/check_portability.py +2 -0
- package/scripts/check_public_links.py +185 -0
- package/scripts/check_references.py +1 -0
- package/scripts/lint_no_new_atomic_commands.py +179 -0
- package/scripts/lint_rule_interactions.py +149 -0
- package/scripts/memory_lookup.py +1 -1
- package/scripts/release.py +297 -64
- package/scripts/skill_linter.py +14 -0
- package/scripts/update_counts.py +10 -0
- package/.agent-src/rules/chat-history.md +0 -200
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: stable
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Stability policy for `docs/contracts/`
|
|
6
|
+
|
|
7
|
+
This directory ships the **public contract surface** of `agent-config`.
|
|
8
|
+
Every file here declares a stability level in YAML frontmatter:
|
|
9
|
+
|
|
10
|
+
```yaml
|
|
11
|
+
---
|
|
12
|
+
stability: stable | beta | experimental
|
|
13
|
+
---
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The level dictates how the contract may be linked from the public
|
|
17
|
+
surface (README, AGENTS.md, `docs/architecture.md`) and what kind of
|
|
18
|
+
change to it requires what kind of release.
|
|
19
|
+
|
|
20
|
+
## Levels
|
|
21
|
+
|
|
22
|
+
### `stable`
|
|
23
|
+
|
|
24
|
+
- **Breaking change** requires a **SemVer-major** bump (`X.0.0`).
|
|
25
|
+
- README, AGENTS.md, and `docs/architecture.md` MAY link to it
|
|
26
|
+
without a marker.
|
|
27
|
+
- Typical content: settled ADRs (decisions don't reopen without a
|
|
28
|
+
successor ADR); fully released contracts that have shipped through
|
|
29
|
+
one major release without breaking.
|
|
30
|
+
|
|
31
|
+
### `beta`
|
|
32
|
+
|
|
33
|
+
- **Breaking change** is allowed in a **minor-version** release
|
|
34
|
+
(`1.X.0`), provided the change appears in `CHANGELOG.md` under a
|
|
35
|
+
`### Breaking` heading.
|
|
36
|
+
- README, AGENTS.md, and `docs/architecture.md` MAY link to it,
|
|
37
|
+
**provided** the link text or the surrounding sentence carries a
|
|
38
|
+
visible `(beta)` marker.
|
|
39
|
+
- Typical content: flow contracts and recipes that are shipped and
|
|
40
|
+
load-bearing, but whose surface is expected to evolve before a
|
|
41
|
+
SemVer-major lock.
|
|
42
|
+
|
|
43
|
+
### `experimental`
|
|
44
|
+
|
|
45
|
+
- **Breaking change** is allowed in **any release** (including
|
|
46
|
+
patches), with a CHANGELOG note.
|
|
47
|
+
- README, AGENTS.md, and `docs/architecture.md` MUST NOT link to
|
|
48
|
+
experimental contracts. Only the index inside `docs/contracts/`
|
|
49
|
+
may reference them.
|
|
50
|
+
- Typical content: spike artefacts, runtime modules in pilot status,
|
|
51
|
+
early API drafts not yet wired into a roadmap-locked phase.
|
|
52
|
+
|
|
53
|
+
## Frontmatter requirement
|
|
54
|
+
|
|
55
|
+
Every `*.md` under `docs/contracts/` (except this `STABILITY.md` file
|
|
56
|
+
itself) MUST start with a YAML frontmatter block declaring `stability:`.
|
|
57
|
+
|
|
58
|
+
The link checker (`scripts/check_public_links.py`, P0.1b) reads this
|
|
59
|
+
frontmatter and:
|
|
60
|
+
|
|
61
|
+
- **fails CI** when README / AGENTS.md / `docs/architecture.md` links to
|
|
62
|
+
a contract marked `experimental`, to a missing target, or into
|
|
63
|
+
`agents/contexts/` (internal surface).
|
|
64
|
+
- **warns** (non-fatal in default mode; fatal under `--strict`) when a
|
|
65
|
+
public-surface link to a `beta` contract has no `(beta)` marker in
|
|
66
|
+
the surrounding text.
|
|
67
|
+
- ignores `stable` links.
|
|
68
|
+
|
|
69
|
+
Run `task check-public-links` locally; `task ci` invokes the same
|
|
70
|
+
checker in default mode.
|
|
71
|
+
|
|
72
|
+
## Promotion path
|
|
73
|
+
|
|
74
|
+
`experimental → beta → stable`. Demotion is allowed (e.g. `stable →
|
|
75
|
+
beta` to permit a refactor) but appears in `CHANGELOG.md` under
|
|
76
|
+
`### Breaking` and gets a SemVer-major bump.
|
|
77
|
+
|
|
78
|
+
Promotion criteria:
|
|
79
|
+
|
|
80
|
+
- `experimental → beta` — at least one shipped roadmap phase has
|
|
81
|
+
consumed the contract end-to-end without a breaking change.
|
|
82
|
+
- `beta → stable` — at least one SemVer-minor release has shipped
|
|
83
|
+
with the contract unchanged, or the contract has been explicitly
|
|
84
|
+
frozen as part of a roadmap step.
|
|
85
|
+
|
|
86
|
+
## Current contracts
|
|
87
|
+
|
|
88
|
+
See the file headers themselves for current levels. The frontmatter is
|
|
89
|
+
the authoritative source — this list is illustrative, not load-bearing,
|
|
90
|
+
and is generated by `scripts/check_public_links.py --list`.
|
|
91
|
+
|
|
92
|
+
## See also
|
|
93
|
+
|
|
94
|
+
- [`agents/roadmaps/road-to-post-pr29-optimize.md`](../../agents/roadmaps/road-to-post-pr29-optimize.md) — P0.1, P0.1a, P0.1b
|
|
95
|
+
- [`docs/architecture.md`](../architecture.md) — package architecture overview
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: beta
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ADR — Chat-history rule split
|
|
6
|
+
|
|
7
|
+
> **Status:** Decided · 2026-05-02 · scoped under
|
|
8
|
+
> [`road-to-post-pr29-optimize.md`](../../agents/roadmaps/archive/road-to-post-pr29-optimize.md)
|
|
9
|
+
> Phase 2 item P2.1.
|
|
10
|
+
> **Context:** AI #1, AI #3, AI #5 review of PR #29 flagged the
|
|
11
|
+
> 200-line monolithic `rules/chat-history.md` as the rule the agent
|
|
12
|
+
> revisited 12+ times during the 1.14.0 cycle — three independent
|
|
13
|
+
> concerns coupled into one Iron Law block.
|
|
14
|
+
> **Builds on:** [`adr-implement-ticket-runtime.md`](adr-implement-ticket-runtime.md)
|
|
15
|
+
> — engine path was added to the existing rule mid-flight, which
|
|
16
|
+
> exposed the coupling.
|
|
17
|
+
> **Defers to:** Phase 2 P2.9 (memory-visibility surface) for the
|
|
18
|
+
> reuse of the heartbeat plumbing.
|
|
19
|
+
|
|
20
|
+
## Decision
|
|
21
|
+
|
|
22
|
+
`rules/chat-history.md` is split into **three sibling `always` rules**,
|
|
23
|
+
each owning one orthogonal concern and a clear single Iron Law:
|
|
24
|
+
|
|
25
|
+
| Rule | Iron Law owned | What it answers |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `chat-history-ownership.md` | Foreign/Returning/Missing handshake — whose file is this? | Activation, two-paths table (HOOK/ENGINE/CHECKPOINT/MANUAL), Foreign/Returning prompts |
|
|
28
|
+
| `chat-history-cadence.md` | turn-check + append gates — when to write? | Turn-start gate, append cadence (`per_turn`/`per_phase`/`per_tool`), `OWNERSHIP_REFUSED` handling |
|
|
29
|
+
| `chat-history-visibility.md` | Heartbeat marker — how does the user see drift? | Heartbeat invocation, `on`/`off`/`hybrid` modes, memory-typing-the-marker hard-rule |
|
|
30
|
+
|
|
31
|
+
The original `rules/chat-history.md` is deleted. Cross-references
|
|
32
|
+
across the three splits are explicit one-line backlinks at the top of
|
|
33
|
+
each file. The CHECKPOINT-path Iron Law (the three-gate block) is
|
|
34
|
+
re-anchored: ownership owns gate 1 (turn-check), cadence owns gate 2
|
|
35
|
+
(append), visibility owns gate 3 (heartbeat).
|
|
36
|
+
|
|
37
|
+
## Why this was a real question
|
|
38
|
+
|
|
39
|
+
Three options were on the table:
|
|
40
|
+
|
|
41
|
+
1. **Leave the monolith, add sub-section index.** Rejected: the
|
|
42
|
+
12-iteration churn was on individual sub-sections (heartbeat
|
|
43
|
+
visibility modes, foreign/returning prompts, cadence frequencies)
|
|
44
|
+
touching unrelated parts of the file. Index doesn't separate
|
|
45
|
+
concerns; it only renames the problem.
|
|
46
|
+
2. **Move the Iron Law block to a context doc, leave the rule as a
|
|
47
|
+
thin pointer.** Rejected: contexts are reference, rules are
|
|
48
|
+
triggers — the three gates ARE the trigger surface. Demoting them
|
|
49
|
+
to context bleeds enforcement.
|
|
50
|
+
3. **Three sibling rules, one concern each (chosen).** Adopted
|
|
51
|
+
because each concern has a distinct lifecycle: ownership is a
|
|
52
|
+
first-turn handshake (rare event, high stakes), cadence is per-
|
|
53
|
+
phase (high frequency, low stakes per write), visibility is per-
|
|
54
|
+
reply (every turn, observability-only). Coupling them produced the
|
|
55
|
+
"memory-typing the marker" failure mode we hardened against in
|
|
56
|
+
1.14.0 — separating them makes future hardening surgical.
|
|
57
|
+
|
|
58
|
+
## Sizing & always-rule budget
|
|
59
|
+
|
|
60
|
+
Pre-split: `chat-history.md` = 201 lines. Always-rule budget pre-split = 2207 lines across 18 rules.
|
|
61
|
+
|
|
62
|
+
Post-split target (frontmatter + cloud-behavior + interactions
|
|
63
|
+
sections triplicated):
|
|
64
|
+
|
|
65
|
+
| File | Target lines |
|
|
66
|
+
|---|---:|
|
|
67
|
+
| `chat-history-ownership.md` | ≤ 95 |
|
|
68
|
+
| `chat-history-cadence.md` | ≤ 80 |
|
|
69
|
+
| `chat-history-visibility.md` | ≤ 65 |
|
|
70
|
+
| **Total** | **≤ 240** |
|
|
71
|
+
|
|
72
|
+
Net always-rule budget delta: **+39 lines** (≈ 1.8 % of the current
|
|
73
|
+
2207-line total). Within the ~49k-token target ceiling tracked in
|
|
74
|
+
`road-to-governance-cleanup.md`.
|
|
75
|
+
|
|
76
|
+
## Consequences
|
|
77
|
+
|
|
78
|
+
**Wins**
|
|
79
|
+
|
|
80
|
+
- Each rule has one Iron Law instead of three. Future edits to
|
|
81
|
+
cadence don't risk touching ownership prompt mechanics.
|
|
82
|
+
- The `chat-history-visibility.md` rule becomes a clean reuse target
|
|
83
|
+
for Phase 2 P2.9 (memory-visibility surface).
|
|
84
|
+
- Refactoring the engine-side hooks (`chat_history_turn_check.py`,
|
|
85
|
+
`chat_history_append.py`, `chat_history_heartbeat.py`) is now
|
|
86
|
+
1:1 with rule files — one rule per hook.
|
|
87
|
+
|
|
88
|
+
**Costs / migration surface**
|
|
89
|
+
|
|
90
|
+
- Every cross-reference to `chat-history` across the package must be
|
|
91
|
+
updated to point at the right split. Inventory: ~30 files (rules,
|
|
92
|
+
templates, scripts, commands, contexts, README, AGENTS.md).
|
|
93
|
+
- `docs-sync.md` table needs the new triple instead of the singleton.
|
|
94
|
+
- `scripts/check_references.py` runs catch broken links; CI gates the
|
|
95
|
+
split.
|
|
96
|
+
- Any consumer project carrying a project-level override of
|
|
97
|
+
`chat-history` must also split (or alias) — handled by an explicit
|
|
98
|
+
migration note in `docs/migrations/commands-1.15.0.md` (extended
|
|
99
|
+
for this rule split).
|
|
100
|
+
|
|
101
|
+
**Reversibility**
|
|
102
|
+
|
|
103
|
+
Split is a structural refactor, not a behavior change. Reverting
|
|
104
|
+
would mean re-concatenating the three files — mechanical but loud
|
|
105
|
+
in CI. The CHECKPOINT-path Iron Law numbering is preserved, so
|
|
106
|
+
agents that learned "gates 1-2-3" still find the same numbered
|
|
107
|
+
sequence, just across three files.
|
|
108
|
+
|
|
109
|
+
## Out of scope
|
|
110
|
+
|
|
111
|
+
- Behavior changes to `scripts/chat_history.py` — the script's
|
|
112
|
+
CLI surface is unchanged.
|
|
113
|
+
- Adding new cadence frequencies or visibility modes — separate
|
|
114
|
+
decision, not part of this split.
|
|
115
|
+
- Removing the CHECKPOINT-path entirely — Cline-on-Windows still
|
|
116
|
+
needs cooperative gates; that's a Phase 3+ conversation.
|
|
117
|
+
|
|
118
|
+
## Implementation plan (this PR)
|
|
119
|
+
|
|
120
|
+
1. Create the three new rules under `.agent-src.uncompressed/rules/`.
|
|
121
|
+
2. Delete `.agent-src.uncompressed/rules/chat-history.md`.
|
|
122
|
+
3. Run `bash scripts/compress.sh --sync` to project the change into
|
|
123
|
+
`.agent-src/`, `.augment/`, `.claude/`, `.cursor/`, `.clinerules/`,
|
|
124
|
+
`.windsurfrules`.
|
|
125
|
+
4. Update every cross-reference (~30 files) — `check-refs` is the
|
|
126
|
+
gate.
|
|
127
|
+
5. Append a migration note to `docs/migrations/commands-1.15.0.md`
|
|
128
|
+
under a new "Rule splits" section.
|
|
129
|
+
6. Regenerate `agents/roadmaps-progress.md`.
|
|
130
|
+
7. Verify: `task ci` (lint-skills, check-refs, check-public-links,
|
|
131
|
+
check-compression, counts-check, lint-readme, runtime-e2e,
|
|
132
|
+
roadmap-progress-check, lint-readme).
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: stable
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ADR — Context-Aware Command Suggestion
|
|
6
|
+
|
|
7
|
+
> **Status:** Decided · Phases 1–7 shipped · 2026-04-30
|
|
8
|
+
> **Roadmap:** [`road-to-context-aware-command-suggestion.md`](../../agents/roadmaps/road-to-context-aware-command-suggestion.md)
|
|
9
|
+
> **Rule:** [`command-suggestion`](../../.agent-src.uncompressed/rules/command-suggestion.md)
|
|
10
|
+
> **Eligibility table:** [`command-suggestion-eligibility.md`](command-suggestion-eligibility.md)
|
|
11
|
+
> **Engine:** `scripts/command_suggester/`
|
|
12
|
+
> **Orthogonal to:** R1 (`adr-work-engine-rename.md`) — the suggester is a
|
|
13
|
+
> read-only shortcut *finder*; it never invokes a command. Engine boundaries
|
|
14
|
+
> stay intact.
|
|
15
|
+
|
|
16
|
+
## Decision
|
|
17
|
+
|
|
18
|
+
Add a **deterministic, read-only** suggestion layer that scans every
|
|
19
|
+
non-`/`-prefixed user turn against eligible command frontmatter
|
|
20
|
+
(`suggestion.trigger_description` + `trigger_context`) and surfaces matches
|
|
21
|
+
as a **numbered-options block** with the user-interaction Iron Law shape:
|
|
22
|
+
|
|
23
|
+
- N command options, neutral labels (no inline `(recommended)` tag).
|
|
24
|
+
- Always-last "Just run the prompt as-is, no command" escape hatch.
|
|
25
|
+
- Exactly one `**Recommendation: K — /command**` line, omitted when the
|
|
26
|
+
top two scores are within `0.05` of each other.
|
|
27
|
+
|
|
28
|
+
The suggester **never executes** anything — option-N is what triggers the
|
|
29
|
+
standard slash-command flow on the next turn (with all per-command halts
|
|
30
|
+
intact). The user picks every time.
|
|
31
|
+
|
|
32
|
+
## Why this was a real question
|
|
33
|
+
|
|
34
|
+
A maintainer who types "Setze Ticket ABC-123 um" got a generic
|
|
35
|
+
implementation walk-through, not the `/implement-ticket` engine. The
|
|
36
|
+
package owns 75 commands; the agent has the list in context but no
|
|
37
|
+
contract telling it "when the prompt looks like *this*, offer *that*
|
|
38
|
+
command". Three forces converged:
|
|
39
|
+
|
|
40
|
+
1. **Discoverability gap.** Users learn `/command` only when documented;
|
|
41
|
+
most never type it.
|
|
42
|
+
2. **Safety anchor.** Auto-execution is non-negotiably out (`scope-control`,
|
|
43
|
+
per-command halts). Anything we ship cannot weaken that floor.
|
|
44
|
+
3. **Determinism.** ML-based intent detection is non-replayable; goldens
|
|
45
|
+
would drift. Pattern + keyword matching keeps GT-CS replays byte-stable.
|
|
46
|
+
|
|
47
|
+
Three alternatives were rejected:
|
|
48
|
+
|
|
49
|
+
- **Auto-route to commands** (bypass the user). Rejected: violates the
|
|
50
|
+
"user always picks" anchor; one wrong route inside `/implement-ticket`
|
|
51
|
+
is a multi-hour blast radius.
|
|
52
|
+
- **Trigger-based command auto-prefix** (silently rewrite the prompt
|
|
53
|
+
to `/command <prompt>`). Rejected: same anchor breach, plus the user
|
|
54
|
+
loses the "skip" option.
|
|
55
|
+
- **LLM intent classifier**. Rejected: non-deterministic, untestable in
|
|
56
|
+
the GT-CS harness, and the eligibility table is small enough that
|
|
57
|
+
pattern matching reaches the same precision at zero cost.
|
|
58
|
+
|
|
59
|
+
## Eligibility rubric
|
|
60
|
+
|
|
61
|
+
A command is **eligible** (default `true`) unless:
|
|
62
|
+
|
|
63
|
+
- Invocation is **intentional-only** (`/onboard`, `/package-reset`,
|
|
64
|
+
`/mode`, `/agent-handoff`, `/chat-history-clear`).
|
|
65
|
+
- Triggers would overlap so heavily with normal prose that the floor +
|
|
66
|
+
cooldown can't suppress the noise.
|
|
67
|
+
- The command has no natural-language signal distinct from neighbours.
|
|
68
|
+
|
|
69
|
+
The locked table is
|
|
70
|
+
[`command-suggestion-eligibility.md`](command-suggestion-eligibility.md).
|
|
71
|
+
Eligibility changes are roadmap follow-ups, not drive-by edits.
|
|
72
|
+
|
|
73
|
+
## Anti-noise heuristics
|
|
74
|
+
|
|
75
|
+
`rank.py` drops matches that fail any of:
|
|
76
|
+
|
|
77
|
+
- Score below `confidence_floor` (default `0.6`; per-command override
|
|
78
|
+
via frontmatter).
|
|
79
|
+
- Single match within `floor + 0.1` of the floor and no structural
|
|
80
|
+
bonus (high uncertainty isn't worth interrupting).
|
|
81
|
+
- Short prompt (< 6 words) hitting > 2 commands without a structural
|
|
82
|
+
bonus (too vague to disambiguate).
|
|
83
|
+
- Pure continuation phrase (`ok`, `weiter`, `mach weiter`, `go on`,
|
|
84
|
+
`continue`) with no structural bonus.
|
|
85
|
+
- Same `(command, evidence)` pair shown within `cooldown_seconds`
|
|
86
|
+
(default `600`, per-command override).
|
|
87
|
+
|
|
88
|
+
Structural bonuses (ticket key, file path, branch shape) override
|
|
89
|
+
suppression when they signal real intent.
|
|
90
|
+
|
|
91
|
+
## Hardening — what suggestion must never do
|
|
92
|
+
|
|
93
|
+
The rule (`.agent-src.uncompressed/rules/command-suggestion.md`)
|
|
94
|
+
binds the engine to five non-negotiables, mirrored as goldens:
|
|
95
|
+
|
|
96
|
+
1. **No execution without user pick.** `SUGGEST. NEVER INVOKE.` is the
|
|
97
|
+
first Iron Law in the rule.
|
|
98
|
+
2. **No multi-question stacks.** Clarification (`ask-when-uncertain`)
|
|
99
|
+
wins; suggestion stays silent that turn.
|
|
100
|
+
3. **No conversation hijack.** `enabled: false`, no matches above floor,
|
|
101
|
+
or a senior rule active → zero output.
|
|
102
|
+
4. **No echo-trigger.** `sanitize.py` strips fenced/inline code and the
|
|
103
|
+
engine's own previous block shape (`> N. /command — …`,
|
|
104
|
+
`**Recommendation: N — …**`) before scoring.
|
|
105
|
+
5. **Hard subordination.** `scope-control`, `ask-when-uncertain`,
|
|
106
|
+
`verify-before-complete`, and any active role-mode contract outrank
|
|
107
|
+
suggestion.
|
|
108
|
+
|
|
109
|
+
GT-CS1 through GT-CS9 (`tests/test_command_suggester_goldens.py`) lock
|
|
110
|
+
the contract end-to-end.
|
|
111
|
+
|
|
112
|
+
## Three opt-out paths
|
|
113
|
+
|
|
114
|
+
| Path | Mechanism | Scope |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| Global | `commands.suggestion.enabled: false` in `.agent-settings.yml` | Whole project |
|
|
117
|
+
| Per-command | `commands.suggestion.blocklist: [/cmd]` | Specific command stays as-is |
|
|
118
|
+
| Per-conversation | `/command-suggestion-off` directive | Until user re-enables or chat ends |
|
|
119
|
+
|
|
120
|
+
All three are deterministic and tested. `/command-suggestion-on`
|
|
121
|
+
re-enables mid-conversation.
|
|
122
|
+
|
|
123
|
+
## Consequences
|
|
124
|
+
|
|
125
|
+
**Positive.** The maintainer's intent surfaces commands they didn't
|
|
126
|
+
remember to type. Anti-noise heuristics keep the layer near-silent on
|
|
127
|
+
prose. Goldens replay byte-stable; GT-CS9 covers adversarial echo.
|
|
128
|
+
|
|
129
|
+
**Negative.** A new always-on rule adds context budget — kept under
|
|
130
|
+
size budget by the size-enforcement rule. Per-command frontmatter now
|
|
131
|
+
carries `suggestion.*` keys; the linter enforces them so drift is
|
|
132
|
+
caught early.
|
|
133
|
+
|
|
134
|
+
**Open.** Trigger drift over time — a command's
|
|
135
|
+
`trigger_description` gets stale as conventions move. Mitigation: the
|
|
136
|
+
artefact-engagement telemetry pipeline (default-off) measures
|
|
137
|
+
suggestion pick-rate per command, surfacing weak triggers as
|
|
138
|
+
retirement candidates without a hard SLA.
|
|
139
|
+
|
|
140
|
+
## See also
|
|
141
|
+
|
|
142
|
+
- [`command-suggestion`](../../.agent-src.uncompressed/rules/command-suggestion.md) — runtime rule
|
|
143
|
+
- [`command-suggestion-eligibility.md`](command-suggestion-eligibility.md) — locked eligibility table
|
|
144
|
+
- [`road-to-context-aware-command-suggestion.md`](../../agents/roadmaps/road-to-context-aware-command-suggestion.md) — phased delivery
|
|
145
|
+
- [`adr-prompt-driven-execution.md`](adr-prompt-driven-execution.md) — `/work` entrypoint that explicit slash invocations route to
|
|
146
|
+
- [`agent-settings`](../../.agent-src.uncompressed/templates/agent-settings.md) — `commands.suggestion.*` reference
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
---
|
|
2
|
+
stability: stable
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# ADR — `/implement-ticket` runtime: Python
|
|
6
|
+
|
|
7
|
+
> **Status:** Decided · Phase 0 spike closed · 2026-04-22
|
|
8
|
+
> **Context:** [`implement-ticket-flow.md`](implement-ticket-flow.md) ·
|
|
9
|
+
> [`road-to-implement-ticket.md`](../../agents/roadmaps/road-to-implement-ticket.md)
|
|
10
|
+
> **Supersedes:** the `Runtime: TBD` placeholder in `implement-ticket-flow.md`.
|
|
11
|
+
|
|
12
|
+
## Decision
|
|
13
|
+
|
|
14
|
+
The `/implement-ticket` orchestrator ships on **Python 3.10+** (stdlib + `pyyaml`).
|
|
15
|
+
|
|
16
|
+
Bash is rejected as the runtime. It stays only where it already lives —
|
|
17
|
+
the install driver, compression helper, and test runner — not the
|
|
18
|
+
delivery flow.
|
|
19
|
+
|
|
20
|
+
## Why this was a real question
|
|
21
|
+
|
|
22
|
+
The repo already ships a Bash install + compression toolchain. A
|
|
23
|
+
shell-native dispatcher would have reused the existing muscle memory and
|
|
24
|
+
avoided adding Python as a delivery-runtime dependency. The spike
|
|
25
|
+
existed to verify whether Bash could still carry the 8-step linear flow
|
|
26
|
+
once real orchestration needs showed up (structured state, blocked/partial
|
|
27
|
+
outcomes, metrics, tests). Result: not well.
|
|
28
|
+
|
|
29
|
+
## Spike scope
|
|
30
|
+
|
|
31
|
+
Both prototypes implement the same shape from
|
|
32
|
+
`implement-ticket-flow.md`:
|
|
33
|
+
|
|
34
|
+
- 8 linear steps (refine → memory → analyze → plan → implement → test →
|
|
35
|
+
verify → report)
|
|
36
|
+
- `DeliveryState` as the only thing shared between steps
|
|
37
|
+
- Three terminal outcomes: `success`, `blocked`, `partial`
|
|
38
|
+
- Metrics JSON line per run (Q38 decision)
|
|
39
|
+
- Identical fixtures: one clean ticket, one ambiguous ticket that must
|
|
40
|
+
block at `refine` with three numbered questions
|
|
41
|
+
|
|
42
|
+
Sources: Phase-0 spike (`spike/implement-ticket/{bash,python}/`) — deleted after Phase 1 shipped; the evidence inlined below is the only surviving record.
|
|
43
|
+
|
|
44
|
+
## Evidence (measured, not asserted)
|
|
45
|
+
|
|
46
|
+
### Wall-clock mean (20 runs, 3 warmup, macOS ARM)
|
|
47
|
+
|
|
48
|
+
| Scenario | Bash | Python | Winner |
|
|
49
|
+
|---|---|---|---|
|
|
50
|
+
| Clean, all 8 steps | 104 ms | 36 ms | **Python 2.9×** |
|
|
51
|
+
| Blocked at step 1 | 60 ms | 35 ms | **Python 1.7×** |
|
|
52
|
+
|
|
53
|
+
Harness was `spike/implement-ticket/bench.sh` (20 runs, 3 warmup, macOS ARM);
|
|
54
|
+
raw numbers preserved in this ADR after the spike directory was deleted.
|
|
55
|
+
|
|
56
|
+
Bash cost is dominated by per-step fork/exec (`yq`, `jq`, `perl`, step
|
|
57
|
+
script). Every step added extends the Bash gap. Python keeps the whole
|
|
58
|
+
dispatch in-process; step count is effectively free.
|
|
59
|
+
|
|
60
|
+
### Test-writability
|
|
61
|
+
|
|
62
|
+
| | pytest (Python) | shell asserts (Bash) |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| Lines to cover 3 scenarios | 59 | 72 |
|
|
65
|
+
| Assert target | typed `state.outcomes`, `state.questions` | stdout string-contains |
|
|
66
|
+
| Suite runtime | 0.01 s | ~2.5 s (15 subprocess launches) |
|
|
67
|
+
| Test isolation | in-process `dispatch(state)` | fork per assertion |
|
|
68
|
+
| IDE affordances | autocomplete, types, stack traces | grep only |
|
|
69
|
+
|
|
70
|
+
### Error-propagation ergonomics
|
|
71
|
+
|
|
72
|
+
- **Python:** outcomes flow through typed `StepResult`/`Outcome`
|
|
73
|
+
enums. One `dispatch()` return tuple covers success/blocked/partial.
|
|
74
|
+
Zero string parsing.
|
|
75
|
+
- **Bash:** outcomes are encoded in exit codes (0/10/20), propagated
|
|
76
|
+
through `set +e` dances per step, mirrored into a JSON file with
|
|
77
|
+
`jq --arg` round-trips. Every step handler re-reads/rewrites the
|
|
78
|
+
state file. Brittle.
|
|
79
|
+
|
|
80
|
+
### Source size
|
|
81
|
+
|
|
82
|
+
Roughly equal (Bash 203 / Python 207 lines), but the Bash total is spread
|
|
83
|
+
across 9 files with per-file shebang + `set -euo pipefail` boilerplate;
|
|
84
|
+
Python is 3 files with shared types.
|
|
85
|
+
|
|
86
|
+
## Tradeoffs we accept
|
|
87
|
+
|
|
88
|
+
- **New hard dependency on Python 3.10+ and `pyyaml`.** Mitigated: Python 3
|
|
89
|
+
is already a build/test dependency of this repo (linters, compression,
|
|
90
|
+
`update_counts.py`). `pyyaml` is already pinned in `pyproject.toml` /
|
|
91
|
+
`requirements-*.txt`. Zero new install surface for contributors.
|
|
92
|
+
- **We lose the "just-shell" story.** The install script stays Bash. The
|
|
93
|
+
delivery runtime being Python is a deliberate split: install is
|
|
94
|
+
side-effecting system work, delivery is structured data transformation.
|
|
95
|
+
- **Python per-invocation boot is ~35 ms.** Accepted — it's flat, not
|
|
96
|
+
proportional to step count, and well below the user-perception floor.
|
|
97
|
+
|
|
98
|
+
## Non-goals of this decision
|
|
99
|
+
|
|
100
|
+
- Does not bless Python for every future spike — each flow decides
|
|
101
|
+
on its own evidence.
|
|
102
|
+
- Does not commit to a specific framework (click, typer, bare argparse);
|
|
103
|
+
that is chosen during Phase 1 and kept minimal.
|
|
104
|
+
- Does not move the compression/install scripts off Bash.
|
|
105
|
+
|
|
106
|
+
## Consequences — unblocks
|
|
107
|
+
|
|
108
|
+
- Phase 1 of `road-to-implement-ticket.md` can start: wire real step
|
|
109
|
+
handlers onto the dispatcher shape spiked here.
|
|
110
|
+
- `implement-ticket-flow.md` will have its `Runtime: TBD` line replaced
|
|
111
|
+
with `Runtime: Python 3.10+` when Phase 1 lands.
|
|
112
|
+
- Metrics contract (Q38, JSON lines under `agents/logs/implement-ticket/`)
|
|
113
|
+
is already demonstrated by both prototypes.
|
|
114
|
+
|
|
115
|
+
## Follow-ups (not part of this ADR)
|
|
116
|
+
|
|
117
|
+
- If later optimisation is needed, port the numbers above into a
|
|
118
|
+
`task bench-implement-ticket` target against the real handlers — the
|
|
119
|
+
original `bench.sh` lives only in this repo's git history now (see
|
|
120
|
+
commit `79f30e7`).
|
|
121
|
+
- Decide CLI framework during Phase 1 (defer — argparse is enough for
|
|
122
|
+
the orchestrator skeleton).
|