@maestrofrontier/frontier 1.4.5 → 1.6.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/.agents/plugins/marketplace.json +21 -21
- package/.codex-plugin/plugin.json +29 -29
- package/.cursorrules +197 -194
- package/AGENTS.md +3 -3
- package/README.md +368 -368
- package/bin/maestro.cjs +75 -75
- package/commands/compress.md +36 -36
- package/commands/frontier.md +124 -124
- package/commands/terse.md +23 -23
- package/docs/codex.md +167 -167
- package/docs/orchestration.md +168 -168
- package/frontier/cli.cjs +279 -252
- package/frontier/config.cjs +468 -468
- package/frontier/dispatch.cjs +267 -255
- package/frontier/judge.cjs +92 -92
- package/frontier/progress.cjs +138 -0
- package/frontier/run.cjs +201 -180
- package/frontier/schema.cjs +112 -112
- package/frontier/semaphore.cjs +49 -49
- package/frontier/synthesize.cjs +79 -79
- package/hooks/frontier-autorun.cjs +135 -120
- package/hooks/hooks.json +103 -103
- package/hooks/maestro-doctrine-guard.cjs +81 -81
- package/hooks/maestro-gate-reminder.cjs +22 -7
- package/hooks/maestro-gate-telemetry.cjs +79 -77
- package/hooks/maestro-phase-scope.cjs +118 -118
- package/hooks/maestro-statusline-sync.cjs +152 -152
- package/hooks/maestro-subagent-guard.cjs +148 -148
- package/hooks/maestro-terse-mode.cjs +189 -189
- package/hooks/maestro-toolbudget-advisory.cjs +127 -127
- package/integrations/README.md +111 -111
- package/integrations/cline/skills/frontier/SKILL.md +75 -75
- package/integrations/codex/prompts/frontier.md +70 -70
- package/integrations/codex/prompts/update.md +39 -39
- package/integrations/codex/skills/maestro-frontier/SKILL.md +122 -122
- package/integrations/codex/skills/maestro-settings/SKILL.md +55 -55
- package/integrations/codex/skills/maestro-terse/SKILL.md +58 -58
- package/integrations/codex/skills/maestro-update/SKILL.md +31 -31
- package/integrations/cursor/commands/frontier.md +63 -63
- package/integrations/cursor/commands/update.md +34 -34
- package/integrations/gemini/commands/frontier.toml +76 -76
- package/integrations/windsurf/workflows/frontier.md +70 -70
- package/package.json +59 -58
- package/scripts/install.cjs +1014 -1014
- package/settings/cli.cjs +140 -140
- package/settings/config.cjs +309 -309
- package/skills/maestro-frontier/SKILL.md +122 -122
- package/skills/maestro-settings/SKILL.md +55 -55
- package/skills/maestro-terse/SKILL.md +58 -58
- package/skills/maestro-update/SKILL.md +31 -31
- package/skills/terse/SKILL.md +74 -74
package/hooks/hooks.json
CHANGED
|
@@ -1,103 +1,103 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"PreToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "Read",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-doctrine-guard.cjs\""
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
],
|
|
14
|
-
"SessionStart": [
|
|
15
|
-
{
|
|
16
|
-
"matcher": "",
|
|
17
|
-
"hooks": [
|
|
18
|
-
{
|
|
19
|
-
"type": "command",
|
|
20
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-terse-mode.cjs\""
|
|
21
|
-
},
|
|
22
|
-
{
|
|
23
|
-
"type": "command",
|
|
24
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-statusline-sync.cjs\""
|
|
25
|
-
}
|
|
26
|
-
]
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
"UserPromptSubmit": [
|
|
30
|
-
{
|
|
31
|
-
"matcher": "",
|
|
32
|
-
"hooks": [
|
|
33
|
-
{
|
|
34
|
-
"type": "command",
|
|
35
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-gate-reminder.cjs\""
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"type": "command",
|
|
39
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-terse-mode.cjs\""
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"type": "command",
|
|
43
|
-
"command": "node -e \"require(require('path').join(process.env.CLAUDE_PLUGIN_ROOT || process.env.PLUGIN_ROOT, 'hooks', 'frontier-autorun.cjs'))\"",
|
|
44
|
-
"timeout": 300
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
],
|
|
49
|
-
"SubagentStop": [
|
|
50
|
-
{
|
|
51
|
-
"matcher": "",
|
|
52
|
-
"hooks": [
|
|
53
|
-
{
|
|
54
|
-
"type": "command",
|
|
55
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-subagent-guard.cjs\""
|
|
56
|
-
}
|
|
57
|
-
]
|
|
58
|
-
}
|
|
59
|
-
],
|
|
60
|
-
"Stop": [
|
|
61
|
-
{
|
|
62
|
-
"matcher": "",
|
|
63
|
-
"hooks": [
|
|
64
|
-
{
|
|
65
|
-
"type": "command",
|
|
66
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-loop-guard.cjs\""
|
|
67
|
-
}
|
|
68
|
-
]
|
|
69
|
-
}
|
|
70
|
-
],
|
|
71
|
-
"PostToolUse": [
|
|
72
|
-
{
|
|
73
|
-
"matcher": "Edit|Write|NotebookEdit|Bash",
|
|
74
|
-
"hooks": [
|
|
75
|
-
{
|
|
76
|
-
"type": "command",
|
|
77
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-phase-scope.cjs\""
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
"matcher": "Edit|Write|NotebookEdit",
|
|
83
|
-
"hooks": [
|
|
84
|
-
{
|
|
85
|
-
"type": "command",
|
|
86
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-toolbudget-advisory.cjs\""
|
|
87
|
-
}
|
|
88
|
-
]
|
|
89
|
-
}
|
|
90
|
-
],
|
|
91
|
-
"SessionEnd": [
|
|
92
|
-
{
|
|
93
|
-
"matcher": "",
|
|
94
|
-
"hooks": [
|
|
95
|
-
{
|
|
96
|
-
"type": "command",
|
|
97
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-gate-telemetry.cjs\""
|
|
98
|
-
}
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
]
|
|
102
|
-
}
|
|
103
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Read",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-doctrine-guard.cjs\""
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"SessionStart": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-terse-mode.cjs\""
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"type": "command",
|
|
24
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-statusline-sync.cjs\""
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"UserPromptSubmit": [
|
|
30
|
+
{
|
|
31
|
+
"matcher": "",
|
|
32
|
+
"hooks": [
|
|
33
|
+
{
|
|
34
|
+
"type": "command",
|
|
35
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-gate-reminder.cjs\""
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-terse-mode.cjs\""
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "command",
|
|
43
|
+
"command": "node -e \"require(require('path').join(process.env.CLAUDE_PLUGIN_ROOT || process.env.PLUGIN_ROOT, 'hooks', 'frontier-autorun.cjs'))\"",
|
|
44
|
+
"timeout": 300
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
],
|
|
49
|
+
"SubagentStop": [
|
|
50
|
+
{
|
|
51
|
+
"matcher": "",
|
|
52
|
+
"hooks": [
|
|
53
|
+
{
|
|
54
|
+
"type": "command",
|
|
55
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-subagent-guard.cjs\""
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"Stop": [
|
|
61
|
+
{
|
|
62
|
+
"matcher": "",
|
|
63
|
+
"hooks": [
|
|
64
|
+
{
|
|
65
|
+
"type": "command",
|
|
66
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-loop-guard.cjs\""
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
],
|
|
71
|
+
"PostToolUse": [
|
|
72
|
+
{
|
|
73
|
+
"matcher": "Edit|Write|NotebookEdit|Bash",
|
|
74
|
+
"hooks": [
|
|
75
|
+
{
|
|
76
|
+
"type": "command",
|
|
77
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-phase-scope.cjs\""
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"matcher": "Edit|Write|NotebookEdit",
|
|
83
|
+
"hooks": [
|
|
84
|
+
{
|
|
85
|
+
"type": "command",
|
|
86
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-toolbudget-advisory.cjs\""
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"SessionEnd": [
|
|
92
|
+
{
|
|
93
|
+
"matcher": "",
|
|
94
|
+
"hooks": [
|
|
95
|
+
{
|
|
96
|
+
"type": "command",
|
|
97
|
+
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/maestro-gate-telemetry.cjs\""
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -1,81 +1,81 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Maestro PreToolUse doctrine-read guard. Enforces AGENTS.md S7.2
|
|
3
|
-
// structurally: when the doctrine is autoloaded (CLAUDE.md/AGENTS.md
|
|
4
|
-
// present at cwd, which Claude Code injects at session start), a Read
|
|
5
|
-
// of AGENTS.md or CLAUDE.md re-buys tokens for content already in
|
|
6
|
-
// context. This hook replaces the probabilistic S7.2 prose line with a
|
|
7
|
-
// deterministic deny.
|
|
8
|
-
//
|
|
9
|
-
// Modes via MAESTRO_DOCTRINE_GUARD:
|
|
10
|
-
// - "always" (default): deny every doctrine Read while doctrine files
|
|
11
|
-
// exist at cwd. Safe on Claude Code, where subagents receive the
|
|
12
|
-
// project doctrine automatically; the deny reason tells the model
|
|
13
|
-
// to use the in-context copy.
|
|
14
|
-
// - "once": allow the first doctrine Read per session (marker file in
|
|
15
|
-
// the OS temp dir keyed by session_id), deny repeats. For runtimes
|
|
16
|
-
// whose subagents genuinely lack the doctrine in context (S7.2:
|
|
17
|
-
// "a subagent without it in context reads AGENTS.md once").
|
|
18
|
-
// - "0": disabled.
|
|
19
|
-
//
|
|
20
|
-
// When no doctrine file exists at cwd nothing was autoloaded, so reads
|
|
21
|
-
// pass through untouched (e.g. inspecting another repo's AGENTS.md).
|
|
22
|
-
// docs/orchestration.md is never guarded -- it is the on-demand layer
|
|
23
|
-
// and reading it is the intended path. Fails open on any error.
|
|
24
|
-
//
|
|
25
|
-
// Payload fields verified against code.claude.com/docs/en/hooks
|
|
26
|
-
// (PreToolUse input: session_id, cwd, tool_name, tool_input; output:
|
|
27
|
-
// hookSpecificOutput.permissionDecision allow|deny|ask + reason),
|
|
28
|
-
// 2026-06-11.
|
|
29
|
-
//
|
|
30
|
-
// .cjs so Node treats it as CommonJS regardless of any "type": "module"
|
|
31
|
-
// package.json in a parent directory of the install location.
|
|
32
|
-
|
|
33
|
-
const fs = require('fs');
|
|
34
|
-
const os = require('os');
|
|
35
|
-
const path = require('path');
|
|
36
|
-
|
|
37
|
-
const mode = process.env.MAESTRO_DOCTRINE_GUARD || 'always';
|
|
38
|
-
if (mode === '0') process.exit(0);
|
|
39
|
-
|
|
40
|
-
let data = {};
|
|
41
|
-
try { data = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(0); }
|
|
42
|
-
if (data.tool_name !== 'Read' || !data.tool_input) process.exit(0);
|
|
43
|
-
|
|
44
|
-
const fp = data.tool_input.file_path;
|
|
45
|
-
if (typeof fp !== 'string') process.exit(0);
|
|
46
|
-
const base = path.basename(fp).toLowerCase();
|
|
47
|
-
if (base !== 'agents.md' && base !== 'claude.md') process.exit(0);
|
|
48
|
-
|
|
49
|
-
// Guard only when the doctrine was actually autoloaded: a doctrine file
|
|
50
|
-
// at cwd is what Claude Code injects at session start.
|
|
51
|
-
const cwd = typeof data.cwd === 'string' ? data.cwd : process.cwd();
|
|
52
|
-
let autoloaded = false;
|
|
53
|
-
try {
|
|
54
|
-
autoloaded = fs.existsSync(path.join(cwd, 'CLAUDE.md'))
|
|
55
|
-
|| fs.existsSync(path.join(cwd, 'AGENTS.md'));
|
|
56
|
-
} catch { autoloaded = false; }
|
|
57
|
-
if (!autoloaded) process.exit(0);
|
|
58
|
-
|
|
59
|
-
if (mode === 'once' && data.session_id) {
|
|
60
|
-
const marker = path.join(
|
|
61
|
-
os.tmpdir(),
|
|
62
|
-
`maestro-doctrine-guard-${String(data.session_id).replace(/[^a-zA-Z0-9-]/g, '_')}`
|
|
63
|
-
);
|
|
64
|
-
if (!fs.existsSync(marker)) {
|
|
65
|
-
try { fs.writeFileSync(marker, '1'); } catch { /* still allow */ }
|
|
66
|
-
process.exit(0);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
process.stdout.write(JSON.stringify({
|
|
71
|
-
hookSpecificOutput: {
|
|
72
|
-
hookEventName: 'PreToolUse',
|
|
73
|
-
permissionDecision: 'deny',
|
|
74
|
-
permissionDecisionReason: 'maestro-doctrine-guard: denied Read of '
|
|
75
|
-
+ path.basename(fp) + ' -- the doctrine is autoloaded into context '
|
|
76
|
-
+ 'at session start (AGENTS.md S7.2); use the in-context copy '
|
|
77
|
-
+ 'instead of re-reading it from disk. The on-demand protocol '
|
|
78
|
-
+ 'layer lives in docs/orchestration.md, which is not blocked.'
|
|
79
|
-
}
|
|
80
|
-
}));
|
|
81
|
-
process.exit(0);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Maestro PreToolUse doctrine-read guard. Enforces AGENTS.md S7.2
|
|
3
|
+
// structurally: when the doctrine is autoloaded (CLAUDE.md/AGENTS.md
|
|
4
|
+
// present at cwd, which Claude Code injects at session start), a Read
|
|
5
|
+
// of AGENTS.md or CLAUDE.md re-buys tokens for content already in
|
|
6
|
+
// context. This hook replaces the probabilistic S7.2 prose line with a
|
|
7
|
+
// deterministic deny.
|
|
8
|
+
//
|
|
9
|
+
// Modes via MAESTRO_DOCTRINE_GUARD:
|
|
10
|
+
// - "always" (default): deny every doctrine Read while doctrine files
|
|
11
|
+
// exist at cwd. Safe on Claude Code, where subagents receive the
|
|
12
|
+
// project doctrine automatically; the deny reason tells the model
|
|
13
|
+
// to use the in-context copy.
|
|
14
|
+
// - "once": allow the first doctrine Read per session (marker file in
|
|
15
|
+
// the OS temp dir keyed by session_id), deny repeats. For runtimes
|
|
16
|
+
// whose subagents genuinely lack the doctrine in context (S7.2:
|
|
17
|
+
// "a subagent without it in context reads AGENTS.md once").
|
|
18
|
+
// - "0": disabled.
|
|
19
|
+
//
|
|
20
|
+
// When no doctrine file exists at cwd nothing was autoloaded, so reads
|
|
21
|
+
// pass through untouched (e.g. inspecting another repo's AGENTS.md).
|
|
22
|
+
// docs/orchestration.md is never guarded -- it is the on-demand layer
|
|
23
|
+
// and reading it is the intended path. Fails open on any error.
|
|
24
|
+
//
|
|
25
|
+
// Payload fields verified against code.claude.com/docs/en/hooks
|
|
26
|
+
// (PreToolUse input: session_id, cwd, tool_name, tool_input; output:
|
|
27
|
+
// hookSpecificOutput.permissionDecision allow|deny|ask + reason),
|
|
28
|
+
// 2026-06-11.
|
|
29
|
+
//
|
|
30
|
+
// .cjs so Node treats it as CommonJS regardless of any "type": "module"
|
|
31
|
+
// package.json in a parent directory of the install location.
|
|
32
|
+
|
|
33
|
+
const fs = require('fs');
|
|
34
|
+
const os = require('os');
|
|
35
|
+
const path = require('path');
|
|
36
|
+
|
|
37
|
+
const mode = process.env.MAESTRO_DOCTRINE_GUARD || 'always';
|
|
38
|
+
if (mode === '0') process.exit(0);
|
|
39
|
+
|
|
40
|
+
let data = {};
|
|
41
|
+
try { data = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(0); }
|
|
42
|
+
if (data.tool_name !== 'Read' || !data.tool_input) process.exit(0);
|
|
43
|
+
|
|
44
|
+
const fp = data.tool_input.file_path;
|
|
45
|
+
if (typeof fp !== 'string') process.exit(0);
|
|
46
|
+
const base = path.basename(fp).toLowerCase();
|
|
47
|
+
if (base !== 'agents.md' && base !== 'claude.md') process.exit(0);
|
|
48
|
+
|
|
49
|
+
// Guard only when the doctrine was actually autoloaded: a doctrine file
|
|
50
|
+
// at cwd is what Claude Code injects at session start.
|
|
51
|
+
const cwd = typeof data.cwd === 'string' ? data.cwd : process.cwd();
|
|
52
|
+
let autoloaded = false;
|
|
53
|
+
try {
|
|
54
|
+
autoloaded = fs.existsSync(path.join(cwd, 'CLAUDE.md'))
|
|
55
|
+
|| fs.existsSync(path.join(cwd, 'AGENTS.md'));
|
|
56
|
+
} catch { autoloaded = false; }
|
|
57
|
+
if (!autoloaded) process.exit(0);
|
|
58
|
+
|
|
59
|
+
if (mode === 'once' && data.session_id) {
|
|
60
|
+
const marker = path.join(
|
|
61
|
+
os.tmpdir(),
|
|
62
|
+
`maestro-doctrine-guard-${String(data.session_id).replace(/[^a-zA-Z0-9-]/g, '_')}`
|
|
63
|
+
);
|
|
64
|
+
if (!fs.existsSync(marker)) {
|
|
65
|
+
try { fs.writeFileSync(marker, '1'); } catch { /* still allow */ }
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
process.stdout.write(JSON.stringify({
|
|
71
|
+
hookSpecificOutput: {
|
|
72
|
+
hookEventName: 'PreToolUse',
|
|
73
|
+
permissionDecision: 'deny',
|
|
74
|
+
permissionDecisionReason: 'maestro-doctrine-guard: denied Read of '
|
|
75
|
+
+ path.basename(fp) + ' -- the doctrine is autoloaded into context '
|
|
76
|
+
+ 'at session start (AGENTS.md S7.2); use the in-context copy '
|
|
77
|
+
+ 'instead of re-reading it from disk. The on-demand protocol '
|
|
78
|
+
+ 'layer lives in docs/orchestration.md, which is not blocked.'
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
process.exit(0);
|
|
@@ -40,14 +40,29 @@ try { fs.writeFileSync(marker, '1'); } catch { /* still remind */ }
|
|
|
40
40
|
|
|
41
41
|
const checklistLines = [
|
|
42
42
|
'Maestro Decision Gate (S1): before the first file edit, output the',
|
|
43
|
-
'counted verdict line `
|
|
44
|
-
'| multi-agent — <reason>`. files>=5
|
|
45
|
-
'spawn the Planner via the
|
|
46
|
-
'
|
|
47
|
-
'<=3 files total in one
|
|
48
|
-
'single-agent.'
|
|
43
|
+
'counted verdict line `Maestro · frontier <on|off> — files=<n>',
|
|
44
|
+
'concerns=<m> -> single-agent | multi-agent — <reason>`. files>=5',
|
|
45
|
+
'across 2+ concerns = multi-agent: spawn the Planner via the',
|
|
46
|
+
'Agent/Task tool BEFORE any edit. A met trigger downgrades ONLY on',
|
|
47
|
+
'>60% file overlap between subtasks or <=3 files total in one',
|
|
48
|
+
'dependency chain. Sub-trigger tasks stay single-agent.'
|
|
49
49
|
];
|
|
50
|
-
|
|
50
|
+
|
|
51
|
+
// Inject the live frontier engine state so the badge in the verdict
|
|
52
|
+
// line is accurate. Degrades to 'off' on any failure — never throws.
|
|
53
|
+
let badge = 'off';
|
|
54
|
+
try {
|
|
55
|
+
const cfg = require('../frontier/config.cjs');
|
|
56
|
+
const cwd = data.cwd || process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
57
|
+
const scope = cfg.resolveScope([], { cwd });
|
|
58
|
+
const st = cfg.loadState(scope);
|
|
59
|
+
badge = (!st || st.mode === 'off')
|
|
60
|
+
? 'off'
|
|
61
|
+
: ('on (' + st.mode + '/' + (st.preset || st.model || '') + ')');
|
|
62
|
+
} catch { badge = 'off'; }
|
|
63
|
+
|
|
64
|
+
const checklist = checklistLines.join('\n') +
|
|
65
|
+
'\nCurrent frontier state for the badge: frontier ' + badge;
|
|
51
66
|
|
|
52
67
|
process.stdout.write(JSON.stringify({
|
|
53
68
|
hookSpecificOutput: {
|
|
@@ -1,77 +1,79 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Maestro SessionEnd gate telemetry. Strictly opt-in, strictly local.
|
|
3
|
-
//
|
|
4
|
-
// Records one JSON line per session so you can audit your own Decision
|
|
5
|
-
// Gate behavior over time (AGENTS.md S1): did the session route
|
|
6
|
-
// single-agent or multi-agent, how many specialists were spawned, and
|
|
7
|
-
// how the session ended.
|
|
8
|
-
//
|
|
9
|
-
// Privacy: does nothing unless MAESTRO_TELEMETRY=1. Writes only to
|
|
10
|
-
// ~/.claude/maestro-telemetry.jsonl on this machine. No network, ever.
|
|
11
|
-
// Captures counts and the project folder NAME only -- no prompts, no
|
|
12
|
-
// file contents, no paths beyond the basename.
|
|
13
|
-
//
|
|
14
|
-
// Payload fields verified against code.claude.com/docs/en/hooks
|
|
15
|
-
// (SessionEnd input: session_id, transcript_path, cwd, reason;
|
|
16
|
-
// SessionEnd output cannot block), 2026-06-10.
|
|
17
|
-
//
|
|
18
|
-
// .cjs so Node treats it as CommonJS regardless of any "type": "module"
|
|
19
|
-
// package.json in a parent directory of the install location.
|
|
20
|
-
//
|
|
21
|
-
// Install: see README "Claude Code: Gate Telemetry".
|
|
22
|
-
|
|
23
|
-
const fs = require('fs');
|
|
24
|
-
const os = require('os');
|
|
25
|
-
const path = require('path');
|
|
26
|
-
|
|
27
|
-
if (process.env.MAESTRO_TELEMETRY !== '1') process.exit(0);
|
|
28
|
-
|
|
29
|
-
let data = {};
|
|
30
|
-
try { data = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(0); }
|
|
31
|
-
|
|
32
|
-
// Spawn count alone misses the measured failure mode: a multi-agent
|
|
33
|
-
// verdict stated in text but no specialist ever spawned. Parse the S1
|
|
34
|
-
// verdict line too and record verdict vs spawned separately; mismatch
|
|
35
|
-
// flags either direction (multi verdict with 0 spawns, single verdict
|
|
36
|
-
// with spawns). Last verdict line wins (re-gated mid-session).
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (item
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Maestro SessionEnd gate telemetry. Strictly opt-in, strictly local.
|
|
3
|
+
//
|
|
4
|
+
// Records one JSON line per session so you can audit your own Decision
|
|
5
|
+
// Gate behavior over time (AGENTS.md S1): did the session route
|
|
6
|
+
// single-agent or multi-agent, how many specialists were spawned, and
|
|
7
|
+
// how the session ended.
|
|
8
|
+
//
|
|
9
|
+
// Privacy: does nothing unless MAESTRO_TELEMETRY=1. Writes only to
|
|
10
|
+
// ~/.claude/maestro-telemetry.jsonl on this machine. No network, ever.
|
|
11
|
+
// Captures counts and the project folder NAME only -- no prompts, no
|
|
12
|
+
// file contents, no paths beyond the basename.
|
|
13
|
+
//
|
|
14
|
+
// Payload fields verified against code.claude.com/docs/en/hooks
|
|
15
|
+
// (SessionEnd input: session_id, transcript_path, cwd, reason;
|
|
16
|
+
// SessionEnd output cannot block), 2026-06-10.
|
|
17
|
+
//
|
|
18
|
+
// .cjs so Node treats it as CommonJS regardless of any "type": "module"
|
|
19
|
+
// package.json in a parent directory of the install location.
|
|
20
|
+
//
|
|
21
|
+
// Install: see README "Claude Code: Gate Telemetry".
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const os = require('os');
|
|
25
|
+
const path = require('path');
|
|
26
|
+
|
|
27
|
+
if (process.env.MAESTRO_TELEMETRY !== '1') process.exit(0);
|
|
28
|
+
|
|
29
|
+
let data = {};
|
|
30
|
+
try { data = JSON.parse(fs.readFileSync(0, 'utf8')); } catch { process.exit(0); }
|
|
31
|
+
|
|
32
|
+
// Spawn count alone misses the measured failure mode: a multi-agent
|
|
33
|
+
// verdict stated in text but no specialist ever spawned. Parse the S1
|
|
34
|
+
// verdict line too and record verdict vs spawned separately; mismatch
|
|
35
|
+
// flags either direction (multi verdict with 0 spawns, single verdict
|
|
36
|
+
// with spawns). Last verdict line wins (re-gated mid-session).
|
|
37
|
+
// Matches BOTH the legacy `GATE: files=...` line and the rebranded
|
|
38
|
+
// `Maestro · frontier <on|off> — files=...` badge line.
|
|
39
|
+
const verdictRe = /(?:GATE|Maestro)[:\s·].*?files=\S+\s+concerns=\S+\s*->\s*(single|multi)-agent/;
|
|
40
|
+
let agentCount = 0;
|
|
41
|
+
let verdict = null;
|
|
42
|
+
if (data.transcript_path && fs.existsSync(data.transcript_path)) {
|
|
43
|
+
try {
|
|
44
|
+
const buf = fs.readFileSync(data.transcript_path, 'utf8');
|
|
45
|
+
const text = buf.length > 8000000 ? buf.slice(-8000000) : buf;
|
|
46
|
+
for (const line of text.split(/\r?\n/)) {
|
|
47
|
+
let e;
|
|
48
|
+
try { e = JSON.parse(line); } catch { continue; }
|
|
49
|
+
if (!e || e.type !== 'assistant' || !e.message || !Array.isArray(e.message.content)) continue;
|
|
50
|
+
for (const item of e.message.content) {
|
|
51
|
+
if (!item) continue;
|
|
52
|
+
if (item.type === 'tool_use' && (item.name === 'Task' || item.name === 'Agent')) agentCount++;
|
|
53
|
+
if (item.type === 'text' && typeof item.text === 'string') {
|
|
54
|
+
const m = item.text.match(verdictRe);
|
|
55
|
+
if (m) verdict = m[1];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch {}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const row = {
|
|
63
|
+
ts: new Date().toISOString(),
|
|
64
|
+
session_id: data.session_id || null,
|
|
65
|
+
gate: agentCount > 0 ? 'multi' : 'single',
|
|
66
|
+
verdict,
|
|
67
|
+
agent_count: agentCount,
|
|
68
|
+
mismatch: verdict !== null && ((verdict === 'multi') !== (agentCount > 0)),
|
|
69
|
+
reason: data.reason || null,
|
|
70
|
+
project: data.cwd ? path.basename(data.cwd) : null
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const dir = path.join(os.homedir(), '.claude');
|
|
75
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
76
|
+
fs.appendFileSync(path.join(dir, 'maestro-telemetry.jsonl'), JSON.stringify(row) + '\n');
|
|
77
|
+
} catch {}
|
|
78
|
+
|
|
79
|
+
process.exit(0);
|