Convert CC Definitions
Import and convert agent, skill, and command definitions written in Claude Code (CC) format — primarily from the Compound Engineering Plugin (CEP) upstream — into Systematic's bundled assets. Applies mechanical conversion via the converter pipeline, then intelligent LLM-powered rewrites to ensure definitions work correctly in OpenCode.
This is NOT a copy-paste operation. Systematic is a cohesive OpenCode plugin, not a mirror. Every imported definition must be evaluated, adapted, and branded for the Systematic ecosystem.
When to Use
- Importing new definitions from CEP or Superpowers upstream repos
- Re-syncing existing bundled definitions after upstream changes
- Converting a one-off CC definition file for inclusion in Systematic
- Populating
sync-manifest.jsonentries for existing bundled content
When NOT to Use
- Writing new Systematic-native skills/agents/commands (use
create-agent-skillskill instead) - Editing existing bundled content that has no upstream source
- Converting definitions for a different project (use the CLI:
systematic convert)
Core Workflow
digraph convert_flow {
rankdir=TB;
node [shape=box];
"Identify target definitions" [shape=doublecircle];
"Fetch upstream content" [shape=box];
"Read manifest for existing entries" [shape=box];
"Check manual_overrides" [shape=diamond];
"Run mechanical converter" [shape=box];
"Intelligent rewrite pass" [shape=box];
"Branding & consistency review" [shape=box];
"Write to bundled directory" [shape=box];
"Update sync-manifest.json" [shape=box];
"Verify (build + tests)" [shape=box];
"Done" [shape=doublecircle];
"Identify target definitions" -> "Fetch upstream content";
"Fetch upstream content" -> "Read manifest for existing entries";
"Read manifest for existing entries" -> "Check manual_overrides";
"Check manual_overrides" -> "Run mechanical converter" [label="no overrides"];
"Check manual_overrides" -> "Merge preserving overrides" [label="has overrides"];
"Merge preserving overrides" -> "Intelligent rewrite pass";
"Run mechanical converter" -> "Intelligent rewrite pass";
"Intelligent rewrite pass" -> "Branding & consistency review";
"Branding & consistency review" -> "Write to bundled directory";
"Write to bundled directory" -> "Update sync-manifest.json";
"Update sync-manifest.json" -> "Verify (build + tests)";
"Verify (build + tests)" -> "Done";
}
Phase 1: Identify and Fetch
1a. Identify Upstream Sources
Determine what to import. Supported sources:
| Source | Repo | Content |
|---|---|---|
| CEP | EveryInc/compound-engineering-plugin |
Agents, skills, commands |
| Superpowers | obra/superpowers |
Skills (personal workflow skills) |
| Local file | N/A | Single CC-format .md file |
For GitHub repos, use gh CLI to fetch content. Note: CEP content lives under plugins/compound-engineering/ — always use the full path:
# Fetch a specific file from CEP (note the full path under plugins/)
gh api repos/EveryInc/compound-engineering-plugin/contents/plugins/compound-engineering/agents/review/security-sentinel.md \
--jq '.content' | base64 -d > /tmp/upstream-security-sentinel.md
# Get the latest commit SHA for the agents directory
gh api "repos/EveryInc/compound-engineering-plugin/commits?path=plugins/compound-engineering/agents&per_page=1" \
--jq '.[0].sha'
# Get content hash for change detection
shasum -a 256 /tmp/upstream-security-sentinel.md | cut -d' ' -f1
Batch fetch pattern — for importing multiple files, loop over a list:
mkdir -p /tmp/cep-upstream
AGENTS=("review/architecture-strategist" "research/best-practices-researcher" "workflow/bug-reproduction-validator")
for agent_path in "${AGENTS[@]}"; do
name=$(basename "$agent_path")
gh api "repos/EveryInc/compound-engineering-plugin/contents/plugins/compound-engineering/agents/${agent_path}.md" \
--jq '.content' | base64 -d > "/tmp/cep-upstream/${name}.md"
shasum -a 256 "/tmp/cep-upstream/${name}.md"
done
Recursive file listing — the contents API fails on subdirectories. Use the git tree API for a complete one-shot listing:
# List ALL files under skills/ recursively (one API call)
gh api "repos/EveryInc/compound-engineering-plugin/git/trees/<COMMIT_SHA>?recursive=1" \
--jq '.tree[] | select(.path | startswith("plugins/compound-engineering/skills/")) | select(.type == "blob") | .path' \
| sed 's|plugins/compound-engineering/skills/||'
Skill folders — Skills are directories, not just SKILL.md files. A skill folder may contain references/, templates/, workflows/, scripts/, assets/, and schema files. The CLI converter (bun src/cli.ts convert skill) ONLY processes SKILL.md files. All other files in the skill folder must be:
- Fetched from upstream individually via the contents API
- Copied to the local skill directory, preserving the folder structure
- Manually rewritten with CC→OC text replacements (
.claude/→.opencode/,CLAUDE.md→AGENTS.md,Claude Code→OpenCode,compound-engineering:→systematic:, etc.) ${CLAUDE_PLUGIN_ROOT}/skills/<name>/...paths simplified to relative paths (skills are bundled in the plugin — no env var prefix needed)
Discovering Sub-Files for New Skills
When importing a new skill (not yet in the manifest), you must discover ALL files in the skill directory before fetching. There are two ways to get the file list:
Option A: Use precheck newUpstreamFiles (automated sync) — When running via the sync-cep workflow, the precheck summary includes a newUpstreamFiles map that lists all files for each new definition:
{
"newUpstreamFiles": {
"skills/every-style-editor": ["SKILL.md", "references/EVERY_WRITE_STYLE.md"],
"skills/gemini-imagegen": ["SKILL.md", "requirements.txt", "scripts/generate.py", "scripts/setup.sh"]
}
}
Use this file list directly — it was collected from the upstream git tree and is authoritative.
Option B: Query the git tree API (manual import) — When importing outside the sync-cep workflow, discover files yourself:
# Get the full tree and filter for the skill directory
gh api "repos/EveryInc/compound-engineering-plugin/git/trees/main?recursive=1" \
--jq '.tree[] | select(.path | startswith("plugins/compound-engineering/skills/<name>/")) | select(.type == "blob") | .path' \
| sed 's|plugins/compound-engineering/skills/<name>/||'
After discovering the file list, fetch each file individually using the contents API:
for file in SKILL.md references/guide.md scripts/setup.sh; do
mkdir -p "/tmp/cep-upstream/<skill-name>/$(dirname "$file")"
gh api "repos/EveryInc/compound-engineering-plugin/contents/plugins/compound-engineering/skills/<skill-name>/${file}" \
--jq '.content' | base64 -d > "/tmp/cep-upstream/<skill-name>/${file}"
done
CRITICAL: Failing to discover sub-files results in incomplete skill imports — only SKILL.md gets copied while references/, scripts/, assets/ etc. are silently dropped. This renders many skills non-functional.
1b. Check Existing Manifest
Read sync-manifest.json to determine if this is a new import or an update:
# Check if definition already exists in manifest
cat sync-manifest.json | jq '.definitions["agents/review/security-sentinel"]'
If updating an existing definition:
- Compare
upstream_content_hashwith current upstream to detect changes - Check
manual_overrides— these fields/sections MUST be preserved - Review
rewriteslog — these intelligent rewrites should be re-applied
1c. Evaluate Fit
STOP and evaluate before converting. Not all upstream definitions belong in Systematic. Present your evaluation to the user before proceeding.
Evaluation criteria (ALL must pass):
- Gap analysis: Does this fill a gap in Systematic's current capabilities? Run
bun src/cli.ts list <type>to check. - Philosophy fit: Is it consistent with Systematic's opinionated workflow approach? (Structured phases, explicit deliverables, skill-driven discipline)
- Overlap check: Does it duplicate an existing bundled definition? If partial overlap, propose enhancing the existing definition instead.
- Dependency check: Does the definition reference agents, skills, or commands that don't exist in Systematic? List any missing dependencies — note as WARN (they can be imported later using this skill, and references should be kept).
- Phantom check: If importing agents or skills referenced by commands, verify they actually exist upstream. Commands may reference definitions that were never created upstream ("phantoms"). Fetch the upstream directory listing to confirm:
# Check agents gh api repos/EveryInc/compound-engineering-plugin/contents/plugins/compound-engineering/agents/review \ --jq '.[].name' # Check skills gh api "repos/EveryInc/compound-engineering-plugin/git/trees/<COMMIT_SHA>?recursive=1" \ --jq '.tree[] | select(.path | startswith("plugins/compound-engineering/skills/")) | select(.type == "tree") | .path' \ | sed 's|plugins/compound-engineering/skills/||' | grep -v '/' - User value: Would a Systematic plugin user actually invoke this? Niche CC-specific tools (e.g.,
feature-video,test-browser) may not translate.
Present your evaluation as a table:
| Criterion | Pass/Fail | Notes |
|-----------|-----------|-------|
| Gap analysis | PASS | No existing code review simplification agent |
| Philosophy fit | PASS | Structured review methodology |
| Overlap check | PASS | No overlap with existing review agents |
| Dependencies | WARN | References `resolve_todo_parallel` command (not in Systematic) |
| User value | PASS | General-purpose, not framework-specific |
If any criterion fails, document why and do not proceed unless the user explicitly overrides.
Phase 2: Mechanical Conversion
Consult docs/CONVERSION-GUIDE.md for the authoritative field mapping reference. That document has the complete tables for frontmatter fields, tool names, paths, and edge cases.
2a. Change Detection (CRITICAL)
The sync workflow MUST focus on converting CHANGED content only. If upstream hasn't changed a section, do NOT modify it.
- Compare content hashes — Only process definitions whose
upstream_content_hashdiffers from the current upstream. - Diff before converting — Run
git diffor text comparison to identify WHAT changed upstream. - Selective application — Apply conversions ONLY to the changed portions. Preserve unchanged sections exactly as they are.
CRITICAL: Preserve Stable Content
| Content Type | Action |
|---|---|
~/.config/opencode/ paths |
DO NOT CHANGE — This is the correct OpenCode global config path |
~/.opencode/ paths |
DO NOT CHANGE — This is WRONG. If you see this, it was a mistake. The correct path is ~/.config/opencode/ |
question tool references |
DO NOT CHANGE — This is the correct OpenCode tool name |
AskUserQuestion in existing bundled files |
Change to question — this was a CC tool that must be converted |
| Trailing newlines | PRESERVE — Do not strip EOL characters |
Path Conversion Rules (MEMORIZE):
| CC Path | OC Path | Notes |
|---|---|---|
~/.claude/ |
~/.config/opencode/ |
Global user config |
.claude/ |
.opencode/ |
Project-relative |
~/.config/opencode/ |
~/.config/opencode/ |
ALREADY CORRECT — NEVER CHANGE |
~/.opencode/ |
~/.config/opencode/ |
WRONG PATH — FIX IF FOUND |
Tool Name Conversion Rules (MEMORIZE):
| CC Tool | OC Tool | Direction |
|---|---|---|
AskUserQuestion |
question |
CC → OC only |
TodoWrite |
todowrite |
CC → OC only |
Task |
task |
CC → OC only |
question |
question |
ALREADY CORRECT — NEVER CHANGE |
todowrite |
todowrite |
ALREADY CORRECT — NEVER CHANGE |
Common mistake: Converting
question→AskUserQuestion. This is BACKWARDS. OpenCode uses lowercase tool names.
2b. Apply Mechanical Converter
Apply the existing converter pipeline. This handles:
- Tool name mappings (
Task->task,TodoWrite->todowrite, etc.) - Path replacements (
.claude/->.opencode/,CLAUDE.md->AGENTS.md) - Prefix conversions (
compound-engineering:->systematic:) - Frontmatter field mapping (tools array->map, permissionMode->permission, maxSteps->steps, etc.)
- Model normalization (provider prefix)
Note: The
colorfield in CC agent frontmatter (e.g.,color: violet) is passed through by the converter. OpenCode does not currently use this field, but it is harmless to keep.
For a single file via CLI:
bun src/cli.ts convert agent /tmp/upstream-security-sentinel.md
Tip: Use
bun src/cli.tsfor local development instead ofbunx systematicto avoid slow resolution.
For programmatic use:
import { convertContent } from './lib/converter.js'
const converted = convertContent(upstreamContent, 'agent')
What mechanical conversion does NOT handle (requires intelligent rewrite):
- Description enhancement with trigger conditions
- Branding beyond regex patterns (contextual references to "Claude Code", "Claude", "CEP")
- Content restructuring for Systematic's style
- Removing CC-specific features with no OC equivalent (
${CLAUDE_SESSION_ID}) - Adding Systematic-specific sections (integration points, skill cross-references)
- Skill path patterns in body text — the converter handles
.claude/->.opencode/in general, but does NOT handle~/.claude/skills/->~/.config/opencode/skills/or bare.claude/skills/->.opencode/skills/references embedded in skill-discovery instructions. Audit these manually. - Tool/path references inside code blocks — the converter skips fenced code blocks to avoid false positives, so
Task(),TodoWrite,CLAUDE.md,.claude/skills/inside ``` blocks must be fixed manually - Attribution badges and footers inside heredoc code blocks (commit messages, PR bodies)
- CC-specific features with no OC equivalent (Swarm Mode /
TeammateAPI, "remote" execution via Claude Code web) - CC-specific exclusion rules — some agents reference
compound-engineering pipeline artifactsor other CC-specific content (e.g.,docs/plans/*.mdexclusions) that should be removed as they're not applicable to Systematic - Frontmatter quoting normalization — the converter may change double quotes to single quotes in
argument-hintand other frontmatter string values. This is cosmetic but verify quoting consistency after conversion.
2c. Mandatory Post-Conversion Fixup (Batch sed)
LLMs consistently fail at simple string replacement. The mechanical converter catches some patterns, but many remain — particularly inside code blocks, multi-platform tool lists, and contextual references. After every conversion (both mechanical converter AND LLM rewrite), run these deterministic sed replacements as a mandatory safety net.
Replacement order matters. Apply more-specific patterns before general ones to avoid double-conversion. Run all phases in sequence on each file:
# Target: all converted .md files EXCEPT exclusions (see below)
# PHASE A: compound-engineering → systematic (most specific first)
sed -i '' \
-e 's/compound-engineering\.local\.md/systematic.local.md/g' \
-e 's/compound-engineering-plugin/systematic/g' \
-e 's/compound-engineering pipeline artifacts/systematic pipeline artifacts/g' \
-e 's|\.context/compound-engineering/|.context/systematic/|g' \
-e 's|plugins/compound-engineering/|plugins/systematic/|g' \
-e 's/compound-engineering:/systematic:/g' \
-e 's/Compound_Engineering/Systematic/g' \
-e 's/Compound Engineering/Systematic/g' \
-e 's/compound-engineering/systematic/g' \
"$FILE"
# PHASE B: Path conversions (most specific first)
sed -i '' \
-e 's|~/\.claude/skills/|~/.config/opencode/skills/|g' \
-e 's|~/\.claude/settings\.json|~/.config/opencode/settings.json|g' \
-e 's|~/\.claude/|~/.config/opencode/|g' \
-e 's|`\.claude/skills/|`.opencode/skills/|g' \
-e 's|`\.claude/settings\.json|`.opencode/settings.json|g' \
-e 's| \.claude/skills/| .opencode/skills/|g' \
-e 's| \.claude/settings\.json| .opencode/settings.json|g' \
-e 's|(\.claude/|(\.opencode/|g' \
-e 's|`\.claude/|`.opencode/|g' \
-e 's| \.claude/| .opencode/|g' \
-e 's|"\.claude/|".opencode/|g' \
-e 's|CLAUDE\.md|AGENTS.md|g' \
"$FILE"
# PHASE C: Branding and tool names
sed -i '' \
-e 's/Claude Code/OpenCode/g' \
-e 's/claude-code/opencode/g' \
-e 's/AskUserQuestion/question/g' \
-e 's/TaskCreate/todowrite/g' \
"$FILE"
File Exclusions
| File/Pattern | Reason | What to convert instead |
|---|---|---|
sync-manifest.json |
Upstream paths (plugins/compound-engineering/...) are correct source references |
Never run sed on manifest upstream paths |
claude-permissions-optimizer/SKILL.md |
Skill targets Claude Code settings files — CC refs and .claude/ paths are intentional |
Only convert: prefix (compound-engineering: → systematic:), tool names (AskUserQuestion → question), product name (Compound Engineering → Systematic) |
Edge Cases Requiring Manual Review After sed
These patterns recur across every sync and need manual attention:
| Pattern | Problem | Fix |
|---|---|---|
EveryInc/systematic in URLs |
Over-conversion of EveryInc/compound-engineering-plugin |
Use generic example (acme/my-app) or remove entirely |
claude.com/opencode |
Claude Code → OpenCode mangles URLs like claude.com/claude-code |
Replace with opencode.ai |
| CEP version attribution badges | [![Compound Engineering v[VERSION]]...] becomes [![Systematic v[VERSION]]...] with dead URL |
Remove the entire badge line |
Task() in code blocks |
Uppercase Task() in code examples not caught by branding sed |
Manually fix to task() |
https://github.com/EveryInc/systematic |
Non-existent URL from catch-all sed | Context-dependent: remove, genericize, or update to actual Systematic repo URL |
| Multi-platform tool lists | (question in OpenCode, ...) after conversion — verify the list is coherent |
Should read naturally with OpenCode as the primary platform |
Post-Fixup Verification (MANDATORY)
After running the batch sed fixup, verify with grep. Both checks MUST pass:
# CHECK 1: Remaining CC/CEP refs (should be zero for non-exception files)
grep -rnE 'Claude Code|claude-code|\.claude/|CLAUDE\.md|~/\.claude|AskUserQuestion|TaskCreate|compound-engineering|Compound Engineering|Compound_Engineering|EveryInc/systematic|claude\.com/opencode' <files>
# CHECK 2: Over-conversions (should ALWAYS be zero across ALL files)
grep -rnE '\.opencode/\.opencode/|config/opencode/\.config/|systematic\.systematic|systematic:systematic:|opencode\.ai/opencode' <files>
If CHECK 1 returns hits on non-exception files, fix them. If CHECK 2 returns any hits, you have a double-conversion bug — investigate immediately.
Phase 3: Intelligent Rewrite
This is the critical step that distinguishes a good import from a broken one. Every converted definition MUST go through intelligent rewrite.
3a. Description Rewrite
CC descriptions are typically short and capability-focused. OC descriptions must include trigger conditions for auto-invocation.
CC style (bad for OC):
description: Reviews code for unnecessary complexity and suggests simplifications
OC/Systematic style (good):
description: "Use this agent when you need a final review pass focused on simplicity, YAGNI principles, and removing unnecessary complexity. <example>...</example>"
Rewrite rules for descriptions:
- Start with "Use this agent/skill/command when..." or "This skill should be used when..."
- Include specific trigger symptoms and situations
- For agents: include
<example>blocks showing context + user message + assistant response + commentary - Max 1024 characters total for skill descriptions
- Write in third person (injected into system prompt)
3b. Branding Audit
The mechanical converter catches regex-matchable patterns. You must catch contextual ones:
| Pattern to find | Replacement |
|---|---|
| "Claude Code" (the product) | "OpenCode" |
| "Claude" (the AI model, in instructions) | Keep — model name is fine |
| "CEP" or "Compound Engineering Plugin" | "Systematic" |
| "claude-code" (in paths not caught by converter) | "opencode" |
| References to CC-specific behavior | Adapt or remove |
Task agent-name("prompt") patterns |
task tool or @agent-name |
TodoWrite in prose (not just tool calls) |
todowrite or "update your task list" |
| "the built-in grep tool" (lowercase tool name) | "the built-in Grep tool" (OC capitalizes tool names) |
compound-engineering pipeline artifacts |
Remove or replace with "systematic pipeline artifacts" |
Version attribution footers (e.g., *Based on Claude Code v2.1.19*) |
Remove entirely — CC version numbers are not applicable to Systematic. Blind Claude Code → OpenCode rewrite turns these into nonsensical Based on OpenCode v2.1.19. |
Source attribution URLs (e.g., claude.com, docs.anthropic.com) |
Keep as-is — these are upstream source references, not branding |
3c. Content Adaptation
Review and adapt the body content for Systematic's style:
For agents:
- Ensure the system prompt is self-contained (agent definitions are the full prompt)
- Add structured output format if missing (numbered phases, deliverables)
- Reference Systematic tools and skill cross-references where appropriate
- Match temperature/mode conventions (see
docs/CONVERSION-GUIDE.md)
For skills:
- Add "When to Use" / "When NOT to Use" sections if missing
- Add integration points with other Systematic workflows
- Add cross-references to related bundled skills/commands
- Ensure progressive disclosure (SKILL.md + references/ if content is heavy)
For commands:
- Verify slash command sequences use
systematic:prefix - Ensure
$ARGUMENTSand positional args are correct (OC is 1-indexed) - Verify referenced agents and skills exist in Systematic's bundled set
- Keep references to not-yet-imported agents/skills — they will be brought over later using this same skill and will keep their names. Only apply mechanical CC→OC tool/path conversion, not removal.
3d. Code Block Audit
The mechanical converter intentionally skips content inside fenced code blocks to avoid false positives. You MUST manually audit all code blocks for:
| Pattern in code blocks | Action |
|---|---|
Task(agent-name) or Task({ ... }) |
→ task(agent-name) / task({ ... }) |
TodoWrite |
→ todowrite |
CLAUDE.md |
→ AGENTS.md |
.claude/skills/ or .claude/ paths |
→ .opencode/skills/ or .opencode/ |
Teammate({ operation: ... }) |
Add aspirational note or adapt to task with background execution |
Attribution badges/footers (Compound Engineered, Claude Code links) |
→ Systematic branding |
AskUserQuestion |
→ question tool |
High-risk pattern: Long skills with many code examples (e.g., orchestrating-swarms has 47
Task({calls across 1700+ lines). After mechanical conversion, run a targeted search for capitalized tool names inside code blocks:grep -n "Task(\|TodoWrite\|AskUserQuestion" <file>. Fix all occurrences — users copying broken examples will get runtime errors.
3e. CC-Specific Features
Some CC features have no direct OC equivalent. For each, make a case-by-case decision:
| CC Feature | OC Equivalent | Recommendation |
|---|---|---|
Teammate API (spawnTeam, requestShutdown, cleanup) |
None — task with run_in_background is partial |
Keep as aspirational reference with explanatory note |
| "Remote" execution (Claude Code web background) | None | Remove — no OC equivalent exists |
${CLAUDE_SESSION_ID} |
None | Remove (keep in upstream API spec docs as-is) |
${CLAUDE_PLUGIN_ROOT} |
None — bundled skills use relative paths | Simplify to relative paths (e.g., scripts/worktree-manager.sh not ${CLAUDE_PLUGIN_ROOT}/skills/git-worktree/scripts/worktree-manager.sh) |
AskUserQuestion with complex schemas |
question tool (simpler) |
Adapt to OC's question tool format |
Present CC-specific feature decisions to the user before proceeding.
3f. Quality Checklist
Before writing the file, verify:
- Frontmatter parses without errors
- Description includes trigger conditions (not just capability summary)
- No stale references to Claude Code, CEP,
.claude/paths - Tool references use OC names (
task,todowrite,google_search,systematic_skill) - Code blocks audited — tool names, paths, and branding inside ``` blocks are fixed
- Attribution badges/footers in heredoc code blocks updated to Systematic branding
- CC-specific features with no OC equivalent handled (removed, adapted, or noted as aspirational)
- Cross-referenced agents/skills/commands exist in Systematic (or are marked for future import)
- Path sanity check — No
~/.opencode/paths (should be~/.config/opencode/) - Tool name sanity check — No
AskUserQuestion(should bequestion) - Formatting preserved — Trailing newlines maintained, no gratuitous whitespace changes
- Content matches Systematic's style (structured phases, explicit deliverables)
- Agent
modefield is set (subagent,primary, orall) - Agent
temperatureis appropriate for the agent's purpose - Batch sed fixup ran — Phase 2c sed commands executed on all converted files
- Grep verification passed — Phase 2c CHECK 1 (remaining refs) and CHECK 2 (over-conversions) both clean
- Edge cases reviewed — Checked for mangled URLs, dead badge links, uppercase
Task()in code blocks (see Phase 2c edge cases table)
3g. Discrepancy Reporting
If you encounter content that looks incorrect but wasn't changed by upstream:
- DO NOT silently fix it — You might break something
- Report it as a discrepancy — Include in the sync summary
- Flag for human review — "Found existing path
~/.opencode/in line X — should this be~/.config/opencode/?"
Example discrepancy report:
### Discrepancies Found (not from upstream changes)
| File | Line | Issue | Recommended Action |
|------|------|-------|-------------------|
| skills/foo/SKILL.md | 42 | Uses `~/.opencode/` path | Verify if intentional, fix to `~/.config/opencode/` if not |
| commands/bar.md | 15 | Uses `AskUserQuestion` | Convert to `question` tool |
Phase 4: Write and Register
4a. Place the File
| Type | Location | Naming |
|---|---|---|
| Agent | agents/<category>/<name>.md |
kebab-case, category from purpose |
| Skill | skills/<name>/SKILL.md |
kebab-case directory |
| Command | commands/<name>.md or commands/workflows/<name>.md |
kebab-case, workflows/ for workflow commands |
Categories for agents: design/, research/, review/, workflow/
4b. Update sync-manifest.json
Every imported definition MUST have a manifest entry. This is not optional.
Use the date CLI to generate the synced_at timestamp in ISO 8601 UTC format:
date -u +'%Y-%m-%dT%H:%M:%SZ'
Run this once at the start of a batch import and use the same timestamp for all entries in that batch.
{
"definitions": {
"agents/review/security-sentinel": {
"source": "cep",
"upstream_path": "plugins/compound-engineering/agents/review/security-sentinel.md",
"upstream_commit": "abc123def456...",
"synced_at": "<run: date -u +'%Y-%m-%dT%H:%M:%SZ'>",
"notes": "Imported from CEP. Enhanced description with trigger examples. Updated tool references.",
"upstream_content_hash": "sha256-of-upstream-content",
"rewrites": [
{
"field": "description",
"reason": "CC description lacked OC trigger conditions and examples",
"original": "Security audits, vulnerability assessment, OWASP compliance"
},
{
"field": "body:branding",
"reason": "Contextual reference to Claude Code in analysis instructions"
}
],
"manual_overrides": []
}
}
}
Manifest key format: Repo-relative path without file extension.
- Agents:
agents/<category>/<name> - Skills:
skills/<name> - Commands:
commands/<name>orcommands/workflows/<name>
Multi-file skills MUST include a files array listing all files in the skill directory (relative to the skill's upstream path). This is how the precheck script knows which files to hash for change detection. Without it, sub-file changes go undetected:
{
"skills/my-skill": {
"files": ["SKILL.md", "references/guide.md", "scripts/setup.sh"],
...
}
}
Ensure sources has an entry for the upstream repo:
{
"sources": {
"cep": {
"repo": "EveryInc/compound-engineering-plugin",
"branch": "main",
"url": "https://github.com/EveryInc/compound-engineering-plugin"
},
"superpowers": {
"repo": "obra/superpowers",
"branch": "main",
"url": "https://github.com/obra/superpowers"
}
}
}
4c. Record Rewrites
Every intelligent rewrite MUST be logged in the rewrites array. This is how future syncs know what to re-apply.
Each rewrite entry needs:
field: What was changed (description,body:branding,body:tool-references,body:structure,frontmatter:<field>)reason: Why (one sentence)original: The original value before rewrite (optional but recommended for descriptions)
4d. Respect Manual Overrides
If manual_overrides contains entries, those fields/sections were customized after import. On re-import:
- Read the current bundled file
- Extract the overridden fields/sections
- Apply conversion to non-overridden content only
- Merge overrides back in
- Update manifest
synced_atandupstream_commitbut keepmanual_overridesintact
Override entries MUST be structured objects (string arrays are invalid):
{
"manual_overrides": [
{
"field": "description",
"reason": "Customized triggers for our auth-heavy codebase",
"original": "Security audits, vulnerability assessment, OWASP compliance",
"overridden_at": "2026-02-10T06:30:00Z"
}
]
}
Each entry has:
field: Same naming convention asrewrites[].field(e.g.,description,body:section-name,frontmatter:<field>,*for full local ownership)reason: Why the override exists — one sentenceoriginal: Pre-override value (for conflict detection and rollback; truncate to 500 chars for large sections)overridden_at: ISO 8601 UTC timestamp (date -u +'%Y-%m-%dT%H:%M:%SZ')
Override vs rewrite precedence: If a field appears in both rewrites and manual_overrides, the manual override takes precedence. The rewrite is kept for historical record but will NOT be re-applied to that field on re-sync.
4e. Record Manual Edit
When you make a targeted edit to an already-imported definition file (NOT during initial import — this is for post-import customization):
- Before editing: Read and store the current value of the field(s) you will change
- Make your edit to the bundled definition file
- Update
sync-manifest.json: a. Read the current manifest entry for this definition b. For each field you changed:- If field is already in
manual_overrides: updatereasonif it changed, keep theoriginalfrom the FIRST override (don't overwrite history), keepoverridden_atunchanged - If field is NOT in
manual_overrides: add new entry withfield,reason,original(value from step 1), andoverridden_at(current UTC timestamp) c. Write the updated manifest
- If field is already in
- Validate:
cat sync-manifest.json | python3 -m json.tool > /dev/null(confirm valid JSON)
Idempotency rules:
- Running this workflow twice for the same edit MUST NOT duplicate entries (check
fieldname before adding) - MUST NOT overwrite the
originalvalue (first override's original is canonical) - MUST NOT change
overridden_atif the field was already overridden
| Thought | Reality |
|---|---|
| "I'll update the manifest later" | Update NOW, in the same operation as the edit |
| "The reason is obvious" | Future agents can't read your mind. Write it. |
| "I don't need to store the original" | Without it, you can't detect conflicts on re-sync |
| "This field is too small to track" | If you changed it, track it. No exceptions. |
Phase 5: Verify
5a. Build and Test
bun run build && bun run typecheck && bun run lint && bun test
5b. Validate Converted Content
# Check the definition loads via the plugin
bun src/cli.ts list agents
bun src/cli.ts list skills
bun src/cli.ts list commands
# For agents: verify frontmatter extracts correctly
bun test tests/unit/agents.test.ts
# For skills: verify skill loading
bun test tests/unit/skills.test.ts
# Integration: verify conversion round-trip
bun test tests/integration/converter-validation.test.ts
5c. Manual Spot-Check
For each converted definition, verify:
systematic_skilltool lists it (for skills)- Agent config merges correctly (for agents)
- Command is available via slash prefix (for commands)
Re-Sync Workflow (Updating Existing Definitions)
When pulling upstream changes for an already-imported definition:
- Read manifest entry — Get
upstream_content_hash,rewrites,manual_overrides - Fetch upstream — Get current content and compute hash
- Compare hashes — If unchanged, skip (idempotent)
- Diff upstream changes — Use
git diffor text diff to understand what changed - Re-apply mechanical conversion on the new upstream content
- Re-apply rewrites from the manifest log — same fields, same reasons, adapted to new content (skip fields that have manual overrides — overrides take precedence)
- Handle manual overrides using the merge matrix below
- Update manifest — New commit SHA, hash, timestamp (
date -u +'%Y-%m-%dT%H:%M:%SZ'). Update rewrites if they changed. - Verify — Build, test, spot-check
Issue/PR Dedupe and Reporting
When running automated syncs, always:
- Reuse branch
chore/sync-cepfor all sync PRs. - If a PR exists for that branch, update it instead of creating a new one.
- Use or create a tracking issue labeled
sync-cepand append run summaries as comments.
Include the following sections in both issue and PR bodies:
- Summary
- Hash changes table (definition, old hash, new hash)
- Conflicts (manual overrides)
- New upstream definitions (report-only)
- Upstream deletions (report-only, include keep/remove prompt)
- Rewrite failures
- Phantom references (commands referencing missing agents/skills)
Override Merge Matrix
| Scenario | Detection | Agent Behavior |
|---|---|---|
| Upstream unchanged + override exists | New upstream hash matches stored hash | Preserve override. No action needed. |
| Upstream changed + override on SAME field | Changed upstream field overlaps manual_overrides[].field |
Flag conflict. Present both versions to user. Do NOT auto-merge. |
| Upstream changed + override on DIFFERENT field | Changed fields don't intersect with override fields | Apply upstream changes normally, preserve override fields. |
Override is "*" (full local ownership) |
Any upstream change | Skip re-sync entirely. Log that upstream was skipped. |
Conflict Presentation
When upstream changes conflict with a manual override, present to the user:
CONFLICT: `agents/review/security-sentinel` field `description`
**Your override** (overridden_at: 2026-02-15T10:30:00Z):
> "Use when auditing authentication flows for OWASP Top 10..."
**Upstream change** (commit abc123):
> "Security audits with enhanced SAST integration..."
**Override reason**: "Customized triggers for our auth-heavy codebase"
Options:
1. Keep override (skip upstream change for this field)
2. Accept upstream (remove override entry from manifest)
3. Merge manually (edit the field, then record as new override via Phase 4e)
Batch Import
For importing multiple definitions at once:
- Get shared metadata — fetch the upstream commit SHA and generate a UTC timestamp (
date -u +'%Y-%m-%dT%H:%M:%SZ') once at the start. Use the same values for all entries in the batch. - Fetch all upstream files — use the batch fetch pattern from Phase 1a to download all targets in one pass.
- List target definitions (files to import)
- For each definition, run Phases 1-4 sequentially (converter + intelligent rewrite + write + manifest)
- Run Phase 5 once at the end (build/test covers all)
- Commit all changes together with a descriptive message:
git add agents/ skills/ commands/ sync-manifest.json
git commit -m "feat: import N definitions from CEP upstream (commit abc123)"
Red Flags — STOP If You Think This
| Thought | Reality |
|---|---|
| "The converter handles everything" | Converter is mechanical only — you MUST do intelligent rewrite |
| "The description is fine as-is" | CC descriptions lack trigger conditions. Always rewrite. |
| "I'll update the manifest later" | Manifest update is part of the workflow, not a follow-up |
| "This is just a quick import" | Every import requires evaluation, conversion, rewrite, manifest, verification |
| "I don't need to check for branding" | Regex misses contextual references. Always audit manually. |
| "I'll skip the evaluation since the user asked for it" | User request != automatic fit. Evaluate and present findings. |
| "Manual overrides don't apply — this is a new import" | Check anyway. Previous imports may have been customized since. |
Anti-Patterns
| Anti-Pattern | Correct Approach |
|---|---|
| Copy file and only run converter | Always do intelligent rewrite pass |
| Import everything from upstream | Curate — evaluate fit before importing |
| Skip manifest update | Every import MUST have a manifest entry |
| Overwrite human edits on re-sync | Check manual_overrides first, use merge matrix |
| Leave CC descriptions as-is | Rewrite with OC trigger conditions |
| Forget to log rewrites | Every intelligent change goes in rewrites[] |
| Import definition that duplicates existing | Enhance existing instead |
| Skip branding audit | Always check for contextual Claude/CEP references |
Handling Upstream Deletions
If an upstream file was deleted but the manifest still has an entry:
- The
findStaleEntries()function insrc/lib/manifest.tsdetects these - Do NOT auto-remove the bundled definition — it may have been intentionally kept
- Flag to the user: "Upstream deleted
<path>. Keep local copy or remove?" - If removing: delete the bundled file AND the manifest entry
- If keeping: add
"manual_overrides": [{"field": "*", "reason": "Local ownership", "overridden_at": "<ISO timestamp>"}]to indicate full local ownership
Reference: Existing Bundled Content
Always check live inventory — this list may be stale:
bun src/cli.ts list agents
bun src/cli.ts list skills
bun src/cli.ts list commands
Reference: Key Files
| File | Purpose |
|---|---|
src/lib/converter.ts |
Mechanical conversion pipeline |
src/lib/manifest.ts |
Manifest types and read/write/validate |
sync-manifest.json |
Provenance data (repo root) |
| `sync-manifest.s |
…(truncated)