Chapter 2: Compound Engineering Philosophy and Workflow Loop
April 13, 2026 ยท View on GitHub
Welcome to Chapter 2: Compound Engineering Philosophy and Workflow Loop. In this part of Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.
This chapter explains the project's core premise: each work cycle should improve future cycles.
Learning Goals
- understand the plan-work-review-compound loop deeply
- map philosophy to daily engineering decisions
- separate workflow discipline from tool-specific implementation details
- avoid anti-patterns that erase compounding benefits
Workflow Core
Plan -> Work -> Review -> Compound -> Repeat
Compounding Principles
- invest heavily in planning and review quality
- capture reusable patterns and pitfalls after each cycle
- feed learnings back into future planning and execution
Common Anti-Patterns
- skipping review phase under schedule pressure
- treating compound step as optional documentation overhead
- scaling scope before baseline workflow reliability is proven
Source References
Summary
You now understand how the workflow loop creates durable engineering leverage.
Next: Chapter 3: Architecture of Agents, Commands, and Skills
Source Code Walkthrough
src/converters/claude-to-opencode.ts
The renderHookStatements function in src/converters/claude-to-opencode.ts handles a key part of this chapter's functionality:
const statements: string[] = []
for (const matcher of matchers) {
statements.push(...renderHookStatements(matcher, options.useToolMatcher))
}
const rendered = statements.map((line) => ` ${line}`).join("\n")
const wrapped = options.requireError
? ` if (input?.error) {\n${statements.map((line) => ` ${line}`).join("\n")}\n }`
: rendered
// Wrap tool.execute.before handlers in try-catch to prevent a failing hook
// from crashing parallel tool call batches (causes API 400 errors).
// See: https://github.com/EveryInc/compound-engineering-plugin/issues/85
const isPreToolUse = event === "tool.execute.before"
const note = options.note ? ` // ${options.note}\n` : ""
if (isPreToolUse) {
return ` "${event}": async (input) => {\n${note} try {\n ${wrapped}\n } catch (err) {\n console.error("[hook] ${event} error (non-fatal):", err)\n }\n }`
}
return ` "${event}": async (input) => {\n${note}${wrapped}\n }`
}
function renderHookStatements(
matcher: ClaudeHooks["hooks"][string][number],
useToolMatcher: boolean,
): string[] {
if (!matcher.hooks || matcher.hooks.length === 0) return []
const tools = matcher.matcher
? matcher.matcher
.split("|")
.map((tool) => tool.trim().toLowerCase())
.filter(Boolean)
: []
This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
src/converters/claude-to-opencode.ts
The rewriteClaudePaths function in src/converters/claude-to-opencode.ts handles a key part of this chapter's functionality:
}
const content = formatFrontmatter(frontmatter, rewriteClaudePaths(agent.body))
return {
name: agent.name,
content,
}
}
// Commands are written as individual .md files rather than entries in opencode.json.
// Chosen over JSON map because opencode resolves commands by filename at runtime (ADR-001).
function convertCommands(commands: ClaudeCommand[]): OpenCodeCommandFile[] {
const files: OpenCodeCommandFile[] = []
for (const command of commands) {
if (command.disableModelInvocation) continue
const frontmatter: Record<string, unknown> = {
description: command.description,
}
if (command.model && command.model !== "inherit") {
frontmatter.model = normalizeModelWithProvider(command.model)
}
const content = formatFrontmatter(frontmatter, rewriteClaudePaths(command.body))
files.push({ name: command.name, content })
}
return files
}
function convertMcp(servers: Record<string, ClaudeMcpServer>): Record<string, OpenCodeMcpServer> {
const result: Record<string, OpenCodeMcpServer> = {}
for (const [name, server] of Object.entries(servers)) {
if (server.command) {
This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
src/converters/claude-to-opencode.ts
The transformSkillContentForOpenCode function in src/converters/claude-to-opencode.ts handles a key part of this chapter's functionality:
* See #477.
*/
export function transformSkillContentForOpenCode(body: string): string {
let result = rewriteClaudePaths(body)
// Rewrite 3-segment FQ agent refs: plugin:category:agent-name -> agent-name.
// Boundary assertions prevent partial matching on 4+ segment names
// (e.g. `a:b:c:d` would otherwise produce `c:d` or `a:d`).
// The `/` in the lookbehind prevents rewriting slash commands like
// `/team:ops:deploy` โ agent names are never preceded by `/`.
result = result.replace(
/(?<![a-z0-9:/-])[a-z][a-z0-9-]*:[a-z][a-z0-9-]*:([a-z][a-z0-9-]*)(?![a-z0-9:-])/g,
"\$1",
)
return result
}
function inferTemperature(agent: ClaudeAgent): number | undefined {
const sample = `${agent.name} ${agent.description ?? ""}`.toLowerCase()
if (/(review|audit|security|sentinel|oracle|lint|verification|guardian)/.test(sample)) {
return 0.1
}
if (/(plan|planning|architecture|strategist|analysis|research)/.test(sample)) {
return 0.2
}
if (/(doc|readme|changelog|editor|writer)/.test(sample)) {
return 0.3
}
if (/(brainstorm|creative|ideate|design|concept)/.test(sample)) {
return 0.6
}
return 0.3
}
This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
src/converters/claude-to-opencode.ts
The inferTemperature function in src/converters/claude-to-opencode.ts handles a key part of this chapter's functionality:
export type ClaudeToOpenCodeOptions = {
agentMode: "primary" | "subagent"
inferTemperature: boolean
permissions: PermissionMode
}
const TOOL_MAP: Record<string, string> = {
bash: "bash",
read: "read",
write: "write",
edit: "edit",
grep: "grep",
glob: "glob",
list: "list",
webfetch: "webfetch",
skill: "skill",
patch: "patch",
task: "task",
question: "question",
todowrite: "todowrite",
todoread: "todoread",
}
type HookEventMapping = {
events: string[]
type: "tool" | "session" | "permission" | "message"
requireError?: boolean
note?: string
}
const HOOK_EVENT_MAP: Record<string, HookEventMapping> = {
PreToolUse: { events: ["tool.execute.before"], type: "tool" },
This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
How These Components Connect
flowchart TD
A[renderHookStatements]
B[rewriteClaudePaths]
C[transformSkillContentForOpenCode]
D[inferTemperature]
E[applyPermissions]
A --> B
B --> C
C --> D
D --> E