Compare commits

...

10 Commits

Author SHA1 Message Date
John Lamb
a3cef61d5d update test
Some checks failed
CI / test (push) Has been cancelled
2026-01-26 10:08:19 -06:00
Kieran Klaassen
36e7f3a370 Fix CI to run on all PRs and add manual trigger
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 14:49:49 -08:00
Kieran Klaassen
63ab7cbc3a Update badge to link to npm package
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 14:46:06 -08:00
Kieran Klaassen
49100ef3d1 Add build and Bun badges to README
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 14:44:35 -08:00
Kieran Klaassen
ea202c0373 Add GitHub CI workflow for running tests
Runs bun test on push to main and on PRs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 13:33:58 -08:00
terry-li-hm
1dea33c305 fix(codex): Transform Claude Code syntax to Codex-compatible syntax (#120)
Adds comprehensive content transformation for Codex compatibility:

1. Task agent calls: `Task agent-name(args)` → `Use the $agent-name skill to: args`
2. Slash commands: `/command-name` → `/prompts:command-name`
3. Agent references: `@agent-name` → `$agent-name skill`

This bridges the syntax gap between Claude Code and Codex:
- Claude Code uses Task tool with subagent_types
- Codex uses skills and /prompts: namespace

Transformations are applied to both skill and prompt files during conversion.

Tested with Codex CLI 0.89.0 - all transformations working correctly.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 15:33:19 -06:00
terry-li-hm
2eae6ad21a fix: remove hardcoded CORA project references (#121)
The plugin had hardcoded references to 'CORA' (Every's internal project)
throughout the documentation workflow, making it project-specific rather
than generic. This affected users trying to use the plugin on non-CORA
projects.

Changes:
- Replace 'cora-critical-patterns.md' with 'critical-patterns.md'
- Replace 'Which CORA module' with 'Which module or component'
- Replace 'CORA-Specific Resources' with 'Project-Specific Resources'
- Replace 'CORA-MODULES.md' with 'modules documentation'
- Replace 'CORA system' with 'System-wide' in templates
- Update cora-test-reviewer description to be generic

Files modified:
- learnings-researcher.md: Fixed critical patterns file reference
- compound-docs/SKILL.md: Removed module and filename hardcoding
- compound-docs/assets/*.md: Generalized template references
- workflows/compound.md: Changed 'CORA schema' to 'solution schema'
- workflows/work.md: Made test reviewer description generic

This makes the plugin truly project-agnostic as advertised.
2026-01-24 15:08:43 -06:00
Kieran Klaassen
12b83e683f chore: bump version to 0.1.1
Includes fix for OpenCode global config path (#114, #117)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-23 08:54:23 -08:00
Kieran Klaassen
907746f83e fix(opencode): use correct global config path ~/.config/opencode (#117)
The OpenCode installer was writing to ~/.opencode but OpenCode expects
global configuration at ~/.config/opencode per XDG Base Directory spec.

Fixes:
- src/commands/install.ts: Change default output from ~/.opencode to
  ~/.config/opencode
- src/targets/opencode.ts: Recognize "opencode" basename (not just
  ".opencode") for direct writes without nesting

Closes #114

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 08:53:52 -08:00
Kieran Klaassen
ab38e2ffd0 chore: bump to v2.28.0 and fix repo URLs
- Bump version to 2.28.0 in plugin.json and marketplace.json
  (CHANGELOG was updated but version numbers were missed)
- Fix all repo URLs from kieranklaassen/* to EveryInc/compound-engineering-plugin
- Update component counts in docs: 28 agents, 24 commands, 15 skills, 1 MCP

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-22 07:44:08 -08:00
23 changed files with 256 additions and 55 deletions

View File

@@ -11,14 +11,14 @@
"plugins": [ "plugins": [
{ {
"name": "compound-engineering", "name": "compound-engineering",
"description": "AI-powered development tools that get smarter with every use. Make each unit of engineering work easier than the last. Includes 27 specialized agents, 23 commands, and 14 skills.", "description": "AI-powered development tools that get smarter with every use. Make each unit of engineering work easier than the last. Includes 28 specialized agents, 24 commands, and 15 skills.",
"version": "2.27.0", "version": "2.28.0",
"author": { "author": {
"name": "Kieran Klaassen", "name": "Kieran Klaassen",
"url": "https://github.com/kieranklaassen", "url": "https://github.com/kieranklaassen",
"email": "kieran@every.to" "email": "kieran@every.to"
}, },
"homepage": "https://github.com/kieranklaassen/compound-engineering-plugin", "homepage": "https://github.com/EveryInc/compound-engineering-plugin",
"tags": ["ai-powered", "compound-engineering", "workflow-automation", "code-review", "quality", "knowledge-management", "image-generation"], "tags": ["ai-powered", "compound-engineering", "workflow-automation", "code-review", "quality", "knowledge-management", "image-generation"],
"source": "./plugins/compound-engineering" "source": "./plugins/compound-engineering"
}, },
@@ -29,7 +29,7 @@
"author": { "author": {
"name": "Nityesh Agarwal" "name": "Nityesh Agarwal"
}, },
"homepage": "https://github.com/kieranklaassen/compound-engineering-plugin", "homepage": "https://github.com/EveryInc/compound-engineering-plugin",
"tags": ["coding", "programming", "tutorial", "learning", "spaced-repetition", "education"], "tags": ["coding", "programming", "tutorial", "learning", "spaced-repetition", "education"],
"source": "./plugins/coding-tutor" "source": "./plugins/coding-tutor"
} }

25
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install dependencies
run: bun install
- name: Run tests
run: bun test

View File

@@ -1,11 +1,14 @@
# Compound Marketplace # Compound Marketplace
[![Build Status](https://github.com/EveryInc/compound-engineering-plugin/actions/workflows/ci.yml/badge.svg)](https://github.com/EveryInc/compound-engineering-plugin/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/@every-env/compound-plugin)](https://www.npmjs.com/package/@every-env/compound-plugin)
A Claude Code plugin marketplace featuring the **Compound Engineering Plugin** — tools that make each unit of engineering work easier than the last. A Claude Code plugin marketplace featuring the **Compound Engineering Plugin** — tools that make each unit of engineering work easier than the last.
## Claude Code Install ## Claude Code Install
```bash ```bash
/plugin marketplace add https://github.com/kieranklaassen/compound-engineering-plugin /plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin
/plugin install compound-engineering /plugin install compound-engineering
``` ```

View File

@@ -4,7 +4,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Compounding Engineering - AI-Powered Development Tools for Claude Code</title> <title>Compounding Engineering - AI-Powered Development Tools for Claude Code</title>
<meta content="Your code reviews just got 12 expert opinions in 30 seconds. 27 specialized agents, 19 workflow commands, and 12 skills that make today's work easier than yesterday's." name="description" /> <meta content="Your code reviews just got 12 expert opinions in 30 seconds. 28 specialized agents, 24 workflow commands, and 15 skills that make today's work easier than yesterday's." name="description" />
<meta content="width=device-width, initial-scale=1" name="viewport" /> <meta content="width=device-width, initial-scale=1" name="viewport" />
<!-- Open Graph --> <!-- Open Graph -->
@@ -12,7 +12,7 @@
<meta property="og:site_name" content="Compounding Engineering" /> <meta property="og:site_name" content="Compounding Engineering" />
<meta property="og:locale" content="en_US" /> <meta property="og:locale" content="en_US" />
<meta property="og:title" content="Compounding Engineering - AI Development Tools" /> <meta property="og:title" content="Compounding Engineering - AI Development Tools" />
<meta property="og:description" content="Get 12 expert code reviews in 30 seconds. 27 specialized agents that make today's work easier than yesterday's." /> <meta property="og:description" content="Get 12 expert code reviews in 30 seconds. 28 specialized agents that make today's work easier than yesterday's." />
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Compounding Engineering" /> <meta name="twitter:title" content="Compounding Engineering" />
<meta name="twitter:description" content="12 expert code reviews in 30 seconds. Make today's work easier than yesterday's." /> <meta name="twitter:description" content="12 expert code reviews in 30 seconds. Make today's work easier than yesterday's." />
@@ -139,7 +139,7 @@
<a href="pages/getting-started.html" class="nav-link">Docs</a> <a href="pages/getting-started.html" class="nav-link">Docs</a>
</nav> </nav>
<div class="button-group"> <div class="button-group">
<a href="https://github.com/kieranklaassen/every-marketplace" class="button ghost compact hide-on-mobile"> <a href="https://github.com/EveryInc/compound-engineering-plugin" class="button ghost compact hide-on-mobile">
<div class="fa-brands fa-github icon l"></div> <div class="fa-brands fa-github icon l"></div>
</a> </a>
<a href="#install" class="button primary compact">Install</a> <a href="#install" class="button primary compact">Install</a>
@@ -154,14 +154,14 @@
<section class="hero-section"> <section class="hero-section">
<div class="hero-decoration"></div> <div class="hero-decoration"></div>
<div class="heading hero centered"> <div class="heading hero centered">
<a href="https://github.com/kieranklaassen/every-marketplace/releases" class="eyebrow"> <a href="https://github.com/EveryInc/compound-engineering-plugin/releases" class="eyebrow">
<i class="fa-solid fa-rocket"></i> Version 2.6.0 released! <i class="fa-solid fa-rocket"></i> Version 2.28.0 released!
</a> </a>
<h1 class="balanced" style="margin-bottom: 32px;"> <h1 class="balanced" style="margin-bottom: 32px;">
Your Code Reviews Just Got 12 Expert Opinions. In 30 Seconds. Your Code Reviews Just Got 12 Expert Opinions. In 30 Seconds.
</h1> </h1>
<p class="paragraph m secondary balanced" style="margin-bottom: 32px;"> <p class="paragraph m secondary balanced" style="margin-bottom: 32px;">
Here's what happened when we shipped yesterday: security audit, performance analysis, architectural review, pattern detection, and eight more specialized checks—all running in parallel. No meetings. No waiting. Just answers. That's compounding engineering: 27 specialized agents, 19 workflow commands, and 12 skills that make today's work easier than yesterday's. Here's what happened when we shipped yesterday: security audit, performance analysis, architectural review, pattern detection, and eight more specialized checks—all running in parallel. No meetings. No waiting. Just answers. That's compounding engineering: 28 specialized agents, 24 workflow commands, and 15 skills that make today's work easier than yesterday's.
</p> </p>
<div class="button-group margin-paragraph centered"> <div class="button-group margin-paragraph centered">
<a href="#install" class="button primary"> <a href="#install" class="button primary">
@@ -179,23 +179,23 @@
<div class="stats-container"> <div class="stats-container">
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon"><i class="fa-solid fa-users-gear"></i></div> <div class="stat-icon"><i class="fa-solid fa-users-gear"></i></div>
<div class="stat-number">27</div> <div class="stat-number">28</div>
<div class="stat-label">Specialized Agents</div> <div class="stat-label">Specialized Agents</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon"><i class="fa-solid fa-terminal"></i></div> <div class="stat-icon"><i class="fa-solid fa-terminal"></i></div>
<div class="stat-number">19</div> <div class="stat-number">24</div>
<div class="stat-label">Slash Commands</div> <div class="stat-label">Slash Commands</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon"><i class="fa-solid fa-wand-magic-sparkles"></i></div> <div class="stat-icon"><i class="fa-solid fa-wand-magic-sparkles"></i></div>
<div class="stat-number">12</div> <div class="stat-number">15</div>
<div class="stat-label">Intelligent Skills</div> <div class="stat-label">Intelligent Skills</div>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<div class="stat-icon"><i class="fa-solid fa-server"></i></div> <div class="stat-icon"><i class="fa-solid fa-server"></i></div>
<div class="stat-number">2</div> <div class="stat-number">1</div>
<div class="stat-label">MCP Servers</div> <div class="stat-label">MCP Server</div>
</div> </div>
</div> </div>
</section> </section>
@@ -884,7 +884,7 @@
<div class="step-content"> <div class="step-content">
<h3>Add the Marketplace</h3> <h3>Add the Marketplace</h3>
<div class="card-code-block"> <div class="card-code-block">
<pre><code>claude /plugin marketplace add https://github.com/kieranklaassen/every-marketplace</code></pre> <pre><code>claude /plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin</code></pre>
</div> </div>
</div> </div>
</div> </div>
@@ -996,7 +996,7 @@ skill: gemini-imagegen</code></pre>
<i class="fa-solid fa-download"></i> Install Plugin Now <i class="fa-solid fa-download"></i> Install Plugin Now
<span class="button-arrow"></span> <span class="button-arrow"></span>
</a> </a>
<a href="https://github.com/kieranklaassen/every-marketplace" class="button tertiary cta-secondary"> <a href="https://github.com/EveryInc/compound-engineering-plugin" class="button tertiary cta-secondary">
<i class="fa-brands fa-github"></i> View on GitHub <i class="fa-brands fa-github"></i> View on GitHub
</a> </a>
</div> </div>
@@ -1024,7 +1024,7 @@ skill: gemini-imagegen</code></pre>
</div> </div>
<div> <div>
<div class="link-list"> <div class="link-list">
<a href="https://github.com/kieranklaassen/every-marketplace" class="icon-link ui s" target="_blank"> <a href="https://github.com/EveryInc/compound-engineering-plugin" class="icon-link ui s" target="_blank">
<div class="fa-brands fa-github icon m color-accent"></div> <div class="fa-brands fa-github icon m color-accent"></div>
<div class="pseudo-link">GitHub</div> <div class="pseudo-link">GitHub</div>
</a> </a>

View File

@@ -118,7 +118,7 @@
<strong><code>/report-bug</code> command</strong> - New slash command for reporting bugs in the <strong><code>/report-bug</code> command</strong> - New slash command for reporting bugs in the
compound-engineering plugin. Provides a structured workflow that gathers bug information compound-engineering plugin. Provides a structured workflow that gathers bug information
through guided questions, collects environment details automatically, and creates a GitHub through guided questions, collects environment details automatically, and creates a GitHub
issue in the kieranklaassen/every-marketplace repository. issue in the EveryInc/compound-engineering-plugin repository.
</li> </li>
</ul> </ul>
</div> </div>

View File

@@ -97,7 +97,7 @@
<h3>Step 1: Add the Marketplace</h3> <h3>Step 1: Add the Marketplace</h3>
<p>Think of the marketplace as an app store. You're adding it to Claude Code's list of places to look for plugins:</p> <p>Think of the marketplace as an app store. You're adding it to Claude Code's list of places to look for plugins:</p>
<div class="card-code-block"> <div class="card-code-block">
<pre><code>claude /plugin marketplace add https://github.com/kieranklaassen/every-marketplace</code></pre> <pre><code>claude /plugin marketplace add https://github.com/EveryInc/compound-engineering-plugin</code></pre>
</div> </div>
<h3>Step 2: Install the Plugin</h3> <h3>Step 2: Install the Plugin</h3>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@every-env/compound-plugin", "name": "@every-env/compound-plugin",
"version": "0.1.0", "version": "0.1.1",
"type": "module", "type": "module",
"private": false, "private": false,
"bin": { "bin": {

View File

@@ -1,7 +1,7 @@
{ {
"name": "compound-engineering", "name": "compound-engineering",
"version": "2.27.0", "version": "2.28.0",
"description": "AI-powered development tools. 27 agents, 23 commands, 14 skills, 1 MCP server for code review, research, design, and workflow automation.", "description": "AI-powered development tools. 28 agents, 24 commands, 15 skills, 1 MCP server for code review, research, design, and workflow automation.",
"author": { "author": {
"name": "Kieran Klaassen", "name": "Kieran Klaassen",
"email": "kieran@every.to", "email": "kieran@every.to",

View File

@@ -1,6 +1,6 @@
--- ---
name: best-practices-researcher name: best-practices-researcher
description: "Use this agent when you need to research and gather external best practices, documentation, and examples for any technology, framework, or development practice. This includes finding official documentation, community standards, well-regarded examples from open source projects, and domain-specific conventions. The agent excels at synthesizing information from multiple sources to provide comprehensive guidance on how to implement features or solve problems according to industry standards. <example>Context: User wants to know the best way to structure GitHub issues for their Rails project. user: \"I need to create some GitHub issues for our project. Can you research best practices for writing good issues?\" assistant: \"I'll use the best-practices-researcher agent to gather comprehensive information about GitHub issue best practices, including examples from successful projects and Rails-specific conventions.\" <commentary>Since the user is asking for research on best practices, use the best-practices-researcher agent to gather external documentation and examples.</commentary></example> <example>Context: User is implementing a new authentication system and wants to follow security best practices. user: \"We're adding JWT authentication to our Rails API. What are the current best practices?\" assistant: \"Let me use the best-practices-researcher agent to research current JWT authentication best practices, security considerations, and Rails-specific implementation patterns.\" <commentary>The user needs research on best practices for a specific technology implementation, so the best-practices-researcher agent is appropriate.</commentary></example>" description: "Use this agent when you need to research and gather external best practices, documentation, and examples for any technology, framework, or development practice. This includes finding official documentation, community standards, well-regarded examples from open source projects, and domain-specific conventions. The agent excels at synthesizing information from multiple sources to provide comprehensive guidance on how to implement features or solve problems according to industry standards. <example>Context: User wants to know the best way to structure GitHub issues for their FastAPI project. user: \"I need to create some GitHub issues for our project. Can you research best practices for writing good issues?\" assistant: \"I'll use the best-practices-researcher agent to gather comprehensive information about GitHub issue best practices, including examples from successful projects and FastAPI-specific conventions.\" <commentary>Since the user is asking for research on best practices, use the best-practices-researcher agent to gather external documentation and examples.</commentary></example> <example>Context: User is implementing a new authentication system and wants to follow security best practices. user: \"We're adding JWT authentication to our FastAPI API. What are the current best practices?\" assistant: \"Let me use the best-practices-researcher agent to research current JWT authentication best practices, security considerations, and FastAPI-specific implementation patterns.\" <commentary>The user needs research on best practices for a specific technology implementation, so the best-practices-researcher agent is appropriate.</commentary></example>"
model: inherit model: inherit
--- ---

View File

@@ -66,7 +66,7 @@ Grep: pattern="email" path=docs/solutions/ output_mode=files_with_matches -i=tru
**Regardless of Grep results**, always read the critical patterns file: **Regardless of Grep results**, always read the critical patterns file:
```bash ```bash
Read: docs/solutions/patterns/cora-critical-patterns.md Read: docs/solutions/patterns/critical-patterns.md
``` ```
This file contains must-know patterns that apply across all work - high-severity issues promoted to required reading. Scan for patterns relevant to the current feature/task. This file contains must-know patterns that apply across all work - high-severity issues promoted to required reading. Scan for patterns relevant to the current feature/task.
@@ -182,7 +182,7 @@ Structure your findings as:
- **Relevant Matches**: [Y files] - **Relevant Matches**: [Y files]
### Critical Patterns (Always Check) ### Critical Patterns (Always Check)
[Any matching patterns from cora-critical-patterns.md] [Any matching patterns from critical-patterns.md]
### Relevant Learnings ### Relevant Learnings

View File

@@ -100,7 +100,7 @@ Use the GitHub CLI to create the issue:
```bash ```bash
gh issue create \ gh issue create \
--repo kieranklaassen/every-marketplace \ --repo EveryInc/compound-engineering-plugin \
--title "[compound-engineering] Bug: [Brief description]" \ --title "[compound-engineering] Bug: [Brief description]" \
--body "[Formatted bug report from Step 3]" \ --body "[Formatted bug report from Step 3]" \
--label "bug,compound-engineering" --label "bug,compound-engineering"
@@ -109,7 +109,7 @@ gh issue create \
**Note:** If labels don't exist, create without labels: **Note:** If labels don't exist, create without labels:
```bash ```bash
gh issue create \ gh issue create \
--repo kieranklaassen/every-marketplace \ --repo EveryInc/compound-engineering-plugin \
--title "[compound-engineering] Bug: [Brief description]" \ --title "[compound-engineering] Bug: [Brief description]" \
--body "[Formatted bug report]" --body "[Formatted bug report]"
``` ```
@@ -126,7 +126,7 @@ After the issue is created:
``` ```
✅ Bug report submitted successfully! ✅ Bug report submitted successfully!
Issue: https://github.com/kieranklaassen/every-marketplace/issues/[NUMBER] Issue: https://github.com/EveryInc/compound-engineering-plugin/issues/[NUMBER]
Title: [compound-engineering] Bug: [description] Title: [compound-engineering] Bug: [description]
Thank you for helping improve the compound-engineering plugin! Thank you for helping improve the compound-engineering plugin!

View File

@@ -28,7 +28,7 @@ This command launches multiple specialized subagents IN PARALLEL to maximize eff
### 1. **Context Analyzer** (Parallel) ### 1. **Context Analyzer** (Parallel)
- Extracts conversation history - Extracts conversation history
- Identifies problem type, component, symptoms - Identifies problem type, component, symptoms
- Validates against CORA schema - Validates against solution schema
- Returns: YAML frontmatter skeleton - Returns: YAML frontmatter skeleton
### 2. **Solution Extractor** (Parallel) ### 2. **Solution Extractor** (Parallel)

View File

@@ -181,7 +181,7 @@ This command takes a work document (plan, specification, or todo file) and execu
- **kieran-rails-reviewer**: Verify Rails conventions (Rails projects) - **kieran-rails-reviewer**: Verify Rails conventions (Rails projects)
- **performance-oracle**: Check for performance issues - **performance-oracle**: Check for performance issues
- **security-sentinel**: Scan for security vulnerabilities - **security-sentinel**: Scan for security vulnerabilities
- **cora-test-reviewer**: Review test quality (CORA projects) - **cora-test-reviewer**: Review test quality (Rails projects with comprehensive test coverage)
Run reviewers in parallel with Task tool: Run reviewers in parallel with Task tool:
@@ -279,7 +279,7 @@ This command takes a work document (plan, specification, or todo file) and execu
--- ---
[![Compound Engineered](https://img.shields.io/badge/Compound-Engineered-6366f1)](https://github.com/kieranklaassen/compound-engineering-plugin) 🤖 Generated with [Claude Code](https://claude.com/claude-code) [![Compound Engineered](https://img.shields.io/badge/Compound-Engineered-6366f1)](https://github.com/EveryInc/compound-engineering-plugin) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF EOF
)" )"
``` ```

View File

@@ -61,7 +61,7 @@ Extract from conversation history:
**Required information:** **Required information:**
- **Module name**: Which CORA module had the problem - **Module name**: Which module or component had the problem
- **Symptom**: Observable error/behavior (exact error messages) - **Symptom**: Observable error/behavior (exact error messages)
- **Investigation attempts**: What didn't work and why - **Investigation attempts**: What didn't work and why
- **Root cause**: Technical explanation of actual problem - **Root cause**: Technical explanation of actual problem
@@ -249,7 +249,7 @@ But **NEVER auto-promote**. User decides via decision menu (Option 2).
**Template for critical pattern addition:** **Template for critical pattern addition:**
When user selects Option 2 (Add to Required Reading), use the template from `assets/critical-pattern-template.md` to structure the pattern entry. Number it sequentially based on existing patterns in `docs/solutions/patterns/cora-critical-patterns.md`. When user selects Option 2 (Add to Required Reading), use the template from `assets/critical-pattern-template.md` to structure the pattern entry. Number it sequentially based on existing patterns in `docs/solutions/patterns/critical-patterns.md`.
</step> </step>
</critical_sequence> </critical_sequence>
@@ -270,7 +270,7 @@ File created:
What's next? What's next?
1. Continue workflow (recommended) 1. Continue workflow (recommended)
2. Add to Required Reading - Promote to critical patterns (cora-critical-patterns.md) 2. Add to Required Reading - Promote to critical patterns (critical-patterns.md)
3. Link related issues - Connect to similar problems 3. Link related issues - Connect to similar problems
4. Add to existing skill - Add to a learning skill (e.g., hotwire-native) 4. Add to existing skill - Add to a learning skill (e.g., hotwire-native)
5. Create new skill - Extract into new learning skill 5. Create new skill - Extract into new learning skill
@@ -295,7 +295,7 @@ User selects this when:
Action: Action:
1. Extract pattern from the documentation 1. Extract pattern from the documentation
2. Format as ❌ WRONG vs ✅ CORRECT with code examples 2. Format as ❌ WRONG vs ✅ CORRECT with code examples
3. Add to `docs/solutions/patterns/cora-critical-patterns.md` 3. Add to `docs/solutions/patterns/critical-patterns.md`
4. Add cross-reference back to this doc 4. Add cross-reference back to this doc
5. Confirm: "✓ Added to Required Reading. All subagents will see this pattern before code generation." 5. Confirm: "✓ Added to Required Reading. All subagents will see this pattern before code generation."
@@ -317,7 +317,7 @@ Action:
4. Confirm: "✓ Added to [skill-name] skill in [file]" 4. Confirm: "✓ Added to [skill-name] skill in [file]"
Example: For Hotwire Native Tailwind variants solution: Example: For Hotwire Native Tailwind variants solution:
- Add to `hotwire-native/references/resources.md` under "CORA-Specific Resources" - Add to `hotwire-native/references/resources.md` under "Project-Specific Resources"
- Add to `hotwire-native/references/examples.md` with link to solution doc - Add to `hotwire-native/references/examples.md` with link to solution doc
**Option 5: Create new skill** **Option 5: Create new skill**
@@ -397,11 +397,11 @@ Documentation is successful when ALL of the following are true:
- Present multiple matches - Present multiple matches
- Let user choose: new doc, update existing, or link as duplicate - Let user choose: new doc, update existing, or link as duplicate
**Module not in CORA-MODULES.md:** **Module not in modules documentation:**
- Warn but don't block - Warn but don't block
- Proceed with documentation - Proceed with documentation
- Suggest: "Add [Module] to CORA-MODULES.md if not there" - Suggest: "Add [Module] to modules documentation if not there"
--- ---
@@ -488,7 +488,7 @@ File created:
What's next? What's next?
1. Continue workflow (recommended) 1. Continue workflow (recommended)
2. Add to Required Reading - Promote to critical patterns (cora-critical-patterns.md) 2. Add to Required Reading - Promote to critical patterns (critical-patterns.md)
3. Link related issues - Connect to similar problems 3. Link related issues - Connect to similar problems
4. Add to existing skill - Add to a learning skill (e.g., hotwire-native) 4. Add to existing skill - Add to a learning skill (e.g., hotwire-native)
5. Create new skill - Extract into new learning skill 5. Create new skill - Extract into new learning skill

View File

@@ -1,6 +1,6 @@
# Critical Pattern Template # Critical Pattern Template
Use this template when adding a pattern to `docs/solutions/patterns/cora-critical-patterns.md`: Use this template when adding a pattern to `docs/solutions/patterns/critical-patterns.md`:
--- ---

View File

@@ -1,5 +1,5 @@
--- ---
module: [Module name or "CORA" for system-wide] module: [Module name or "System" for system-wide]
date: [YYYY-MM-DD] date: [YYYY-MM-DD]
problem_type: [build_error|test_failure|runtime_error|performance_issue|database_issue|security_issue|ui_bug|integration_issue|logic_error] problem_type: [build_error|test_failure|runtime_error|performance_issue|database_issue|security_issue|ui_bug|integration_issue|logic_error]
component: [rails_model|rails_controller|rails_view|service_object|background_job|database|frontend_stimulus|hotwire_turbo|email_processing|brief_system|assistant|authentication|payments] component: [rails_model|rails_controller|rails_view|service_object|background_job|database|frontend_stimulus|hotwire_turbo|email_processing|brief_system|assistant|authentication|payments]
@@ -19,7 +19,7 @@ tags: [keyword1, keyword2, keyword3]
[1-2 sentence clear description of the issue and what the user experienced] [1-2 sentence clear description of the issue and what the user experienced]
## Environment ## Environment
- Module: [Name or "CORA system"] - Module: [Name or "System-wide"]
- Rails Version: [e.g., 7.1.2] - Rails Version: [e.g., 7.1.2]
- Affected Component: [e.g., "Email Processing model", "Brief System service", "Authentication controller"] - Affected Component: [e.g., "Email Processing model", "Brief System service", "Authentication controller"]
- Date: [YYYY-MM-DD when this was solved] - Date: [YYYY-MM-DD when this was solved]
@@ -78,7 +78,7 @@ tags: [keyword1, keyword2, keyword3]
## Prevention ## Prevention
[How to avoid this problem in future CORA development:] [How to avoid this problem in future development:]
- [Specific coding practice, check, or pattern to follow] - [Specific coding practice, check, or pattern to follow]
- [What to watch out for] - [What to watch out for]
- [How to catch this early] - [How to catch this early]

View File

@@ -4,7 +4,7 @@
## Required Fields ## Required Fields
- **module** (string): Module name (e.g., "EmailProcessing") or "CORA" for system-wide issues - **module** (string): Module name (e.g., "EmailProcessing") or "System" for system-wide issues
- **date** (string): ISO 8601 date (YYYY-MM-DD) - **date** (string): ISO 8601 date (YYYY-MM-DD)
- **problem_type** (enum): One of [build_error, test_failure, runtime_error, performance_issue, database_issue, security_issue, ui_bug, integration_issue, logic_error, developer_experience, workflow_issue, best_practice, documentation_gap] - **problem_type** (enum): One of [build_error, test_failure, runtime_error, performance_issue, database_issue, security_issue, ui_bug, integration_issue, logic_error, developer_experience, workflow_issue, best_practice, documentation_gap]
- **component** (enum): One of [rails_model, rails_controller, rails_view, service_object, background_job, database, frontend_stimulus, hotwire_turbo, email_processing, brief_system, assistant, authentication, payments, development_workflow, testing_framework, documentation, tooling] - **component** (enum): One of [rails_model, rails_controller, rails_view, service_object, background_job, database, frontend_stimulus, hotwire_turbo, email_processing, brief_system, assistant, authentication, payments, development_workflow, testing_framework, documentation, tooling]

View File

@@ -175,7 +175,9 @@ function resolveOutputRoot(value: unknown): string {
const expanded = expandHome(String(value).trim()) const expanded = expandHome(String(value).trim())
return path.resolve(expanded) return path.resolve(expanded)
} }
return path.join(os.homedir(), ".opencode") // OpenCode global config lives at ~/.config/opencode per XDG spec
// See: https://opencode.ai/docs/config/
return path.join(os.homedir(), ".config", "opencode")
} }
async function resolveGitHubPluginPath(pluginName: string): Promise<ResolvedPluginPath> { async function resolveGitHubPluginPath(pluginName: string): Promise<ResolvedPluginPath> {

View File

@@ -73,19 +73,76 @@ function convertCommandSkill(command: ClaudeCommand, usedNames: Set<string>): Co
if (command.allowedTools && command.allowedTools.length > 0) { if (command.allowedTools && command.allowedTools.length > 0) {
sections.push(`## Allowed tools\n${command.allowedTools.map((tool) => `- ${tool}`).join("\n")}`) sections.push(`## Allowed tools\n${command.allowedTools.map((tool) => `- ${tool}`).join("\n")}`)
} }
sections.push(command.body.trim()) // Transform Task agent calls to Codex skill references
const transformedBody = transformTaskCalls(command.body.trim())
sections.push(transformedBody)
const body = sections.filter(Boolean).join("\n\n").trim() const body = sections.filter(Boolean).join("\n\n").trim()
const content = formatFrontmatter(frontmatter, body.length > 0 ? body : command.body) const content = formatFrontmatter(frontmatter, body.length > 0 ? body : command.body)
return { name, content } return { name, content }
} }
/**
* Transform Claude Code content to Codex-compatible content.
*
* Handles multiple syntax differences:
* 1. Task agent calls: Task agent-name(args) → Use the $agent-name skill to: args
* 2. Slash commands: /command-name → /prompts:command-name
* 3. Agent references: @agent-name → $agent-name skill
*
* This bridges the gap since Claude Code and Codex have different syntax
* for invoking commands, agents, and skills.
*/
function transformContentForCodex(body: string): string {
let result = body
// 1. Transform Task agent calls
// Match: Task repo-research-analyst(feature_description)
// Match: - Task learnings-researcher(args)
const taskPattern = /^(\s*-?\s*)Task\s+([a-z][a-z0-9-]*)\(([^)]+)\)/gm
result = result.replace(taskPattern, (_match, prefix: string, agentName: string, args: string) => {
const skillName = normalizeName(agentName)
const trimmedArgs = args.trim()
return `${prefix}Use the $${skillName} skill to: ${trimmedArgs}`
})
// 2. Transform slash command references
// Match: /command-name or /workflows:command but NOT /path/to/file or URLs
// Look for slash commands in contexts like "Run /command", "use /command", etc.
// Avoid matching file paths (contain multiple slashes) or URLs (contain ://)
const slashCommandPattern = /(?<![:\w])\/([a-z][a-z0-9_:-]*?)(?=[\s,."')\]}`]|$)/gi
result = result.replace(slashCommandPattern, (match, commandName: string) => {
// Skip if it looks like a file path (contains /)
if (commandName.includes('/')) return match
// Skip common non-command patterns
if (['dev', 'tmp', 'etc', 'usr', 'var', 'bin', 'home'].includes(commandName)) return match
// Transform to Codex prompt syntax
const normalizedName = normalizeName(commandName)
return `/prompts:${normalizedName}`
})
// 3. Transform @agent-name references
// Match: @agent-name in text (not emails)
const agentRefPattern = /@([a-z][a-z0-9-]*-(?:agent|reviewer|researcher|analyst|specialist|oracle|sentinel|guardian|strategist))/gi
result = result.replace(agentRefPattern, (_match, agentName: string) => {
const skillName = normalizeName(agentName)
return `$${skillName} skill`
})
return result
}
// Alias for backward compatibility
const transformTaskCalls = transformContentForCodex
function renderPrompt(command: ClaudeCommand, skillName: string): string { function renderPrompt(command: ClaudeCommand, skillName: string): string {
const frontmatter: Record<string, unknown> = { const frontmatter: Record<string, unknown> = {
description: command.description, description: command.description,
"argument-hint": command.argumentHint, "argument-hint": command.argumentHint,
} }
const instructions = `Use the $${skillName} skill for this command and follow its instructions.` const instructions = `Use the $${skillName} skill for this command and follow its instructions.`
const body = [instructions, "", command.body].join("\n").trim() // Transform Task calls in prompt body too (not just skill body)
const transformedBody = transformTaskCalls(command.body)
const body = [instructions, "", transformedBody].join("\n").trim()
return formatFrontmatter(frontmatter, body) return formatFrontmatter(frontmatter, body)
} }

View File

@@ -28,7 +28,10 @@ export async function writeOpenCodeBundle(outputRoot: string, bundle: OpenCodeBu
} }
function resolveOpenCodePaths(outputRoot: string) { function resolveOpenCodePaths(outputRoot: string) {
if (path.basename(outputRoot) === ".opencode") { const base = path.basename(outputRoot)
// Global install: ~/.config/opencode (basename is "opencode")
// Project install: .opencode (basename is ".opencode")
if (base === "opencode" || base === ".opencode") {
return { return {
root: outputRoot, root: outputRoot,
configPath: path.join(outputRoot, "opencode.json"), configPath: path.join(outputRoot, "opencode.json"),
@@ -38,6 +41,7 @@ function resolveOpenCodePaths(outputRoot: string) {
} }
} }
// Custom output directory - nest under .opencode subdirectory
return { return {
root: outputRoot, root: outputRoot,
configPath: path.join(outputRoot, "opencode.json"), configPath: path.join(outputRoot, "opencode.json"),

View File

@@ -63,7 +63,7 @@ describe("CLI", () => {
expect(await exists(path.join(tempRoot, ".opencode", "plugins", "converted-hooks.ts"))).toBe(true) expect(await exists(path.join(tempRoot, ".opencode", "plugins", "converted-hooks.ts"))).toBe(true)
}) })
test("install defaults output to ~/.opencode", async () => { test("install defaults output to ~/.config/opencode", async () => {
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-local-default-")) const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "cli-local-default-"))
const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin") const fixtureRoot = path.join(import.meta.dir, "fixtures", "sample-plugin")
@@ -95,8 +95,9 @@ describe("CLI", () => {
} }
expect(stdout).toContain("Installed compound-engineering") expect(stdout).toContain("Installed compound-engineering")
expect(await exists(path.join(tempRoot, ".opencode", "opencode.json"))).toBe(true) // OpenCode global config lives at ~/.config/opencode per XDG spec
expect(await exists(path.join(tempRoot, ".opencode", "agents", "repo-research-analyst.md"))).toBe(true) expect(await exists(path.join(tempRoot, ".config", "opencode", "opencode.json"))).toBe(true)
expect(await exists(path.join(tempRoot, ".config", "opencode", "agents", "repo-research-analyst.md"))).toBe(true)
}) })
test("list returns plugins in a temp workspace", async () => { test("list returns plugins in a temp workspace", async () => {
@@ -174,8 +175,9 @@ describe("CLI", () => {
} }
expect(stdout).toContain("Installed compound-engineering") expect(stdout).toContain("Installed compound-engineering")
expect(await exists(path.join(tempRoot, ".opencode", "opencode.json"))).toBe(true) // OpenCode global config lives at ~/.config/opencode per XDG spec
expect(await exists(path.join(tempRoot, ".opencode", "agents", "repo-research-analyst.md"))).toBe(true) expect(await exists(path.join(tempRoot, ".config", "opencode", "opencode.json"))).toBe(true)
expect(await exists(path.join(tempRoot, ".config", "opencode", "agents", "repo-research-analyst.md"))).toBe(true)
}) })
test("convert writes OpenCode output", async () => { test("convert writes OpenCode output", async () => {

View File

@@ -89,6 +89,89 @@ describe("convertClaudeToCodex", () => {
expect(bundle.mcpServers?.local?.args).toEqual(["hello"]) expect(bundle.mcpServers?.local?.args).toEqual(["hello"])
}) })
test("transforms Task agent calls to skill references", () => {
const plugin: ClaudePlugin = {
...fixturePlugin,
commands: [
{
name: "plan",
description: "Planning with agents",
body: `Run these agents in parallel:
- Task repo-research-analyst(feature_description)
- Task learnings-researcher(feature_description)
Then consolidate findings.
Task best-practices-researcher(topic)`,
sourcePath: "/tmp/plugin/commands/plan.md",
},
],
agents: [],
skills: [],
}
const bundle = convertClaudeToCodex(plugin, {
agentMode: "subagent",
inferTemperature: false,
permissions: "none",
})
const commandSkill = bundle.generatedSkills.find((s) => s.name === "plan")
expect(commandSkill).toBeDefined()
const parsed = parseFrontmatter(commandSkill!.content)
// Task calls should be transformed to skill references
expect(parsed.body).toContain("Use the $repo-research-analyst skill to: feature_description")
expect(parsed.body).toContain("Use the $learnings-researcher skill to: feature_description")
expect(parsed.body).toContain("Use the $best-practices-researcher skill to: topic")
// Original Task syntax should not remain
expect(parsed.body).not.toContain("Task repo-research-analyst")
expect(parsed.body).not.toContain("Task learnings-researcher")
})
test("transforms slash commands to prompts syntax", () => {
const plugin: ClaudePlugin = {
...fixturePlugin,
commands: [
{
name: "plan",
description: "Planning with commands",
body: `After planning, you can:
1. Run /deepen-plan to enhance
2. Run /plan_review for feedback
3. Start /workflows:work to implement
Don't confuse with file paths like /tmp/output.md or /dev/null.`,
sourcePath: "/tmp/plugin/commands/plan.md",
},
],
agents: [],
skills: [],
}
const bundle = convertClaudeToCodex(plugin, {
agentMode: "subagent",
inferTemperature: false,
permissions: "none",
})
const commandSkill = bundle.generatedSkills.find((s) => s.name === "plan")
expect(commandSkill).toBeDefined()
const parsed = parseFrontmatter(commandSkill!.content)
// Slash commands should be transformed to /prompts: syntax
expect(parsed.body).toContain("/prompts:deepen-plan")
expect(parsed.body).toContain("/prompts:plan_review")
expect(parsed.body).toContain("/prompts:workflows-work")
// File paths should NOT be transformed
expect(parsed.body).toContain("/tmp/output.md")
expect(parsed.body).toContain("/dev/null")
})
test("truncates generated skill descriptions to Codex limits and single line", () => { test("truncates generated skill descriptions to Codex limits and single line", () => {
const longDescription = `Line one\nLine two ${"a".repeat(2000)}` const longDescription = `Line one\nLine two ${"a".repeat(2000)}`
const plugin: ClaudePlugin = { const plugin: ClaudePlugin = {

View File

@@ -59,4 +59,29 @@ describe("writeOpenCodeBundle", () => {
expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true) expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true)
expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false) expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false)
}) })
test("writes directly into ~/.config/opencode style output root", async () => {
// Simulates the global install path: ~/.config/opencode
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "config-opencode-"))
const outputRoot = path.join(tempRoot, ".config", "opencode")
const bundle: OpenCodeBundle = {
config: { $schema: "https://opencode.ai/config.json" },
agents: [{ name: "agent-one", content: "Agent content" }],
plugins: [],
skillDirs: [
{
name: "skill-one",
sourceDir: path.join(import.meta.dir, "fixtures", "sample-plugin", "skills", "skill-one"),
},
],
}
await writeOpenCodeBundle(outputRoot, bundle)
// Should write directly, not nested under .opencode
expect(await exists(path.join(outputRoot, "opencode.json"))).toBe(true)
expect(await exists(path.join(outputRoot, "agents", "agent-one.md"))).toBe(true)
expect(await exists(path.join(outputRoot, "skills", "skill-one", "SKILL.md"))).toBe(true)
expect(await exists(path.join(outputRoot, ".opencode"))).toBe(false)
})
}) })