| layout | default |
|---|---|
| title | Chapter 7: Troubleshooting and Runtime Maintenance |
| nav_order | 7 |
| parent | Compound Engineering Plugin Tutorial |
Welcome to Chapter 7: Troubleshooting and Runtime Maintenance. 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 provides practical recovery patterns for common runtime and integration failures.
- diagnose plugin install and command resolution issues
- recover from MCP server auto-load failures
- debug cross-provider conversion/sync problems
- maintain runtime consistency during rapid iteration
- marketplace install mismatch or stale plugin cache
- MCP config not loading automatically
- provider-target conversion output mismatches
- dependency/runtime version drift in Bun/Node environments
- verify install and plugin metadata
- inspect command availability and namespace
- verify MCP configuration and permissions
- re-run narrow-scope conversion tests
You now have a troubleshooting and maintenance playbook for compound workflows.
Next: Chapter 8: Contribution Workflow and Versioning Discipline
The formatTomlString function in src/converters/claude-to-gemini.ts handles a key part of this chapter's functionality:
export function toToml(description: string, prompt: string): string {
const lines: string[] = []
lines.push(`description = ${formatTomlString(description)}`)
// Use multi-line string for prompt
const escapedPrompt = prompt.replace(/\\/g, "\\\\").replace(/"""/g, '\\"\\"\\"')
lines.push(`prompt = """`)
lines.push(escapedPrompt)
lines.push(`"""`)
return lines.join("\n")
}
function formatTomlString(value: string): string {
return JSON.stringify(value)
}
function normalizeName(value: string): string {
const trimmed = value.trim()
if (!trimmed) return "item"
const normalized = trimmed
.toLowerCase()
.replace(/[\\/]+/g, "-")
.replace(/[:\s]+/g, "-")
.replace(/[^a-z0-9_-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-+|-+$/g, "")
return normalized || "item"
}
function sanitizeDescription(value: string, maxLength = GEMINI_DESCRIPTION_MAX_LENGTH): string {
const normalized = value.replace(/\s+/g, " ").trim()This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
The normalizeName function in src/converters/claude-to-gemini.ts handles a key part of this chapter's functionality:
// Reserve skill names from pass-through skills
for (const skill of skillDirs) {
usedSkillNames.add(normalizeName(skill.name))
}
const generatedSkills = plugin.agents.map((agent) => convertAgentToSkill(agent, usedSkillNames))
const commands = plugin.commands.map((command) => convertCommand(command, usedCommandNames))
const mcpServers = convertMcpServers(plugin.mcpServers)
if (plugin.hooks && Object.keys(plugin.hooks.hooks).length > 0) {
console.warn("Warning: Gemini CLI hooks use a different format (BeforeTool/AfterTool with matchers). Hooks were skipped during conversion.")
}
return { generatedSkills, skillDirs, commands, mcpServers }
}
function convertAgentToSkill(agent: ClaudeAgent, usedNames: Set<string>): GeminiSkill {
const name = uniqueName(normalizeName(agent.name), usedNames)
const description = sanitizeDescription(
agent.description ?? `Use this skill for ${agent.name} tasks`,
)
const frontmatter: Record<string, unknown> = { name, description }
let body = transformContentForGemini(agent.body.trim())
if (agent.capabilities && agent.capabilities.length > 0) {
const capabilities = agent.capabilities.map((c) => `- ${c}`).join("\n")
body = `## Capabilities\n${capabilities}\n\n${body}`.trim()
}
if (body.length === 0) {This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
The sanitizeDescription function in src/converters/claude-to-gemini.ts handles a key part of this chapter's functionality:
function convertAgentToSkill(agent: ClaudeAgent, usedNames: Set<string>): GeminiSkill {
const name = uniqueName(normalizeName(agent.name), usedNames)
const description = sanitizeDescription(
agent.description ?? `Use this skill for ${agent.name} tasks`,
)
const frontmatter: Record<string, unknown> = { name, description }
let body = transformContentForGemini(agent.body.trim())
if (agent.capabilities && agent.capabilities.length > 0) {
const capabilities = agent.capabilities.map((c) => `- ${c}`).join("\n")
body = `## Capabilities\n${capabilities}\n\n${body}`.trim()
}
if (body.length === 0) {
body = `Instructions converted from the ${agent.name} agent.`
}
const content = formatFrontmatter(frontmatter, body)
return { name, content }
}
function convertCommand(command: ClaudeCommand, usedNames: Set<string>): GeminiCommand {
// Preserve namespace structure: workflows:plan -> workflows/plan
const commandPath = resolveCommandPath(command.name)
const pathKey = commandPath.join("/")
uniqueName(pathKey, usedNames) // Track for dedup
const description = command.description ?? `Converted from Claude command ${command.name}`
const transformedBody = transformContentForGemini(command.body.trim())
let prompt = transformedBody
if (command.argumentHint) {This function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
The uniqueName function in src/converters/claude-to-gemini.ts handles a key part of this chapter's functionality:
function convertAgentToSkill(agent: ClaudeAgent, usedNames: Set<string>): GeminiSkill {
const name = uniqueName(normalizeName(agent.name), usedNames)
const description = sanitizeDescription(
agent.description ?? `Use this skill for ${agent.name} tasks`,
)
const frontmatter: Record<string, unknown> = { name, description }
let body = transformContentForGemini(agent.body.trim())
if (agent.capabilities && agent.capabilities.length > 0) {
const capabilities = agent.capabilities.map((c) => `- ${c}`).join("\n")
body = `## Capabilities\n${capabilities}\n\n${body}`.trim()
}
if (body.length === 0) {
body = `Instructions converted from the ${agent.name} agent.`
}
const content = formatFrontmatter(frontmatter, body)
return { name, content }
}
function convertCommand(command: ClaudeCommand, usedNames: Set<string>): GeminiCommand {
// Preserve namespace structure: workflows:plan -> workflows/plan
const commandPath = resolveCommandPath(command.name)
const pathKey = commandPath.join("/")
uniqueName(pathKey, usedNames) // Track for dedup
const description = command.description ?? `Converted from Claude command ${command.name}`
const transformedBody = transformContentForGemini(command.body.trim())
let prompt = transformedBodyThis function is important because it defines how Compound Engineering Plugin Tutorial: Compounding Agent Workflows Across Toolchains implements the patterns covered in this chapter.
flowchart TD
A[formatTomlString]
B[normalizeName]
C[sanitizeDescription]
D[uniqueName]
E[convertClaudeToOpenClaw]
A --> B
B --> C
C --> D
D --> E