.opencode/skills/convert-cc-defs/SKILL.md
Use when importing, converting, or syncing agent, skill, or command definitions from CEP or other Claude Code-format sources into the Systematic plugin for OpenCode. Triggers on "import from CEP", "sync upstream", "convert CC definition", "add agent/skill/command from upstream", or when updating existing bundled definitions from upstream sources.
npx skillsauth add marcusrbrown/systematic convert-cc-defsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
sync-manifest.json entries for existing bundled contentcreate-agent-skill skill instead)systematic convert)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";
}
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:
.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)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.
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:
upstream_content_hash with current upstream to detect changesmanual_overrides — these fields/sections MUST be preservedrewrites log — these intelligent rewrites should be re-appliedSTOP and evaluate before converting. Not all upstream definitions belong in Systematic. Present your evaluation to the user before proceeding.
Evaluation criteria (ALL must pass):
bun src/cli.ts list <type> to check.# 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 '/'
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.
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.
The sync workflow MUST focus on converting CHANGED content only. If upstream hasn't changed a section, do NOT modify it.
upstream_content_hash differs from the current upstream.git diff or text comparison to identify WHAT changed upstream.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.
Apply the existing converter pipeline. This handles:
Task -> task, TodoWrite -> todowrite, etc.).claude/ -> .opencode/, CLAUDE.md -> AGENTS.md)compound-engineering: -> systematic:)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):
${CLAUDE_SESSION_ID}).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.Task(), TodoWrite, CLAUDE.md, .claude/skills/ inside ``` blocks must be fixed manuallyTeammate API, "remote" execution via Claude Code web)compound-engineering pipeline artifacts or other CC-specific content (e.g., docs/plans/*.md exclusions) that should be removed as they're not applicable to Systematicargument-hint and other frontmatter string values. This is cosmetic but verify quoting consistency after conversion.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/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) |
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 |
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.
This is the critical step that distinguishes a good import from a broken one. Every converted definition MUST go through intelligent 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:
<example> blocks showing context + user message + assistant response + commentaryThe 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 |
Review and adapt the body content for Systematic's style:
For agents:
docs/CONVERSION-GUIDE.md)For skills:
For commands:
systematic: prefix$ARGUMENTS and positional args are correct (OC is 1-indexed)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.
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.
Before writing the file, verify:
.claude/ pathstask, todowrite, google_search, systematic_skill)~/.opencode/ paths (should be ~/.config/opencode/)AskUserQuestion (should be question)mode field is set (subagent, primary, or all)temperature is appropriate for the agent's purposeTask() in code blocks (see Phase 2c edge cases table)If you encounter content that looks incorrect but wasn't changed by upstream:
~/.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 |
| 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/
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/<category>/<name>skills/<name>commands/<name> or commands/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"
}
}
}
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)If manual_overrides contains entries, those fields/sections were customized after import. On re-import:
synced_at and upstream_commit but keep manual_overrides intactOverride 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 as rewrites[].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.
When you make a targeted edit to an already-imported definition file (NOT during initial import — this is for post-import customization):
sync-manifest.json:
a. Read the current manifest entry for this definition
b. For each field you changed:
manual_overrides: update reason if it changed, keep the original from the FIRST override (don't overwrite history), keep overridden_at unchangedmanual_overrides: add new entry with field, reason, original (value from step 1), and overridden_at (current UTC timestamp)
c. Write the updated manifestcat sync-manifest.json | python3 -m json.tool > /dev/null (confirm valid JSON)Idempotency rules:
field name before adding)original value (first override's original is canonical)overridden_at if 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. |
bun run build && bun run typecheck && bun run lint && bun test
# 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
For each converted definition, verify:
systematic_skill tool lists it (for skills)When pulling upstream changes for an already-imported definition:
upstream_content_hash, rewrites, manual_overridesgit diff or text diff to understand what changeddate -u +'%Y-%m-%dT%H:%M:%SZ'). Update rewrites if they changed.When running automated syncs, always:
chore/sync-cep for all sync PRs.sync-cep and append run summaries as comments.Include the following sections in both issue and PR bodies:
| 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. |
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)
For importing multiple definitions at once:
date -u +'%Y-%m-%dT%H:%M:%SZ') once at the start. Use the same values for all entries in the batch.git add agents/ skills/ commands/ sync-manifest.json
git commit -m "feat: import N definitions from CEP upstream (commit abc123)"
| 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-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 |
If an upstream file was deleted but the manifest still has an entry:
findStaleEntries() function in src/lib/manifest.ts detects these<path>. Keep local copy or remove?""manual_overrides": [{"field": "*", "reason": "Local ownership", "overridden_at": "<ISO timestamp>"}] to indicate full local ownershipAlways 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
| 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.schema.json | JSON Schema for manifest |
| docs/CONVERSION-GUIDE.md | Full field mapping reference |
development
Use when dispatching parallel or serial subagents in OpenCode, coordinating multi-unit plan execution, synthesizing results from independent subagent runs, or handling subagent failure and retry. Triggers on requests to run tasks in parallel, divide work across subagents, orchestrate a pipeline of dependent steps, or coordinate multiple agents without shared-file conflicts.
testing
Use when creating new skills, editing existing skills, or verifying skills work before deployment
testing
Use when creating, editing, auditing, or fixing bundled Systematic skills, especially when authoring SKILL.md files, adding skill reference files, resolving content-integrity frontmatter failures, or deciding which Systematic conventions apply beyond the general writing-skills guidance.
development
Generate or regenerate ONBOARDING.md to help new contributors understand a codebase. Use when the user asks to 'create onboarding docs', 'generate ONBOARDING.md', 'document this project for new developers', 'write onboarding documentation', 'vonboard', 'vonboarding', 'prepare this repo for a new contributor', 'refresh the onboarding doc', or 'update ONBOARDING.md'. Also use when someone needs to onboard a new team member and wants a written artifact, or when a codebase lacks onboarding documentation and the user wants to generate one.