|
| 1 | +--- |
| 2 | +title: 'The Mode-Command-Tool Pattern: Framework Design Specification' |
| 3 | +slug: mode-command-tool-pattern |
| 4 | +date: '2026-03-27' |
| 5 | +tags: |
| 6 | +- framework |
| 7 | +- design-pattern |
| 8 | +- architecture |
| 9 | +- agent-design |
| 10 | +--- |
| 11 | + |
| 12 | +# The Mode-Command-Tool Pattern |
| 13 | + |
| 14 | +## Overview |
| 15 | + |
| 16 | +This document defines the canonical three-layer architecture for the opencode framework, establishing clear separation of concerns between **Modes** (behavioral philosophy), **Commands** (workflow entry points), and **Tools** (execution engines with state management). |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## The Three-Layer Architecture |
| 21 | + |
| 22 | +``` |
| 23 | +┌─────────────────────────────────────────────────────────────┐ |
| 24 | +│ LAYER 1: MODE (.opencode/agents/{mode}.md) │ |
| 25 | +│ └── Defines: Thinking style, behavioral principles │ |
| 26 | +│ Permissions: Explicit allow/deny boundaries │ |
| 27 | +│ Tone: Open-ended, exploratory, suggestive │ |
| 28 | +│ │ |
| 29 | +│ ↓ suggests at appropriate moments │ |
| 30 | +│ │ |
| 31 | +│ LAYER 2: COMMAND (.opencode/commands/{cmd}.md) │ |
| 32 | +│ └── Defines: Workflow entry point │ |
| 33 | +│ Structure: Minimal, delegates to tool │ |
| 34 | +│ Key Phrase: "Read the output and follow instructions" │ |
| 35 | +│ │ |
| 36 | +│ ↓ delegates execution │ |
| 37 | +│ │ |
| 38 | +│ LAYER 3: TOOL (.opencode/bin/{tool}.py) │ |
| 39 | +│ └── Defines: Validation, state management, continuation │ |
| 40 | +│ Returns: Descriptive instructions for next steps │ |
| 41 | +│ Guards: Safety checks, branching logic │ |
| 42 | +└─────────────────────────────────────────────────────────────┘ |
| 43 | +``` |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Layer 1: Mode Specification |
| 48 | + |
| 49 | +### Correct Structure |
| 50 | + |
| 51 | +**YAML Frontmatter:** |
| 52 | +```yaml |
| 53 | +--- |
| 54 | +description: Brief purpose statement |
| 55 | +mode: primary|subagent |
| 56 | +permissions: |
| 57 | + "*": deny |
| 58 | + read: allow |
| 59 | + [tool]: [scope]: allow|deny |
| 60 | +--- |
| 61 | +``` |
| 62 | + |
| 63 | +**Content Sections:** |
| 64 | +1. **Identity Statement** — "You are in X Mode — purpose" |
| 65 | +2. **Thinking Style** — 3-5 bullet points (principles, not procedures) |
| 66 | +3. **Subagents** — Clear role definitions |
| 67 | +4. **Behavior** — Split: "If running command / If freestyle" |
| 68 | +5. **Key Mandates** — Non-negotiable rules |
| 69 | +6. **When to Suggest Commands** — Bridge to command layer |
| 70 | + |
| 71 | +### Golden Rules for Modes |
| 72 | + |
| 73 | +**DO:** |
| 74 | +- Define thinking style (exploratory, analytical, disciplined) |
| 75 | +- Use suggestive language: "Suggest `/command` when..." |
| 76 | +- Set explicit permission boundaries |
| 77 | +- Separate command-running vs freestyle behavior |
| 78 | + |
| 79 | +**DON'T:** |
| 80 | +- Define procedural workflows (Step 1, Step 2) |
| 81 | +- Mandate commands ("Run `/command` now") |
| 82 | +- Leave permissions implicit |
| 83 | + |
| 84 | +--- |
| 85 | + |
| 86 | +## Layer 2: Command Specification |
| 87 | + |
| 88 | +### Correct Structure |
| 89 | + |
| 90 | +**YAML Frontmatter:** |
| 91 | +```yaml |
| 92 | +--- |
| 93 | +description: Brief purpose statement |
| 94 | +agent: [mode-name] # Which mode executes this |
| 95 | +subagents: [list] # Allowed subagents (optional) |
| 96 | +--- |
| 97 | +``` |
| 98 | + |
| 99 | +**Content Pattern:** |
| 100 | +```markdown |
| 101 | +# /command-name |
| 102 | + |
| 103 | +One-line description of what this command does. |
| 104 | + |
| 105 | +## What to do next |
| 106 | + |
| 107 | +Run: `uv run .opencode/bin/tool.py --arg1 [VAL]` |
| 108 | + |
| 109 | +[Any stdin requirements] |
| 110 | + |
| 111 | +**Read the output and follow instructions from there.** |
| 112 | +``` |
| 113 | + |
| 114 | +### Critical: The Reactive Pattern |
| 115 | + |
| 116 | +Commands use **reactive workflow delegation**: |
| 117 | +- **NOT:** Enumerate all branches and steps |
| 118 | +- **INSTEAD:** Delegate to tool, read output, follow instructions |
| 119 | + |
| 120 | +**Key Phrase (Required):** |
| 121 | +> "**Read the output and follow instructions from there.**" |
| 122 | +
|
| 123 | +This phrase signals to the agent that: |
| 124 | +1. The tool will return descriptive messages |
| 125 | +2. The agent should parse and act on those messages |
| 126 | +3. The tool owns the workflow continuation logic |
| 127 | + |
| 128 | +### Golden Rules for Commands |
| 129 | + |
| 130 | +**DO:** |
| 131 | +- Keep under 25 lines |
| 132 | +- Provide only entry point and parameters |
| 133 | +- Delegate all branching to tool |
| 134 | +- Include the "follow instructions" phrase |
| 135 | + |
| 136 | +**DON'T:** |
| 137 | +- Define multi-phase workflows inline |
| 138 | +- Enumerate if/then branches |
| 139 | +- Try to predict all tool outputs |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## Layer 3: Tool Specification |
| 144 | + |
| 145 | +### Correct Characteristics |
| 146 | + |
| 147 | +**Validation:** |
| 148 | +- Check required inputs (stdin, args, files) |
| 149 | +- Validate before acting (existence checks, format checks) |
| 150 | +- Provide clear error messages |
| 151 | + |
| 152 | +**State Management:** |
| 153 | +- Track workflow state internally |
| 154 | +- Return descriptive status messages |
| 155 | +- Handle branching logic (draft→confirm→save) |
| 156 | + |
| 157 | +**Output Format:** |
| 158 | +- Human-readable instructions, not codes |
| 159 | +- Tell the agent explicitly what to do next: |
| 160 | + - `"Draft mode. Ask user for changes, rerun with --save"` |
| 161 | + - `"✓ Saved to: {path}"` |
| 162 | + - `"Error: File exists. Choose different slug"` |
| 163 | + |
| 164 | +**Safety Guards:** |
| 165 | +- Prevent destructive actions without confirmation |
| 166 | +- Two-phase patterns (draft → save) |
| 167 | +- Exit codes for success/failure |
| 168 | + |
| 169 | +### Example: note.py Pattern |
| 170 | + |
| 171 | +```python |
| 172 | +# 1. Validate required inputs |
| 173 | +content = sys.stdin.read().strip() |
| 174 | +if not content: |
| 175 | + print("Error: No content via stdin") |
| 176 | + exit(1) |
| 177 | + |
| 178 | +# 2. Set defaults (reduce decision fatigue) |
| 179 | +if not slug: |
| 180 | + slug = slugify(title) |
| 181 | + |
| 182 | +# 3. Two-phase workflow (safety) |
| 183 | +if not save: |
| 184 | + print("Draft mode. Review with user, then rerun with --save") |
| 185 | + exit(0) |
| 186 | + |
| 187 | +# 4. Safety check |
| 188 | +if filepath.exists(): |
| 189 | + print("Error: File exists") |
| 190 | + exit(1) |
| 191 | + |
| 192 | +# 5. Execute + confirm |
| 193 | +filepath.write_text(content) |
| 194 | +print(f"✓ Saved to: {filepath}") |
| 195 | +``` |
| 196 | + |
| 197 | +### Golden Rules for Tools |
| 198 | + |
| 199 | +**DO:** |
| 200 | +- Validate all inputs |
| 201 | +- Return descriptive next-step instructions |
| 202 | +- Implement branching logic internally |
| 203 | +- Use two-phase patterns for destructive ops |
| 204 | + |
| 205 | +**DON'T:** |
| 206 | +- Return silent success |
| 207 | +- Return machine codes (JSON) instead of instructions |
| 208 | +- Skip validation |
| 209 | +- Assume agent will track state |
| 210 | + |
| 211 | +--- |
| 212 | + |
| 213 | +## The Pattern Decision Framework |
| 214 | + |
| 215 | +### When to Use Reactive (Tool-Driven) vs Prescriptive (Command-Driven) |
| 216 | + |
| 217 | +**Use Reactive Pattern (like /note):** |
| 218 | +- Requires user confirmation before final action |
| 219 | +- Multiple exit states (draft, saved, error, conflict) |
| 220 | +- Natural "review → confirm → execute" lifecycle |
| 221 | +- Tool can validate better than agent (file existence, etc.) |
| 222 | + |
| 223 | +**Use Prescriptive Pattern (like /build phases):** |
| 224 | +- Linear workflow with few branches |
| 225 | +- All info available upfront |
| 226 | +- Steps are deterministic |
| 227 | +- Complex logic handled by subagents |
| 228 | + |
| 229 | +### Anti-Patterns to Avoid |
| 230 | + |
| 231 | +**Mode Anti-Patterns:** |
| 232 | +- Defining procedures instead of principles |
| 233 | +- Missing "When to suggest commands" section |
| 234 | +- Implicit permissions |
| 235 | +- Mandating instead of suggesting |
| 236 | + |
| 237 | +**Command Anti-Patterns:** |
| 238 | +- Overly prescriptive (50+ lines of steps) |
| 239 | +- Enumerating all branches inline |
| 240 | +- Missing "follow instructions" phrase |
| 241 | +- Owning branching logic that belongs in tool |
| 242 | + |
| 243 | +**Tool Anti-Patterns:** |
| 244 | +- Silent success (no confirmation) |
| 245 | +- Returning data instead of instructions |
| 246 | +- No validation |
| 247 | +- No safety guards for destructive actions |
| 248 | + |
| 249 | +--- |
| 250 | + |
| 251 | +## Summary: The Golden Rules |
| 252 | + |
| 253 | +### 1. Modes Define Philosophy |
| 254 | +- Thinking style > workflow steps |
| 255 | +- Suggest commands, don't mandate them |
| 256 | +- Permission boundaries explicit |
| 257 | + |
| 258 | +### 2. Commands Are Entry Points |
| 259 | +- Minimal workflow description |
| 260 | +- Delegate to tools for execution |
| 261 | +- **Key phrase:** "Read the output and follow instructions from there" |
| 262 | + |
| 263 | +### 3. Tools Own The Workflow |
| 264 | +- Validate everything |
| 265 | +- Return descriptive instructions for next steps |
| 266 | +- Handle branching logic internally |
| 267 | +- Guide agent through state transitions |
| 268 | + |
| 269 | +### 4. Progressive Disclosure |
| 270 | +``` |
| 271 | +Mode: "Be exploratory" (philosophy) |
| 272 | +Command: "Run this tool" (intent) |
| 273 | +Tool: "Draft mode, ask user, then rerun with --save" (execution) |
| 274 | +``` |
| 275 | + |
| 276 | +--- |
| 277 | + |
| 278 | +## Examples in Framework |
| 279 | + |
| 280 | +**Good Example:** analyze.md + note.md + note.py |
| 281 | +- Mode: Suggests /note at right moments |
| 282 | +- Command: "Run tool, read output, follow instructions" |
| 283 | +- Tool: Validates, returns "draft mode" or "saved" |
| 284 | + |
| 285 | +**Anti-Pattern:** build.md command spec |
| 286 | +- Enumerates all TCR phases inline |
| 287 | +- No tool delegation |
| 288 | +- Agent must track state mentally |
| 289 | +- Brittle to changes |
| 290 | + |
| 291 | +--- |
| 292 | + |
| 293 | +## Application Guidelines |
| 294 | + |
| 295 | +When creating new framework components: |
| 296 | + |
| 297 | +1. **Start with Mode** — Define thinking style and when to suggest commands |
| 298 | +2. **Create Command** — Minimal entry point with "follow instructions" phrase |
| 299 | +3. **Build Tool** — Validation, state management, descriptive outputs |
| 300 | +4. **Test Workflow** — Ensure tool messages guide agent correctly |
| 301 | + |
| 302 | +The goal: **Agent reads tool output and knows exactly what to do next**, without the command spec enumerating all possibilities. |
0 commit comments