opencode-titan 0.1.0 → 0.1.2

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
@@ -1,6 +1,9 @@
1
1
  <div align="center">
2
2
  <h3>⚡ opencode-titan ⚡</h3>
3
3
 
4
+ <img src="assets/titan-demo.gif" alt="opencode-titan demo" width="100%">
5
+
6
+
4
7
  <p><i>One mind that never touches the keyboard. A fleet of hands that never stops moving.<br>Plan with the slow, expensive genius, and let the fast ones build in parallel.</i></p>
5
8
 
6
9
  <p><b>OpenCode Orchestration Plugin</b> · Mix any models · Delegate everything · Run in parallel</p>
@@ -32,8 +35,30 @@ The plugin builds a two-tier hierarchy of agents:
32
35
 
33
36
  ## Installation
34
37
 
35
- > [!NOTE]
36
- > This plugin is not published to npm yet, so install it manually from source. npm/Bun package installation is coming soon.
38
+ Add the [`opencode-titan`](https://www.npmjs.com/package/opencode-titan) package to the `plugin` array in your OpenCode config (`opencode.json`). OpenCode installs it automatically from npm on startup:
39
+
40
+ ```json
41
+ {
42
+ "$schema": "https://opencode.ai/config.json",
43
+ "plugin": ["opencode-titan"]
44
+ }
45
+ ```
46
+
47
+ To pin a specific version, append it with `@`:
48
+
49
+ ```json
50
+ {
51
+ "$schema": "https://opencode.ai/config.json",
52
+ "plugin": ["opencode-titan@0.1.0"]
53
+ }
54
+ ```
55
+
56
+ Restart OpenCode and Titan becomes your default agent.
57
+
58
+ <details>
59
+ <summary><b>Alternative: install from source</b></summary>
60
+
61
+ Use this if you want to hack on the plugin or run an unreleased version.
37
62
 
38
63
  **1. Clone and build the plugin:**
39
64
 
@@ -59,6 +84,8 @@ OpenCode treats any plugin entry starting with `.`, `file://`, or an absolute pa
59
84
 
60
85
  Restart OpenCode and Titan becomes your default agent.
61
86
 
87
+ </details>
88
+
62
89
  ## Getting Started
63
90
 
64
91
  1. **Create your plugin config** at `~/.config/opencode/opencode-titan.jsonc`
@@ -120,7 +147,7 @@ Titan is the most intelligent agent in the fleet, and by far the slowest and mos
120
147
 
121
148
  ### ⚙️ Myrmidons — The Fleet
122
149
 
123
- Myrmidons are the hands. Each executes a delegated task and reports back concisely — responses to Titan are enforced to a single paragraph, 500 words max, keeping Titan's context lean. Every Myrmidon declares a `modelType` that shapes how Titan routes work to it:
150
+ Myrmidons are the hands. Each executes a delegated task and reports back concisely — responses to Titan are enforced to a single paragraph, 1000 words max by default (configurable via `maxResponseWords`), keeping Titan's context lean. Every Myrmidon declares a `modelType` that shapes how Titan routes work to it:
124
151
 
125
152
  <table>
126
153
  <tr>
@@ -172,6 +199,7 @@ Myrmidons are the hands. Each executes a delegated task and reports back concise
172
199
  | `myrmidons` | `array` | The Myrmidon fleet (see above) |
173
200
  | `children` | `array` | **Deprecated** alias for `myrmidons`, kept for backwards compatibility. Prefer `myrmidons`; if both are set, `myrmidons` wins |
174
201
  | `disabled_tools` | `string[]` | Tool names to disable for the plugin's agents |
202
+ | `maxResponseWords` | `number` (≥1) | Max word count enforced on each Myrmidon's one-paragraph response to Titan (default: `1000`) |
175
203
  | `backgroundJobs.maxSessionsPerAgent` | `number` (1–10) | Max concurrent sessions per agent (default: `10`) |
176
204
 
177
205
  ### Config Locations
@@ -1,6 +1,6 @@
1
- import type { MyrmidonConfig } from '../config';
1
+ import { type MyrmidonConfig } from '../config';
2
2
  import type { AgentDefinition } from './titan';
3
- export declare function createMyrmidonAgent(index: number, config: MyrmidonConfig): AgentDefinition;
3
+ export declare function createMyrmidonAgent(index: number, config: MyrmidonConfig, maxResponseWords?: number): AgentDefinition;
4
4
  /**
5
5
  * @deprecated Use `createMyrmidonAgent`. Retained as a backwards-compatible
6
6
  * alias for the former "child agent" naming.
@@ -13,5 +13,5 @@ export declare function resolvePrompt(base: string, customPrompt?: string, custo
13
13
  /**
14
14
  * Build the Titan prompt with Myrmidon descriptions dynamically injected.
15
15
  */
16
- export declare function buildTitanPrompt(myrmidons: MyrmidonConfig[]): string;
17
- export declare function createTitanAgent(myrmidons: MyrmidonConfig[], model?: string, customPrompt?: string, customAppendPrompt?: string): AgentDefinition;
16
+ export declare function buildTitanPrompt(myrmidons: MyrmidonConfig[], maxResponseWords?: number): string;
17
+ export declare function createTitanAgent(myrmidons: MyrmidonConfig[], model?: string, customPrompt?: string, customAppendPrompt?: string, maxResponseWords?: number): AgentDefinition;
@@ -1,9 +1,14 @@
1
1
  export declare const TITAN_AGENT_NAME: "titan";
2
+ /**
3
+ * Default maximum word count enforced on a Myrmidon's final response to Titan.
4
+ * Overridable via the `maxResponseWords` plugin config key.
5
+ */
6
+ export declare const DEFAULT_MAX_RESPONSE_WORDS: 1000;
2
7
  export declare const ALL_AGENT_NAMES: readonly ["titan"];
3
8
  export type AgentName = (typeof ALL_AGENT_NAMES)[number];
4
9
  /** Agents that cannot be disabled. */
5
10
  export declare const PROTECTED_AGENTS: Set<"titan">;
6
- export declare const DELEGATION_REMINDER = "<internal_reminder>DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS. You are the slowest agent by far - your only job is planning, routing, and synthesizing results. Never do work a Myrmidon can handle. Parallelize aggressively: tool calls made in the SAME response turn run concurrently \u2014 always batch all ready task() dispatches into ONE response, never one per turn. SAY WHAT YOU DO: if you announce launching N Myrmidons, emit exactly N task() calls in that same response \u2014 never announce multiple then dispatch only one. Before ending a dispatch turn, count your task() calls and confirm they match the number of Myrmidons you named. The task() tool takes only subagent_type, description, and prompt \u2014 never pass any other parameters. </internal_reminder>";
11
+ export declare const DELEGATION_REMINDER = "<internal_reminder>DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS. You are the slowest agent by far - your only job is planning, routing, and synthesizing results. Never do work a Myrmidon can handle. THE ONE EXCEPTION: context-bound synthesis. If a task's input is your OWN accumulated context \u2014 findings you gathered, results Myrmidons reported back, reasoning built up this session \u2014 do it YOURSELF. Delegating a summary/report/plan/file of what you found or decided strips the context the task needs (Myrmidons start blank), so the write-up stays with you. Parallelize aggressively: tool calls made in the SAME response turn run concurrently \u2014 always batch all ready task() dispatches into ONE response, never one per turn. SAY WHAT YOU DO: if you announce launching N Myrmidons, emit exactly N task() calls in that same response \u2014 never announce multiple then dispatch only one. Before ending a dispatch turn, count your task() calls and confirm they match the number of Myrmidons you named. The task() tool takes only subagent_type, description, and prompt \u2014 never pass any other parameters. </internal_reminder>";
7
12
  /**
8
13
  * Sentinel substring used to detect whether {@link DELEGATION_REMINDER} has
9
14
  * already been injected into a system prompt, avoiding double-injection.
@@ -18,4 +23,4 @@ export declare const DELEGATION_REMINDER_SENTINEL = "DELEGATE EVERYTHING POSSIBL
18
23
  * at the point of each new user message keeps that behavior consistent — it
19
24
  * mimics the user manually prefixing "delegate this" onto every ask.
20
25
  */
21
- export declare const PER_MESSAGE_DELEGATION_REMINDER = "<delegation_directive>\nBefore you act on the user's message above, STOP and route it through delegation first.\n\n1. Decompose the request (including any follow-up tweaks, fixes, or refinements to prior work) into concrete units of work.\n2. For every unit that would require even a SINGLE tool call \u2014 reading/searching/editing files, running commands, testing, validating, looking things up, gathering information, or any mechanical work \u2014 you MUST delegate it to Myrmidons via task(). This applies to small iterative changes on the existing task just as much as to brand-new work. Do NOT do it yourself because it \"seems quick.\"\n3. Dispatch all independent units in parallel: emit one task() call per unit in a SINGLE response, and make the number of task() calls match the number of Myrmidons you announce.\n4. The ONLY time you may answer directly without delegating is when the request is trivially simple, purely conversational, and requires zero tool calls (e.g., clarifying a question, restating a plan, a one-word answer). When in doubt, delegate.\n\nTreat this as if the user explicitly said: \"delegate this to your Myrmidons.\"\n</delegation_directive>";
26
+ export declare const PER_MESSAGE_DELEGATION_REMINDER = "<delegation_directive>\nBefore you act on the user's message above, STOP and route it through delegation first.\n\n1. Decompose the request (including any follow-up tweaks, fixes, or refinements to prior work) into concrete units of work.\n2. For every unit that would require even a SINGLE tool call \u2014 reading/searching/editing files, running commands, testing, validating, looking things up, gathering information, or any mechanical work \u2014 you MUST delegate it to Myrmidons via task(). This applies to small iterative changes on the existing task just as much as to brand-new work. Do NOT do it yourself because it \"seems quick.\"\n3. EXCEPTION \u2014 context-bound synthesis: if a unit's real input is YOUR OWN accumulated context (findings you gathered, results your Myrmidons already reported back, reasoning or decisions from earlier in this session) and the deliverable is just expressing/organizing/persisting that context \u2014 e.g. writing a summary, report, plan, or markdown file of what was found/decided \u2014 do it YOURSELF. Delegating it would hand a blank-context Myrmidon a task it cannot do correctly, losing the very information the deliverable depends on. Writing a file is one cheap tool call; never delegate it just to avoid that call. You may still delegate any fresh lookups the write-up needs, but the context-bearing synthesis stays with you.\n4. Dispatch all independent units in parallel: emit one task() call per unit in a SINGLE response, and make the number of task() calls match the number of Myrmidons you announce.\n5. The ONLY time you may answer directly without delegating is when the request is trivially simple, purely conversational, and requires zero tool calls (e.g., clarifying a question, restating a plan, a one-word answer), OR when it is context-bound synthesis per point 3. When in doubt about fresh work, delegate; when in doubt about whether the task needs context only you hold, keep it.\n\nTreat this as if the user explicitly said: \"delegate this to your Myrmidons.\"\n</delegation_directive>";
@@ -85,6 +85,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
85
85
  displayName: z.ZodOptional<z.ZodString>;
86
86
  provider: z.ZodOptional<z.ZodString>;
87
87
  }, z.core.$strict>>>;
88
+ maxResponseWords: z.ZodOptional<z.ZodNumber>;
88
89
  disabled_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
89
90
  backgroundJobs: z.ZodOptional<z.ZodObject<{
90
91
  maxSessionsPerAgent: z.ZodDefault<z.ZodNumber>;
package/dist/index.js CHANGED
@@ -1,14 +1,16 @@
1
1
  // src/config/constants.ts
2
2
  var TITAN_AGENT_NAME = "titan";
3
- var DELEGATION_REMINDER = `<internal_reminder>DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS. You are the slowest agent by far - your only job is planning, routing, and synthesizing results. Never do work a Myrmidon can handle. Parallelize aggressively: tool calls made in the SAME response turn run concurrently \u2014 always batch all ready task() dispatches into ONE response, never one per turn. SAY WHAT YOU DO: if you announce launching N Myrmidons, emit exactly N task() calls in that same response \u2014 never announce multiple then dispatch only one. Before ending a dispatch turn, count your task() calls and confirm they match the number of Myrmidons you named. The task() tool takes only subagent_type, description, and prompt \u2014 never pass any other parameters. </internal_reminder>`;
3
+ var DEFAULT_MAX_RESPONSE_WORDS = 1e3;
4
+ var DELEGATION_REMINDER = `<internal_reminder>DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS. You are the slowest agent by far - your only job is planning, routing, and synthesizing results. Never do work a Myrmidon can handle. THE ONE EXCEPTION: context-bound synthesis. If a task's input is your OWN accumulated context \u2014 findings you gathered, results Myrmidons reported back, reasoning built up this session \u2014 do it YOURSELF. Delegating a summary/report/plan/file of what you found or decided strips the context the task needs (Myrmidons start blank), so the write-up stays with you. Parallelize aggressively: tool calls made in the SAME response turn run concurrently \u2014 always batch all ready task() dispatches into ONE response, never one per turn. SAY WHAT YOU DO: if you announce launching N Myrmidons, emit exactly N task() calls in that same response \u2014 never announce multiple then dispatch only one. Before ending a dispatch turn, count your task() calls and confirm they match the number of Myrmidons you named. The task() tool takes only subagent_type, description, and prompt \u2014 never pass any other parameters. </internal_reminder>`;
4
5
  var DELEGATION_REMINDER_SENTINEL = "DELEGATE EVERYTHING POSSIBLE TO MYRMIDONS";
5
6
  var PER_MESSAGE_DELEGATION_REMINDER = `<delegation_directive>
6
7
  Before you act on the user's message above, STOP and route it through delegation first.
7
8
 
8
9
  1. Decompose the request (including any follow-up tweaks, fixes, or refinements to prior work) into concrete units of work.
9
10
  2. For every unit that would require even a SINGLE tool call \u2014 reading/searching/editing files, running commands, testing, validating, looking things up, gathering information, or any mechanical work \u2014 you MUST delegate it to Myrmidons via task(). This applies to small iterative changes on the existing task just as much as to brand-new work. Do NOT do it yourself because it "seems quick."
10
- 3. Dispatch all independent units in parallel: emit one task() call per unit in a SINGLE response, and make the number of task() calls match the number of Myrmidons you announce.
11
- 4. The ONLY time you may answer directly without delegating is when the request is trivially simple, purely conversational, and requires zero tool calls (e.g., clarifying a question, restating a plan, a one-word answer). When in doubt, delegate.
11
+ 3. EXCEPTION \u2014 context-bound synthesis: if a unit's real input is YOUR OWN accumulated context (findings you gathered, results your Myrmidons already reported back, reasoning or decisions from earlier in this session) and the deliverable is just expressing/organizing/persisting that context \u2014 e.g. writing a summary, report, plan, or markdown file of what was found/decided \u2014 do it YOURSELF. Delegating it would hand a blank-context Myrmidon a task it cannot do correctly, losing the very information the deliverable depends on. Writing a file is one cheap tool call; never delegate it just to avoid that call. You may still delegate any fresh lookups the write-up needs, but the context-bearing synthesis stays with you.
12
+ 4. Dispatch all independent units in parallel: emit one task() call per unit in a SINGLE response, and make the number of task() calls match the number of Myrmidons you announce.
13
+ 5. The ONLY time you may answer directly without delegating is when the request is trivially simple, purely conversational, and requires zero tool calls (e.g., clarifying a question, restating a plan, a one-word answer), OR when it is context-bound synthesis per point 3. When in doubt about fresh work, delegate; when in doubt about whether the task needs context only you hold, keep it.
12
14
 
13
15
  Treat this as if the user explicitly said: "delegate this to your Myrmidons."
14
16
  </delegation_directive>`;
@@ -51,6 +53,9 @@ var PluginConfigSchema = z.object({
51
53
  // Deprecated alias for `myrmidons`, retained for backwards compatibility.
52
54
  // If both are present, `myrmidons` takes precedence.
53
55
  children: z.array(MyrmidonConfigSchema).optional(),
56
+ // Maximum word count enforced on each Myrmidon's final response to Titan.
57
+ // Keeps Titan's context lean. Defaults to DEFAULT_MAX_RESPONSE_WORDS (1000).
58
+ maxResponseWords: z.number().int().min(1).optional(),
54
59
  disabled_tools: z.array(z.string()).optional(),
55
60
  backgroundJobs: z.object({
56
61
  maxSessionsPerAgent: z.number().int().min(1).max(10).default(10)
@@ -300,7 +305,7 @@ You are operating with a hard context budget. Exceeding it causes failure. Follo
300
305
  </ContextBudget>
301
306
 
302
307
  <OutputConstraints>
303
- - **CRITICAL: Your final response to Titan MUST be ONE PARAGRAPH, no more than 500 words.**
308
+ - **CRITICAL: Your final response to Titan MUST be ONE PARAGRAPH, no more than {{MAX_WORDS}} words.**
304
309
  - No preamble, no summary of what you did \u2014 just the results.
305
310
  - Report success/failure clearly in your first sentence.
306
311
  - Include only actionable details: file paths, line numbers, errors, generated code snippets.
@@ -317,10 +322,14 @@ You are operating with a hard context budget. Exceeding it causes failure. Follo
317
322
  {{TASK_PROMPT}}
318
323
  </Task>
319
324
  `;
320
- function createMyrmidonAgent(index, config) {
325
+ function createMyrmidonAgent(index, config, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
321
326
  const name = `myrmidon-${index}`;
322
327
  const modelTypeHint = config.modelType === "dense" ? "You are running a dense model \u2014 you excel at logic, reasoning, and complex problem-solving. Use this strength for tasks requiring careful analysis." : "You are running a sparse model \u2014 you excel at fast information gathering, broad search, and rapid lookups. Use this strength for research and exploration tasks.";
323
- const prompt = `${MYRMIDON_PROMPT_TEMPLATE.replace("{{TASK_PROMPT}}", "")}
328
+ const template = MYRMIDON_PROMPT_TEMPLATE.replace(
329
+ "{{MAX_WORDS}}",
330
+ String(maxResponseWords)
331
+ );
332
+ const prompt = `${template.replace("{{TASK_PROMPT}}", "")}
324
333
 
325
334
  ${modelTypeHint}`;
326
335
  return {
@@ -348,7 +357,7 @@ function resolvePrompt(base, customPrompt, customAppendPrompt) {
348
357
 
349
358
  ${customAppendPrompt}` : effectiveBase;
350
359
  }
351
- function buildTitanPrompt(myrmidons) {
360
+ function buildTitanPrompt(myrmidons, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
352
361
  const resolveProvider = resolveMyrmidonProvider;
353
362
  const myrmidonDescriptions = myrmidons.map((myrmidon, idx) => {
354
363
  const name = `myrmidon-${idx}`;
@@ -430,7 +439,7 @@ ${selfParallelMyrmidons.join("\n")}` : ""}
430
439
 
431
440
  <DelegationPhilosophy>
432
441
  ## The Golden Rule
433
- If a task can be abstracted away to a Myrmidon, it MUST be. No exceptions. This includes:
442
+ If a task can be abstracted away to a Myrmidon, it MUST be. The only exception is context-bound synthesis (see below). This includes:
434
443
  - Looking up things in the code
435
444
  - Testing ideas
436
445
  - Writing code
@@ -441,6 +450,26 @@ If a task can be abstracted away to a Myrmidon, it MUST be. No exceptions. This
441
450
  - Any information gathering
442
451
  - Any mechanical implementation
443
452
 
453
+ ## The One Exception: Context-Bound Synthesis
454
+ Delegation works by handing a Myrmidon a self-contained task. A Myrmidon starts with a BLANK context \u2014 it sees only the prompt you give it, never your conversation history, never the results your other Myrmidons reported back to you, never the reasoning you've accumulated across this session.
455
+
456
+ Therefore, there is exactly one class of work you must do YOURSELF: **tasks whose actual input is your own accumulated context.** If completing the task requires knowledge that lives only in your head \u2014 the findings you gathered, the results Myrmidons already reported, the analysis you synthesized, the decisions made earlier in this conversation \u2014 then delegating it would strip away the very information the task needs. The Myrmidon would produce a hollow, wrong, or generic result.
457
+
458
+ Concrete examples you MUST handle yourself (do not delegate these):
459
+ - Writing a summary, report, or markdown file of findings YOU discovered during this task
460
+ - Writing a plan document that reflects the reasoning and context YOU built up
461
+ - Synthesizing or consolidating results that multiple Myrmidons reported back to you
462
+ - Answering a question that depends on what was already discussed or discovered in this session
463
+ - Any "write down / capture / summarize what we found/decided/did" request
464
+
465
+ The mechanical distinction:
466
+ - **Does the task need NEW information or NEW work from the codebase/web/tools?** \u2192 Delegate. (The Myrmidon gathers it fresh.)
467
+ - **Is the task's input ALREADY in your context, and the deliverable is just expressing/organizing/persisting it?** \u2192 Do it yourself. Delegating would only lose that context.
468
+
469
+ When you do produce such a deliverable yourself, you may still delegate the *mechanical* sub-parts you don't have context for. E.g., you write the summary from your own findings, but if you need one extra fact verified you delegate just that verification. The context-bearing synthesis stays with you; the fresh lookups go to Myrmidons.
470
+
471
+ Writing a file is a single tool call \u2014 cheap. Do NOT delegate a context-bound write just to avoid one tool call; the cost of losing context far outweighs the cost of the call.
472
+
444
473
  ## Parallelization is Key
445
474
  You are slow. Your Myrmidons are fast \u2014 sometimes 50x faster. You have **${myrmidons.length} Myrmidon${myrmidons.length !== 1 ? "s" : ""}**. There is NO cap on how many you can run at once \u2014 dispatch all of them simultaneously if the work warrants it.
446
475
 
@@ -520,7 +549,7 @@ Before you finish a dispatch turn, silently count: "Independent tasks ready = N.
520
549
  Each task() call returns the Myrmidon's result when it completes. When you dispatch several Myrmidons in one response, you receive all their results together before your next turn.
521
550
 
522
551
  ## 5. Synthesize
523
- When Myrmidons report back, integrate their results into a coherent outcome. If something is missing or wrong, re-delegate \u2014 don't do it yourself.
552
+ When Myrmidons report back, integrate their results into a coherent outcome. If something is missing or wrong, re-delegate \u2014 don't do it yourself. **But synthesis itself \u2014 consolidating multiple Myrmidons' results, and writing any summary/report/plan/file that captures findings or reasoning you accumulated \u2014 is YOUR job (see "The One Exception: Context-Bound Synthesis"). Never delegate the write-up of context that lives only in your head; the Myrmidon would start blank and lose it.
524
553
 
525
554
  ## 6. Verify
526
555
  Use a Myrmidon to run checks/diagnostics/validations. Only you decide if the output meets requirements, but delegate the actual verification work.
@@ -539,14 +568,14 @@ When delegating to a Myrmidon:
539
568
  - Be specific about the task and expected output format
540
569
  - Reference file paths/lines, don't paste full contents
541
570
  - Set clear boundaries: what to do and what not to do
542
- - Tell the Myrmidon to report back concisely (one paragraph, under 500 words max)
571
+ - Tell the Myrmidon to report back concisely (one paragraph, under ${maxResponseWords} words max)
543
572
  </CommunicationWithMyrmidons>
544
573
 
545
574
  ${DELEGATION_REMINDER}
546
575
  `;
547
576
  }
548
- function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt) {
549
- const basePrompt = buildTitanPrompt(myrmidons);
577
+ function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt, maxResponseWords = DEFAULT_MAX_RESPONSE_WORDS) {
578
+ const basePrompt = buildTitanPrompt(myrmidons, maxResponseWords);
550
579
  const prompt = resolvePrompt(basePrompt, customPrompt, customAppendPrompt);
551
580
  const definition = {
552
581
  name: "titan",
@@ -565,6 +594,7 @@ function createTitanAgent(myrmidons, model, customPrompt, customAppendPrompt) {
565
594
  // src/agents/index.ts
566
595
  function createAgents(config, options) {
567
596
  const myrmidons = getMyrmidonConfigs(config);
597
+ const maxResponseWords = config?.maxResponseWords ?? DEFAULT_MAX_RESPONSE_WORDS;
568
598
  const titanModel = config?.titan?.model;
569
599
  const titanPrompts = loadAgentPrompt("titan", {
570
600
  projectDirectory: options?.projectDirectory
@@ -573,7 +603,8 @@ function createAgents(config, options) {
573
603
  myrmidons,
574
604
  typeof titanModel === "string" ? titanModel : void 0,
575
605
  config?.titan?.prompt,
576
- void 0
606
+ void 0,
607
+ maxResponseWords
577
608
  );
578
609
  titan.config.prompt = resolvePrompt(
579
610
  titan.config.prompt ?? "",
@@ -589,7 +620,7 @@ function createAgents(config, options) {
589
620
  }
590
621
  }
591
622
  const myrmidonAgents = myrmidons.map(
592
- (myrmidonConfig, idx) => createMyrmidonAgent(idx, myrmidonConfig)
623
+ (myrmidonConfig, idx) => createMyrmidonAgent(idx, myrmidonConfig, maxResponseWords)
593
624
  );
594
625
  const aliasAgents = myrmidonAgents.map((agent, idx) => ({
595
626
  ...agent,
@@ -41,6 +41,12 @@
41
41
  "$ref": "#/$defs/myrmidon"
42
42
  }
43
43
  },
44
+ "maxResponseWords": {
45
+ "type": "integer",
46
+ "minimum": 1,
47
+ "default": 1000,
48
+ "description": "Maximum word count enforced on each Myrmidon's final (one-paragraph) response to Titan. Keeps Titan's context lean. Defaults to 1000."
49
+ },
44
50
  "disabled_tools": {
45
51
  "type": "array",
46
52
  "description": "Tool names to disable completely. Disabled tools are not registered with OpenCode.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-titan",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Distributed delegation plugin for OpenCode — Titan orchestrator with parallel Myrmidons",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",