forge-delegate 1.0.3 → 1.0.4

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 CHANGED
@@ -91,16 +91,16 @@ rate-limited; switch anytime with `forge-delegate config set --model <m>`.
91
91
  | Tool | What it does | Context cost |
92
92
  |---|---|---|
93
93
  | `ask_model` | One-shot question to any model (direct API, no file access) | Small |
94
- | `delegate` | Model works **autonomously** in the **background** (recommended) — returns a job id instantly; poll `check_delegation` | Tiny |
95
- | `delegate_sync` | Send a task + optional files to a model agent running via opencode; returns the result inline in your context | Medium |
94
+ | `delegate` | Model works **autonomously** via opencode's own tool loop — inline by default; `background:true` returns a job id to poll via `check_delegation` | Tiny→Medium |
96
95
  | `check_delegation` | Poll a background job (or list all with no id) | Tiny |
97
96
  | `list_models` | List local/keyless, direct-API, and agentic models | Small |
98
97
  | `get_delegate_config` | Read current configuration (default model, directory, autoApprove, profiles) | Tiny |
99
98
  | `set_delegate_config` | Change configuration at runtime — no reinstall | Tiny |
100
99
 
101
100
  `delegate` is the token-saver: the external model gets its own tool loop executed by
102
- opencode locally. File contents never touch your main agent's context. The delegation runs as a
103
- detached background process, so the MCP call returns instantly.
101
+ opencode locally. File contents never touch your main agent's context. Fast tasks return
102
+ inline; long ones are auto-backgrounded by Claude Code (past ~2 min) or run detached with
103
+ `background:true` — so the delegation never blocks your session.
104
104
 
105
105
  ## When to delegate
106
106
 
@@ -30,8 +30,8 @@ Unsure → keep it.
30
30
  | Need | Tool |
31
31
  |---|---|
32
32
  | Quick one-shot question, no file access needed | `ask_model` |
33
- | A self-contained task with concrete code output, inline | `delegate_sync` |
34
- | Autonomous multi-file work, don't want to block (recommended) | `delegate` + `check_delegation` |
33
+ | A self-contained coding task (inline; auto-backgrounds past ~2 min in Claude Code) | `delegate` |
34
+ | Parallel fan-out or fire-and-forget | `delegate` with `background:true` + `check_delegation` |
35
35
  | See what's available | `list_models` |
36
36
 
37
37
  ## Cost policy (non-negotiable)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-delegate",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "MCP server that relays coding work to other AI models (DeepSeek, Gemini, OpenAI, Ollama) so Claude Code saves tokens",
5
5
  "type": "module",
6
6
  "bin": {
package/server.mjs CHANGED
@@ -28,12 +28,12 @@ const RUNS_DIR = join(homedir(), ".forge-delegate", "runs");
28
28
  const INSTRUCTIONS = `forge-delegate gives you a crew of external AI models to delegate coding work to. Hand off the high-volume, low-risk work (boilerplate, tests, lint/type fixes, mechanical edits) to a cheap or free model and keep the expensive agent focused on architecture and judgment calls.
29
29
 
30
30
  COST POLICY — MANDATORY, NON-NEGOTIABLE:
31
- The user pays per delegated call on a budget plan. You MUST pick only cheap or free models for EVERY delegation (ask_model, delegate_sync, delegate). NEVER pick top-tier, premium, flagship, or frontier models — not even "just this once" or for hard tasks. If a task seems too hard for a cheap model, split it into smaller delegated steps instead of upgrading. Run list_models and prefer free/cheap models (deepseek flash tiers, free opencode models, local ollama).
31
+ The user pays per delegated call on a budget plan. You MUST pick only cheap or free models for EVERY delegation (ask_model, delegate). NEVER pick top-tier, premium, flagship, or frontier models — not even "just this once" or for hard tasks. If a task seems too hard for a cheap model, split it into smaller delegated steps instead of upgrading. Run list_models and prefer free/cheap models (deepseek flash tiers, free opencode models, local ollama).
32
32
 
33
33
  Routing:
34
34
  - Quick one-shot questions → ask_model (direct API, no file access).
35
- - Multi-file edits/refactors/tests → delegate (background, recommended) or delegate_sync (inline).
36
- - delegate returns a job id instantly; poll check_delegation for the result.
35
+ - Multi-file edits/refactors/tests → delegate (inline by default; Claude Code auto-backgrounds calls past 2 min).
36
+ - Parallel or fire-and-forget → delegate with background:true (returns a job id instantly); poll check_delegation for the result.
37
37
  - Follow-ups on a delegated area: pass the returned session id as continue_session.
38
38
  - Omit model/directory to use the configured defaults (get_delegate_config); change them anytime with set_delegate_config — never reinstall.
39
39
  - Never paste large files into your own context for delegation — delegate and let the agent read files itself.
@@ -120,7 +120,7 @@ server.tool(
120
120
 
121
121
  server.tool(
122
122
  "ask_model",
123
- "Send a one-shot prompt to an external AI model and get its raw response. Fast direct API call; the model has NO file access and CANNOT take actions. For work requiring tools/files use delegate (background) or delegate_sync (inline) instead. model defaults to the configured defaultModel.",
123
+ "Send a one-shot prompt to an external AI model and get its raw response. Fast direct API call; the model has NO file access and CANNOT take actions. For work requiring tools/files use delegate instead. model defaults to the configured defaultModel.",
124
124
  {
125
125
  model: z.string().optional().describe("provider/model, e.g. deepseek/deepseek-v4-flash, ollama:llama3 (defaults to config defaultModel)"),
126
126
  prompt: z.string(),
@@ -136,21 +136,34 @@ server.tool(
136
136
  );
137
137
 
138
138
  server.tool(
139
- "delegate_sync",
140
- "Delegate a coding task to another AI model running as a full agent (via local opencode): it can read your project and answer with concrete code. Runs INLINE (foreground) — the result is returned in your context when done. Prefer `delegate` (background) to keep your context small. Optionally attach specific files. model/directory/agent/autoApprove default from config.",
139
+ "delegate",
140
+ "Delegate a coding task to another AI model running as a full agent (via local opencode): it reads your project, explores, and writes concrete code in its own tool loop — invisible to the caller's context. Runs INLINE by default (the result is returned in your context when done; Claude Code auto-backgrounds calls running past 2 minutes). Pass background:true to run detached and return a job id instantly, then poll check_delegation for the result — use that for parallel fan-out or hosts that block on long calls. Pass continue_session (returned by a previous delegation) to keep the same agent session instead of re-exploring. Optionally attach specific files in inline mode. model/directory/agent/autoApprove default from config.",
141
141
  {
142
142
  model: z.string().optional().describe("provider/model format, e.g. opencode/mimo-v2.5-free (defaults to config defaultModel)"),
143
143
  task: z.string(),
144
- files: z.array(z.string()).optional(),
144
+ files: z.array(z.string()).optional().describe("specific files to attach (inline mode)"),
145
+ background: z.boolean().optional().describe("run detached and return a job id (default false)"),
146
+ continue_session: z.string().optional().describe("session id returned by a previous delegation"),
145
147
  directory: z.string().optional().describe("absolute path to run in (defaults to config defaultDirectory, else server cwd)"),
146
148
  agent: z.string().optional().describe("opencode agent to use (defaults to config defaultAgent)"),
147
149
  autoApprove: z.boolean().optional().describe("auto-approve permissions (defaults to config autoApprove, true)"),
148
150
  profile: z.string().optional().describe("named config profile to apply"),
149
151
  },
150
- async ({ model, task, files, directory, agent, autoApprove, profile }) => {
152
+ async ({ model, task, files, background, continue_session, directory, agent, autoApprove, profile }) => {
151
153
  const r = resolveConfig({ model, directory, agent, autoApprove, profile });
152
154
  if (!r.model) return { content: [{ type: "text", text: "ERROR: no model specified and no defaultModel configured. Call set_delegate_config or pass model." }], isError: true };
153
- return withUsage("delegate_sync", r.model, async () => {
155
+ if (background) {
156
+ return withUsage("delegate", r.model, async () => {
157
+ const id = await startBackgroundJob(r.model, task, {
158
+ sessionId: continue_session,
159
+ directory: r.directory,
160
+ agent: r.agent,
161
+ autoApprove: r.autoApprove,
162
+ });
163
+ return `Started background job ${id}. Poll with check_delegation(id: "${id}").`;
164
+ });
165
+ }
166
+ return withUsage("delegate", r.model, async () => {
154
167
  const res = await opencodeRun(r.model, task, {
155
168
  files,
156
169
  directory: r.directory,
@@ -163,33 +176,6 @@ server.tool(
163
176
  }
164
177
  );
165
178
 
166
- server.tool(
167
- "delegate",
168
- "Fully delegate a coding task to another AI model working autonomously on this project (via local opencode): it explores, reads, edits and creates files in its own loop — invisible to the caller's context. Runs in the BACKGROUND (recommended): returns a job id instantly, poll check_delegation for the result. Pass continue_session (returned by a previous delegation) to keep the same agent session instead of re-exploring. Use this over delegate_sync to keep the caller's context small. model/directory/agent/autoApprove default from config.",
169
- {
170
- model: z.string().optional().describe("provider/model format, e.g. opencode/mimo-v2.5-free (defaults to config defaultModel)"),
171
- task: z.string(),
172
- continue_session: z.string().optional().describe("session id returned by a previous delegation"),
173
- directory: z.string().optional().describe("absolute path to run in (defaults to config defaultDirectory, else server cwd)"),
174
- agent: z.string().optional().describe("opencode agent to use (defaults to config defaultAgent)"),
175
- autoApprove: z.boolean().optional().describe("auto-approve permissions (defaults to config autoApprove, true)"),
176
- profile: z.string().optional().describe("named config profile to apply"),
177
- },
178
- async ({ model, task, continue_session, directory, agent, autoApprove, profile }) => {
179
- const r = resolveConfig({ model, directory, agent, autoApprove, profile });
180
- if (!r.model) return { content: [{ type: "text", text: "ERROR: no model specified and no defaultModel configured. Call set_delegate_config or pass model." }], isError: true };
181
- return withUsage("delegate", r.model, async () => {
182
- const id = await startBackgroundJob(r.model, task, {
183
- sessionId: continue_session,
184
- directory: r.directory,
185
- agent: r.agent,
186
- autoApprove: r.autoApprove,
187
- });
188
- return `Started background job ${id}. Poll with check_delegation(id: "${id}").`;
189
- });
190
- }
191
- );
192
-
193
179
  server.tool(
194
180
  "check_delegation",
195
181
  "Check status of a background delegation job: running/completed plus output so far. Call with no id to list all jobs.",