@doingdev/opencode-claude-manager-plugin 0.1.25 → 0.1.26
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/README.md +27 -27
- package/dist/plugin/agent-hierarchy.d.ts +47 -0
- package/dist/plugin/agent-hierarchy.js +110 -0
- package/dist/plugin/claude-manager.plugin.js +18 -155
- package/dist/plugin/service-factory.js +1 -1
- package/dist/prompts/registry.js +78 -33
- package/dist/types/contracts.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenCode Claude Manager Plugin
|
|
2
2
|
|
|
3
|
-
This package provides an OpenCode plugin that lets an OpenCode-side
|
|
3
|
+
This package provides an OpenCode plugin that lets an OpenCode-side agent hierarchy orchestrate Claude Code sessions through a stable local bridge.
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
@@ -51,43 +51,43 @@ If you are testing locally, point OpenCode at the local package or plugin file u
|
|
|
51
51
|
|
|
52
52
|
## OpenCode tools
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### Engineer session
|
|
55
55
|
|
|
56
|
-
- `
|
|
56
|
+
- `engineer_send` — send a message to the persistent Claude Code session. Auto-creates on first call, resumes on subsequent calls.
|
|
57
57
|
- `message` (required) — the instruction to send.
|
|
58
58
|
- `mode` — `"plan"` (read-only investigation) or `"free"` (default, normal execution with edits).
|
|
59
59
|
- `freshSession` — set to `true` to clear the active session before sending. Use when switching to an unrelated task or when context is contaminated.
|
|
60
60
|
- `model` — `"claude-opus-4-6"` (default, recommended for most coding work), `"claude-sonnet-4-6"`, or `"claude-sonnet-4-5"` (faster/lighter tasks).
|
|
61
61
|
- `effort` — `"high"` (default), `"medium"` (lighter tasks), `"low"`, or `"max"` (especially hard problems).
|
|
62
|
-
- `
|
|
63
|
-
- `
|
|
64
|
-
- `
|
|
62
|
+
- `engineer_compact` — compress the active session context while preserving session state. Use before clearing when context is high but salvageable.
|
|
63
|
+
- `engineer_clear` — drop the active session entirely; next send starts fresh.
|
|
64
|
+
- `engineer_status` — get current session health: context %, turns, cost, session ID.
|
|
65
65
|
|
|
66
66
|
### Git operations
|
|
67
67
|
|
|
68
|
-
- `
|
|
69
|
-
- `
|
|
70
|
-
- `
|
|
68
|
+
- `git_diff` — review all uncommitted changes (staged + unstaged).
|
|
69
|
+
- `git_commit` — stage all changes and commit with a message.
|
|
70
|
+
- `git_reset` — hard reset + clean (destructive).
|
|
71
71
|
|
|
72
72
|
### Inspection
|
|
73
73
|
|
|
74
|
-
- `
|
|
75
|
-
- `
|
|
76
|
-
- `
|
|
74
|
+
- `engineer_metadata` — inspect available Claude commands, skills, hooks, and settings.
|
|
75
|
+
- `engineer_sessions` — list Claude sessions or inspect a saved transcript.
|
|
76
|
+
- `engineer_runs` — list or inspect persisted manager run records (may be empty if tasks were sent directly via `engineer_send` rather than the run-tracking path).
|
|
77
77
|
|
|
78
78
|
### Tool approval
|
|
79
79
|
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
82
|
-
- `
|
|
80
|
+
- `approval_policy` — view the current tool approval policy.
|
|
81
|
+
- `approval_decisions` — view recent tool approval decisions.
|
|
82
|
+
- `approval_update` — add/remove rules, change default action, or enable/disable approval.
|
|
83
83
|
|
|
84
|
-
##
|
|
84
|
+
## Agent hierarchy
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
The plugin registers a CTO → Manager → Engineer hierarchy through the OpenCode plugin `config` hook:
|
|
87
87
|
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
88
|
+
- **`cto`** (primary agent) — sets direction and orchestrates work by spawning `manager` subagents. Has read/search/web tools but does NOT operate Claude Code directly.
|
|
89
|
+
- **`manager`** (subagent) — operates a Claude Code engineer through a persistent session. Has the full tool surface (`engineer_*`, `git_*`, `approval_*`) plus read/search/web tools for investigation.
|
|
90
|
+
- **Engineer** — the Claude Code persistent session itself (not an OpenCode agent). Receives instructions from the manager, executes code changes, and reports results.
|
|
91
91
|
|
|
92
92
|
These are added to OpenCode config at runtime by the plugin, so they do not require separate manual `opencode.json` entries.
|
|
93
93
|
|
|
@@ -95,27 +95,27 @@ These are added to OpenCode config at runtime by the plugin, so they do not requ
|
|
|
95
95
|
|
|
96
96
|
Typical flow inside OpenCode:
|
|
97
97
|
|
|
98
|
-
1. Inspect Claude capabilities with `
|
|
99
|
-
2. Delegate work with `
|
|
100
|
-
3. Review changes with `
|
|
101
|
-
4. Inspect saved Claude history with `
|
|
98
|
+
1. Inspect Claude capabilities with `engineer_metadata`.
|
|
99
|
+
2. Delegate work with `engineer_send`.
|
|
100
|
+
3. Review changes with `git_diff`, then commit or reset.
|
|
101
|
+
4. Inspect saved Claude history with `engineer_sessions` or prior orchestration records with `engineer_runs`.
|
|
102
102
|
|
|
103
103
|
Example tasks:
|
|
104
104
|
|
|
105
105
|
```text
|
|
106
|
-
Use
|
|
106
|
+
Use engineer_send to implement the new validation logic in src/auth.ts, then review with git_diff.
|
|
107
107
|
```
|
|
108
108
|
|
|
109
109
|
Start a fresh session for an unrelated task:
|
|
110
110
|
|
|
111
111
|
```text
|
|
112
|
-
Use
|
|
112
|
+
Use engineer_send with freshSession:true to investigate the failing CI test in test/api.test.ts using mode:"plan".
|
|
113
113
|
```
|
|
114
114
|
|
|
115
115
|
Reclaim context mid-session:
|
|
116
116
|
|
|
117
117
|
```text
|
|
118
|
-
Use
|
|
118
|
+
Use engineer_compact to free up context, then continue with the next implementation step.
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
## Local Development
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent hierarchy configuration for the CTO → Manager → Engineer architecture.
|
|
3
|
+
*
|
|
4
|
+
* CTO (cto) — direction-setting, orchestration, spawns managers
|
|
5
|
+
* Manager (manager) — operates Claude Code engineer via persistent session
|
|
6
|
+
* Engineer — the Claude Code session itself (prompt only, no OpenCode agent)
|
|
7
|
+
*/
|
|
8
|
+
import type { ManagerPromptRegistry } from '../types/contracts.js';
|
|
9
|
+
export declare const AGENT_CTO = "cto";
|
|
10
|
+
export declare const AGENT_MANAGER = "manager";
|
|
11
|
+
/** All restricted tool IDs (union of engineer + git + approval) */
|
|
12
|
+
export declare const ALL_RESTRICTED_TOOL_IDS: readonly ["engineer_send", "engineer_compact", "engineer_clear", "engineer_status", "engineer_metadata", "engineer_sessions", "engineer_runs", "git_diff", "git_commit", "git_reset", "approval_policy", "approval_decisions", "approval_update"];
|
|
13
|
+
type ToolPermission = 'allow' | 'ask' | 'deny';
|
|
14
|
+
type AgentPermission = {
|
|
15
|
+
'*'?: ToolPermission;
|
|
16
|
+
read?: ToolPermission;
|
|
17
|
+
grep?: ToolPermission;
|
|
18
|
+
glob?: ToolPermission;
|
|
19
|
+
codesearch?: ToolPermission;
|
|
20
|
+
webfetch?: ToolPermission;
|
|
21
|
+
websearch?: ToolPermission;
|
|
22
|
+
/** OpenCode built-in: manage session todo list */
|
|
23
|
+
todowrite?: ToolPermission;
|
|
24
|
+
/** OpenCode built-in: read session todo list */
|
|
25
|
+
todoread?: ToolPermission;
|
|
26
|
+
/** OpenCode built-in: ask the user structured questions with options */
|
|
27
|
+
question?: ToolPermission;
|
|
28
|
+
bash?: ToolPermission | Record<string, ToolPermission>;
|
|
29
|
+
[tool: string]: ToolPermission | Record<string, ToolPermission> | undefined;
|
|
30
|
+
};
|
|
31
|
+
export declare function buildCtoAgentConfig(prompts: ManagerPromptRegistry): {
|
|
32
|
+
description: string;
|
|
33
|
+
mode: "primary";
|
|
34
|
+
color: string;
|
|
35
|
+
permission: AgentPermission;
|
|
36
|
+
prompt: string;
|
|
37
|
+
};
|
|
38
|
+
export declare function buildManagerAgentConfig(prompts: ManagerPromptRegistry): {
|
|
39
|
+
description: string;
|
|
40
|
+
mode: "subagent";
|
|
41
|
+
color: string;
|
|
42
|
+
permission: AgentPermission;
|
|
43
|
+
prompt: string;
|
|
44
|
+
};
|
|
45
|
+
/** Deny all restricted tools at the global level so only designated agents can use them. */
|
|
46
|
+
export declare function denyRestrictedToolsGlobally(permissions: Record<string, ToolPermission>): void;
|
|
47
|
+
export {};
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent hierarchy configuration for the CTO → Manager → Engineer architecture.
|
|
3
|
+
*
|
|
4
|
+
* CTO (cto) — direction-setting, orchestration, spawns managers
|
|
5
|
+
* Manager (manager) — operates Claude Code engineer via persistent session
|
|
6
|
+
* Engineer — the Claude Code session itself (prompt only, no OpenCode agent)
|
|
7
|
+
*/
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Agent names
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export const AGENT_CTO = 'cto';
|
|
12
|
+
export const AGENT_MANAGER = 'manager';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Tool IDs — grouped by domain
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/** Engineer-facing session tools */
|
|
17
|
+
const ENGINEER_TOOL_IDS = [
|
|
18
|
+
'engineer_send',
|
|
19
|
+
'engineer_compact',
|
|
20
|
+
'engineer_clear',
|
|
21
|
+
'engineer_status',
|
|
22
|
+
'engineer_metadata',
|
|
23
|
+
'engineer_sessions',
|
|
24
|
+
'engineer_runs',
|
|
25
|
+
];
|
|
26
|
+
/** Git tools */
|
|
27
|
+
const GIT_TOOL_IDS = ['git_diff', 'git_commit', 'git_reset'];
|
|
28
|
+
/** Approval tools */
|
|
29
|
+
const APPROVAL_TOOL_IDS = [
|
|
30
|
+
'approval_policy',
|
|
31
|
+
'approval_decisions',
|
|
32
|
+
'approval_update',
|
|
33
|
+
];
|
|
34
|
+
/** All restricted tool IDs (union of engineer + git + approval) */
|
|
35
|
+
export const ALL_RESTRICTED_TOOL_IDS = [
|
|
36
|
+
...ENGINEER_TOOL_IDS,
|
|
37
|
+
...GIT_TOOL_IDS,
|
|
38
|
+
...APPROVAL_TOOL_IDS,
|
|
39
|
+
];
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Shared read-only tool permissions
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
const READONLY_TOOLS = {
|
|
44
|
+
read: 'allow',
|
|
45
|
+
grep: 'allow',
|
|
46
|
+
glob: 'allow',
|
|
47
|
+
codesearch: 'allow',
|
|
48
|
+
webfetch: 'allow',
|
|
49
|
+
websearch: 'allow',
|
|
50
|
+
todowrite: 'allow',
|
|
51
|
+
todoread: 'allow',
|
|
52
|
+
question: 'allow',
|
|
53
|
+
};
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Permission builders
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/** CTO: orchestration only — explicitly denies every restricted tool, no edit, no bash. */
|
|
58
|
+
function buildCtoPermissions() {
|
|
59
|
+
const denied = {};
|
|
60
|
+
for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
|
|
61
|
+
denied[toolId] = 'deny';
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
'*': 'deny',
|
|
65
|
+
...READONLY_TOOLS,
|
|
66
|
+
...denied,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Manager: full restricted tool surface + read-only codebase tools. No edit, no bash. */
|
|
70
|
+
function buildManagerPermissions() {
|
|
71
|
+
const allowed = {};
|
|
72
|
+
for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
|
|
73
|
+
allowed[toolId] = 'allow';
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
'*': 'deny',
|
|
77
|
+
...READONLY_TOOLS,
|
|
78
|
+
...allowed,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// Agent config builders
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
export function buildCtoAgentConfig(prompts) {
|
|
85
|
+
return {
|
|
86
|
+
description: 'CTO agent that sets direction and orchestrates work by spawning manager subagents. Does not operate Claude Code directly.',
|
|
87
|
+
mode: 'primary',
|
|
88
|
+
color: '#D97757',
|
|
89
|
+
permission: buildCtoPermissions(),
|
|
90
|
+
prompt: prompts.ctoSystemPrompt,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function buildManagerAgentConfig(prompts) {
|
|
94
|
+
return {
|
|
95
|
+
description: 'Manager agent that operates Claude Code through a persistent session, reviews work via git diff, and commits/resets changes.',
|
|
96
|
+
mode: 'subagent',
|
|
97
|
+
color: '#D97757',
|
|
98
|
+
permission: buildManagerPermissions(),
|
|
99
|
+
prompt: prompts.managerSystemPrompt,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Global permission helper
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
/** Deny all restricted tools at the global level so only designated agents can use them. */
|
|
106
|
+
export function denyRestrictedToolsGlobally(permissions) {
|
|
107
|
+
for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
|
|
108
|
+
permissions[toolId] ??= 'deny';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -1,115 +1,19 @@
|
|
|
1
1
|
import { tool } from '@opencode-ai/plugin';
|
|
2
2
|
import { managerPromptRegistry } from '../prompts/registry.js';
|
|
3
|
+
import { AGENT_CTO, AGENT_MANAGER, buildCtoAgentConfig, buildManagerAgentConfig, denyRestrictedToolsGlobally, } from './agent-hierarchy.js';
|
|
3
4
|
import { getOrCreatePluginServices } from './service-factory.js';
|
|
4
|
-
const MANAGER_TOOL_IDS = [
|
|
5
|
-
'claude_manager_send',
|
|
6
|
-
'claude_manager_compact',
|
|
7
|
-
'claude_manager_git_diff',
|
|
8
|
-
'claude_manager_git_commit',
|
|
9
|
-
'claude_manager_git_reset',
|
|
10
|
-
'claude_manager_clear',
|
|
11
|
-
'claude_manager_status',
|
|
12
|
-
'claude_manager_metadata',
|
|
13
|
-
'claude_manager_sessions',
|
|
14
|
-
'claude_manager_runs',
|
|
15
|
-
'claude_manager_approval_policy',
|
|
16
|
-
'claude_manager_approval_decisions',
|
|
17
|
-
'claude_manager_approval_update',
|
|
18
|
-
];
|
|
19
5
|
export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
20
6
|
const services = getOrCreatePluginServices(worktree);
|
|
21
7
|
return {
|
|
22
8
|
config: async (config) => {
|
|
23
9
|
config.agent ??= {};
|
|
24
|
-
config.command ??= {};
|
|
25
10
|
config.permission ??= {};
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
for (const toolId of MANAGER_TOOL_IDS) {
|
|
30
|
-
globalPermissions[toolId] ??= 'deny';
|
|
31
|
-
managerPermissions[toolId] = 'allow';
|
|
32
|
-
// Research agent can inspect but not send or modify
|
|
33
|
-
researchPermissions[toolId] =
|
|
34
|
-
toolId === 'claude_manager_send' ||
|
|
35
|
-
toolId === 'claude_manager_compact' ||
|
|
36
|
-
toolId === 'claude_manager_git_commit' ||
|
|
37
|
-
toolId === 'claude_manager_git_reset' ||
|
|
38
|
-
toolId === 'claude_manager_clear' ||
|
|
39
|
-
toolId === 'claude_manager_approval_update'
|
|
40
|
-
? 'deny'
|
|
41
|
-
: 'allow';
|
|
42
|
-
}
|
|
43
|
-
config.agent['claude-manager'] ??= {
|
|
44
|
-
description: 'Primary agent that operates Claude Code through a persistent session, reviews work via git diff, and commits/resets changes.',
|
|
45
|
-
mode: 'primary',
|
|
46
|
-
color: '#D97757',
|
|
47
|
-
permission: {
|
|
48
|
-
'*': 'deny',
|
|
49
|
-
read: 'allow',
|
|
50
|
-
grep: 'allow',
|
|
51
|
-
glob: 'allow',
|
|
52
|
-
codesearch: 'allow',
|
|
53
|
-
webfetch: 'allow',
|
|
54
|
-
websearch: 'allow',
|
|
55
|
-
todowrite: 'allow',
|
|
56
|
-
todoread: 'allow',
|
|
57
|
-
question: 'allow',
|
|
58
|
-
...managerPermissions,
|
|
59
|
-
},
|
|
60
|
-
prompt: managerPromptRegistry.managerSystemPrompt,
|
|
61
|
-
};
|
|
62
|
-
config.agent['claude-manager-research'] ??= {
|
|
63
|
-
description: 'Subagent that inspects Claude metadata, prior sessions, and manager runs without changing repository state.',
|
|
64
|
-
mode: 'subagent',
|
|
65
|
-
color: 'info',
|
|
66
|
-
permission: {
|
|
67
|
-
'*': 'deny',
|
|
68
|
-
...researchPermissions,
|
|
69
|
-
},
|
|
70
|
-
prompt: [
|
|
71
|
-
'Focus on inspection and summarization.',
|
|
72
|
-
'Use claude_manager_status, claude_manager_metadata, claude_manager_sessions, and claude_manager_runs to gather information.',
|
|
73
|
-
].join(' '),
|
|
74
|
-
};
|
|
75
|
-
config.command['claude-run'] ??= {
|
|
76
|
-
description: 'Send a task to the persistent Claude Code session.',
|
|
77
|
-
agent: 'claude-manager',
|
|
78
|
-
subtask: true,
|
|
79
|
-
template: [
|
|
80
|
-
'Use claude_manager_send to send the following task to Claude Code:',
|
|
81
|
-
'$ARGUMENTS',
|
|
82
|
-
'After it completes, review the result and use claude_manager_git_diff if changes were expected. Commit or reset accordingly.',
|
|
83
|
-
].join('\n\n'),
|
|
84
|
-
};
|
|
85
|
-
config.command['claude-metadata'] ??= {
|
|
86
|
-
description: 'Inspect bundled Claude commands, skills, hooks, and agents.',
|
|
87
|
-
agent: 'claude-manager-research',
|
|
88
|
-
subtask: true,
|
|
89
|
-
template: [
|
|
90
|
-
'Use claude_manager_metadata to inspect the current repository.',
|
|
91
|
-
'Summarize Claude commands, skills, hooks, discovered agents, and important config files.',
|
|
92
|
-
].join(' '),
|
|
93
|
-
};
|
|
94
|
-
config.command['claude-sessions'] ??= {
|
|
95
|
-
description: 'Inspect Claude session history and manager run records.',
|
|
96
|
-
agent: 'claude-manager-research',
|
|
97
|
-
subtask: true,
|
|
98
|
-
template: [
|
|
99
|
-
'Use claude_manager_sessions and claude_manager_runs to inspect recent Claude activity for this repository.',
|
|
100
|
-
'If the user provided extra arguments, use them to focus the inspection:',
|
|
101
|
-
'$ARGUMENTS',
|
|
102
|
-
].join('\n\n'),
|
|
103
|
-
};
|
|
104
|
-
},
|
|
105
|
-
'command.execute.before': async (input, output) => {
|
|
106
|
-
const commandText = buildCommandText(input.command, input.arguments);
|
|
107
|
-
if (commandText) {
|
|
108
|
-
output.parts = rewriteCommandParts(output.parts, commandText);
|
|
109
|
-
}
|
|
11
|
+
denyRestrictedToolsGlobally(config.permission);
|
|
12
|
+
config.agent[AGENT_CTO] ??= buildCtoAgentConfig(managerPromptRegistry);
|
|
13
|
+
config.agent[AGENT_MANAGER] ??= buildManagerAgentConfig(managerPromptRegistry);
|
|
110
14
|
},
|
|
111
15
|
tool: {
|
|
112
|
-
|
|
16
|
+
engineer_send: tool({
|
|
113
17
|
description: 'Send a message to the persistent Claude Code session. ' +
|
|
114
18
|
'Auto-creates a session on first call. Resumes the existing session on subsequent calls. ' +
|
|
115
19
|
'Returns the assistant response and current context health snapshot. ' +
|
|
@@ -320,7 +224,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
320
224
|
}, null, 2);
|
|
321
225
|
},
|
|
322
226
|
}),
|
|
323
|
-
|
|
227
|
+
engineer_compact: tool({
|
|
324
228
|
description: 'Compact the active Claude Code session to reclaim context space. ' +
|
|
325
229
|
'Sends /compact to the session, which compresses prior conversation while preserving state. ' +
|
|
326
230
|
'Use before clearing when context is high but the session still has useful state. ' +
|
|
@@ -350,7 +254,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
350
254
|
}, null, 2);
|
|
351
255
|
},
|
|
352
256
|
}),
|
|
353
|
-
|
|
257
|
+
git_diff: tool({
|
|
354
258
|
description: 'Run git diff to see all current changes (staged + unstaged) relative to HEAD.',
|
|
355
259
|
args: {
|
|
356
260
|
cwd: tool.schema.string().optional(),
|
|
@@ -361,7 +265,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
361
265
|
return JSON.stringify(result, null, 2);
|
|
362
266
|
},
|
|
363
267
|
}),
|
|
364
|
-
|
|
268
|
+
git_commit: tool({
|
|
365
269
|
description: 'Stage all changes and commit with the given message.',
|
|
366
270
|
args: {
|
|
367
271
|
message: tool.schema.string().min(1),
|
|
@@ -375,7 +279,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
375
279
|
return JSON.stringify(result, null, 2);
|
|
376
280
|
},
|
|
377
281
|
}),
|
|
378
|
-
|
|
282
|
+
git_reset: tool({
|
|
379
283
|
description: 'Run git reset --hard HEAD and git clean -fd to discard ALL uncommitted changes and untracked files.',
|
|
380
284
|
args: {
|
|
381
285
|
cwd: tool.schema.string().optional(),
|
|
@@ -386,7 +290,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
386
290
|
return JSON.stringify(result, null, 2);
|
|
387
291
|
},
|
|
388
292
|
}),
|
|
389
|
-
|
|
293
|
+
engineer_clear: tool({
|
|
390
294
|
description: 'Clear the active Claude Code session. The next send will start a fresh session. ' +
|
|
391
295
|
'Use when context is full, the session is confused, or starting a different task.',
|
|
392
296
|
args: {
|
|
@@ -401,7 +305,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
401
305
|
return JSON.stringify({ clearedSessionId: clearedId });
|
|
402
306
|
},
|
|
403
307
|
}),
|
|
404
|
-
|
|
308
|
+
engineer_status: tool({
|
|
405
309
|
description: 'Get the current persistent session status: context usage %, turns, cost, active session ID.',
|
|
406
310
|
args: {
|
|
407
311
|
cwd: tool.schema.string().optional(),
|
|
@@ -418,7 +322,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
418
322
|
}, null, 2);
|
|
419
323
|
},
|
|
420
324
|
}),
|
|
421
|
-
|
|
325
|
+
engineer_metadata: tool({
|
|
422
326
|
description: 'Inspect Claude slash commands, skills, hooks, and repo settings.',
|
|
423
327
|
args: {
|
|
424
328
|
cwd: tool.schema.string().optional(),
|
|
@@ -434,9 +338,9 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
434
338
|
return JSON.stringify(metadata, null, 2);
|
|
435
339
|
},
|
|
436
340
|
}),
|
|
437
|
-
|
|
341
|
+
engineer_sessions: tool({
|
|
438
342
|
description: 'List Claude sessions or inspect a saved transcript. ' +
|
|
439
|
-
'When sessionId is provided, returns both SDK transcript and local
|
|
343
|
+
'When sessionId is provided, returns both SDK transcript and local events.',
|
|
440
344
|
args: {
|
|
441
345
|
cwd: tool.schema.string().optional(),
|
|
442
346
|
sessionId: tool.schema.string().optional(),
|
|
@@ -458,7 +362,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
458
362
|
return JSON.stringify(sessions, null, 2);
|
|
459
363
|
},
|
|
460
364
|
}),
|
|
461
|
-
|
|
365
|
+
engineer_runs: tool({
|
|
462
366
|
description: 'List persistent manager run records.',
|
|
463
367
|
args: {
|
|
464
368
|
cwd: tool.schema.string().optional(),
|
|
@@ -474,7 +378,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
474
378
|
return JSON.stringify(runs, null, 2);
|
|
475
379
|
},
|
|
476
380
|
}),
|
|
477
|
-
|
|
381
|
+
approval_policy: tool({
|
|
478
382
|
description: 'View the current tool approval policy: rules, default action, and enabled status.',
|
|
479
383
|
args: {},
|
|
480
384
|
async execute(_args, context) {
|
|
@@ -482,7 +386,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
482
386
|
return JSON.stringify(services.approvalManager.getPolicy(), null, 2);
|
|
483
387
|
},
|
|
484
388
|
}),
|
|
485
|
-
|
|
389
|
+
approval_decisions: tool({
|
|
486
390
|
description: 'View recent tool approval decisions. Shows what tools were allowed or denied. ' +
|
|
487
391
|
'Use deniedOnly to see only denied calls.',
|
|
488
392
|
args: {
|
|
@@ -497,7 +401,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
497
401
|
return JSON.stringify({ total: decisions.length, decisions }, null, 2);
|
|
498
402
|
},
|
|
499
403
|
}),
|
|
500
|
-
|
|
404
|
+
approval_update: tool({
|
|
501
405
|
description: 'Update the tool approval policy. Add/remove rules, change default action, or enable/disable. ' +
|
|
502
406
|
'Rules are evaluated top-to-bottom; first match wins.',
|
|
503
407
|
args: {
|
|
@@ -568,47 +472,6 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
568
472
|
function annotateToolRun(context, title, metadata) {
|
|
569
473
|
context.metadata({ title, metadata });
|
|
570
474
|
}
|
|
571
|
-
function buildCommandText(command, rawArguments) {
|
|
572
|
-
const argumentsText = rawArguments.trim();
|
|
573
|
-
if (command === 'claude-run') {
|
|
574
|
-
return [
|
|
575
|
-
'Use `claude_manager_send` to send the following task to Claude Code:',
|
|
576
|
-
argumentsText
|
|
577
|
-
? argumentsText
|
|
578
|
-
: 'Inspect the current repository and wait for follow-up instructions.',
|
|
579
|
-
'After it completes, review the result. If code changes were expected, use `claude_manager_git_diff` to review, then `claude_manager_git_commit` or `claude_manager_git_reset` accordingly.',
|
|
580
|
-
].join('\n\n');
|
|
581
|
-
}
|
|
582
|
-
if (command === 'claude-metadata') {
|
|
583
|
-
return [
|
|
584
|
-
'Call `claude_manager_metadata` immediately for the current repository.',
|
|
585
|
-
argumentsText ? `Focus: ${argumentsText}` : '',
|
|
586
|
-
'Then summarize the discovered Claude commands, skills, hooks, agents, and config files briefly.',
|
|
587
|
-
]
|
|
588
|
-
.filter(Boolean)
|
|
589
|
-
.join('\n\n');
|
|
590
|
-
}
|
|
591
|
-
if (command === 'claude-sessions') {
|
|
592
|
-
return [
|
|
593
|
-
'Call `claude_manager_sessions` and `claude_manager_runs` immediately for the current repository.',
|
|
594
|
-
argumentsText ? `Focus: ${argumentsText}` : '',
|
|
595
|
-
'Then summarize the most relevant recent Claude activity briefly.',
|
|
596
|
-
]
|
|
597
|
-
.filter(Boolean)
|
|
598
|
-
.join('\n\n');
|
|
599
|
-
}
|
|
600
|
-
return null;
|
|
601
|
-
}
|
|
602
|
-
function rewriteCommandParts(parts, text) {
|
|
603
|
-
let hasRewrittenText = false;
|
|
604
|
-
return parts.map((part) => {
|
|
605
|
-
if (part.type !== 'text' || hasRewrittenText) {
|
|
606
|
-
return part;
|
|
607
|
-
}
|
|
608
|
-
hasRewrittenText = true;
|
|
609
|
-
return { ...part, text };
|
|
610
|
-
});
|
|
611
|
-
}
|
|
612
475
|
function formatContextWarning(context) {
|
|
613
476
|
const { warningLevel, estimatedContextPercent, totalTurns, totalCostUsd } = context;
|
|
614
477
|
if (warningLevel === 'ok' || estimatedContextPercent === null) {
|
|
@@ -22,7 +22,7 @@ export function getOrCreatePluginServices(worktree) {
|
|
|
22
22
|
const metadataService = new ClaudeMetadataService(new RepoClaudeConfigReader(), sdkAdapter);
|
|
23
23
|
const sessionService = new ClaudeSessionService(sdkAdapter, metadataService);
|
|
24
24
|
const contextTracker = new ContextTracker();
|
|
25
|
-
const sessionController = new SessionController(sdkAdapter, contextTracker, managerPromptRegistry.
|
|
25
|
+
const sessionController = new SessionController(sdkAdapter, contextTracker, managerPromptRegistry.engineerSessionPrompt, managerPromptRegistry.modePrefixes);
|
|
26
26
|
const gitOps = new GitOperations(worktree);
|
|
27
27
|
const stateStore = new FileRunStateStore();
|
|
28
28
|
const transcriptStore = new TranscriptStore();
|
package/dist/prompts/registry.js
CHANGED
|
@@ -1,19 +1,61 @@
|
|
|
1
1
|
export const managerPromptRegistry = {
|
|
2
|
+
ctoSystemPrompt: [
|
|
3
|
+
'You are the CTO — you set direction and orchestrate, but you never execute directly.',
|
|
4
|
+
'',
|
|
5
|
+
'## Your role',
|
|
6
|
+
"- Analyze the user's request and break it into focused slices of work.",
|
|
7
|
+
'- Spawn one or more `manager` subagents, each with a clear, scoped objective.',
|
|
8
|
+
'- Each `manager` has its own Claude Code persistent session and can investigate,',
|
|
9
|
+
' delegate to the engineer, review diffs, and commit.',
|
|
10
|
+
'- Review subagent results and synthesize them for the user.',
|
|
11
|
+
'',
|
|
12
|
+
'## What you can do',
|
|
13
|
+
'- Read files, grep, and search the codebase to understand the problem.',
|
|
14
|
+
'- Use webfetch / websearch for external context.',
|
|
15
|
+
'- Use todowrite / todoread to track high-level progress.',
|
|
16
|
+
'- Ask the user structured questions when decisions require their input.',
|
|
17
|
+
'',
|
|
18
|
+
'## What you must NOT do',
|
|
19
|
+
'- Do NOT call any engineer_*, git_*, or approval_* tools. You do not operate Claude Code directly.',
|
|
20
|
+
'- Do NOT edit files, run bash commands, or make code changes yourself.',
|
|
21
|
+
'- Do NOT micro-manage subagents — give them clear objectives and let them execute.',
|
|
22
|
+
'',
|
|
23
|
+
'## Spawning subagents',
|
|
24
|
+
'- Spawn a `manager` subagent for each independent slice of work.',
|
|
25
|
+
'- If slices are independent, spawn them in parallel.',
|
|
26
|
+
'- Provide each subagent with:',
|
|
27
|
+
' 1. A clear, scoped objective.',
|
|
28
|
+
' 2. Relevant file paths, function names, and context you gathered.',
|
|
29
|
+
' 3. Success criteria so the subagent knows when it is done.',
|
|
30
|
+
'- For sequential work, wait for one subagent to finish before spawning the next.',
|
|
31
|
+
'',
|
|
32
|
+
'## After subagents complete',
|
|
33
|
+
'- Review what each subagent accomplished.',
|
|
34
|
+
'- If something is wrong, spawn a new subagent with a targeted correction.',
|
|
35
|
+
'- Synthesize results and report to the user.',
|
|
36
|
+
'',
|
|
37
|
+
'## Handling ambiguity',
|
|
38
|
+
'When requirements are unclear:',
|
|
39
|
+
'1. First, try to resolve it yourself — read code, check tests, grep for usage.',
|
|
40
|
+
'2. If ambiguity remains, ask the user ONE specific question.',
|
|
41
|
+
' Prefer the question tool when discrete options exist.',
|
|
42
|
+
'3. Never block on multiple questions at once.',
|
|
43
|
+
].join('\n'),
|
|
2
44
|
managerSystemPrompt: [
|
|
3
|
-
'You are a
|
|
4
|
-
'Your job is to make
|
|
45
|
+
'You are a manager operating a Claude Code engineer through a persistent session.',
|
|
46
|
+
'Your job is to make the engineer do the work — not to write code yourself.',
|
|
5
47
|
'Think like a staff engineer: correctness, maintainability, tests, rollback safety,',
|
|
6
48
|
'and clear communication to the user.',
|
|
7
49
|
'',
|
|
8
50
|
'## Decision loop',
|
|
9
51
|
'On every turn, choose exactly one action:',
|
|
10
52
|
' investigate — read files, grep, search the codebase to build context',
|
|
11
|
-
' delegate — send a focused instruction to
|
|
12
|
-
' review — run
|
|
13
|
-
' validate — tell
|
|
14
|
-
' commit — checkpoint good work with
|
|
53
|
+
' delegate — send a focused instruction to the engineer via engineer_send',
|
|
54
|
+
' review — run git_diff to inspect what changed',
|
|
55
|
+
' validate — tell the engineer to run tests, lint, or typecheck',
|
|
56
|
+
' commit — checkpoint good work with git_commit',
|
|
15
57
|
' correct — send a targeted fix instruction (never "try again")',
|
|
16
|
-
' reset — discard bad work with
|
|
58
|
+
' reset — discard bad work with git_reset',
|
|
17
59
|
' ask — use the question tool for structured choices, or one narrow text question',
|
|
18
60
|
'',
|
|
19
61
|
'Default order: investigate → delegate → review → validate → commit.',
|
|
@@ -33,12 +75,12 @@ export const managerPromptRegistry = {
|
|
|
33
75
|
'',
|
|
34
76
|
'## After delegation — mandatory review',
|
|
35
77
|
'Never claim success without evidence:',
|
|
36
|
-
'1.
|
|
78
|
+
'1. git_diff — read the actual diff, not just the summary.',
|
|
37
79
|
'2. Verify the diff matches what you asked for. Check for:',
|
|
38
80
|
' - Unintended changes or regressions',
|
|
39
81
|
' - Missing test updates',
|
|
40
82
|
' - Style violations against repo conventions',
|
|
41
|
-
'3. If changes look correct, tell
|
|
83
|
+
'3. If changes look correct, tell the engineer to run tests/lint/typecheck.',
|
|
42
84
|
'4. Only commit after verification passes.',
|
|
43
85
|
'5. If the diff is wrong: send a specific correction or reset.',
|
|
44
86
|
'',
|
|
@@ -54,7 +96,7 @@ export const managerPromptRegistry = {
|
|
|
54
96
|
'3. Never block on multiple questions at once.',
|
|
55
97
|
'',
|
|
56
98
|
'## Correction and recovery',
|
|
57
|
-
'If
|
|
99
|
+
'If the engineer produces wrong output:',
|
|
58
100
|
'1. First correction: send a specific, targeted fix instruction.',
|
|
59
101
|
'2. Second correction on the same issue: reset, clear the session,',
|
|
60
102
|
' and rewrite the prompt incorporating lessons from both failures.',
|
|
@@ -64,18 +106,18 @@ export const managerPromptRegistry = {
|
|
|
64
106
|
'- Use todowrite / todoread to track steps in OpenCode; keep items concrete and few.',
|
|
65
107
|
'- Decompose large tasks into sequential focused instructions.',
|
|
66
108
|
'- Commit after each successful step (checkpoint for rollback).',
|
|
67
|
-
'- Tell
|
|
68
|
-
'- For complex design decisions, tell
|
|
109
|
+
'- Tell the engineer to use subagents for independent parallel work.',
|
|
110
|
+
'- For complex design decisions, tell the engineer to "think hard".',
|
|
69
111
|
'- Prefer small diffs — they are easier to review and safer to ship.',
|
|
70
112
|
'',
|
|
71
113
|
'## Context management',
|
|
72
114
|
'Check the context snapshot returned by each send:',
|
|
73
115
|
'- Under 50%: proceed freely.',
|
|
74
116
|
'- 50–70%: finish current step, then evaluate if a fresh session is needed.',
|
|
75
|
-
'- Over 70%: use
|
|
117
|
+
'- Over 70%: use engineer_compact to reclaim context if the session',
|
|
76
118
|
' still has useful state. Only clear if compaction is insufficient.',
|
|
77
119
|
'- Over 85%: clear the session immediately.',
|
|
78
|
-
'Use freshSession:true on
|
|
120
|
+
'Use freshSession:true on engineer_send when switching to an unrelated',
|
|
79
121
|
'task or when the session context is contaminated. Prefer this over a manual',
|
|
80
122
|
'clear+send sequence — it is atomic and self-documenting.',
|
|
81
123
|
'',
|
|
@@ -90,27 +132,30 @@ export const managerPromptRegistry = {
|
|
|
90
132
|
"- Do not use Haiku for this plugin's coding-agent role.",
|
|
91
133
|
'',
|
|
92
134
|
'## Plan mode',
|
|
93
|
-
'When delegating with mode:"plan",
|
|
135
|
+
'When delegating with mode:"plan", the engineer returns a read-only',
|
|
94
136
|
'implementation plan. The plan MUST be returned inline in the assistant',
|
|
95
137
|
'response — do NOT write plan artifacts to disk, create files, or rely on',
|
|
96
138
|
'ExitPlanMode. Treat the returned finalText as the plan. If the plan is',
|
|
97
139
|
'acceptable, switch to mode:"free" and delegate the implementation steps.',
|
|
98
140
|
'',
|
|
99
141
|
'## Tools reference',
|
|
100
|
-
'todowrite / todoread
|
|
101
|
-
'question
|
|
102
|
-
'
|
|
103
|
-
' freshSession:true
|
|
104
|
-
' model / effort
|
|
105
|
-
'
|
|
106
|
-
'
|
|
107
|
-
'
|
|
108
|
-
'
|
|
109
|
-
'
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
113
|
-
'
|
|
142
|
+
'todowrite / todoread — OpenCode session todo list (track multi-step work)',
|
|
143
|
+
'question — OpenCode user prompt with options (clarify trade-offs)',
|
|
144
|
+
'engineer_send — send instruction (creates or resumes session)',
|
|
145
|
+
' freshSession:true — clear session first (use for unrelated tasks)',
|
|
146
|
+
' model / effort — choose deliberately (see "Model and effort selection")',
|
|
147
|
+
'engineer_compact — compress session context (preserves session state)',
|
|
148
|
+
'engineer_clear — drop session, next send starts fresh',
|
|
149
|
+
'engineer_status — context health snapshot',
|
|
150
|
+
'engineer_metadata — inspect repo Claude config',
|
|
151
|
+
'engineer_sessions — list sessions or read transcripts',
|
|
152
|
+
'engineer_runs — list or inspect run records',
|
|
153
|
+
'git_diff — review all uncommitted changes',
|
|
154
|
+
'git_commit — stage all + commit',
|
|
155
|
+
'git_reset — hard reset + clean (destructive)',
|
|
156
|
+
'approval_policy — view tool approval rules',
|
|
157
|
+
'approval_decisions — view recent approval decisions',
|
|
158
|
+
'approval_update — modify tool approval policy',
|
|
114
159
|
'',
|
|
115
160
|
'## Autonomy blockers — surface these to the user',
|
|
116
161
|
'Be candid about what you cannot do autonomously:',
|
|
@@ -120,9 +165,9 @@ export const managerPromptRegistry = {
|
|
|
120
165
|
'- Access to external services or environments you cannot reach.',
|
|
121
166
|
'State the blocker, what you need, and a concrete suggestion to unblock.',
|
|
122
167
|
].join('\n'),
|
|
123
|
-
|
|
124
|
-
'You are directed by
|
|
125
|
-
'Treat each message as a precise instruction from
|
|
168
|
+
engineerSessionPrompt: [
|
|
169
|
+
'You are directed by a manager acting as your technical lead.',
|
|
170
|
+
'Treat each message as a precise instruction from your manager.',
|
|
126
171
|
'',
|
|
127
172
|
'## Execution rules',
|
|
128
173
|
'- Execute instructions directly. Do not ask for clarification.',
|
|
@@ -139,7 +184,7 @@ export const managerPromptRegistry = {
|
|
|
139
184
|
'',
|
|
140
185
|
'## Git boundary — do NOT run these commands:',
|
|
141
186
|
'git commit, git push, git reset, git checkout, git stash.',
|
|
142
|
-
'The
|
|
187
|
+
'The manager handles all git operations externally.',
|
|
143
188
|
'',
|
|
144
189
|
'## Reporting',
|
|
145
190
|
'- End with a brief verification summary: what was done, what was verified.',
|