token-pilot 0.29.0 → 0.30.1
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 +2 -2
- package/.claude-plugin/plugin.json +2 -4
- package/CHANGELOG.md +35 -0
- package/README.md +57 -384
- package/agents/tp-api-surface-tracker.md +1 -1
- package/agents/tp-audit-scanner.md +1 -1
- package/agents/tp-commit-writer.md +1 -1
- package/agents/tp-context-engineer.md +1 -1
- package/agents/tp-dead-code-finder.md +1 -1
- package/agents/tp-debugger.md +1 -1
- package/agents/tp-dep-health.md +1 -1
- package/agents/tp-doc-writer.md +1 -1
- package/agents/tp-history-explorer.md +1 -1
- package/agents/tp-impact-analyzer.md +1 -1
- package/agents/tp-incident-timeline.md +1 -1
- package/agents/tp-incremental-builder.md +1 -1
- package/agents/tp-migration-scout.md +1 -1
- package/agents/tp-onboard.md +1 -1
- package/agents/tp-performance-profiler.md +1 -1
- package/agents/tp-pr-reviewer.md +1 -1
- package/agents/tp-refactor-planner.md +1 -1
- package/agents/tp-review-impact.md +1 -1
- package/agents/tp-run.md +1 -1
- package/agents/tp-session-restorer.md +1 -1
- package/agents/tp-ship-coordinator.md +1 -1
- package/agents/tp-spec-writer.md +1 -1
- package/agents/tp-test-coverage-gapper.md +1 -1
- package/agents/tp-test-triage.md +1 -1
- package/agents/tp-test-writer.md +1 -1
- package/dist/ast-index/client.d.ts +17 -2
- package/dist/ast-index/client.js +233 -107
- package/dist/cli/tool-audit.d.ts +5 -0
- package/dist/cli/tool-audit.js +9 -1
- package/dist/core/edit-prep-state.d.ts +42 -0
- package/dist/core/edit-prep-state.js +108 -0
- package/dist/core/policy-engine.d.ts +1 -5
- package/dist/core/policy-engine.js +9 -24
- package/dist/handlers/explore-area.js +6 -1
- package/dist/handlers/read-for-edit.d.ts +5 -5
- package/dist/handlers/read-for-edit.js +188 -110
- package/dist/hooks/installer.js +18 -0
- package/dist/hooks/pre-bash.d.ts +11 -1
- package/dist/hooks/pre-bash.js +51 -1
- package/dist/hooks/pre-edit.d.ts +69 -0
- package/dist/hooks/pre-edit.js +104 -0
- package/dist/hooks/pre-grep.d.ts +12 -1
- package/dist/hooks/pre-grep.js +39 -1
- package/dist/index.d.ts +30 -0
- package/dist/index.js +87 -22
- package/dist/server/enforcement-mode.d.ts +47 -0
- package/dist/server/enforcement-mode.js +59 -0
- package/dist/server/tool-definitions.d.ts +20 -0
- package/dist/server/tool-definitions.js +127 -12
- package/dist/server/tool-profiles.d.ts +19 -1
- package/dist/server/tool-profiles.js +38 -4
- package/dist/server.d.ts +2 -0
- package/dist/server.js +89 -21
- package/docs/agents.md +82 -0
- package/docs/configuration.md +117 -0
- package/docs/hooks.md +99 -0
- package/docs/installation.md +169 -0
- package/docs/tools.md +61 -0
- package/hooks/hooks.json +18 -0
- package/package.json +2 -2
- package/start.sh +19 -9
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP tool definitions and system instructions.
|
|
3
3
|
* Pure static data — no runtime dependencies.
|
|
4
|
+
*
|
|
5
|
+
* v0.30.0 — Profile-specific instructions. Each profile advertises only
|
|
6
|
+
* the tools it includes; instructions are trimmed to match so the agent
|
|
7
|
+
* doesn't hallucinate tools that aren't in tools/list.
|
|
8
|
+
*
|
|
9
|
+
* minimal — 5 core tools, minimal context overhead
|
|
10
|
+
* nav — 10 exploration tools, no editing
|
|
11
|
+
* edit — nav + 6 edit-prep tools (DEFAULT)
|
|
12
|
+
* full — everything including audit tools
|
|
13
|
+
*/
|
|
14
|
+
import type { ToolProfile } from "./tool-profiles.js";
|
|
15
|
+
/**
|
|
16
|
+
* Select MCP instructions for the given tool profile.
|
|
17
|
+
* Each profile only mentions tools that are actually advertised in its
|
|
18
|
+
* tools/list — prevents the agent from calling tools it can't see.
|
|
19
|
+
*/
|
|
20
|
+
export declare function getMcpInstructions(profile: ToolProfile): string;
|
|
21
|
+
/**
|
|
22
|
+
* @deprecated Use getMcpInstructions(profile) instead.
|
|
23
|
+
* Kept for backward-compat — resolves to the full profile instructions.
|
|
4
24
|
*/
|
|
5
25
|
export declare const MCP_INSTRUCTIONS: string;
|
|
6
26
|
export declare const TOOL_DEFINITIONS: ({
|
|
@@ -1,10 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Minimal profile — 5 essential tools, near-zero instructions overhead
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
const MCP_INSTRUCTIONS_MINIMAL = [
|
|
5
|
+
"Token Pilot — token-efficient code reading. ALWAYS prefer these tools over Read/cat/grep.",
|
|
6
|
+
"",
|
|
7
|
+
"TOOLS:",
|
|
8
|
+
"• smart_read(path) — read a code file (NOT cat/Read — returns structure, 60-80% fewer tokens)",
|
|
9
|
+
"• read_symbol(path, symbol) — read ONE function/class body (NOT the whole file)",
|
|
10
|
+
"• find_usages(symbol) — find where a symbol is defined, imported, or used",
|
|
11
|
+
"• smart_diff — review git changes mapped to functions/classes (NOT git diff)",
|
|
12
|
+
"• smart_log — structured commit history (NOT git log)",
|
|
13
|
+
"",
|
|
14
|
+
"USE Read/Grep ONLY for: non-code configs (JSON, YAML, markdown), regex patterns.",
|
|
15
|
+
].join("\n");
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Nav profile — exploration only, no edit-prep tools
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
const MCP_INSTRUCTIONS_NAV = [
|
|
20
|
+
"Token Pilot — token-efficient code reading (saves 60-80% tokens). ALWAYS prefer these tools over Read/cat/grep.",
|
|
21
|
+
"",
|
|
22
|
+
"DECISION RULES — pick the first match:",
|
|
23
|
+
"1. New codebase / unfamiliar project → project_overview",
|
|
24
|
+
"2. Starting work on a directory → explore_area (outline + imports + tests + git log in one call)",
|
|
25
|
+
"3. Need to read a code file → smart_read (NOT Read/cat — returns structure, 60-80% fewer tokens)",
|
|
26
|
+
' - For navigation/browsing: smart_read(scope="nav") — names + lines only, 2-3x smaller',
|
|
27
|
+
' - For public API overview: smart_read(scope="exports")',
|
|
28
|
+
"4. Need one function/class body → read_symbol (loads only that symbol, NOT the whole file)",
|
|
29
|
+
"5. Find where a symbol is used → find_usages (semantic: definitions + imports + usages)",
|
|
30
|
+
' - For initial discovery: find_usages(mode="list") — file:line only, 5-10x smaller',
|
|
31
|
+
"6. Understand file dependencies → related_files (imports, importers, tests — ranked by relevance)",
|
|
32
|
+
"7. List all symbols in a directory → outline (classes, functions, methods in one call)",
|
|
33
|
+
"8. Review git changes → smart_diff (NOT git diff — maps changes to functions/classes)",
|
|
34
|
+
"9. Commit history → smart_log (NOT git log — structured with categories)",
|
|
35
|
+
"10. Module architecture → module_info (deps, dependents, public API)",
|
|
36
|
+
"11. Read markdown/yaml/json/csv section → read_section (loads one heading/key/row-range, NOT the whole file)",
|
|
37
|
+
"12. Long session / before compaction → session_snapshot (<200 token state capture)",
|
|
38
|
+
"",
|
|
39
|
+
"USE Read/Grep ONLY for: regex text search → Grep | exact raw content → Read",
|
|
40
|
+
"",
|
|
41
|
+
"WORKFLOW:",
|
|
42
|
+
"• Explore: project_overview → explore_area → smart_read → read_symbol",
|
|
43
|
+
].join("\n");
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Edit profile — nav + batch reads + edit-prep (DEFAULT)
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
const MCP_INSTRUCTIONS_EDIT = [
|
|
6
48
|
"Token Pilot — token-efficient code reading (saves 60-80% tokens). ALWAYS prefer these tools over Read/cat/grep.",
|
|
7
49
|
"",
|
|
50
|
+
"MANDATORY EDIT SAFETY — before ANY Edit/Write tool call on an existing code file:",
|
|
51
|
+
" → FIRST call read_for_edit(path, symbol=<target>) to obtain the exact old_string.",
|
|
52
|
+
" → NEVER build Edit's old_string from a smart_read / Read snippet — whitespace and",
|
|
53
|
+
" line-number prefixes diverge from disk and Edit silently mismatches.",
|
|
54
|
+
" → For a brand-new file, Write is fine; read_for_edit is only required for edits.",
|
|
55
|
+
"",
|
|
8
56
|
"DECISION RULES — pick the first match:",
|
|
9
57
|
"1. New codebase / unfamiliar project → project_overview",
|
|
10
58
|
"2. Starting work on a directory → explore_area (outline + imports + tests + git log in one call)",
|
|
@@ -14,7 +62,52 @@ export const MCP_INSTRUCTIONS = [
|
|
|
14
62
|
"4. Need one function/class body → read_symbol (loads only that symbol, NOT the whole file)",
|
|
15
63
|
" - Preparing edit? Add include_edit_context=true to skip separate read_for_edit call",
|
|
16
64
|
"5. Need MULTIPLE function/class bodies from same file → read_symbols (batch — one call instead of N)",
|
|
17
|
-
"6. Preparing an
|
|
65
|
+
"6. Preparing an Edit → read_for_edit — MANDATORY, not optional. Returns exact old_string.",
|
|
66
|
+
"7. Verify edits after editing → read_diff (only changed hunks — REQUIRES smart_read BEFORE editing)",
|
|
67
|
+
"8. Multiple files at once → smart_read_many (batch up to 20 files)",
|
|
68
|
+
"9. Find where a symbol is used → find_usages (semantic: definitions + imports + usages)",
|
|
69
|
+
' - For initial discovery: find_usages(mode="list") — file:line only, 5-10x smaller',
|
|
70
|
+
"10. Understand file dependencies → related_files (imports, importers, tests — ranked by relevance)",
|
|
71
|
+
"11. List all symbols in a directory → outline (classes, functions, methods in one call)",
|
|
72
|
+
"12. Review git changes → smart_diff (NOT git diff — maps changes to functions/classes)",
|
|
73
|
+
"13. Commit history → smart_log (NOT git log — structured with categories)",
|
|
74
|
+
"14. Module architecture → module_info (deps, dependents, public API)",
|
|
75
|
+
"15. Read markdown/yaml/json/csv section → read_section (loads one heading/key/row-range, NOT the whole file)",
|
|
76
|
+
' - For editing sections: read_for_edit(path, section="Section Name")',
|
|
77
|
+
"16. Long session / before compaction → session_snapshot (capture goal, decisions, confirmed facts, files, next step as <200 token block)",
|
|
78
|
+
" - Budget-constrained? Use smart_read(max_tokens=N) to auto-downgrade output size",
|
|
79
|
+
"",
|
|
80
|
+
"USE Read/Grep ONLY for: regex text search → Grep | exact raw content → Read",
|
|
81
|
+
"",
|
|
82
|
+
"WORKFLOWS:",
|
|
83
|
+
"• Explore: project_overview → explore_area → smart_read → read_symbol",
|
|
84
|
+
"• Edit (mandatory): smart_read (to pick target) → read_for_edit → Edit → read_diff",
|
|
85
|
+
"• Docs: smart_read (outline) → read_section → read_for_edit(section=) → Edit → read_diff",
|
|
86
|
+
"• Refactor: find_usages → read_symbols → read_for_edit → Edit",
|
|
87
|
+
"• Long session: session_snapshot → compact context → continue with minimal state",
|
|
88
|
+
].join("\n");
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Full profile — all tools including audit (code_audit, find_unused, test_summary)
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
const MCP_INSTRUCTIONS_FULL = [
|
|
93
|
+
"Token Pilot — token-efficient code reading (saves 60-80% tokens). ALWAYS prefer these tools over Read/cat/grep.",
|
|
94
|
+
"",
|
|
95
|
+
"MANDATORY EDIT SAFETY — before ANY Edit/Write tool call on an existing code file:",
|
|
96
|
+
" → FIRST call read_for_edit(path, symbol=<target>) to obtain the exact old_string.",
|
|
97
|
+
" → NEVER build Edit's old_string from a smart_read / Read snippet — whitespace and",
|
|
98
|
+
" line-number prefixes diverge from disk and Edit silently mismatches.",
|
|
99
|
+
" → For a brand-new file, Write is fine; read_for_edit is only required for edits.",
|
|
100
|
+
"",
|
|
101
|
+
"DECISION RULES — pick the first match:",
|
|
102
|
+
"1. New codebase / unfamiliar project → project_overview",
|
|
103
|
+
"2. Starting work on a directory → explore_area (outline + imports + tests + git log in one call)",
|
|
104
|
+
"3. Need to read a code file → smart_read (NOT Read/cat — returns structure, 60-80% fewer tokens)",
|
|
105
|
+
' - For navigation/browsing: smart_read(scope="nav") — names + lines only, 2-3x smaller',
|
|
106
|
+
' - For public API overview: smart_read(scope="exports")',
|
|
107
|
+
"4. Need one function/class body → read_symbol (loads only that symbol, NOT the whole file)",
|
|
108
|
+
" - Preparing edit? Add include_edit_context=true to skip separate read_for_edit call",
|
|
109
|
+
"5. Need MULTIPLE function/class bodies from same file → read_symbols (batch — one call instead of N)",
|
|
110
|
+
"6. Preparing an Edit → read_for_edit — MANDATORY, not optional. Returns exact old_string.",
|
|
18
111
|
"7. Verify edits after editing → read_diff (only changed hunks — REQUIRES smart_read BEFORE editing)",
|
|
19
112
|
"8. Multiple files at once → smart_read_many (batch up to 20 files)",
|
|
20
113
|
"9. Find where a symbol is used → find_usages (semantic: definitions + imports + usages)",
|
|
@@ -28,20 +121,42 @@ export const MCP_INSTRUCTIONS = [
|
|
|
28
121
|
"16. Dead code → find_unused (unreferenced symbols across project)",
|
|
29
122
|
"17. Module architecture → module_info (deps, dependents, public API)",
|
|
30
123
|
"18. Read markdown/yaml/json/csv section → read_section (loads one heading/key/row-range, NOT the whole file)",
|
|
31
|
-
'
|
|
124
|
+
' - For editing sections: read_for_edit(path, section="Section Name")',
|
|
32
125
|
"19. Long session / before compaction → session_snapshot (capture goal, decisions, confirmed facts, files, next step as <200 token block)",
|
|
33
|
-
"
|
|
126
|
+
" - Budget-constrained? Use smart_read(max_tokens=N) to auto-downgrade output size",
|
|
34
127
|
"",
|
|
35
|
-
"USE
|
|
128
|
+
"USE Read/Grep ONLY for: regex text search → Grep | exact raw content → Read | non-code configs → Read",
|
|
36
129
|
"",
|
|
37
130
|
"WORKFLOWS:",
|
|
38
131
|
"• Explore: project_overview → explore_area → smart_read → read_symbol",
|
|
39
|
-
"• Edit: smart_read
|
|
132
|
+
"• Edit (mandatory): smart_read (to pick target) → read_for_edit → Edit → read_diff",
|
|
40
133
|
"• Docs: smart_read (outline) → read_section → read_for_edit(section=) → Edit → read_diff",
|
|
41
134
|
"• Refactor: find_usages → read_symbols → read_for_edit → Edit → test_summary",
|
|
42
135
|
"• Audit: code_audit + find_unused + Grep (for regex patterns)",
|
|
43
136
|
"• Long session: session_snapshot → compact context → continue with minimal state",
|
|
44
137
|
].join("\n");
|
|
138
|
+
/**
|
|
139
|
+
* Select MCP instructions for the given tool profile.
|
|
140
|
+
* Each profile only mentions tools that are actually advertised in its
|
|
141
|
+
* tools/list — prevents the agent from calling tools it can't see.
|
|
142
|
+
*/
|
|
143
|
+
export function getMcpInstructions(profile) {
|
|
144
|
+
switch (profile) {
|
|
145
|
+
case "minimal":
|
|
146
|
+
return MCP_INSTRUCTIONS_MINIMAL;
|
|
147
|
+
case "nav":
|
|
148
|
+
return MCP_INSTRUCTIONS_NAV;
|
|
149
|
+
case "edit":
|
|
150
|
+
return MCP_INSTRUCTIONS_EDIT;
|
|
151
|
+
case "full":
|
|
152
|
+
return MCP_INSTRUCTIONS_FULL;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @deprecated Use getMcpInstructions(profile) instead.
|
|
157
|
+
* Kept for backward-compat — resolves to the full profile instructions.
|
|
158
|
+
*/
|
|
159
|
+
export const MCP_INSTRUCTIONS = MCP_INSTRUCTIONS_FULL;
|
|
45
160
|
export const TOOL_DEFINITIONS = [
|
|
46
161
|
// --- Core reading tools ---
|
|
47
162
|
{
|
|
@@ -477,7 +592,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
477
592
|
},
|
|
478
593
|
{
|
|
479
594
|
name: "explore_area",
|
|
480
|
-
description: "One-call exploration of a directory: outline (all symbols), imports (external deps + who imports this area), tests (matching test files), recent git changes. Use INSTEAD OF separate outline + related_files + git log calls.",
|
|
595
|
+
description: "One-call exploration of a directory: outline (all symbols), imports (external deps + who imports this area), tests (matching test files), recent git changes. Use INSTEAD OF separate outline + related_files + git log calls. Default since v0.30.0 returns only outline+changes — telemetry showed the all-4 default producing negative token reduction for small areas. Opt into imports/tests explicitly via `include` when you need them.",
|
|
481
596
|
inputSchema: {
|
|
482
597
|
type: "object",
|
|
483
598
|
properties: {
|
|
@@ -491,7 +606,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
491
606
|
type: "string",
|
|
492
607
|
enum: ["outline", "imports", "tests", "changes"],
|
|
493
608
|
},
|
|
494
|
-
description:
|
|
609
|
+
description: 'Sections to include. Default: ["outline","changes"]. Add "imports" for dep graph, "tests" to map test files — both can be heavy on large areas.',
|
|
495
610
|
},
|
|
496
611
|
},
|
|
497
612
|
required: ["path"],
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Selection: TOKEN_PILOT_PROFILE=nav|edit|full env var. Unknown values
|
|
22
22
|
* fall back to full with a stderr warning. Silent on missing env.
|
|
23
23
|
*/
|
|
24
|
-
export type ToolProfile = "full" | "nav" | "edit";
|
|
24
|
+
export type ToolProfile = "full" | "nav" | "edit" | "minimal";
|
|
25
25
|
export declare const PROFILE_NAMES: readonly ToolProfile[];
|
|
26
26
|
/**
|
|
27
27
|
* Meta-tools — diagnostic / self-observation tools that must be visible
|
|
@@ -30,6 +30,12 @@ export declare const PROFILE_NAMES: readonly ToolProfile[];
|
|
|
30
30
|
* would you trust the savings number?
|
|
31
31
|
*/
|
|
32
32
|
export declare const META_TOOLS: ReadonlySet<string>;
|
|
33
|
+
/**
|
|
34
|
+
* Minimal profile — 5 core tools for emergency / context-constrained sessions.
|
|
35
|
+
* Token overhead: tools/list is tiny; instructions are ~80 tokens vs ~350 for full.
|
|
36
|
+
* Use TOKEN_PILOT_PROFILE=minimal when the agent's context budget is nearly full.
|
|
37
|
+
*/
|
|
38
|
+
export declare const MINIMAL_TOOLS: ReadonlySet<string>;
|
|
33
39
|
/** Minimum nav profile — exploration only, no editing support. */
|
|
34
40
|
export declare const NAV_TOOLS: ReadonlySet<string>;
|
|
35
41
|
/** Edit profile adds batch reads + edit-preparation tools. */
|
|
@@ -48,5 +54,17 @@ export declare function filterToolsByProfile<T extends {
|
|
|
48
54
|
* Parse the TOKEN_PILOT_PROFILE env value. Unknown values get a warning
|
|
49
55
|
* and fall back to full — we never silently apply a guess.
|
|
50
56
|
*/
|
|
57
|
+
/**
|
|
58
|
+
* Parse the TOKEN_PILOT_PROFILE env value.
|
|
59
|
+
*
|
|
60
|
+
* Default changed in v0.30.0: full → edit.
|
|
61
|
+
* Rationale: 'full' was exposing 22 tools + full instruction set on every
|
|
62
|
+
* session, burning ~3 k tokens before any work. 'edit' covers 99% of
|
|
63
|
+
* development workflows (reading + writing code). Switch to 'full' only
|
|
64
|
+
* when you need audit tools (code_audit, find_unused, test_summary).
|
|
65
|
+
*
|
|
66
|
+
* Unknown values fall back to 'edit' with a stderr warning — we never
|
|
67
|
+
* silently apply a guess.
|
|
68
|
+
*/
|
|
51
69
|
export declare function parseProfileEnv(envValue: string | undefined, warn?: (msg: string) => void): ToolProfile;
|
|
52
70
|
//# sourceMappingURL=tool-profiles.d.ts.map
|
|
@@ -25,6 +25,7 @@ export const PROFILE_NAMES = [
|
|
|
25
25
|
"full",
|
|
26
26
|
"nav",
|
|
27
27
|
"edit",
|
|
28
|
+
"minimal",
|
|
28
29
|
];
|
|
29
30
|
/**
|
|
30
31
|
* Meta-tools — diagnostic / self-observation tools that must be visible
|
|
@@ -37,6 +38,18 @@ export const META_TOOLS = new Set([
|
|
|
37
38
|
"session_budget",
|
|
38
39
|
"session_snapshot",
|
|
39
40
|
]);
|
|
41
|
+
/**
|
|
42
|
+
* Minimal profile — 5 core tools for emergency / context-constrained sessions.
|
|
43
|
+
* Token overhead: tools/list is tiny; instructions are ~80 tokens vs ~350 for full.
|
|
44
|
+
* Use TOKEN_PILOT_PROFILE=minimal when the agent's context budget is nearly full.
|
|
45
|
+
*/
|
|
46
|
+
export const MINIMAL_TOOLS = new Set([
|
|
47
|
+
"smart_read",
|
|
48
|
+
"read_symbol",
|
|
49
|
+
"find_usages",
|
|
50
|
+
"smart_diff",
|
|
51
|
+
"smart_log",
|
|
52
|
+
]);
|
|
40
53
|
/** Minimum nav profile — exploration only, no editing support. */
|
|
41
54
|
export const NAV_TOOLS = new Set([
|
|
42
55
|
"smart_read",
|
|
@@ -49,6 +62,7 @@ export const NAV_TOOLS = new Set([
|
|
|
49
62
|
"explore_area",
|
|
50
63
|
"smart_log",
|
|
51
64
|
"smart_diff",
|
|
65
|
+
"read_section", // v0.30.0: section reading is nav-class (read-only, no edit prep)
|
|
52
66
|
]);
|
|
53
67
|
/** Edit profile adds batch reads + edit-preparation tools. */
|
|
54
68
|
export const EDIT_EXTRAS = new Set([
|
|
@@ -73,6 +87,11 @@ export function filterToolsByProfile(tools, profile) {
|
|
|
73
87
|
// session_snapshot are the instruments for verifying the profile is
|
|
74
88
|
// doing its job. Hiding them would turn "did this save tokens?" into
|
|
75
89
|
// a guess.
|
|
90
|
+
if (profile === "minimal") {
|
|
91
|
+
// Minimal: 5 core tools only. META excluded — keep the footprint tiny.
|
|
92
|
+
// The agent can still call session_analytics by name if it knows it.
|
|
93
|
+
return tools.filter((t) => MINIMAL_TOOLS.has(t.name));
|
|
94
|
+
}
|
|
76
95
|
if (profile === "nav") {
|
|
77
96
|
return tools.filter((t) => NAV_TOOLS.has(t.name) || META_TOOLS.has(t.name));
|
|
78
97
|
}
|
|
@@ -85,14 +104,29 @@ export function filterToolsByProfile(tools, profile) {
|
|
|
85
104
|
* Parse the TOKEN_PILOT_PROFILE env value. Unknown values get a warning
|
|
86
105
|
* and fall back to full — we never silently apply a guess.
|
|
87
106
|
*/
|
|
107
|
+
/**
|
|
108
|
+
* Parse the TOKEN_PILOT_PROFILE env value.
|
|
109
|
+
*
|
|
110
|
+
* Default changed in v0.30.0: full → edit.
|
|
111
|
+
* Rationale: 'full' was exposing 22 tools + full instruction set on every
|
|
112
|
+
* session, burning ~3 k tokens before any work. 'edit' covers 99% of
|
|
113
|
+
* development workflows (reading + writing code). Switch to 'full' only
|
|
114
|
+
* when you need audit tools (code_audit, find_unused, test_summary).
|
|
115
|
+
*
|
|
116
|
+
* Unknown values fall back to 'edit' with a stderr warning — we never
|
|
117
|
+
* silently apply a guess.
|
|
118
|
+
*/
|
|
88
119
|
export function parseProfileEnv(envValue, warn = () => { }) {
|
|
89
120
|
if (!envValue)
|
|
90
|
-
return "
|
|
121
|
+
return "edit";
|
|
91
122
|
const lower = envValue.trim().toLowerCase();
|
|
92
|
-
if (lower === "full" ||
|
|
123
|
+
if (lower === "full" ||
|
|
124
|
+
lower === "nav" ||
|
|
125
|
+
lower === "edit" ||
|
|
126
|
+
lower === "minimal") {
|
|
93
127
|
return lower;
|
|
94
128
|
}
|
|
95
|
-
warn(`[token-pilot] Unknown TOKEN_PILOT_PROFILE="${envValue}". Expected full|nav|edit. Falling back to
|
|
96
|
-
return "
|
|
129
|
+
warn(`[token-pilot] Unknown TOKEN_PILOT_PROFILE="${envValue}". Expected full|nav|edit|minimal. Falling back to edit.`);
|
|
130
|
+
return "edit";
|
|
97
131
|
}
|
|
98
132
|
//# sourceMappingURL=tool-profiles.js.map
|
package/dist/server.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { type EnforcementMode } from "./server/enforcement-mode.js";
|
|
2
3
|
export declare function createServer(projectRoot: string, options?: {
|
|
3
4
|
skipAstIndex?: boolean;
|
|
5
|
+
enforcementMode?: EnforcementMode;
|
|
4
6
|
}): Promise<Server<{
|
|
5
7
|
method: string;
|
|
6
8
|
params?: {
|
package/dist/server.js
CHANGED
|
@@ -45,11 +45,13 @@ import { detectContextMode } from "./integration/context-mode-detector.js";
|
|
|
45
45
|
import { estimateTokens } from "./core/token-estimator.js";
|
|
46
46
|
import { checkPolicy, isFullReadTool } from "./core/policy-engine.js";
|
|
47
47
|
import { appendToolCall } from "./core/tool-call-log.js";
|
|
48
|
-
import {
|
|
48
|
+
import { getMcpInstructions, TOOL_DEFINITIONS, } from "./server/tool-definitions.js";
|
|
49
49
|
import { filterToolsByProfile, parseProfileEnv, } from "./server/tool-profiles.js";
|
|
50
|
+
import { STRICT_SMART_READ_MAX_TOKENS, STRICT_EXPLORE_AREA_INCLUDE, } from "./server/enforcement-mode.js";
|
|
50
51
|
import { createTokenEstimates } from "./server/token-estimates.js";
|
|
51
52
|
import { validateSmartReadArgs, validateReadSymbolArgs, validateReadSymbolsArgs, validateReadRangeArgs, validateReadDiffArgs, validateFindUsagesArgs, validateSmartReadManyArgs, validateReadForEditArgs, validateRelatedFilesArgs, validateOutlineArgs, validateFindUnusedArgs, validateCodeAuditArgs, validateProjectOverviewArgs, validateModuleInfoArgs, validateSmartDiffArgs, validateExploreAreaArgs, validateSmartLogArgs, validateTestSummaryArgs, validateReadSectionArgs, } from "./core/validation.js";
|
|
52
53
|
export async function createServer(projectRoot, options) {
|
|
54
|
+
const mode = options?.enforcementMode ?? "deny";
|
|
53
55
|
const config = await loadConfig(projectRoot);
|
|
54
56
|
const astIndex = new AstIndexClient(projectRoot, config.astIndex.timeout, {
|
|
55
57
|
binaryPath: config.astIndex.binaryPath,
|
|
@@ -67,6 +69,10 @@ export async function createServer(projectRoot, options) {
|
|
|
67
69
|
// entirely; callers that care about durability should not use it.
|
|
68
70
|
const shutdownFlush = () => {
|
|
69
71
|
void sessionRegistries.flushAll();
|
|
72
|
+
// Stop the 5-minute ast-index tick so we don't block exit on SIGINT/SIGTERM.
|
|
73
|
+
// .unref() already makes it non-keeping, but clearing is defensive and
|
|
74
|
+
// avoids a stray `update` firing during shutdown.
|
|
75
|
+
astIndex.stopPeriodicUpdate();
|
|
70
76
|
};
|
|
71
77
|
process.once("beforeExit", shutdownFlush);
|
|
72
78
|
process.once("SIGINT", shutdownFlush);
|
|
@@ -193,7 +199,6 @@ export async function createServer(projectRoot, options) {
|
|
|
193
199
|
let fullFileReadsCount = 0;
|
|
194
200
|
let totalCallCount = 0;
|
|
195
201
|
let totalTokensReturned = 0;
|
|
196
|
-
const readForEditCalled = new Set();
|
|
197
202
|
// Detect context-mode companion
|
|
198
203
|
const cmEnabled = config.contextMode.enabled;
|
|
199
204
|
const contextModeStatus = await detectContextMode(projectRoot, cmEnabled === "auto" ? undefined : cmEnabled);
|
|
@@ -221,13 +226,25 @@ export async function createServer(projectRoot, options) {
|
|
|
221
226
|
fileWatcher.onAstUpdate(() => sessionCache.invalidateByAst());
|
|
222
227
|
}
|
|
223
228
|
}
|
|
224
|
-
// Wire session cache
|
|
225
|
-
|
|
226
|
-
|
|
229
|
+
// Wire git-watcher → session cache + AST index.
|
|
230
|
+
// Always registers — even without sessionCache — so branch-switch still
|
|
231
|
+
// triggers the index update. Without this the index went stale on every
|
|
232
|
+
// `git checkout` until the next file-touch (or never, for branches that
|
|
233
|
+
// only moved files the agent hadn't read yet).
|
|
234
|
+
gitWatcher.onBranchSwitchEvent((changedFiles) => {
|
|
235
|
+
if (sessionCache) {
|
|
227
236
|
sessionCache.invalidateByFiles(changedFiles);
|
|
228
237
|
sessionCache.invalidateByGit();
|
|
229
|
-
}
|
|
230
|
-
|
|
238
|
+
}
|
|
239
|
+
// Fire-and-forget. incrementalUpdate self-guards against
|
|
240
|
+
// disabled / oversized / uninitialised index states.
|
|
241
|
+
void astIndex.incrementalUpdate();
|
|
242
|
+
});
|
|
243
|
+
// 5-minute safety-net for long sessions where FileWatcher may miss events
|
|
244
|
+
// (Docker bind mounts, NFS, files mutated by sibling processes). Cheap —
|
|
245
|
+
// each tick is a single `ast-index update` call that bails early if the
|
|
246
|
+
// index isn't ready or the previous tick is still running.
|
|
247
|
+
astIndex.startPeriodicUpdate();
|
|
231
248
|
// Read version from package.json
|
|
232
249
|
let pkgVersion = "0.1.1";
|
|
233
250
|
try {
|
|
@@ -238,18 +255,20 @@ export async function createServer(projectRoot, options) {
|
|
|
238
255
|
catch {
|
|
239
256
|
/* fallback to hardcoded */
|
|
240
257
|
}
|
|
258
|
+
// v0.26.3 — tool profiles. TOKEN_PILOT_PROFILE=nav|edit|full|minimal
|
|
259
|
+
// (default: edit since v0.30.0) trims the advertised tools/list payload.
|
|
260
|
+
// Handlers stay live, so a subagent that explicitly names a filtered-out
|
|
261
|
+
// tool still gets a response — we just don't brag about every tool upfront.
|
|
262
|
+
// v0.30.0 — profile also selects matching MCP instructions so the agent
|
|
263
|
+
// doesn't see rules for tools that aren't in its tools/list.
|
|
264
|
+
const activeProfile = parseProfileEnv(process.env.TOKEN_PILOT_PROFILE, (m) => process.stderr.write(m + "\n"));
|
|
241
265
|
const server = new Server({ name: "token-pilot", version: pkgVersion }, {
|
|
242
266
|
capabilities: { tools: {} },
|
|
243
|
-
instructions:
|
|
267
|
+
instructions: getMcpInstructions(activeProfile),
|
|
244
268
|
});
|
|
245
|
-
// v0.26.3 — tool profiles. TOKEN_PILOT_PROFILE=nav|edit|full (default
|
|
246
|
-
// full) trims the advertised tools/list payload. Handlers stay live,
|
|
247
|
-
// so a subagent that explicitly names a filtered-out tool still gets
|
|
248
|
-
// a response — we just don't brag about every tool upfront.
|
|
249
|
-
const activeProfile = parseProfileEnv(process.env.TOKEN_PILOT_PROFILE, (m) => process.stderr.write(m + "\n"));
|
|
250
269
|
const advertisedTools = filterToolsByProfile(TOOL_DEFINITIONS, activeProfile);
|
|
251
|
-
if (activeProfile !== "
|
|
252
|
-
process.stderr.write(`[token-pilot] Profile: ${activeProfile} — advertising ${advertisedTools.length}/${TOOL_DEFINITIONS.length} tools.
|
|
270
|
+
if (activeProfile !== "edit") {
|
|
271
|
+
process.stderr.write(`[token-pilot] Profile: ${activeProfile} — advertising ${advertisedTools.length}/${TOOL_DEFINITIONS.length} tools. Set TOKEN_PILOT_PROFILE=edit for the default set.\n`);
|
|
253
272
|
}
|
|
254
273
|
server.setRequestHandler(ListToolsRequestSchema, () => ({
|
|
255
274
|
tools: advertisedTools,
|
|
@@ -289,14 +308,10 @@ export async function createServer(projectRoot, options) {
|
|
|
289
308
|
if (isFullReadTool(rest.tool)) {
|
|
290
309
|
fullFileReadsCount++;
|
|
291
310
|
}
|
|
292
|
-
if (rest.tool === "read_for_edit" && call.path) {
|
|
293
|
-
readForEditCalled.add(call.path);
|
|
294
|
-
}
|
|
295
311
|
// Policy check
|
|
296
312
|
const advisory = checkPolicy(config.policies, rest.tool, {
|
|
297
313
|
fullFileReadsCount,
|
|
298
314
|
tokensReturned: rest.tokensReturned,
|
|
299
|
-
readForEditCalled,
|
|
300
315
|
totalCallCount,
|
|
301
316
|
totalTokensReturned,
|
|
302
317
|
});
|
|
@@ -331,6 +346,14 @@ export async function createServer(projectRoot, options) {
|
|
|
331
346
|
switch (name) {
|
|
332
347
|
case "smart_read": {
|
|
333
348
|
const validArgs = validateSmartReadArgs(args);
|
|
349
|
+
// v0.30.0 strict mode: cap max_tokens when caller didn't set it.
|
|
350
|
+
let strictReadCapNote;
|
|
351
|
+
if (mode === "strict" && validArgs.max_tokens === undefined) {
|
|
352
|
+
validArgs.max_tokens = STRICT_SMART_READ_MAX_TOKENS;
|
|
353
|
+
strictReadCapNote =
|
|
354
|
+
`\n\n[token-pilot strict] Output capped at ${STRICT_SMART_READ_MAX_TOKENS} tokens ` +
|
|
355
|
+
`(TOKEN_PILOT_MODE=strict). Pass max_tokens explicitly to override.`;
|
|
356
|
+
}
|
|
334
357
|
const picked = pickRegistry(args);
|
|
335
358
|
// Try non-code handler for JSON/YAML/MD etc.
|
|
336
359
|
if (isNonCodeStructured(validArgs.path)) {
|
|
@@ -373,8 +396,9 @@ export async function createServer(projectRoot, options) {
|
|
|
373
396
|
absPath: resolve(projectRoot, validArgs.path),
|
|
374
397
|
args: validArgs,
|
|
375
398
|
});
|
|
376
|
-
|
|
377
|
-
|
|
399
|
+
const srSuffix = (policyAdv ?? "") + (strictReadCapNote ?? "");
|
|
400
|
+
if (srSuffix)
|
|
401
|
+
result.content[0] = { type: "text", text: text + srSuffix };
|
|
378
402
|
return result;
|
|
379
403
|
}
|
|
380
404
|
case "read_symbol": {
|
|
@@ -527,6 +551,15 @@ export async function createServer(projectRoot, options) {
|
|
|
527
551
|
}
|
|
528
552
|
case "find_usages": {
|
|
529
553
|
const usagesArgs = validateFindUsagesArgs(args);
|
|
554
|
+
// v0.30.0 strict mode: default mode to "list" when caller didn't set it.
|
|
555
|
+
// Injected before cache lookup so the key matches strict-mode cached results.
|
|
556
|
+
let strictFuNote;
|
|
557
|
+
if (mode === "strict" && usagesArgs.mode === undefined) {
|
|
558
|
+
usagesArgs.mode = "list";
|
|
559
|
+
strictFuNote =
|
|
560
|
+
`\n\n[token-pilot strict] find_usages mode defaulted to "list" ` +
|
|
561
|
+
`(TOKEN_PILOT_MODE=strict). Pass mode explicitly to override.`;
|
|
562
|
+
}
|
|
530
563
|
const cachedUsages = sessionCache?.get("find_usages", usagesArgs);
|
|
531
564
|
if (cachedUsages) {
|
|
532
565
|
recordWithTrace({
|
|
@@ -558,6 +591,12 @@ export async function createServer(projectRoot, options) {
|
|
|
558
591
|
savingsCategory: "compression",
|
|
559
592
|
args: usagesArgs,
|
|
560
593
|
});
|
|
594
|
+
if (strictFuNote && usagesResult.content[0]) {
|
|
595
|
+
usagesResult.content[0] = {
|
|
596
|
+
type: "text",
|
|
597
|
+
text: usagesText + strictFuNote,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
561
600
|
return usagesResult;
|
|
562
601
|
}
|
|
563
602
|
case "project_overview": {
|
|
@@ -801,6 +840,15 @@ export async function createServer(projectRoot, options) {
|
|
|
801
840
|
}
|
|
802
841
|
case "explore_area": {
|
|
803
842
|
const eaArgs = validateExploreAreaArgs(args);
|
|
843
|
+
// v0.30.0 strict mode: default include to outline-only when caller didn't set it.
|
|
844
|
+
// Injected before cache lookup so the key matches strict-mode cached results.
|
|
845
|
+
let strictEaCapNote;
|
|
846
|
+
if (mode === "strict" && eaArgs.include === undefined) {
|
|
847
|
+
eaArgs.include = STRICT_EXPLORE_AREA_INCLUDE;
|
|
848
|
+
strictEaCapNote =
|
|
849
|
+
`\n\n[token-pilot strict] include defaulted to ["outline"] ` +
|
|
850
|
+
`(TOKEN_PILOT_MODE=strict). Pass include explicitly to override.`;
|
|
851
|
+
}
|
|
804
852
|
const cachedEa = sessionCache?.get("explore_area", eaArgs);
|
|
805
853
|
if (cachedEa) {
|
|
806
854
|
recordWithTrace({
|
|
@@ -833,10 +881,24 @@ export async function createServer(projectRoot, options) {
|
|
|
833
881
|
savingsCategory: "compression",
|
|
834
882
|
args: eaArgs,
|
|
835
883
|
});
|
|
884
|
+
if (strictEaCapNote && eaResult.content[0]) {
|
|
885
|
+
eaResult.content[0] = {
|
|
886
|
+
type: "text",
|
|
887
|
+
text: eaText + strictEaCapNote,
|
|
888
|
+
};
|
|
889
|
+
}
|
|
836
890
|
return eaResult;
|
|
837
891
|
}
|
|
838
892
|
case "smart_log": {
|
|
839
893
|
const slArgs = validateSmartLogArgs(args);
|
|
894
|
+
// v0.30.0 strict mode: bound count to 20 when caller didn't set it.
|
|
895
|
+
let strictSlNote;
|
|
896
|
+
if (mode === "strict" && slArgs.count === undefined) {
|
|
897
|
+
slArgs.count = 20;
|
|
898
|
+
strictSlNote =
|
|
899
|
+
`\n\n[token-pilot strict] smart_log count defaulted to 20 ` +
|
|
900
|
+
`(TOKEN_PILOT_MODE=strict). Pass count explicitly to override.`;
|
|
901
|
+
}
|
|
840
902
|
const slResult = await handleSmartLog(slArgs, projectRoot);
|
|
841
903
|
const slText = slResult.content[0]?.text ?? "";
|
|
842
904
|
const slTokens = estimateTokens(slText);
|
|
@@ -849,6 +911,12 @@ export async function createServer(projectRoot, options) {
|
|
|
849
911
|
savingsCategory: "compression",
|
|
850
912
|
args: slArgs,
|
|
851
913
|
});
|
|
914
|
+
if (strictSlNote && slResult.content[0]) {
|
|
915
|
+
slResult.content[0] = {
|
|
916
|
+
type: "text",
|
|
917
|
+
text: slText + strictSlNote,
|
|
918
|
+
};
|
|
919
|
+
}
|
|
852
920
|
return { content: slResult.content };
|
|
853
921
|
}
|
|
854
922
|
case "test_summary": {
|
package/docs/agents.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# tp-* Subagents (Claude Code only)
|
|
2
|
+
|
|
3
|
+
`tp-*` subagents are a Claude Code feature. Other clients get the MCP tools + hooks but cannot invoke subagents. Each agent carries an explicit `model:` field in its frontmatter; the budget is enforced post-response — overshoots beyond 10% land in `.token-pilot/over-budget.log`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx token-pilot install-agents --scope=user # all projects
|
|
9
|
+
npx token-pilot install-agents --scope=project # this repo only
|
|
10
|
+
npx token-pilot install-agents --scope=user --force # re-apply after an update
|
|
11
|
+
npx token-pilot uninstall-agents --scope=user|project
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`init` offers to install these; to add them to another project run `npx token-pilot install-agents`.
|
|
15
|
+
|
|
16
|
+
## Tier 1 — Workhorses (invoke proactively)
|
|
17
|
+
|
|
18
|
+
| Agent | When to invoke | Budget |
|
|
19
|
+
|-------|---------------|-------:|
|
|
20
|
+
| `tp-run` | General MCP-first workhorse; use when no specialised agent fits | 800 |
|
|
21
|
+
| `tp-onboard` | Orient to an unfamiliar repo (layout, entry points, modules) | 600 |
|
|
22
|
+
| `tp-pr-reviewer` | Review a diff / PR / changeset; verdict-first, Critical/Important tiers | 600 |
|
|
23
|
+
| `tp-impact-analyzer` | Trace blast-radius of a change (callers, transitive deps) | 400 |
|
|
24
|
+
| `tp-refactor-planner` | Plan a refactor with exact edit context per step | 500 |
|
|
25
|
+
| `tp-test-triage` | Investigate test failures → root cause → minimal fix | 500 |
|
|
26
|
+
|
|
27
|
+
## Tier 2 — Specialists
|
|
28
|
+
|
|
29
|
+
| Agent | When to invoke | Budget |
|
|
30
|
+
|-------|---------------|-------:|
|
|
31
|
+
| `tp-debugger` | Stack trace / error → root-cause line via call-tree traversal | 700 |
|
|
32
|
+
| `tp-migration-scout` | Pre-migration impact map grouped by effort class | 800 |
|
|
33
|
+
| `tp-test-writer` | Write tests for ONE symbol, mirrors project style, runs tests | 900 |
|
|
34
|
+
| `tp-dead-code-finder` | Cross-checked dead-code detection, output-only (never deletes) | 600 |
|
|
35
|
+
| `tp-commit-writer` | Draft Conventional-Commit from staged diff; refuses failing tests | 400 |
|
|
36
|
+
| `tp-history-explorer` | "Why is this like this?" — minimum commit chain explaining current state | 600 |
|
|
37
|
+
| `tp-audit-scanner` | Read-only security / quality audit; Critical / Important / Minor findings | 800 |
|
|
38
|
+
| `tp-session-restorer` | Rehydrate state after /clear or compaction from latest snapshot | 400 |
|
|
39
|
+
|
|
40
|
+
## Tier 3 — Combo / Workflow
|
|
41
|
+
|
|
42
|
+
| Agent | When to invoke | Budget |
|
|
43
|
+
|-------|---------------|-------:|
|
|
44
|
+
| `tp-review-impact` | Pre-merge blast-radius review (diff × dependents × API surface) | 700 |
|
|
45
|
+
| `tp-test-coverage-gapper` | Find symbols with zero test references, prioritised | 500 |
|
|
46
|
+
| `tp-api-surface-tracker` | Public API diff vs last release → MAJOR / MINOR / PATCH verdict | 600 |
|
|
47
|
+
| `tp-dep-health` | Dep audit: stale × heavily-used × removable | 600 |
|
|
48
|
+
| `tp-incident-timeline` | Correlate an incident window with commits, rank likely culprits | 700 |
|
|
49
|
+
|
|
50
|
+
## Tier 4 — Methodology
|
|
51
|
+
|
|
52
|
+
| Agent | When to invoke | Budget |
|
|
53
|
+
|-------|---------------|-------:|
|
|
54
|
+
| `tp-context-engineer` | Audit / write CLAUDE.md / AGENTS.md rules files per project | 800 |
|
|
55
|
+
| `tp-spec-writer` | Pre-code spec with gated workflow; surfaces assumptions before code | 900 |
|
|
56
|
+
| `tp-performance-profiler` | Measure → identify → fix → verify → guard; refuses to optimise without data | 800 |
|
|
57
|
+
| `tp-incremental-builder` | Multi-file feature work in thin vertical slices, test between each | 900 |
|
|
58
|
+
| `tp-doc-writer` | ADRs + READMEs + API docs; documents *why* not *what* | 700 |
|
|
59
|
+
| `tp-ship-coordinator` | 5-pillar pre-launch checklist (quality / security / observability / rollback / rollout) | 800 |
|
|
60
|
+
|
|
61
|
+
## Model Tiers
|
|
62
|
+
|
|
63
|
+
Every agent carries an explicit `model:` field:
|
|
64
|
+
|
|
65
|
+
| Model | Count | Used for |
|
|
66
|
+
|-------|------:|---------|
|
|
67
|
+
| `haiku` | 9 | Structured / format-bound output (commit messages, onboarding maps, ADRs, session briefings) |
|
|
68
|
+
| `sonnet` | 15 | Reasoning tasks (review, debug, test, plan, audit, spec, profile, ship) |
|
|
69
|
+
| `inherit` | 1 | Deep correlation needing the main thread's model (`tp-incident-timeline`) |
|
|
70
|
+
|
|
71
|
+
Under Opus 4.7's +35% tokenizer tax, keeping the majority of agent spawns on haiku/sonnet saves 5–10× model cost vs an all-Opus baseline.
|
|
72
|
+
|
|
73
|
+
## Third-party Agent Integration (bless-agents)
|
|
74
|
+
|
|
75
|
+
For third-party agents (e.g. `acc-*` plugins) whose tool allowlist excludes token-pilot MCP:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx token-pilot bless-agents # add token-pilot MCP to project-level overrides
|
|
79
|
+
npx token-pilot unbless-agents <name>... | --all
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`doctor` warns when the original agent has changed since blessing.
|