sequant 2.1.2 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +73 -0
- package/dist/bin/cli.js +95 -9
- package/dist/src/commands/doctor.d.ts +25 -0
- package/dist/src/commands/doctor.js +36 -1
- package/dist/src/commands/init.d.ts +1 -0
- package/dist/src/commands/init.js +118 -0
- package/dist/src/commands/locks.d.ts +67 -0
- package/dist/src/commands/locks.js +290 -0
- package/dist/src/commands/merge.js +11 -0
- package/dist/src/commands/prompt.d.ts +39 -0
- package/dist/src/commands/prompt.js +179 -0
- package/dist/src/commands/run-display.d.ts +26 -0
- package/dist/src/commands/run-display.js +150 -0
- package/dist/src/commands/run-progress.d.ts +32 -0
- package/dist/src/commands/run-progress.js +76 -0
- package/dist/src/commands/run.js +83 -73
- package/dist/src/commands/stats.d.ts +2 -0
- package/dist/src/commands/stats.js +94 -8
- package/dist/src/commands/status.js +27 -1
- package/dist/src/commands/watch.d.ts +16 -0
- package/dist/src/commands/watch.js +147 -0
- package/dist/src/lib/ac-linter.d.ts +1 -1
- package/dist/src/lib/ac-linter.js +81 -0
- package/dist/src/lib/assess-collision-detect.d.ts +91 -0
- package/dist/src/lib/assess-collision-detect.js +217 -0
- package/dist/src/lib/assess-comment-parser.d.ts +59 -1
- package/dist/src/lib/assess-comment-parser.js +124 -2
- package/dist/src/lib/cli-ui/format.d.ts +19 -0
- package/dist/src/lib/cli-ui/format.js +34 -0
- package/dist/src/lib/cli-ui/run-renderer-types.d.ts +181 -0
- package/dist/src/lib/cli-ui/run-renderer-types.js +7 -0
- package/dist/src/lib/cli-ui/run-renderer.d.ts +239 -0
- package/dist/src/lib/cli-ui/run-renderer.js +1173 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.d.ts +94 -0
- package/dist/src/lib/heuristics/behavior-rule-detector.js +467 -0
- package/dist/src/lib/locks/index.d.ts +7 -0
- package/dist/src/lib/locks/index.js +5 -0
- package/dist/src/lib/locks/lock-manager.d.ts +168 -0
- package/dist/src/lib/locks/lock-manager.js +433 -0
- package/dist/src/lib/locks/types.d.ts +59 -0
- package/dist/src/lib/locks/types.js +31 -0
- package/dist/src/lib/qa/markdown-only-ci.d.ts +46 -0
- package/dist/src/lib/qa/markdown-only-ci.js +74 -0
- package/dist/src/lib/relay/activation.d.ts +60 -0
- package/dist/src/lib/relay/activation.js +122 -0
- package/dist/src/lib/relay/archive.d.ts +34 -0
- package/dist/src/lib/relay/archive.js +106 -0
- package/dist/src/lib/relay/frame.d.ts +20 -0
- package/dist/src/lib/relay/frame.js +76 -0
- package/dist/src/lib/relay/index.d.ts +13 -0
- package/dist/src/lib/relay/index.js +13 -0
- package/dist/src/lib/relay/paths.d.ts +43 -0
- package/dist/src/lib/relay/paths.js +59 -0
- package/dist/src/lib/relay/pid.d.ts +34 -0
- package/dist/src/lib/relay/pid.js +72 -0
- package/dist/src/lib/relay/reader.d.ts +35 -0
- package/dist/src/lib/relay/reader.js +115 -0
- package/dist/src/lib/relay/types.d.ts +68 -0
- package/dist/src/lib/relay/types.js +76 -0
- package/dist/src/lib/relay/writer.d.ts +48 -0
- package/dist/src/lib/relay/writer.js +113 -0
- package/dist/src/lib/settings.d.ts +31 -1
- package/dist/src/lib/settings.js +18 -3
- package/dist/src/lib/skill-version.d.ts +19 -0
- package/dist/src/lib/skill-version.js +68 -0
- package/dist/src/lib/templates.d.ts +1 -0
- package/dist/src/lib/templates.js +1 -1
- package/dist/src/lib/version-check.d.ts +60 -5
- package/dist/src/lib/version-check.js +97 -9
- package/dist/src/lib/workflow/batch-executor.d.ts +20 -1
- package/dist/src/lib/workflow/batch-executor.js +249 -176
- package/dist/src/lib/workflow/config-resolver.js +4 -0
- package/dist/src/lib/workflow/heartbeat.d.ts +71 -0
- package/dist/src/lib/workflow/heartbeat.js +194 -0
- package/dist/src/lib/workflow/phase-executor.d.ts +88 -3
- package/dist/src/lib/workflow/phase-executor.js +276 -52
- package/dist/src/lib/workflow/phase-mapper.d.ts +3 -2
- package/dist/src/lib/workflow/phase-mapper.js +17 -20
- package/dist/src/lib/workflow/platforms/github.d.ts +1 -1
- package/dist/src/lib/workflow/platforms/github.js +20 -3
- package/dist/src/lib/workflow/pr-status.d.ts +18 -2
- package/dist/src/lib/workflow/pr-status.js +41 -9
- package/dist/src/lib/workflow/qa-stagnation.d.ts +117 -0
- package/dist/src/lib/workflow/qa-stagnation.js +179 -0
- package/dist/src/lib/workflow/run-orchestrator.d.ts +76 -0
- package/dist/src/lib/workflow/run-orchestrator.js +382 -29
- package/dist/src/lib/workflow/run-reflect.js +1 -1
- package/dist/src/lib/workflow/run-state.d.ts +71 -0
- package/dist/src/lib/workflow/run-state.js +14 -0
- package/dist/src/lib/workflow/state-cleanup.d.ts +13 -5
- package/dist/src/lib/workflow/state-cleanup.js +17 -5
- package/dist/src/lib/workflow/state-manager.d.ts +12 -1
- package/dist/src/lib/workflow/state-manager.js +37 -0
- package/dist/src/lib/workflow/state-schema.d.ts +62 -0
- package/dist/src/lib/workflow/state-schema.js +35 -1
- package/dist/src/lib/workflow/types.d.ts +74 -1
- package/dist/src/lib/workflow/worktree-manager.d.ts +12 -4
- package/dist/src/lib/workflow/worktree-manager.js +76 -17
- package/dist/src/mcp/tools/run.d.ts +44 -0
- package/dist/src/mcp/tools/run.js +104 -13
- package/dist/src/ui/tui/App.d.ts +14 -0
- package/dist/src/ui/tui/App.js +41 -0
- package/dist/src/ui/tui/ElapsedTimer.d.ts +10 -0
- package/dist/src/ui/tui/ElapsedTimer.js +31 -0
- package/dist/src/ui/tui/Header.d.ts +6 -0
- package/dist/src/ui/tui/Header.js +15 -0
- package/dist/src/ui/tui/IssueBox.d.ts +16 -0
- package/dist/src/ui/tui/IssueBox.js +68 -0
- package/dist/src/ui/tui/Spinner.d.ts +9 -0
- package/dist/src/ui/tui/Spinner.js +18 -0
- package/dist/src/ui/tui/index.d.ts +15 -0
- package/dist/src/ui/tui/index.js +29 -0
- package/dist/src/ui/tui/theme.d.ts +29 -0
- package/dist/src/ui/tui/theme.js +52 -0
- package/dist/src/ui/tui/truncate.d.ts +11 -0
- package/dist/src/ui/tui/truncate.js +31 -0
- package/package.json +10 -3
- package/templates/agents/sequant-explorer.md +1 -0
- package/templates/agents/sequant-qa-checker.md +2 -1
- package/templates/agents/sequant-testgen.md +1 -0
- package/templates/hooks/post-tool.sh +11 -0
- package/templates/hooks/pre-tool.sh +18 -9
- package/templates/hooks/relay-check.sh +107 -0
- package/templates/relay/frame.txt +11 -0
- package/templates/scripts/cleanup-worktree.sh +25 -3
- package/templates/scripts/new-feature.sh +6 -0
- package/templates/skills/_shared/references/behavior-rule-detection.md +205 -0
- package/templates/skills/_shared/references/subagent-types.md +21 -8
- package/templates/skills/assess/SKILL.md +261 -94
- package/templates/skills/assess/references/predicted-collision-detection.md +109 -0
- package/templates/skills/docs/SKILL.md +141 -22
- package/templates/skills/exec/SKILL.md +10 -49
- package/templates/skills/fullsolve/SKILL.md +80 -32
- package/templates/skills/loop/SKILL.md +28 -0
- package/templates/skills/merger/SKILL.md +621 -0
- package/templates/skills/qa/SKILL.md +746 -8
- package/templates/skills/qa/scripts/quality-checks.sh +47 -1
- package/templates/skills/setup/SKILL.md +6 -0
- package/templates/skills/spec/SKILL.md +217 -964
- package/templates/skills/spec/references/parallel-groups.md +7 -0
- package/templates/skills/spec/references/quality-checklist.md +75 -0
- package/templates/skills/spec/references/recommended-workflow.md +4 -2
- package/templates/skills/test/SKILL.md +0 -27
- package/templates/skills/testgen/SKILL.md +24 -44
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sequant-testgen
|
|
3
3
|
description: Test stub generator for sequant /testgen phase. Parses verification criteria from /spec comments and generates Jest/Vitest test stubs with Given/When/Then structure. Use when spawned by the /testgen skill.
|
|
4
|
+
# Note: per anthropics/claude-code#43869 this is currently a no-op; agent runs on parent's model
|
|
4
5
|
model: haiku
|
|
5
6
|
maxTurns: 25
|
|
6
7
|
tools:
|
|
@@ -13,6 +13,17 @@ if [[ "${CLAUDE_HOOKS_DISABLED:-}" == "true" ]]; then
|
|
|
13
13
|
exit 0
|
|
14
14
|
fi
|
|
15
15
|
|
|
16
|
+
# === RELAY CHECK (#383) ===
|
|
17
|
+
# Sourced only when SEQUANT_RELAY=true. The check itself is a single env-var
|
|
18
|
+
# comparison when relay is disabled (default), so non-relay runs incur no cost.
|
|
19
|
+
if [[ "${SEQUANT_RELAY:-}" == "true" ]]; then
|
|
20
|
+
_RELAY_CHECK="$(dirname "${BASH_SOURCE[0]:-$0}")/relay-check.sh"
|
|
21
|
+
if [[ -f "${_RELAY_CHECK}" ]]; then
|
|
22
|
+
# shellcheck source=relay-check.sh disable=SC1091
|
|
23
|
+
source "${_RELAY_CHECK}" || true
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
|
|
16
27
|
# === READ INPUT FROM STDIN ===
|
|
17
28
|
# Claude Code passes tool data as JSON via stdin, not environment variables
|
|
18
29
|
INPUT_JSON=$(cat)
|
|
@@ -104,20 +104,23 @@ if echo "$TOOL_INPUT" | grep -qE '^(env|printenv|export)$'; then
|
|
|
104
104
|
fi
|
|
105
105
|
|
|
106
106
|
# Destructive system commands
|
|
107
|
-
|
|
107
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#570)
|
|
108
|
+
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'sudo|rm -rf /|rm -rf ~|rm -rf \$HOME'; then
|
|
108
109
|
echo "HOOK_BLOCKED: Destructive system command" | tee -a "$HOOK_LOG" >&2
|
|
109
110
|
exit 2
|
|
110
111
|
fi
|
|
111
112
|
|
|
112
113
|
# Deployment (should never happen in issue automation)
|
|
113
|
-
|
|
114
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#570)
|
|
115
|
+
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'vercel (deploy|--prod)|terraform (apply|destroy)|kubectl (apply|delete)'; then
|
|
114
116
|
echo "HOOK_BLOCKED: Deployment command" | tee -a "$HOOK_LOG" >&2
|
|
115
117
|
exit 2
|
|
116
118
|
fi
|
|
117
119
|
|
|
118
120
|
# Force push
|
|
119
121
|
# Pattern requires -f to be a standalone flag (not part of branch name like -fix)
|
|
120
|
-
|
|
122
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#564)
|
|
123
|
+
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git push.*(--force| -f($| ))'; then
|
|
121
124
|
echo "HOOK_BLOCKED: Force push" | tee -a "$HOOK_LOG" >&2
|
|
122
125
|
exit 2
|
|
123
126
|
fi
|
|
@@ -127,7 +130,8 @@ fi
|
|
|
127
130
|
# - Unpushed commits on main/master
|
|
128
131
|
# - Uncommitted changes (staged or unstaged)
|
|
129
132
|
# - Unfinished merge in progress
|
|
130
|
-
|
|
133
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#570)
|
|
134
|
+
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git reset.*(--hard|origin)'; then
|
|
131
135
|
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
132
136
|
BLOCK_REASONS=""
|
|
133
137
|
|
|
@@ -167,7 +171,8 @@ if echo "$TOOL_INPUT" | grep -qE 'git reset.*(--hard|origin)'; then
|
|
|
167
171
|
fi
|
|
168
172
|
|
|
169
173
|
# CI/CD triggers (automation shouldn't trigger more automation)
|
|
170
|
-
|
|
174
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#570)
|
|
175
|
+
if ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'gh workflow run'; then
|
|
171
176
|
echo "HOOK_BLOCKED: Workflow trigger" | tee -a "$HOOK_LOG" >&2
|
|
172
177
|
exit 2
|
|
173
178
|
fi
|
|
@@ -225,7 +230,8 @@ check_sensitive_files() {
|
|
|
225
230
|
|
|
226
231
|
if [[ "${CLAUDE_HOOKS_SECURITY:-true}" != "false" ]]; then
|
|
227
232
|
# Security checks for git commit
|
|
228
|
-
|
|
233
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#564)
|
|
234
|
+
if [[ "$TOOL_NAME" == "Bash" ]] && ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git commit'; then
|
|
229
235
|
# Skip security checks if --no-verify is used
|
|
230
236
|
if ! echo "$TOOL_INPUT" | grep -qE -- '--no-verify'; then
|
|
231
237
|
# Check staged files for secrets
|
|
@@ -257,7 +263,8 @@ fi
|
|
|
257
263
|
# --- No-Changes Guard (AC-7) ---
|
|
258
264
|
# Block commits when there are no staged or unstaged changes (prevents empty commits)
|
|
259
265
|
# Skips for --amend since amending doesn't require new changes
|
|
260
|
-
|
|
266
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#564)
|
|
267
|
+
if [[ "$TOOL_NAME" == "Bash" ]] && ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git commit'; then
|
|
261
268
|
if ! echo "$TOOL_INPUT" | grep -qE -- '--amend|--allow-empty'; then
|
|
262
269
|
# Extract target directory from cd command if present (for worktree commits)
|
|
263
270
|
# Handles: "cd /path && git commit" or "cd /path; git commit"
|
|
@@ -284,7 +291,8 @@ fi
|
|
|
284
291
|
# Warn (but don't block) when committing outside a feature worktree
|
|
285
292
|
# This catches accidental commits to main repo during feature work
|
|
286
293
|
QUALITY_LOG="${_LOG_DIR}/claude-quality.log"
|
|
287
|
-
|
|
294
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#564)
|
|
295
|
+
if [[ "$TOOL_NAME" == "Bash" ]] && ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git commit'; then
|
|
288
296
|
CWD=$(pwd)
|
|
289
297
|
if ! echo "$CWD" | grep -qE 'worktrees/feature/'; then
|
|
290
298
|
echo "$(date +%H:%M:%S) WORKTREE_WARNING: Committing outside feature worktree ($CWD)" >> "$QUALITY_LOG"
|
|
@@ -295,7 +303,8 @@ fi
|
|
|
295
303
|
# --- Commit Message Validation (AC-3) ---
|
|
296
304
|
# Enforce conventional commits format: type(scope): description
|
|
297
305
|
# Types: feat|fix|docs|style|refactor|test|chore|ci|build|perf
|
|
298
|
-
|
|
306
|
+
# Skip for gh issue/pr commands — body text may legitimately reference these tokens (#564)
|
|
307
|
+
if [[ "$TOOL_NAME" == "Bash" ]] && ! echo "$TOOL_INPUT" | grep -qE '^gh (issue|pr) ' && echo "$TOOL_INPUT" | grep -qE 'git commit'; then
|
|
299
308
|
# Extract message from -m flag
|
|
300
309
|
MSG=""
|
|
301
310
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Relay check (#383): sourced from post-tool.sh on every PostToolUse when
|
|
3
|
+
# SEQUANT_RELAY=true. Reads unread user messages from inbox.jsonl, renders the
|
|
4
|
+
# framing prompt to stdout (which Claude Code surfaces as additional context),
|
|
5
|
+
# and advances the per-issue read cursor.
|
|
6
|
+
#
|
|
7
|
+
# Fast path (no pending messages): exits silently in well under 5 ms.
|
|
8
|
+
# Slow path (messages pending): renders one framing block per invocation.
|
|
9
|
+
|
|
10
|
+
# Opt-in guard. Fast path #1: env var unset / not exactly "true".
|
|
11
|
+
# Bash precedence makes `cmd1 && cmd2 || cmd3` equivalent to `(cmd1 && cmd2) || cmd3`,
|
|
12
|
+
# so we must use an explicit `if` block to avoid falling through to `exit 0`
|
|
13
|
+
# when the test is FALSE (which is the relay-enabled case).
|
|
14
|
+
if [[ "${SEQUANT_RELAY:-}" != "true" ]]; then
|
|
15
|
+
return 0 2>/dev/null || exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Resolve relay directory. Inside an isolated worktree, the phase-executor sets
|
|
19
|
+
# SEQUANT_WORKTREE. During the spec phase (main repo) we fall back to the
|
|
20
|
+
# per-issue layout under .sequant/relay/<issue>/.
|
|
21
|
+
if [[ -n "${SEQUANT_WORKTREE:-}" ]]; then
|
|
22
|
+
_RELAY_DIR="${SEQUANT_WORKTREE}/.sequant/relay"
|
|
23
|
+
elif [[ -n "${SEQUANT_ISSUE:-}" ]]; then
|
|
24
|
+
_RELAY_DIR="${PWD}/.sequant/relay/${SEQUANT_ISSUE}"
|
|
25
|
+
else
|
|
26
|
+
# Nothing to do without a target issue or worktree.
|
|
27
|
+
return 0 2>/dev/null || exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
_INBOX="${_RELAY_DIR}/inbox.jsonl"
|
|
31
|
+
_CURSOR="${_RELAY_DIR}/.cursor"
|
|
32
|
+
|
|
33
|
+
# Fast path #2: AC-8 — `test -s` is sub-millisecond. Empty/missing inbox skips.
|
|
34
|
+
[[ -s "${_INBOX}" ]] || return 0 2>/dev/null || exit 0
|
|
35
|
+
|
|
36
|
+
# Cursor read (missing → 0). Compare against current inbox line count.
|
|
37
|
+
_CURSOR_VAL=0
|
|
38
|
+
if [[ -f "${_CURSOR}" ]]; then
|
|
39
|
+
_CURSOR_VAL=$(cat "${_CURSOR}" 2>/dev/null || echo 0)
|
|
40
|
+
[[ "${_CURSOR_VAL}" =~ ^[0-9]+$ ]] || _CURSOR_VAL=0
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
_INBOX_LINES=$(wc -l < "${_INBOX}" 2>/dev/null || echo 0)
|
|
44
|
+
_INBOX_LINES=${_INBOX_LINES// /} # trim whitespace from wc output on macOS
|
|
45
|
+
|
|
46
|
+
# Fast path #3: cursor caught up.
|
|
47
|
+
if [[ "${_INBOX_LINES}" -le "${_CURSOR_VAL}" ]]; then
|
|
48
|
+
return 0 2>/dev/null || exit 0
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Slow path: render frame.
|
|
52
|
+
|
|
53
|
+
# Resolve frame template. Phase-executor sets SEQUANT_RELAY_FRAME to the
|
|
54
|
+
# absolute path within the sequant installation. Falls back to ./templates/
|
|
55
|
+
# (when running from the sequant repo itself).
|
|
56
|
+
_FRAME_PATH="${SEQUANT_RELAY_FRAME:-}"
|
|
57
|
+
if [[ -z "${_FRAME_PATH}" || ! -f "${_FRAME_PATH}" ]]; then
|
|
58
|
+
for _candidate in \
|
|
59
|
+
"${PWD}/.claude/relay/frame.txt" \
|
|
60
|
+
"${PWD}/templates/relay/frame.txt"; do
|
|
61
|
+
if [[ -f "${_candidate}" ]]; then
|
|
62
|
+
_FRAME_PATH="${_candidate}"
|
|
63
|
+
break
|
|
64
|
+
fi
|
|
65
|
+
done
|
|
66
|
+
fi
|
|
67
|
+
if [[ -z "${_FRAME_PATH}" || ! -f "${_FRAME_PATH}" ]]; then
|
|
68
|
+
# Missing template — emit a minimal frame so the user still gets through.
|
|
69
|
+
_FRAME_PATH=""
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Skip the lines we've already shown the model. `tail -n +N` is 1-indexed.
|
|
73
|
+
_START=$((_CURSOR_VAL + 1))
|
|
74
|
+
|
|
75
|
+
# Render messages. Sort by timestamp ascending (AC-9). jq handles JSON parsing.
|
|
76
|
+
# Messages are separated by `---` lines; a single message has no separator.
|
|
77
|
+
_render_messages() {
|
|
78
|
+
if command -v jq &>/dev/null; then
|
|
79
|
+
tail -n "+${_START}" "${_INBOX}" \
|
|
80
|
+
| jq -s -r 'sort_by(.timestamp) | map("Type: \(.type)\nMessage: \((.message // "") | tojson)") | join("\n---\n")'
|
|
81
|
+
else
|
|
82
|
+
# Fallback without jq: dump raw lines.
|
|
83
|
+
tail -n "+${_START}" "${_INBOX}"
|
|
84
|
+
fi
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if [[ -n "${_FRAME_PATH}" ]]; then
|
|
88
|
+
# Split frame template at {{MESSAGES}} placeholder.
|
|
89
|
+
_PREFIX=$(awk '/\{\{MESSAGES\}\}/ {exit} {print}' "${_FRAME_PATH}")
|
|
90
|
+
_SUFFIX=$(awk '/\{\{MESSAGES\}\}/ {found=1; next} found {print}' "${_FRAME_PATH}")
|
|
91
|
+
printf '%s\n' "${_PREFIX}"
|
|
92
|
+
_render_messages
|
|
93
|
+
if [[ -n "${_SUFFIX}" ]]; then
|
|
94
|
+
printf '%s\n' "${_SUFFIX}"
|
|
95
|
+
fi
|
|
96
|
+
else
|
|
97
|
+
printf '[SEQUANT RELAY — message from user]\n'
|
|
98
|
+
_render_messages
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# Advance cursor atomically (temp + rename on same fs).
|
|
102
|
+
_TMP="${_CURSOR}.tmp.$$"
|
|
103
|
+
if printf '%s' "${_INBOX_LINES}" > "${_TMP}" 2>/dev/null; then
|
|
104
|
+
mv -f "${_TMP}" "${_CURSOR}" 2>/dev/null || rm -f "${_TMP}" 2>/dev/null || true
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
return 0 2>/dev/null || exit 0
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
[SEQUANT RELAY — message from user]
|
|
2
|
+
Respond briefly in .sequant/relay/outbox.jsonl, then continue your current task unchanged.
|
|
3
|
+
Rules:
|
|
4
|
+
- Do NOT modify acceptance criteria
|
|
5
|
+
- Do NOT change your current objective or phase
|
|
6
|
+
- Do NOT treat this as a new requirement
|
|
7
|
+
- For "query" type: provide a brief status update only
|
|
8
|
+
- For "directive" type: acknowledge and adjust approach if reasonable, but do not abandon current work
|
|
9
|
+
- For "abort" type: stop gracefully, commit progress, and exit
|
|
10
|
+
|
|
11
|
+
{{MESSAGES}}
|
|
@@ -15,6 +15,12 @@ NC='\033[0m'
|
|
|
15
15
|
|
|
16
16
|
BRANCH_NAME=$1
|
|
17
17
|
|
|
18
|
+
# Resolve main worktree (first entry in porcelain output) so subsequent git
|
|
19
|
+
# commands run from a stable cwd even if the caller invoked us from inside the
|
|
20
|
+
# worktree we are about to delete. `sed` keeps the path intact when it contains
|
|
21
|
+
# whitespace; `awk '{print $2}'` would truncate at the first space.
|
|
22
|
+
MAIN_WORKTREE=$(git worktree list --porcelain | sed -n 's/^worktree //p' | head -n 1)
|
|
23
|
+
|
|
18
24
|
# Check if branch name provided
|
|
19
25
|
if [ -z "$BRANCH_NAME" ]; then
|
|
20
26
|
echo -e "${RED}❌ Error: Branch name required${NC}"
|
|
@@ -25,8 +31,17 @@ if [ -z "$BRANCH_NAME" ]; then
|
|
|
25
31
|
exit 1
|
|
26
32
|
fi
|
|
27
33
|
|
|
28
|
-
# Find worktree path
|
|
29
|
-
|
|
34
|
+
# Find worktree path. Parse porcelain (which separates path/branch onto distinct
|
|
35
|
+
# lines) so paths containing whitespace survive intact, and so we match against
|
|
36
|
+
# the branch ref rather than against a free-form `grep` over the entire line —
|
|
37
|
+
# the latter false-matches whenever the branch name appears in the path string.
|
|
38
|
+
WORKTREE_PATH=$(git worktree list --porcelain | awk -v target="$BRANCH_NAME" '
|
|
39
|
+
/^worktree / { sub(/^worktree /, ""); path = $0 }
|
|
40
|
+
/^branch refs\/heads\// {
|
|
41
|
+
sub(/^branch refs\/heads\//, "")
|
|
42
|
+
if (index($0, target) > 0) { print path; exit }
|
|
43
|
+
}
|
|
44
|
+
')
|
|
30
45
|
|
|
31
46
|
if [ -z "$WORKTREE_PATH" ]; then
|
|
32
47
|
echo -e "${RED}❌ Error: Worktree not found for branch: $BRANCH_NAME${NC}"
|
|
@@ -53,6 +68,13 @@ if [ "$PR_STATUS" != "MERGED" ]; then
|
|
|
53
68
|
fi
|
|
54
69
|
fi
|
|
55
70
|
|
|
71
|
+
# Move to the main worktree before any destructive operation. If the caller's
|
|
72
|
+
# cwd is inside $WORKTREE_PATH (or any of its .exec-agents/agent-* sub-worktrees
|
|
73
|
+
# below), the first `git worktree remove` would invalidate cwd and every
|
|
74
|
+
# subsequent git/gh call would silently fail with "Unable to read current
|
|
75
|
+
# working directory" — including the ones with `2>/dev/null || true`.
|
|
76
|
+
cd "$MAIN_WORKTREE"
|
|
77
|
+
|
|
56
78
|
# Clean up any exec-agent sub-worktrees first (from parallel isolation)
|
|
57
79
|
EXEC_AGENTS_DIR="$WORKTREE_PATH/.exec-agents"
|
|
58
80
|
if [ -d "$EXEC_AGENTS_DIR" ]; then
|
|
@@ -71,7 +93,7 @@ if [ -d "$EXEC_AGENTS_DIR" ]; then
|
|
|
71
93
|
rmdir "$EXEC_AGENTS_DIR" 2>/dev/null || true
|
|
72
94
|
fi
|
|
73
95
|
|
|
74
|
-
# Remove worktree
|
|
96
|
+
# Remove worktree (cwd already pinned to $MAIN_WORKTREE above)
|
|
75
97
|
echo -e "${BLUE}📂 Removing worktree...${NC}"
|
|
76
98
|
git worktree remove "$WORKTREE_PATH" --force
|
|
77
99
|
|
|
@@ -152,6 +152,12 @@ git pull origin "$BASE_BRANCH"
|
|
|
152
152
|
echo -e "${BLUE}🌿 Creating new worktree from ${BASE_BRANCH}...${NC}"
|
|
153
153
|
git worktree add "$WORKTREE_DIR" -b "$BRANCH_NAME"
|
|
154
154
|
|
|
155
|
+
# Record the base branch on the new branch so downstream tooling
|
|
156
|
+
# (e.g. phase-executor zero-diff guard, see #537) can resolve the
|
|
157
|
+
# correct comparison ref when the worktree was branched off something
|
|
158
|
+
# other than origin/main.
|
|
159
|
+
git -C "$WORKTREE_DIR" config "branch.${BRANCH_NAME}.sequantBase" "$BASE_BRANCH"
|
|
160
|
+
|
|
155
161
|
# Navigate to worktree
|
|
156
162
|
cd "$WORKTREE_DIR"
|
|
157
163
|
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Behavior-Rule Detection (Shared Heuristic for /spec + /qa)
|
|
2
|
+
|
|
3
|
+
> **Source of truth:** `src/lib/heuristics/behavior-rule-detector.ts`. The
|
|
4
|
+
> keyword set, threshold, and pattern list live in TypeScript so they can be
|
|
5
|
+
> unit-tested (per AC-5 of #552); this doc cites them.
|
|
6
|
+
|
|
7
|
+
## Why this exists
|
|
8
|
+
|
|
9
|
+
Behavior-rule ACs ("default becomes X", "always include Y", "never skip Z") are
|
|
10
|
+
routinely implemented at **multiple touchpoints** — typically a skill prompt
|
|
11
|
+
(LLM-interpreted) **and** runtime TypeScript that duplicates the same rule.
|
|
12
|
+
Without a shared check, edits land at one site and the other goes stale.
|
|
13
|
+
|
|
14
|
+
**Motivating miss — issue #533** ("default /assess spec phase ON, remove
|
|
15
|
+
bug/docs auto-skip"):
|
|
16
|
+
|
|
17
|
+
- The AC explicitly named `.claude/skills/assess/SKILL.md`.
|
|
18
|
+
- `/spec` scoped the work to that file + CHANGELOG. `/exec` implemented it.
|
|
19
|
+
`/qa` returned `READY_FOR_MERGE`.
|
|
20
|
+
- Meanwhile the runtime CLI (`phase-mapper.ts` `detectPhasesFromLabels` +
|
|
21
|
+
`batch-executor.ts` auto-detect branch) still short-circuited bug/docs
|
|
22
|
+
issues to `exec → qa`, contradicting the new "spec by default" rule.
|
|
23
|
+
- Caught only by manual user follow-up; required two extra commits and four
|
|
24
|
+
doc updates on top of the original PR.
|
|
25
|
+
|
|
26
|
+
A pre-flight grep for `BUG_LABELS` / `DOCS_LABELS` / `"skip spec"` at /spec
|
|
27
|
+
time would have surfaced 90% of these in one pass. That's exactly what this
|
|
28
|
+
heuristic does.
|
|
29
|
+
|
|
30
|
+
## Trigger keywords
|
|
31
|
+
|
|
32
|
+
A `BEHAVIOR_KEYWORDS` constant in `behavior-rule-detector.ts`. Each keyword
|
|
33
|
+
also matches common inflections via the `KEYWORD_REGEXES` map (mirrors the
|
|
34
|
+
stem-aware pattern landed by #597 in `ac-linter.ts`); word boundaries are
|
|
35
|
+
preserved so `defaultValue` (camelCase identifier) does NOT trigger.
|
|
36
|
+
|
|
37
|
+
| Keyword | Inflections matched | Why it's in the set |
|
|
38
|
+
|---------|---------------------|---------------------|
|
|
39
|
+
| `default` | `defaults`, `defaulted`, `defaulting` | "default becomes X", "defaults to Y" |
|
|
40
|
+
| `always` | (adverb, no inflections) | "always include", "always run" |
|
|
41
|
+
| `never` | (adverb, no inflections) | "never skip", "never run when X" |
|
|
42
|
+
| `rule` | `rules`, `ruled`, `ruling` | "the rule is", "this rule applies" |
|
|
43
|
+
| `behavior` | `behaviors`, `behavioral`, `behaviorally` | "the behavior is", "behaviors change" |
|
|
44
|
+
| `skip` | `skips`, `skipped`, `skipping` | "skip spec", "skipping when X" |
|
|
45
|
+
|
|
46
|
+
## Trigger threshold (false-positive guard)
|
|
47
|
+
|
|
48
|
+
To avoid flagging localized fixes that happen to mention "default" once
|
|
49
|
+
("set default value to 5"), the detector requires **either**:
|
|
50
|
+
|
|
51
|
+
1. **>= 2 distinct keywords** from `BEHAVIOR_KEYWORDS` in the AC description
|
|
52
|
+
(case-insensitive, word-boundary), **OR**
|
|
53
|
+
2. An **explicit pattern** match (single keyword is enough):
|
|
54
|
+
- Mid-sentence rule constructs:
|
|
55
|
+
- `always X unless Y`
|
|
56
|
+
- `never X unless Y`
|
|
57
|
+
- `default X when Y`
|
|
58
|
+
- Capitalized imperative AC openers (case-sensitive — matches the
|
|
59
|
+
imperative-rule register, not "the system always defaults to..." prose):
|
|
60
|
+
- `Always <verb> ...` — covers AC-5 literal "Always include Y"
|
|
61
|
+
- `Never <verb> ...` — covers AC-5 literal "Never skip Z"
|
|
62
|
+
- `Default <verb> ...` — covers AC-5 literal "Default rule becomes X"
|
|
63
|
+
|
|
64
|
+
Tunable in `EXPLICIT_PATTERNS` in `behavior-rule-detector.ts`.
|
|
65
|
+
|
|
66
|
+
## Symbol categories surfaced by `findTouchpoints`
|
|
67
|
+
|
|
68
|
+
When the trigger fires, `findTouchpoints` extracts identifier-like substrings
|
|
69
|
+
from the AC and greps the codebase for them, plus any line that contains >= 2
|
|
70
|
+
distinct behavior keywords (catches comment-only sites). Symbol categories:
|
|
71
|
+
|
|
72
|
+
| Category | Example | Why include |
|
|
73
|
+
|----------|---------|-------------|
|
|
74
|
+
| Backticked symbols | `` `BUG_LABELS` ``, `` `phase-mapper.ts` `` | Verbatim from issue body — most specific |
|
|
75
|
+
| `SCREAMING_SNAKE_CASE` constants | `BUG_LABELS`, `DOCS_LABELS`, `SKIP_PHASES` | Dominant runtime-rule pattern |
|
|
76
|
+
| `camelCase` function names | `detectPhasesFromLabels`, `shouldSkipSpec` | Rule-implementing functions |
|
|
77
|
+
| File paths with extensions | `.claude/skills/assess/SKILL.md`, `phase-mapper.ts` | Direct touchpoint citations |
|
|
78
|
+
| Bold spans | `**always X unless Y**` | Author-emphasized rule statements |
|
|
79
|
+
|
|
80
|
+
## Inverse search (`findSurvivingInverseSymbols`, used by `/qa`)
|
|
81
|
+
|
|
82
|
+
`/qa` runs the detector against the diff blast radius (changed files +
|
|
83
|
+
optional 1-hop importers) using **inverse** keywords derived from each
|
|
84
|
+
asserted keyword. Asymmetric on purpose — an AC asserting the NEW rule
|
|
85
|
+
"always include spec" should look for "skip" / "exclude" / "bypass"
|
|
86
|
+
survivors, not "always" itself.
|
|
87
|
+
|
|
88
|
+
| Asserted keyword | Inverse search terms |
|
|
89
|
+
|------------------|----------------------|
|
|
90
|
+
| `default` | `skip`, `exclude`, `bypass`, `override` |
|
|
91
|
+
| `always` | `skip`, `never`, `exclude`, `conditional`, `shortcut` |
|
|
92
|
+
| `never` | `always`, `default`, `exclude` |
|
|
93
|
+
| `rule` | `exception`, `override`, `shortcut`, `bypass` |
|
|
94
|
+
| `behavior` | `legacy`, `deprecated` |
|
|
95
|
+
| `skip` | `always`, `default`, `exclude` |
|
|
96
|
+
|
|
97
|
+
High-noise common English words (`include`, `run`, `auto`, `old`,
|
|
98
|
+
`previous`) were pruned from this map after QA's self-dogfood pass on #552
|
|
99
|
+
returned 50 survivors entirely from definitional prose. As defense in
|
|
100
|
+
depth, `deriveInverseTerms` also drops any term in the `COMMON_WORDS`
|
|
101
|
+
filter at runtime, so future tunings that re-add a common word are still
|
|
102
|
+
filtered out.
|
|
103
|
+
|
|
104
|
+
A survival inside the diff blast radius -> AC `NOT_MET` with `path:line`
|
|
105
|
+
listed in the QA output (per AC-2 of #552).
|
|
106
|
+
|
|
107
|
+
## False-positive guards
|
|
108
|
+
|
|
109
|
+
- Test files (`*.test.ts`, `*.spec.ts`) are excluded from `findTouchpoints` —
|
|
110
|
+
they implement *checks* of behavior rules, not the rules themselves.
|
|
111
|
+
- Walk-skip dirs: `node_modules`, `.git`, `dist`, `build`, `.next`,
|
|
112
|
+
`coverage`, `__tests__`, `__snapshots__`.
|
|
113
|
+
- Common English words (`the`, `from`, `should`, `becomes`, ...) are filtered
|
|
114
|
+
from the symbol-extraction pass to avoid grepping for "the".
|
|
115
|
+
- Per-file cap (3) + total cap (200) on `findTouchpoints` results — keeps
|
|
116
|
+
`/spec` output readable when an AC's keywords are ambient in the repo.
|
|
117
|
+
- Total cap (50, `SURVIVOR_TOTAL_CAP`) on `findSurvivingInverseSymbols`
|
|
118
|
+
results — tighter than `findTouchpoints` because survivors are surfaced
|
|
119
|
+
inside the QA verdict and a long list drowns out the rule-relevant hits.
|
|
120
|
+
|
|
121
|
+
## Performance budget
|
|
122
|
+
|
|
123
|
+
- `detectBehaviorRule(ac)` is a cheap regex pass — runs per AC.
|
|
124
|
+
- `findTouchpoints` and `findSurvivingInverseSymbols` short-circuit to `[]`
|
|
125
|
+
when `detectBehaviorRule` returns `triggered: false`.
|
|
126
|
+
- For `/qa`, the per-AC grep cost is bounded by the diff blast radius (not
|
|
127
|
+
the whole repo). For `/spec`, scope is `src/lib`, `src/commands`, `bin`,
|
|
128
|
+
and `.claude/skills` — `bin/` and `src/commands/` are included because CLI
|
|
129
|
+
option registration (Commander.js `.option()` chains, `RunOptions` interface)
|
|
130
|
+
is a recurring rule-drift site. `templates/skills/` and `skills/` are
|
|
131
|
+
intentionally excluded since they 1:1 mirror `.claude/skills/`.
|
|
132
|
+
|
|
133
|
+
When zero behavior-rule ACs are detected across the issue, both detectors
|
|
134
|
+
should be skipped entirely (no per-file grep pass).
|
|
135
|
+
|
|
136
|
+
## Where to call from
|
|
137
|
+
|
|
138
|
+
- **`/spec`** — `### Rule Touchpoints (Conditional)` subsection under
|
|
139
|
+
`## Context Gathering`. Calls `findTouchpoints` per AC; emits a
|
|
140
|
+
`## Rule Touchpoints` section in the plan output when any hits found.
|
|
141
|
+
- **`/qa`** — `### 6e. Behavior-Rule Survival Check` between
|
|
142
|
+
`### 6d. Adversarial Re-Read` and `### 7. A+ Status Verdict`. Calls
|
|
143
|
+
`findSurvivingInverseSymbols` per behavior-rule AC; survivals -> AC
|
|
144
|
+
`NOT_MET`, gated through `behavior_rule_survival_status` in section 7.
|
|
145
|
+
|
|
146
|
+
## API
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import {
|
|
150
|
+
detectBehaviorRule,
|
|
151
|
+
findTouchpoints,
|
|
152
|
+
findSurvivingInverseSymbols,
|
|
153
|
+
} from "./src/lib/heuristics/behavior-rule-detector.ts";
|
|
154
|
+
|
|
155
|
+
// Cheap gate
|
|
156
|
+
const detection = detectBehaviorRule(ac);
|
|
157
|
+
// detection.triggered: boolean
|
|
158
|
+
// detection.keywords: BehaviorKeyword[]
|
|
159
|
+
// detection.matchedPattern?: string
|
|
160
|
+
|
|
161
|
+
// /spec: enumerate likely implementation sites
|
|
162
|
+
const hits = findTouchpoints(ac, repoRoot);
|
|
163
|
+
// hits: { path, line, snippet }[]
|
|
164
|
+
|
|
165
|
+
// /qa: search diff blast radius for OLD-rule survivors
|
|
166
|
+
const survivors = findSurvivingInverseSymbols(ac, repoRoot, diffPaths);
|
|
167
|
+
// survivors: { path, line, snippet }[]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Known limitations
|
|
171
|
+
|
|
172
|
+
**Meta-recursion** — when an AC describes the detector itself (e.g. lists
|
|
173
|
+
all six trigger keywords as part of explaining the trigger condition),
|
|
174
|
+
`findSurvivingInverseSymbols` will self-fire on the new feature's own
|
|
175
|
+
definitional documentation. The pruned `INVERSE_KEYWORDS` map and
|
|
176
|
+
`SURVIVOR_TOTAL_CAP = 50` mitigate noise, but the heuristic cannot
|
|
177
|
+
distinguish "code that implements the OLD rule" from "documentation that
|
|
178
|
+
defines the rule". Treat survivors inside this reference doc and
|
|
179
|
+
`spec/SKILL.md` / `qa/SKILL.md` as definitional, not stale. See QA's
|
|
180
|
+
self-dogfood result on PR #607 for the original observation.
|
|
181
|
+
|
|
182
|
+
**Inverse-phrase fallback (deferred)** — `findSurvivingInverseSymbols`
|
|
183
|
+
relies on the asserted-→-inverse keyword map. When an AC's inverse rule
|
|
184
|
+
has no obvious symbol or keyword (e.g. "API responses always include the
|
|
185
|
+
user ID field"), the natural next layer is to derive an inverse English
|
|
186
|
+
phrase ("exclude user ID", "don't include user ID") and grep for that.
|
|
187
|
+
Not implemented — file a follow-up issue with the concrete fixture if a
|
|
188
|
+
real `/qa` miss surfaces.
|
|
189
|
+
|
|
190
|
+
## Tuning
|
|
191
|
+
|
|
192
|
+
Edit `src/lib/heuristics/behavior-rule-detector.ts`:
|
|
193
|
+
|
|
194
|
+
- `BEHAVIOR_KEYWORDS` — keyword stem set (the source of truth)
|
|
195
|
+
- `KEYWORD_REGEXES` — per-stem inflection regex map; word-boundary
|
|
196
|
+
guarded so identifier-shaped tokens (`defaultValue`, `skipperFn`) do
|
|
197
|
+
not trigger
|
|
198
|
+
- `EXPLICIT_PATTERNS` — single-keyword override patterns (mid-sentence
|
|
199
|
+
rule constructs + capitalized imperative AC openers)
|
|
200
|
+
- `INVERSE_KEYWORDS` — asserted -> inverse mapping for `/qa` (common
|
|
201
|
+
English words filtered at runtime in `deriveInverseTerms`)
|
|
202
|
+
- `TOUCHPOINT_ROOTS` — directories scanned by `findTouchpoints`
|
|
203
|
+
- `SURVIVOR_TOTAL_CAP` — total survivor cap on `findSurvivingInverseSymbols`
|
|
204
|
+
|
|
205
|
+
Re-run `npx vitest run src/lib/heuristics` after tuning.
|
|
@@ -17,10 +17,15 @@ Claude Code supports exactly **4 built-in subagent types**:
|
|
|
17
17
|
|
|
18
18
|
Sequant defines **4 custom agents** in `.claude/agents/`. These centralize model, permissions, effort, and tool restrictions that were previously duplicated inline.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
> **Upstream caveat:** `Model` values below are *declared* in the agent files but
|
|
21
|
+
> currently ignored at runtime per anthropics/claude-code#43869 — every subagent
|
|
22
|
+
> inherits the parent session's model. Tiers are kept aligned with intended
|
|
23
|
+
> defaults so they reactivate when upstream fixes ship.
|
|
24
|
+
|
|
25
|
+
| Agent Name | Based On | Model (declared) | Permission Mode | Used By |
|
|
26
|
+
|------------|----------|------------------|-----------------|---------|
|
|
22
27
|
| `sequant-explorer` | Explore | haiku | (default) | `/spec` |
|
|
23
|
-
| `sequant-qa-checker` | general-purpose |
|
|
28
|
+
| `sequant-qa-checker` | general-purpose | sonnet | bypassPermissions | `/qa` |
|
|
24
29
|
| `sequant-implementer` | general-purpose | (inherits) | bypassPermissions | `/exec` |
|
|
25
30
|
| `sequant-testgen` | general-purpose | haiku | (default) | `/testgen` |
|
|
26
31
|
|
|
@@ -68,7 +73,8 @@ Custom agents are defined in `.claude/agents/*.md` with YAML frontmatter:
|
|
|
68
73
|
---
|
|
69
74
|
name: sequant-qa-checker
|
|
70
75
|
description: Quality check agent for sequant QA phase.
|
|
71
|
-
|
|
76
|
+
# Note: per anthropics/claude-code#43869 this is currently a no-op; agent runs on parent's model
|
|
77
|
+
model: sonnet
|
|
72
78
|
permissionMode: bypassPermissions
|
|
73
79
|
effort: low
|
|
74
80
|
maxTurns: 15
|
|
@@ -139,10 +145,17 @@ Agent(subagent_type="Plan",
|
|
|
139
145
|
|
|
140
146
|
**Default:** Use `haiku` unless the task requires deep reasoning.
|
|
141
147
|
|
|
148
|
+
> **Note:** Per anthropics/claude-code#43869, both the per-call `model:`
|
|
149
|
+
> parameter and the agent-definition `model:` field are currently ignored.
|
|
150
|
+
> Subagents inherit the parent session's model regardless of what you specify
|
|
151
|
+
> here. The guidance below reflects the *intended* tier each task should use
|
|
152
|
+
> once upstream fixes land.
|
|
153
|
+
|
|
142
154
|
Custom agents set their model in the agent definition, so you don't need to specify it inline:
|
|
143
155
|
|
|
144
156
|
```
|
|
145
|
-
# Model comes from .claude/agents/sequant-qa-checker.md (
|
|
157
|
+
# Model comes from .claude/agents/sequant-qa-checker.md (sonnet, declared)
|
|
158
|
+
# Note: declared tier currently inert per anthropics/claude-code#43869
|
|
146
159
|
Agent(subagent_type="sequant-qa-checker",
|
|
147
160
|
prompt="...")
|
|
148
161
|
```
|
|
@@ -201,10 +214,10 @@ inline when spawning them.
|
|
|
201
214
|
|
|
202
215
|
| Task | Recommended Agent | Why |
|
|
203
216
|
|------|-------------------|-----|
|
|
204
|
-
| Quality checks (git diff, npm test) | `sequant-qa-checker` | bypassPermissions +
|
|
205
|
-
| Codebase exploration | `sequant-explorer` | Read-only, haiku,
|
|
217
|
+
| Quality checks (git diff, npm test) | `sequant-qa-checker` | bypassPermissions + effort:low (declared model: sonnet, inert per #43869) |
|
|
218
|
+
| Codebase exploration | `sequant-explorer` | Read-only, focused tools (declared model: haiku, inert per #43869) |
|
|
206
219
|
| Implementation subtask | `sequant-implementer` | Full access, inherits model |
|
|
207
|
-
| Test stub generation | `sequant-testgen` | Write access, no Bash
|
|
220
|
+
| Test stub generation | `sequant-testgen` | Write access, no Bash (declared model: haiku, inert per #43869) |
|
|
208
221
|
| One-off custom task | `general-purpose` | Flexible, specify model/mode inline |
|
|
209
222
|
|
|
210
223
|
**CRITICAL:** If your background agent runs `git diff`, `npm test`, `git status`, or any shell command, use `sequant-qa-checker` or `sequant-implementer` (both have bypassPermissions). Do NOT use `general-purpose` without `mode="bypassPermissions"` — Bash calls will silently fail.
|