Compare commits

...

10 Commits

Author SHA1 Message Date
cexll
c1d3a0a07a fix: correct gitignore to not exclude cmd/codeagent-wrapper
The pattern 'codeagent-wrapper' was matching cmd/codeagent-wrapper/
directory. Changed to '/codeagent-wrapper' to only match root binary.

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-25 18:12:40 +08:00
cexll
2856055e2e fix: support concurrent tasks with unique state files
- Generate unique task_id (timestamp-pid-random) for each /do invocation
- State files now use pattern: do.{task_id}.local.md
- Stop hook scans all state files, aggregates blocking reasons
- Auto-cleanup completed task state files

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-25 18:04:47 +08:00
cexll
a9c1e8178f fix: correct build path in release workflow
- Remove obsolete cmd/codeagent directory
- Fix release.yml build path to ./cmd/codeagent-wrapper

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-25 17:52:34 +08:00
cexll
1afeca88ae fix: increase stdoutDrainTimeout from 100ms to 500ms
Resolves intermittent "completed without agent_message output" errors
when Claude CLI exits before all stdout data is read.

- internal/executor/executor.go:43
- internal/app/app.go:27
- Add benchmark script for stability testing

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-25 17:45:38 +08:00
cexll
326ad85c74 fix: use ANTHROPIC_AUTH_TOKEN for Claude CLI env injection
- Change env var from ANTHROPIC_API_KEY to ANTHROPIC_AUTH_TOKEN
- Add Backend field propagation in taskSpec (cli.go)
- Add stderr logging for injected env vars with API key masking
- Add comprehensive tests for env injection flow

Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-24 15:20:29 +08:00
cexll
e66bec0083 test: use prefix match for version flag tests
Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-24 14:27:43 +08:00
cexll
eb066395c2 docs: restructure root READMEs with do as recommended workflow
Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-24 14:27:41 +08:00
cexll
b49dad842a docs: update do/omo/sparv module READMEs with detailed workflows
Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-24 14:27:39 +08:00
cexll
d98086c661 docs: add README for bmad and requirements modules
Generated with SWE-Agent.ai

Co-Authored-By: SWE-Agent.ai <noreply@swe-agent.ai>
2026-01-24 14:27:37 +08:00
cexll
0420646258 update codeagent version 2026-01-24 14:01:54 +08:00
24 changed files with 1638 additions and 1144 deletions

View File

@@ -74,7 +74,7 @@ jobs:
if [ "${{ matrix.goos }}" = "windows" ]; then
OUTPUT_NAME="${OUTPUT_NAME}.exe"
fi
go build -ldflags="-s -w -X main.version=${VERSION}" -o ${OUTPUT_NAME} ./cmd/codeagent
go build -ldflags="-s -w -X main.version=${VERSION}" -o ${OUTPUT_NAME} ./cmd/codeagent-wrapper
chmod +x ${OUTPUT_NAME}
echo "artifact_path=codeagent-wrapper/${OUTPUT_NAME}" >> $GITHUB_OUTPUT

635
README.md
View File

@@ -3,29 +3,13 @@
# Claude Code Multi-Agent Workflow System
[![Run in Smithery](https://smithery.ai/badge/skills/cexll)](https://smithery.ai/skills?ns=cexll&utm_source=github&utm_medium=badge)
[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code)
[![Version](https://img.shields.io/badge/Version-5.6-green)](https://github.com/cexll/myclaude)
[![Version](https://img.shields.io/badge/Version-6.x-green)](https://github.com/cexll/myclaude)
> AI-powered development automation with multi-backend execution (Codex/Claude/Gemini)
> AI-powered development automation with multi-backend execution (Codex/Claude/Gemini/OpenCode)
## Core Concept: Multi-Backend Architecture
This system leverages a **dual-agent architecture** with pluggable AI backends:
| Role | Agent | Responsibility |
|------|-------|----------------|
| **Orchestrator** | Claude Code | Planning, context gathering, verification, user interaction |
| **Executor** | codeagent-wrapper | Code editing, test execution (Codex/Claude/Gemini backends) |
**Why this separation?**
- Claude Code excels at understanding context and orchestrating complex workflows
- Specialized backends (Codex for code, Claude for reasoning, Gemini for prototyping) excel at focused execution
- Backend selection via `--backend codex|claude|gemini` matches the model to the task
## Quick Start(Please execute in Powershell on Windows)
## Quick Start
```bash
git clone https://github.com/cexll/myclaude.git
@@ -33,199 +17,23 @@ cd myclaude
python3 install.py --install-dir ~/.claude
```
## Workflows Overview
## Modules Overview
### 0. OmO Multi-Agent Orchestrator (Recommended for Complex Tasks)
**Intelligent multi-agent orchestration that routes tasks to specialized agents based on risk signals.**
```bash
/omo "analyze and fix this authentication bug"
```
**Agent Hierarchy:**
| Agent | Role | Backend | Model |
|-------|------|---------|-------|
| `oracle` | Technical advisor | Claude | claude-opus-4-5 |
| `librarian` | External research | Claude | claude-sonnet-4-5 |
| `explore` | Codebase search | OpenCode | grok-code |
| `develop` | Code implementation | Codex | gpt-5.2 |
| `frontend-ui-ux-engineer` | UI/UX specialist | Gemini | gemini-3-pro |
| `document-writer` | Documentation | Gemini | gemini-3-flash |
**Routing Signals (Not Fixed Pipeline):**
- Code location unclear → `explore`
- External library/API → `librarian`
- Risky/multi-file change → `oracle`
- Implementation needed → `develop` / `frontend-ui-ux-engineer`
**Common Recipes:**
- Explain code: `explore`
- Small fix with known location: `develop` directly
- Bug fix, location unknown: `explore → develop`
- Cross-cutting refactor: `explore → oracle → develop`
- External API integration: `explore + librarian → oracle → develop`
**Best For:** Complex bug investigation, multi-file refactoring, architecture decisions
---
### 1. Dev Workflow (Recommended)
**The primary workflow for most development tasks.**
```bash
/dev "implement user authentication with JWT"
```
**6-Step Process:**
1. **Requirements Clarification** - Interactive Q&A to clarify scope
2. **Codex Deep Analysis** - Codebase exploration and architecture decisions
3. **Dev Plan Generation** - Structured task breakdown with test requirements
4. **Parallel Execution** - Codex executes tasks concurrently
5. **Coverage Validation** - Enforce ≥90% test coverage
6. **Completion Summary** - Report with file changes and coverage stats
**Key Features:**
- Claude Code orchestrates, Codex executes all code changes
- Automatic task parallelization for speed
- Mandatory 90% test coverage gate
- Rollback on failure
**Best For:** Feature development, refactoring, bug fixes with tests
---
### 2. BMAD Agile Workflow
**Full enterprise agile methodology with 6 specialized agents.**
```bash
/bmad-pilot "build e-commerce checkout system"
```
**Agents:**
| Agent | Role |
|-------|------|
| Product Owner | Requirements & user stories |
| Architect | System design & tech decisions |
| Tech Lead | Sprint planning & task breakdown |
| Developer | Implementation |
| Code Reviewer | Quality assurance |
| QA Engineer | Testing & validation |
**Process:**
```
Requirements → Architecture → Sprint Plan → Development → Review → QA
↓ ↓ ↓ ↓ ↓ ↓
PRD.md DESIGN.md SPRINT.md Code REVIEW.md TEST.md
```
**Best For:** Large features, team coordination, enterprise projects
---
### 3. Requirements-Driven Workflow
**Lightweight requirements-to-code pipeline.**
```bash
/requirements-pilot "implement API rate limiting"
```
**Process:**
1. Requirements generation with quality scoring
2. Implementation planning
3. Code generation
4. Review and testing
**Best For:** Quick prototypes, well-defined features
---
### 4. Development Essentials
**Direct commands for daily coding tasks.**
| Command | Purpose |
|---------|---------|
| `/code` | Implement a feature |
| `/debug` | Debug an issue |
| `/test` | Write tests |
| `/review` | Code review |
| `/optimize` | Performance optimization |
| `/refactor` | Code refactoring |
| `/docs` | Documentation |
**Best For:** Quick tasks, no workflow overhead needed
## Enterprise Workflow Features
- **Multi-backend execution:** `codeagent-wrapper --backend codex|claude|gemini` (default `codex`) so you can match the model to the task without changing workflows.
- **GitHub workflow commands:** `/gh-create-issue "short need"` creates structured issues; `/gh-issue-implement 123` pulls issue #123, drives development, and prepares the PR.
- **Skills + hooks activation:** .claude/hooks run automation (tests, reviews), while `.claude/skills/skill-rules.json` auto-suggests the right skills. Keep hooks enabled in `.claude/settings.json` to activate the enterprise workflow helpers.
---
## Version Requirements
### Codex CLI
**Minimum version:** Check compatibility with your installation
The codeagent-wrapper uses these Codex CLI features:
- `codex e` - Execute commands (shorthand for `codex exec`)
- `--skip-git-repo-check` - Skip git repository validation
- `--json` - JSON stream output format
- `-C <workdir>` - Set working directory
- `resume <session_id>` - Resume previous sessions
**Verify Codex CLI is installed:**
```bash
which codex
codex --version
```
### Claude CLI
**Minimum version:** Check compatibility with your installation
Required features:
- `--output-format stream-json` - Streaming JSON output format
- `--setting-sources` - Control setting sources (prevents infinite recursion)
- `--dangerously-skip-permissions` - Skip permission prompts (use with caution)
- `-p` - Prompt input flag
- `-r <session_id>` - Resume sessions
**Security Note:** The wrapper adds `--dangerously-skip-permissions` for Claude by default. Set `CODEAGENT_SKIP_PERMISSIONS=false` to disable if you need permission prompts.
**Verify Claude CLI is installed:**
```bash
which claude
claude --version
```
### Gemini CLI
**Minimum version:** Check compatibility with your installation
Required features:
- `-o stream-json` - JSON stream output format
- `-y` - Auto-approve prompts (non-interactive mode)
- `-r <session_id>` - Resume sessions
- `-p` - Prompt input flag
**Verify Gemini CLI is installed:**
```bash
which gemini
gemini --version
```
---
| Module | Description | Documentation |
|--------|-------------|---------------|
| [do](skills/do/README.md) | **Recommended** - 7-phase feature development with codeagent orchestration | `/do` command |
| [dev](dev-workflow/README.md) | Lightweight dev workflow with Codex integration | `/dev` command |
| [omo](skills/omo/README.md) | Multi-agent orchestration with intelligent routing | `/omo` command |
| [bmad](bmad-agile-workflow/README.md) | BMAD agile workflow with 6 specialized agents | `/bmad-pilot` command |
| [requirements](requirements-driven-workflow/README.md) | Lightweight requirements-to-code pipeline | `/requirements-pilot` command |
| [essentials](development-essentials/README.md) | Core development commands and utilities | `/code`, `/debug`, etc. |
| [sparv](skills/sparv/README.md) | SPARV workflow (Specify→Plan→Act→Review→Vault) | `/sparv` command |
| course | Course development (combines dev + product-requirements + test-cases) | Composite module |
## Installation
### Modular Installation (Recommended)
```bash
# Install all enabled modules (dev + essentials by default)
# Install all enabled modules
python3 install.py --install-dir ~/.claude
# Install specific module
@@ -234,173 +42,72 @@ python3 install.py --module dev
# List available modules
python3 install.py --list-modules
# Force overwrite existing files
# Force overwrite
python3 install.py --force
```
### Available Modules
### Module Configuration
| Module | Default | Description |
|--------|---------|-------------|
| `dev` | ✓ Enabled | Dev workflow + Codex integration |
| `essentials` | ✓ Enabled | Core development commands |
| `bmad` | Disabled | Full BMAD agile workflow |
| `requirements` | Disabled | Requirements-driven workflow |
### What Gets Installed
```
~/.claude/
├── bin/
│ └── codeagent-wrapper # Main executable
├── CLAUDE.md # Core instructions and role definition
├── commands/ # Slash commands (/dev, /code, etc.)
├── agents/ # Agent definitions
├── skills/
│ └── codex/
│ └── SKILL.md # Codex integration skill
├── config.json # Configuration
└── installed_modules.json # Installation status
```
### Customizing Installation Directory
By default, myclaude installs to `~/.claude`. You can customize this using the `INSTALL_DIR` environment variable:
```bash
# Install to custom directory
INSTALL_DIR=/opt/myclaude bash install.sh
# Update your PATH accordingly
export PATH="/opt/myclaude/bin:$PATH"
```
**Directory Structure:**
- `$INSTALL_DIR/bin/` - codeagent-wrapper binary
- `$INSTALL_DIR/skills/` - Skill definitions
- `$INSTALL_DIR/config.json` - Configuration file
- `$INSTALL_DIR/commands/` - Slash command definitions
- `$INSTALL_DIR/agents/` - Agent definitions
**Note:** When using a custom installation directory, ensure that `$INSTALL_DIR/bin` is added to your `PATH` environment variable.
### Configuration
Edit `config.json` to customize:
Edit `config.json` to enable/disable modules:
```json
{
"version": "1.0",
"install_dir": "~/.claude",
"modules": {
"dev": {
"enabled": true,
"operations": [
{"type": "merge_dir", "source": "dev-workflow"},
{"type": "copy_file", "source": "memorys/CLAUDE.md", "target": "CLAUDE.md"},
{"type": "copy_file", "source": "skills/codex/SKILL.md", "target": "skills/codex/SKILL.md"},
{"type": "run_command", "command": "bash install.sh"}
]
}
"dev": { "enabled": true },
"bmad": { "enabled": false },
"requirements": { "enabled": false },
"essentials": { "enabled": false },
"omo": { "enabled": false },
"sparv": { "enabled": false },
"do": { "enabled": false },
"course": { "enabled": false }
}
}
```
**Operation Types:**
| Type | Description |
|------|-------------|
| `merge_dir` | Merge subdirs (commands/, agents/) into install dir |
| `copy_dir` | Copy entire directory |
| `copy_file` | Copy single file to target path |
| `run_command` | Execute shell command |
---
## Codex Integration
The `codex` skill enables Claude Code to delegate code execution to Codex CLI.
### Usage in Workflows
```bash
# Codex is invoked via the skill
codeagent-wrapper - <<'EOF'
implement @src/auth.ts with JWT validation
EOF
```
### Parallel Execution
```bash
codeagent-wrapper --parallel <<'EOF'
---TASK---
id: backend_api
workdir: /project/backend
---CONTENT---
implement REST endpoints for /api/users
---TASK---
id: frontend_ui
workdir: /project/frontend
dependencies: backend_api
---CONTENT---
create React components consuming the API
EOF
```
### Install Codex Wrapper
```bash
# Automatic (via dev module)
python3 install.py --module dev
# Manual
bash install.sh
```
#### Windows
Windows installs place `codeagent-wrapper.exe` in `%USERPROFILE%\bin`.
```powershell
# PowerShell (recommended)
powershell -ExecutionPolicy Bypass -File install.ps1
# Batch (cmd)
install.bat
```
**Add to PATH** (if installer doesn't detect it):
```powershell
# PowerShell - persistent for current user
[Environment]::SetEnvironmentVariable('PATH', "$HOME\bin;" + [Environment]::GetEnvironmentVariable('PATH','User'), 'User')
# PowerShell - current session only
$Env:PATH = "$HOME\bin;$Env:PATH"
```
```batch
REM cmd.exe - persistent for current user (use PowerShell method above instead)
REM WARNING: This expands %PATH% which includes system PATH, causing duplication
REM Note: Using reg add instead of setx to avoid 1024-character truncation limit
reg add "HKCU\Environment" /v Path /t REG_EXPAND_SZ /d "%USERPROFILE%\bin;%PATH%" /f
```
---
## Workflow Selection Guide
| Scenario | Recommended Workflow |
|----------|---------------------|
| New feature with tests | `/dev` |
| Quick bug fix | `/debug` or `/code` |
| Large multi-sprint feature | `/bmad-pilot` |
| Prototype or POC | `/requirements-pilot` |
| Code review | `/review` |
| Performance issue | `/optimize` |
| Scenario | Recommended |
|----------|-------------|
| Feature development (default) | `/do` |
| Lightweight feature | `/dev` |
| Bug investigation + fix | `/omo` |
| Large enterprise project | `/bmad-pilot` |
| Quick prototype | `/requirements-pilot` |
| Simple task | `/code`, `/debug` |
---
## Core Architecture
| Role | Agent | Responsibility |
|------|-------|----------------|
| **Orchestrator** | Claude Code | Planning, context gathering, verification |
| **Executor** | codeagent-wrapper | Code editing, test execution (Codex/Claude/Gemini/OpenCode) |
## Backend CLI Requirements
| Backend | Required Features |
|---------|-------------------|
| Codex | `codex e`, `--json`, `-C`, `resume` |
| Claude | `--output-format stream-json`, `-r` |
| Gemini | `-o stream-json`, `-y`, `-r` |
## Directory Structure After Installation
```
~/.claude/
├── bin/codeagent-wrapper
├── CLAUDE.md
├── commands/
├── agents/
├── skills/
└── config.json
```
## Documentation
- [Codeagent-Wrapper Guide](docs/CODEAGENT-WRAPPER.md)
- [Hooks Documentation](docs/HOOKS.md)
- [codeagent-wrapper](codeagent-wrapper/README.md)
## Troubleshooting
@@ -408,214 +115,38 @@ reg add "HKCU\Environment" /v Path /t REG_EXPAND_SZ /d "%USERPROFILE%\bin;%PATH%
**Codex wrapper not found:**
```bash
# Installer auto-adds PATH, check if configured
if [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]]; then
echo "PATH not configured. Reinstalling..."
bash install.sh
fi
# Or manually add (idempotent command)
[[ ":$PATH:" != *":$HOME/.claude/bin:"* ]] && echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc
```
**Permission denied:**
```bash
python3 install.py --install-dir ~/.claude --force
bash install.sh
```
**Module not loading:**
```bash
# Check installation status
cat ~/.claude/installed_modules.json
# Reinstall specific module
python3 install.py --module dev --force
python3 install.py --module <name> --force
```
### Version Compatibility Issues
**Backend CLI not found:**
**Backend CLI errors:**
```bash
# Check if backend CLIs are installed
which codex
which claude
which gemini
# Install missing backends
# Codex: Follow installation instructions at https://codex.docs
# Claude: Follow installation instructions at https://claude.ai/docs
# Gemini: Follow installation instructions at https://ai.google.dev/docs
which codex && codex --version
which claude && claude --version
which gemini && gemini --version
```
**Unsupported CLI flags:**
```bash
# If you see errors like "unknown flag" or "invalid option"
## FAQ
# Check backend CLI version
codex --version
claude --version
gemini --version
| Issue | Solution |
|-------|----------|
| "Unknown event format" | Logging display issue, can be ignored |
| Gemini can't read .gitignore files | Remove from .gitignore or use different backend |
| `/dev` slow | Check logs, try faster model, use single repo |
| Codex permission denied | Set `approval_policy = "never"` in ~/.codex/config.yaml |
# For Codex: Ensure it supports `e`, `--skip-git-repo-check`, `--json`, `-C`, and `resume`
# For Claude: Ensure it supports `--output-format stream-json`, `--setting-sources`, `-r`
# For Gemini: Ensure it supports `-o stream-json`, `-y`, `-r`, `-p`
# Update your backend CLI to the latest version if needed
```
**JSON parsing errors:**
```bash
# If you see "failed to parse JSON output" errors
# Verify the backend outputs stream-json format
codex e --json "test task" # Should output newline-delimited JSON
claude --output-format stream-json -p "test" # Should output stream JSON
# If not, your backend CLI version may be too old or incompatible
```
**Infinite recursion with Claude backend:**
```bash
# The wrapper prevents this with `--setting-sources ""` flag
# If you still see recursion, ensure your Claude CLI supports this flag
claude --help | grep "setting-sources"
# If flag is not supported, upgrade Claude CLI
```
**Session resume failures:**
```bash
# Check if session ID is valid
codex history # List recent sessions
claude history
# Ensure backend CLI supports session resumption
codex resume <session_id> "test" # Should continue from previous session
claude -r <session_id> "test"
# If not supported, use new sessions instead of resume mode
```
---
## FAQ (Frequently Asked Questions)
### Q1: `codeagent-wrapper` execution fails with "Unknown event format"
**Problem:**
```
Unknown event format: {"type":"turn.started"}
Unknown event format: {"type":"assistant", ...}
```
**Solution:**
This is a logging event format display issue and does not affect actual functionality. It will be fixed in the next version. You can ignore these log outputs.
**Related Issue:** [#96](https://github.com/cexll/myclaude/issues/96)
---
### Q2: Gemini cannot read files ignored by `.gitignore`
**Problem:**
When using `codeagent-wrapper --backend gemini`, files in directories like `.claude/` that are ignored by `.gitignore` cannot be read.
**Solution:**
- **Option 1:** Remove `.claude/` from your `.gitignore` file
- **Option 2:** Ensure files that need to be read are not in `.gitignore` list
**Related Issue:** [#75](https://github.com/cexll/myclaude/issues/75)
---
### Q3: `/dev` command parallel execution is very slow
**Problem:**
Using `/dev` command for simple features takes too long (over 30 minutes) with no visibility into task progress.
**Solution:**
1. **Check logs:** Review `C:\Users\User\AppData\Local\Temp\codeagent-wrapper-*.log` to identify bottlenecks
2. **Adjust backend:**
- Try faster models like `gpt-5.1-codex-max`
- Running in WSL may be significantly faster
3. **Workspace:** Use a single repository instead of monorepo with multiple sub-projects
**Related Issue:** [#77](https://github.com/cexll/myclaude/issues/77)
---
### Q4: Codex permission denied with new Go version
**Problem:**
After upgrading to the new Go-based Codex implementation, execution fails with permission denied errors.
**Solution:**
Add the following configuration to `~/.codex/config.yaml` (Windows: `c:\user\.codex\config.toml`):
```yaml
model = "gpt-5.1-codex-max"
model_reasoning_effort = "high"
model_reasoning_summary = "detailed"
approval_policy = "never"
sandbox_mode = "workspace-write"
disable_response_storage = true
network_access = true
```
**Key settings:**
- `approval_policy = "never"` - Remove approval restrictions
- `sandbox_mode = "workspace-write"` - Allow workspace write access
- `network_access = true` - Enable network access
**Related Issue:** [#31](https://github.com/cexll/myclaude/issues/31)
---
### Q5: How to disable default bypass/skip-permissions mode
**Background:**
By default, codeagent-wrapper enables bypass mode for both Codex and Claude backends:
- `CODEX_BYPASS_SANDBOX=true` - Bypasses Codex sandbox restrictions
- `CODEAGENT_SKIP_PERMISSIONS=true` - Skips Claude permission prompts
**To disable (if you need sandbox/permission protection):**
```bash
export CODEX_BYPASS_SANDBOX=false
export CODEAGENT_SKIP_PERMISSIONS=false
```
Or add to your shell profile (`~/.zshrc` or `~/.bashrc`):
```bash
echo 'export CODEX_BYPASS_SANDBOX=false' >> ~/.zshrc
echo 'export CODEAGENT_SKIP_PERMISSIONS=false' >> ~/.zshrc
```
**Note:** Disabling bypass mode will require manual approval for certain operations.
---
**Still having issues?** Visit [GitHub Issues](https://github.com/cexll/myclaude/issues) to search or report new issues.
---
## Documentation
- **[Codeagent-Wrapper Guide](docs/CODEAGENT-WRAPPER.md)** - Multi-backend execution wrapper
- **[Hooks Documentation](docs/HOOKS.md)** - Custom hooks and automation
### Additional Resources
- **[Installation Log](install.log)** - Installation history and troubleshooting
---
See [GitHub Issues](https://github.com/cexll/myclaude/issues) for more.
## License
AGPL-3.0 License - see [LICENSE](LICENSE)
AGPL-3.0 - see [LICENSE](LICENSE)
## Support
- **Issues**: [GitHub Issues](https://github.com/cexll/myclaude/issues)
- **Documentation**: [docs/](docs/)
---
**Claude Code + Codex = Better Development** - Orchestration meets execution.
- [GitHub Issues](https://github.com/cexll/myclaude/issues)
- [Documentation](docs/)

View File

@@ -2,25 +2,11 @@
[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
[![Claude Code](https://img.shields.io/badge/Claude-Code-blue)](https://claude.ai/code)
[![Version](https://img.shields.io/badge/Version-5.6-green)](https://github.com/cexll/myclaude)
[![Version](https://img.shields.io/badge/Version-6.x-green)](https://github.com/cexll/myclaude)
> AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini)
> AI 驱动的开发自动化 - 多后端执行架构 (Codex/Claude/Gemini/OpenCode)
## 核心概念:多后端架构
本系统采用**双智能体架构**与可插拔 AI 后端:
| 角色 | 智能体 | 职责 |
|------|-------|------|
| **编排者** | Claude Code | 规划、上下文收集、验证、用户交互 |
| **执行者** | codeagent-wrapper | 代码编辑、测试执行Codex/Claude/Gemini 后端)|
**为什么分离?**
- Claude Code 擅长理解上下文和编排复杂工作流
- 专业后端Codex 擅长代码、Claude 擅长推理、Gemini 擅长原型)专注执行
- 通过 `--backend codex|claude|gemini` 匹配模型与任务
## 快速开始windows上请在Powershell中执行
## 快速开始
```bash
git clone https://github.com/cexll/myclaude.git
@@ -28,72 +14,125 @@ cd myclaude
python3 install.py --install-dir ~/.claude
```
## 工作流概览
## 模块概览
### 0. OmO 多智能体编排器(复杂任务推荐)
| 模块 | 描述 | 文档 |
|------|------|------|
| [do](skills/do/README.md) | **推荐** - 7 阶段功能开发 + codeagent 编排 | `/do` 命令 |
| [dev](dev-workflow/README.md) | 轻量级开发工作流 + Codex 集成 | `/dev` 命令 |
| [omo](skills/omo/README.md) | 多智能体编排 + 智能路由 | `/omo` 命令 |
| [bmad](bmad-agile-workflow/README.md) | BMAD 敏捷工作流 + 6 个专业智能体 | `/bmad-pilot` 命令 |
| [requirements](requirements-driven-workflow/README.md) | 轻量级需求到代码流水线 | `/requirements-pilot` 命令 |
| [essentials](development-essentials/README.md) | 核心开发命令和工具 | `/code`, `/debug` 等 |
| [sparv](skills/sparv/README.md) | SPARV 工作流 (Specify→Plan→Act→Review→Vault) | `/sparv` 命令 |
| course | 课程开发(组合 dev + product-requirements + test-cases | 组合模块 |
**基于风险信号智能路由任务到专业智能体的多智能体编排系统。**
## 核心架构
| 角色 | 智能体 | 职责 |
|------|-------|------|
| **编排者** | Claude Code | 规划、上下文收集、验证 |
| **执行者** | codeagent-wrapper | 代码编辑、测试执行Codex/Claude/Gemini/OpenCode 后端)|
## 工作流详解
### do 工作流(推荐)
7 阶段功能开发,通过 codeagent-wrapper 编排多个智能体。**大多数功能开发任务的首选工作流。**
```bash
/omo "分析并修复这个认证 bug"
/do "添加用户登录功能"
```
**智能体层级**
| 智能体 | 角色 | 后端 | 模型 |
|-------|------|------|------|
| `oracle` | 技术顾问 | Claude | claude-opus-4-5 |
| `librarian` | 外部研究 | Claude | claude-sonnet-4-5 |
| `explore` | 代码库搜索 | OpenCode | grok-code |
| `develop` | 代码实现 | Codex | gpt-5.2 |
| `frontend-ui-ux-engineer` | UI/UX 专家 | Gemini | gemini-3-pro |
| `document-writer` | 文档撰写 | Gemini | gemini-3-flash |
**7 阶段**
| 阶段 | 名称 | 目标 |
|------|------|------|
| 1 | Discovery | 理解需求 |
| 2 | Exploration | 映射代码库模式 |
| 3 | Clarification | 解决歧义(**强制**|
| 4 | Architecture | 设计实现方案 |
| 5 | Implementation | 构建功能(**需审批**|
| 6 | Review | 捕获缺陷 |
| 7 | Summary | 记录结果 |
**路由信号(非固定流水线)**
- 代码位置不明确 → `explore`
- 外部库/API → `librarian`
- 高风险/多文件变更 → `oracle`
- 需要实现 → `develop` / `frontend-ui-ux-engineer`
**常用配方:**
- 解释代码:`explore`
- 位置已知的小修复:直接 `develop`
- Bug 修复,位置未知:`explore → develop`
- 跨模块重构:`explore → oracle → develop`
- 外部 API 集成:`explore + librarian → oracle → develop`
**适用场景:** 复杂 bug 调查、多文件重构、架构决策
**智能体**
- `code-explorer` - 代码追踪、架构映射
- `code-architect` - 设计方案、文件规划
- `code-reviewer` - 代码审查、简化建议
- `develop` - 实现代码、运行测试
---
### 1. Dev 工作流(推荐)
### Dev 工作流
**大多数开发任务的首选工作流。**
轻量级开发工作流,适合简单功能开发。
```bash
/dev "实现 JWT 用户认证"
```
**6 步流程:**
1. **需求澄清** - 交互式问答明确范围
2. **Codex 深度分析** - 代码库探索和架构决策
3. **开发计划生成** - 结构化任务分解和测试要求
4. **并行执行** - Codex 并发执行任务
5. **覆盖率验证** - 强制 ≥90% 测试覆盖率
6. **完成总结** - 文件变更和覆盖率报告
**核心特性:**
- Claude Code 编排Codex 执行所有代码变更
- 自动任务并行化提升速度
- 强制 90% 测试覆盖率门禁
- 失败自动回滚
**适用场景:** 功能开发、重构、带测试的 bug 修复
1. 需求澄清 - 交互式问答
2. Codex 深度分析 - 代码库探索
3. 开发计划生成 - 结构化任务分解
4. 并行执行 - Codex 并发执行
5. 覆盖率验证 - 强制 ≥90%
6. 完成总结 - 报告生成
---
### 2. BMAD 敏捷工作流
### OmO 多智能体编排器
**包含 6 个专业智能体的完整企业敏捷方法论。**
基于风险信号智能路由任务到专业智能体。
```bash
/omo "分析并修复这个认证 bug"
```
**智能体层级:**
| 智能体 | 角色 | 后端 |
|-------|------|------|
| `oracle` | 技术顾问 | Claude |
| `librarian` | 外部研究 | Claude |
| `explore` | 代码库搜索 | OpenCode |
| `develop` | 代码实现 | Codex |
| `frontend-ui-ux-engineer` | UI/UX 专家 | Gemini |
| `document-writer` | 文档撰写 | Gemini |
**常用配方:**
- 解释代码:`explore`
- 位置已知的小修复:直接 `develop`
- Bug 修复(位置未知):`explore → develop`
- 跨模块重构:`explore → oracle → develop`
---
### SPARV 工作流
极简 5 阶段工作流Specify → Plan → Act → Review → Vault。
```bash
/sparv "实现订单导出功能"
```
**核心规则:**
- **10 分规格门**:得分 0-10必须 >=9 才能进入 Plan
- **2 动作保存**:每 2 次工具调用写入 journal.md
- **3 失败协议**:连续 3 次失败后停止并上报
- **EHRB**:高风险操作需明确确认
**评分维度(各 0-2 分):**
1. Value - 为什么做,可验证的收益
2. Scope - MVP + 不在范围内的内容
3. Acceptance - 可测试的验收标准
4. Boundaries - 错误/性能/兼容/安全边界
5. Risk - EHRB/依赖/未知 + 处理方式
---
### BMAD 敏捷工作流
完整企业敏捷方法论 + 6 个专业智能体。
```bash
/bmad-pilot "构建电商结账系统"
@@ -104,43 +143,36 @@ python3 install.py --install-dir ~/.claude
|-------|------|
| Product Owner | 需求与用户故事 |
| Architect | 系统设计与技术决策 |
| Tech Lead | Sprint 规划与任务分解 |
| Scrum Master | Sprint 规划与任务分解 |
| Developer | 实现 |
| Code Reviewer | 质量保证 |
| QA Engineer | 测试与验证 |
**流程**
```
需求 → 架构 → Sprint计划 → 开发 → 审查 → QA
↓ ↓ ↓ ↓ ↓ ↓
PRD.md DESIGN.md SPRINT.md Code REVIEW.md TEST.md
```
**适用场景:** 大型功能、团队协作、企业项目
**审批门**
- PRD 完成后90+ 分)需用户审批
- 架构完成后90+ 分)需用户审批
---
### 3. 需求驱动工作流
### 需求驱动工作流
**轻量级需求到代码流水线。**
轻量级需求到代码流水线。
```bash
/requirements-pilot "实现 API 限流"
```
**流程**
1. 带质量评分的需求生成
2. 实现规划
3. 代码生成
4. 审查和测试
**适用场景:** 快速原型、明确定义的功能
**100 分质量评分**
- 功能清晰度30 分
- 技术具体性25 分
- 实现完整性25 分
- 业务上下文20 分
---
### 4. 开发基础命令
### 开发基础命令
**日常编码任务的直接命令。**
日常编码任务的直接命令。
| 命令 | 用途 |
|------|------|
@@ -152,16 +184,12 @@ PRD.md DESIGN.md SPRINT.md Code REVIEW.md TEST.md
| `/refactor` | 代码重构 |
| `/docs` | 编写文档 |
**适用场景:** 快速任务,无需工作流开销
---
## 安装
### 模块化安装(推荐)
```bash
# 安装所有启用的模块默认dev + essentials
# 安装所有启用的模块
python3 install.py --install-dir ~/.claude
# 安装特定模块
@@ -170,314 +198,77 @@ python3 install.py --module dev
# 列出可用模块
python3 install.py --list-modules
# 强制覆盖现有文件
# 强制覆盖
python3 install.py --force
```
### 可用模块
### 模块配置
| 模块 | 默认 | 描述 |
|------|------|------|
| `dev` | ✓ 启用 | Dev 工作流 + Codex 集成 |
| `essentials` | ✓ 启用 | 核心开发命令 |
| `bmad` | 禁用 | 完整 BMAD 敏捷工作流 |
| `requirements` | 禁用 | 需求驱动工作流 |
### 安装内容
```
~/.claude/
├── bin/
│ └── codeagent-wrapper # 主可执行文件
├── CLAUDE.md # 核心指令和角色定义
├── commands/ # 斜杠命令 (/dev, /code 等)
├── agents/ # 智能体定义
├── skills/
│ └── codex/
│ └── SKILL.md # Codex 集成技能
├── config.json # 配置文件
└── installed_modules.json # 安装状态
```
### 自定义安装目录
默认情况下myclaude 安装到 `~/.claude`。您可以使用 `INSTALL_DIR` 环境变量自定义安装目录:
```bash
# 安装到自定义目录
INSTALL_DIR=/opt/myclaude bash install.sh
# 相应更新您的 PATH
export PATH="/opt/myclaude/bin:$PATH"
```
**目录结构:**
- `$INSTALL_DIR/bin/` - codeagent-wrapper 可执行文件
- `$INSTALL_DIR/skills/` - 技能定义
- `$INSTALL_DIR/config.json` - 配置文件
- `$INSTALL_DIR/commands/` - 斜杠命令定义
- `$INSTALL_DIR/agents/` - 智能体定义
**注意:** 使用自定义安装目录时,请确保将 `$INSTALL_DIR/bin` 添加到您的 `PATH` 环境变量中。
### 配置
编辑 `config.json` 自定义:
编辑 `config.json` 启用/禁用模块:
```json
{
"version": "1.0",
"install_dir": "~/.claude",
"modules": {
"dev": {
"enabled": true,
"operations": [
{"type": "merge_dir", "source": "dev-workflow"},
{"type": "copy_file", "source": "memorys/CLAUDE.md", "target": "CLAUDE.md"},
{"type": "copy_file", "source": "skills/codex/SKILL.md", "target": "skills/codex/SKILL.md"},
{"type": "run_command", "command": "bash install.sh"}
]
}
"dev": { "enabled": true },
"bmad": { "enabled": false },
"requirements": { "enabled": false },
"essentials": { "enabled": false },
"omo": { "enabled": false },
"sparv": { "enabled": false },
"do": { "enabled": false },
"course": { "enabled": false }
}
}
```
**操作类型:**
| 类型 | 描述 |
|------|------|
| `merge_dir` | 合并子目录 (commands/, agents/) 到安装目录 |
| `copy_dir` | 复制整个目录 |
| `copy_file` | 复制单个文件到目标路径 |
| `run_command` | 执行 shell 命令 |
---
## Codex 集成
`codex` 技能使 Claude Code 能够将代码执行委托给 Codex CLI。
### 工作流中的使用
```bash
# 通过技能调用 Codex
codeagent-wrapper - <<'EOF'
在 @src/auth.ts 中实现 JWT 验证
EOF
```
### 并行执行
```bash
codeagent-wrapper --parallel <<'EOF'
---TASK---
id: backend_api
workdir: /project/backend
---CONTENT---
实现 /api/users 的 REST 端点
---TASK---
id: frontend_ui
workdir: /project/frontend
dependencies: backend_api
---CONTENT---
创建消费 API 的 React 组件
EOF
```
### 安装 Codex Wrapper
```bash
# 自动(通过 dev 模块)
python3 install.py --module dev
# 手动
bash install.sh
```
#### Windows 系统
Windows 系统会将 `codeagent-wrapper.exe` 安装到 `%USERPROFILE%\bin`
```powershell
# PowerShell推荐
powershell -ExecutionPolicy Bypass -File install.ps1
# 批处理cmd
install.bat
```
**添加到 PATH**(如果安装程序未自动检测):
```powershell
# PowerShell - 永久添加(当前用户)
[Environment]::SetEnvironmentVariable('PATH', "$HOME\bin;" + [Environment]::GetEnvironmentVariable('PATH','User'), 'User')
# PowerShell - 仅当前会话
$Env:PATH = "$HOME\bin;$Env:PATH"
```
```batch
REM cmd.exe - 永久添加(当前用户)(建议使用上面的 PowerShell 方法)
REM 警告:此命令会展开 %PATH% 包含系统 PATH导致重复
REM 注意:使用 reg add 而非 setx 以避免 1024 字符截断限制
reg add "HKCU\Environment" /v Path /t REG_EXPAND_SZ /d "%USERPROFILE%\bin;%PATH%" /f
```
---
## 工作流选择指南
| 场景 | 推荐工作流 |
|------|----------|
| 带测试的新功能 | `/dev` |
| 快速 bug 修复 | `/debug``/code` |
| 大型多 Sprint 功能 | `/bmad-pilot` |
| 原型或 POC | `/requirements-pilot` |
| 代码审查 | `/review` |
| 性能问题 | `/optimize` |
| 场景 | 推荐 |
|------|------|
| 功能开发(默认) | `/do` |
| 轻量级功能 | `/dev` |
| Bug 调查 + 修复 | `/omo` |
| 大型企业项目 | `/bmad-pilot` |
| 快速原型 | `/requirements-pilot` |
| 简单任务 | `/code`, `/debug` |
---
## 后端 CLI 要求
| 后端 | 必需功能 |
|------|----------|
| Codex | `codex e`, `--json`, `-C`, `resume` |
| Claude | `--output-format stream-json`, `-r` |
| Gemini | `-o stream-json`, `-y`, `-r` |
## 故障排查
### 常见问题
**Codex wrapper 未找到:**
```bash
# 安装程序会自动添加 PATH检查是否已添加
if [[ ":$PATH:" != *":$HOME/.claude/bin:"* ]]; then
echo "PATH not configured. Reinstalling..."
bash install.sh
fi
# 或手动添加(幂等性命令)
[[ ":$PATH:" != *":$HOME/.claude/bin:"* ]] && echo 'export PATH="$HOME/.claude/bin:$PATH"' >> ~/.zshrc
```
**权限被拒绝:**
```bash
python3 install.py --install-dir ~/.claude --force
bash install.sh
```
**模块未加载:**
```bash
# 检查安装状态
cat ~/.claude/installed_modules.json
# 重新安装特定模块
python3 install.py --module dev --force
python3 install.py --module <name> --force
```
---
## FAQ
## 常见问题 (FAQ)
| 问题 | 解决方案 |
|------|----------|
| "Unknown event format" | 日志显示问题,可忽略 |
| Gemini 无法读取 .gitignore 文件 | 从 .gitignore 移除或使用其他后端 |
| `/dev` 执行慢 | 检查日志,尝试更快模型,使用单一仓库 |
| Codex 权限拒绝 | 在 ~/.codex/config.yaml 设置 `approval_policy = "never"` |
### Q1: `codeagent-wrapper` 执行时报错 "Unknown event format"
**问题描述:**
执行 `codeagent-wrapper` 时出现错误:
```
Unknown event format: {"type":"turn.started"}
Unknown event format: {"type":"assistant", ...}
```
**解决方案:**
这是日志事件流的显示问题,不影响实际功能执行。预计在下个版本中修复。如需排查其他问题,可忽略此日志输出。
**相关 Issue** [#96](https://github.com/cexll/myclaude/issues/96)
---
### Q2: Gemini 无法读取 `.gitignore` 忽略的文件
**问题描述:**
使用 `codeagent-wrapper --backend gemini` 时,无法读取 `.claude/` 等被 `.gitignore` 忽略的目录中的文件。
**解决方案:**
- **方案一:** 在项目根目录的 `.gitignore` 中取消对 `.claude/` 的忽略
- **方案二:** 确保需要读取的文件不在 `.gitignore` 忽略列表中
**相关 Issue** [#75](https://github.com/cexll/myclaude/issues/75)
---
### Q3: `/dev` 命令并行执行特别慢
**问题描述:**
使用 `/dev` 命令开发简单功能耗时过长超过30分钟无法了解任务执行状态。
**解决方案:**
1. **检查日志:** 查看 `C:\Users\User\AppData\Local\Temp\codeagent-wrapper-*.log` 分析瓶颈
2. **调整后端:**
- 尝试使用 `gpt-5.1-codex-max` 等更快的模型
- 在 WSL 环境下运行速度可能更快
3. **工作区选择:** 使用独立的代码仓库而非包含多个子项目的 monorepo
**相关 Issue** [#77](https://github.com/cexll/myclaude/issues/77)
---
### Q4: 新版 Go 实现的 Codex 权限不足
**问题描述:**
升级到新版 Go 实现的 Codex 后,出现权限不足的错误。
**解决方案:**
`~/.codex/config.yaml` 中添加以下配置Windows: `c:\user\.codex\config.toml`
```yaml
model = "gpt-5.1-codex-max"
model_reasoning_effort = "high"
model_reasoning_summary = "detailed"
approval_policy = "never"
sandbox_mode = "workspace-write"
disable_response_storage = true
network_access = true
```
**关键配置说明:**
- `approval_policy = "never"` - 移除审批限制
- `sandbox_mode = "workspace-write"` - 允许工作区写入权限
- `network_access = true` - 启用网络访问
**相关 Issue** [#31](https://github.com/cexll/myclaude/issues/31)
---
### Q5: 执行时遇到权限拒绝或沙箱限制
**问题描述:**
运行 codeagent-wrapper 时出现权限错误或沙箱限制。
**解决方案:**
设置以下环境变量:
```bash
export CODEX_BYPASS_SANDBOX=true
export CODEAGENT_SKIP_PERMISSIONS=true
```
或添加到 shell 配置文件(`~/.zshrc``~/.bashrc`
```bash
echo 'export CODEX_BYPASS_SANDBOX=true' >> ~/.zshrc
echo 'export CODEAGENT_SKIP_PERMISSIONS=true' >> ~/.zshrc
```
**注意:** 这些设置会绕过安全限制,请仅在可信环境中使用。
---
**仍有疑问?** 请访问 [GitHub Issues](https://github.com/cexll/myclaude/issues) 搜索或提交新问题。
---
更多问题请访问 [GitHub Issues](https://github.com/cexll/myclaude/issues)。
## 许可证
AGPL-3.0 License - 查看 [LICENSE](LICENSE)
AGPL-3.0 - 查看 [LICENSE](LICENSE)
## 支持
- **问题反馈**: [GitHub Issues](https://github.com/cexll/myclaude/issues)
- **文档**: [docs/](docs/)
---
**Claude Code + Codex = 更好的开发** - 编排遇见执行。
- [GitHub Issues](https://github.com/cexll/myclaude/issues)
- [文档](docs/)

View File

@@ -0,0 +1,109 @@
# bmad - BMAD Agile Workflow
Full enterprise agile methodology with 6 specialized agents, UltraThink analysis, and repository-aware development.
## Installation
```bash
python install.py --module bmad
```
## Usage
```bash
/bmad-pilot <PROJECT_DESCRIPTION> [OPTIONS]
```
### Options
| Option | Description |
|--------|-------------|
| `--skip-tests` | Skip QA testing phase |
| `--direct-dev` | Skip SM planning, go directly to development |
| `--skip-scan` | Skip initial repository scanning |
## Workflow Phases
| Phase | Agent | Deliverable | Description |
|-------|-------|-------------|-------------|
| 0 | Orchestrator | `00-repo-scan.md` | Repository scanning with UltraThink analysis |
| 1 | Product Owner (PO) | `01-product-requirements.md` | PRD with 90+ quality score required |
| 2 | Architect | `02-system-architecture.md` | Technical design with 90+ score required |
| 3 | Scrum Master (SM) | `03-sprint-plan.md` | Sprint backlog with stories and estimates |
| 4 | Developer | Implementation code | Multi-sprint implementation |
| 4.5 | Reviewer | `04-dev-reviewed.md` | Code review (Pass/Pass with Risk/Fail) |
| 5 | QA Engineer | Test suite | Comprehensive testing and validation |
## Agents
| Agent | Role |
|-------|------|
| `bmad-orchestrator` | Repository scanning, workflow coordination |
| `bmad-po` | Requirements gathering, PRD creation |
| `bmad-architect` | System design, technology decisions |
| `bmad-sm` | Sprint planning, task breakdown |
| `bmad-dev` | Code implementation |
| `bmad-review` | Code review, quality assessment |
| `bmad-qa` | Testing, validation |
## Approval Gates
Two mandatory stop points require explicit user approval:
1. **After PRD** (Phase 1 → 2): User must approve requirements before architecture
2. **After Architecture** (Phase 2 → 3): User must approve design before implementation
## Output Structure
```
.claude/specs/{feature_name}/
├── 00-repo-scan.md
├── 01-product-requirements.md
├── 02-system-architecture.md
├── 03-sprint-plan.md
└── 04-dev-reviewed.md
```
## UltraThink Methodology
Applied throughout the workflow for deep analysis:
1. **Hypothesis Generation** - Form hypotheses about the problem
2. **Evidence Collection** - Gather evidence from codebase
3. **Pattern Recognition** - Identify recurring patterns
4. **Synthesis** - Create comprehensive understanding
5. **Validation** - Cross-check findings
## Interactive Confirmation Flow
PO and Architect phases use iterative refinement:
1. Agent produces initial draft + quality score
2. Orchestrator presents to user with clarification questions
3. User provides responses
4. Agent refines until quality >= 90
5. User confirms to save deliverable
## When to Use
- Large multi-sprint features
- Enterprise projects requiring documentation
- Team coordination scenarios
- Projects needing formal approval gates
## Directory Structure
```
bmad-agile-workflow/
├── README.md
├── commands/
│ └── bmad-pilot.md
└── agents/
├── bmad-orchestrator.md
├── bmad-po.md
├── bmad-architect.md
├── bmad-sm.md
├── bmad-dev.md
├── bmad-review.md
└── bmad-qa.md
```

View File

@@ -2,8 +2,8 @@
bin/
codeagent
codeagent.exe
codeagent-wrapper
codeagent-wrapper.exe
/codeagent-wrapper
/codeagent-wrapper.exe
*.test
# Coverage reports

View File

@@ -1,8 +1,5 @@
GO ?= go
BINARY ?= codeagent
CMD_PKG := ./cmd/codeagent
TOOLS_BIN := $(CURDIR)/bin
TOOLCHAIN ?= go1.22.0
GOLANGCI_LINT_VERSION := v1.56.2
@@ -14,7 +11,8 @@ STATICCHECK := $(TOOLS_BIN)/staticcheck
.PHONY: build test lint clean install
build:
$(GO) build -o $(BINARY) $(CMD_PKG)
$(GO) build -o codeagent ./cmd/codeagent
$(GO) build -o codeagent-wrapper ./cmd/codeagent-wrapper
test:
$(GO) test ./...
@@ -35,4 +33,5 @@ clean:
@python3 -c 'import glob, os; paths=["codeagent","codeagent.exe","codeagent-wrapper","codeagent-wrapper.exe","coverage.out","cover.out","coverage.html"]; paths += glob.glob("coverage*.out") + glob.glob("cover_*.out") + glob.glob("*.test"); [os.remove(p) for p in paths if os.path.exists(p)]'
install:
$(GO) install $(CMD_PKG)
$(GO) install ./cmd/codeagent
$(GO) install ./cmd/codeagent-wrapper

View File

@@ -2,7 +2,7 @@
`codeagent-wrapper` 是一个用 Go 编写的“多后端 AI 代码代理”命令行包装器:用统一的 CLI 入口封装不同的 AI 工具后端Codex / Claude / Gemini / Opencode并提供一致的参数、配置与会话恢复体验。
入口:`cmd/codeagent/main.go`(生成二进制名:`codeagent`)。
入口:`cmd/codeagent/main.go`(生成二进制名:`codeagent``cmd/codeagent-wrapper/main.go`(生成二进制名:`codeagent-wrapper`)。两者行为一致
## 功能特性
@@ -22,12 +22,14 @@
```bash
go install ./cmd/codeagent
go install ./cmd/codeagent-wrapper
```
安装后确认:
```bash
codeagent version
codeagent-wrapper version
```
## 使用示例
@@ -148,4 +150,3 @@ make test
make lint
make clean
```

View File

@@ -10,7 +10,7 @@ import (
)
const (
version = "6.0.0-alpha1"
version = "6.1.2"
defaultWorkdir = "."
defaultTimeout = 7200 // seconds (2 hours)
defaultCoverageTarget = 90.0
@@ -24,7 +24,7 @@ const (
stdoutCloseReasonWait = "wait-done"
stdoutCloseReasonDrain = "drain-timeout"
stdoutCloseReasonCtx = "context-cancel"
stdoutDrainTimeout = 100 * time.Millisecond
stdoutDrainTimeout = 500 * time.Millisecond
)
// Test hooks for dependency injection

View File

@@ -635,6 +635,7 @@ func runSingleMode(cfg *Config, name string) int {
WorkDir: cfg.WorkDir,
Mode: cfg.Mode,
SessionID: cfg.SessionID,
Backend: cfg.Backend,
Model: cfg.Model,
ReasoningEffort: cfg.ReasoningEffort,
Agent: cfg.Agent,

View File

@@ -3698,10 +3698,8 @@ func TestVersionFlag(t *testing.T) {
}
})
want := "codeagent-wrapper version 6.0.0-alpha1\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
if !strings.HasPrefix(output, "codeagent-wrapper version ") {
t.Fatalf("output = %q, want prefix %q", output, "codeagent-wrapper version ")
}
}
@@ -3714,10 +3712,8 @@ func TestVersionShortFlag(t *testing.T) {
}
})
want := "codeagent-wrapper version 6.0.0-alpha1\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
if !strings.HasPrefix(output, "codeagent-wrapper version ") {
t.Fatalf("output = %q, want prefix %q", output, "codeagent-wrapper version ")
}
}
@@ -3730,10 +3726,8 @@ func TestVersionLegacyAlias(t *testing.T) {
}
})
want := "codeagent-wrapper version 6.0.0-alpha1\n"
if output != want {
t.Fatalf("output = %q, want %q", output, want)
if !strings.HasPrefix(output, "codeagent-wrapper version ") {
t.Fatalf("output = %q, want prefix %q", output, "codeagent-wrapper version ")
}
}

View File

@@ -25,7 +25,7 @@ func (ClaudeBackend) Env(baseURL, apiKey string) map[string]string {
env["ANTHROPIC_BASE_URL"] = baseURL
}
if apiKey != "" {
env["ANTHROPIC_API_KEY"] = apiKey
env["ANTHROPIC_AUTH_TOKEN"] = apiKey
}
return env
}

View File

@@ -0,0 +1,193 @@
package executor
import (
"os"
"path/filepath"
"strings"
"testing"
backend "codeagent-wrapper/internal/backend"
config "codeagent-wrapper/internal/config"
)
// TestEnvInjectionWithAgent tests the full flow of env injection with agent config
func TestEnvInjectionWithAgent(t *testing.T) {
// Setup temp config
tmpDir := t.TempDir()
configDir := filepath.Join(tmpDir, ".codeagent")
if err := os.MkdirAll(configDir, 0755); err != nil {
t.Fatal(err)
}
// Write test config with agent that has base_url and api_key
configContent := `{
"default_backend": "codex",
"agents": {
"test-agent": {
"backend": "claude",
"model": "test-model",
"base_url": "https://test.api.com",
"api_key": "test-api-key-12345678"
}
}
}`
configPath := filepath.Join(configDir, "models.json")
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
t.Fatal(err)
}
// Override HOME to use temp dir
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", oldHome)
// Reset config cache
config.ResetModelsConfigCacheForTest()
defer config.ResetModelsConfigCacheForTest()
// Test ResolveAgentConfig
agentBackend, model, _, _, baseURL, apiKey, _ := config.ResolveAgentConfig("test-agent")
t.Logf("ResolveAgentConfig: backend=%q, model=%q, baseURL=%q, apiKey=%q",
agentBackend, model, baseURL, apiKey)
if agentBackend != "claude" {
t.Errorf("expected backend 'claude', got %q", agentBackend)
}
if baseURL != "https://test.api.com" {
t.Errorf("expected baseURL 'https://test.api.com', got %q", baseURL)
}
if apiKey != "test-api-key-12345678" {
t.Errorf("expected apiKey 'test-api-key-12345678', got %q", apiKey)
}
// Test Backend.Env
b := backend.ClaudeBackend{}
env := b.Env(baseURL, apiKey)
t.Logf("Backend.Env: %v", env)
if env == nil {
t.Fatal("expected non-nil env from Backend.Env")
}
if env["ANTHROPIC_BASE_URL"] != baseURL {
t.Errorf("expected ANTHROPIC_BASE_URL=%q, got %q", baseURL, env["ANTHROPIC_BASE_URL"])
}
if env["ANTHROPIC_AUTH_TOKEN"] != apiKey {
t.Errorf("expected ANTHROPIC_AUTH_TOKEN=%q, got %q", apiKey, env["ANTHROPIC_AUTH_TOKEN"])
}
}
// TestEnvInjectionLogic tests the exact logic used in executor
func TestEnvInjectionLogic(t *testing.T) {
// Setup temp config
tmpDir := t.TempDir()
configDir := filepath.Join(tmpDir, ".codeagent")
if err := os.MkdirAll(configDir, 0755); err != nil {
t.Fatal(err)
}
configContent := `{
"default_backend": "codex",
"agents": {
"explore": {
"backend": "claude",
"model": "MiniMax-M2.1",
"base_url": "https://api.minimaxi.com/anthropic",
"api_key": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.test"
}
}
}`
configPath := filepath.Join(configDir, "models.json")
if err := os.WriteFile(configPath, []byte(configContent), 0644); err != nil {
t.Fatal(err)
}
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tmpDir)
defer os.Setenv("HOME", oldHome)
config.ResetModelsConfigCacheForTest()
defer config.ResetModelsConfigCacheForTest()
// Simulate the executor logic
cfgBackend := "claude" // This should come from taskSpec.Backend
agentName := "explore"
// Step 1: Get backend config (usually empty for claude without global config)
baseURL, apiKey := config.ResolveBackendConfig(cfgBackend)
t.Logf("Step 1 - ResolveBackendConfig(%q): baseURL=%q, apiKey=%q", cfgBackend, baseURL, apiKey)
// Step 2: If agent specified, get agent config
if agentName != "" {
agentBackend, _, _, _, agentBaseURL, agentAPIKey, _ := config.ResolveAgentConfig(agentName)
t.Logf("Step 2 - ResolveAgentConfig(%q): backend=%q, baseURL=%q, apiKey=%q",
agentName, agentBackend, agentBaseURL, agentAPIKey)
// Step 3: Check if agent backend matches cfg backend
if strings.EqualFold(strings.TrimSpace(agentBackend), strings.TrimSpace(cfgBackend)) {
baseURL, apiKey = agentBaseURL, agentAPIKey
t.Logf("Step 3 - Backend match! Using agent config: baseURL=%q, apiKey=%q", baseURL, apiKey)
} else {
t.Logf("Step 3 - Backend mismatch: agent=%q, cfg=%q", agentBackend, cfgBackend)
}
}
// Step 4: Get env vars from backend
b := backend.ClaudeBackend{}
injected := b.Env(baseURL, apiKey)
t.Logf("Step 4 - Backend.Env: %v", injected)
// Verify
if len(injected) == 0 {
t.Fatal("Expected env vars to be injected, got none")
}
expectedURL := "https://api.minimaxi.com/anthropic"
if injected["ANTHROPIC_BASE_URL"] != expectedURL {
t.Errorf("ANTHROPIC_BASE_URL: expected %q, got %q", expectedURL, injected["ANTHROPIC_BASE_URL"])
}
if _, ok := injected["ANTHROPIC_AUTH_TOKEN"]; !ok {
t.Error("ANTHROPIC_AUTH_TOKEN not set")
}
// Step 5: Test masking
for k, v := range injected {
masked := maskSensitiveValue(k, v)
t.Logf("Step 5 - Env log: %s=%s", k, masked)
}
}
// TestTaskSpecBackendPropagation tests that taskSpec.Backend is properly used
func TestTaskSpecBackendPropagation(t *testing.T) {
// Simulate what happens in RunCodexTaskWithContext
taskSpec := TaskSpec{
ID: "test",
Task: "hello",
Backend: "claude",
Agent: "explore",
}
// This is the logic from executor.go lines 889-916
cfg := &config.Config{
Mode: "new",
Task: taskSpec.Task,
Backend: "codex", // default
}
var backend Backend = nil // nil in single mode
commandName := "codex" // default
if backend != nil {
cfg.Backend = backend.Name()
} else if taskSpec.Backend != "" {
cfg.Backend = taskSpec.Backend
} else if commandName != "" {
cfg.Backend = commandName
}
t.Logf("taskSpec.Backend=%q, cfg.Backend=%q", taskSpec.Backend, cfg.Backend)
if cfg.Backend != "claude" {
t.Errorf("expected cfg.Backend='claude', got %q", cfg.Backend)
}
}

View File

@@ -0,0 +1,333 @@
package executor
import (
"strings"
"testing"
backend "codeagent-wrapper/internal/backend"
)
func TestMaskSensitiveValue(t *testing.T) {
tests := []struct {
name string
key string
value string
expected string
}{
{
name: "API_KEY with long value",
key: "ANTHROPIC_AUTH_TOKEN",
value: "sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
expected: "sk-a****xxxx",
},
{
name: "api_key lowercase",
key: "api_key",
value: "abcdefghijklmnop",
expected: "abcd****mnop",
},
{
name: "AUTH_TOKEN",
key: "AUTH_TOKEN",
value: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9",
expected: "eyJh****VCJ9",
},
{
name: "SECRET",
key: "MY_SECRET",
value: "super-secret-value-12345",
expected: "supe****2345",
},
{
name: "short key value (8 chars)",
key: "API_KEY",
value: "12345678",
expected: "****",
},
{
name: "very short key value",
key: "API_KEY",
value: "abc",
expected: "****",
},
{
name: "empty key value",
key: "API_KEY",
value: "",
expected: "",
},
{
name: "non-sensitive BASE_URL",
key: "ANTHROPIC_BASE_URL",
value: "https://api.anthropic.com",
expected: "https://api.anthropic.com",
},
{
name: "non-sensitive MODEL",
key: "MODEL",
value: "claude-3-opus",
expected: "claude-3-opus",
},
{
name: "case insensitive - Key",
key: "My_Key",
value: "1234567890abcdef",
expected: "1234****cdef",
},
{
name: "case insensitive - TOKEN",
key: "ACCESS_TOKEN",
value: "access123456789",
expected: "acce****6789",
},
{
name: "partial match - apikey",
key: "MYAPIKEY",
value: "1234567890",
expected: "1234****7890",
},
{
name: "partial match - secretvalue",
key: "SECRETVALUE",
value: "abcdefghij",
expected: "abcd****ghij",
},
{
name: "9 char value (just above threshold)",
key: "API_KEY",
value: "123456789",
expected: "1234****6789",
},
{
name: "exactly 8 char value (at threshold)",
key: "API_KEY",
value: "12345678",
expected: "****",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := maskSensitiveValue(tt.key, tt.value)
if result != tt.expected {
t.Errorf("maskSensitiveValue(%q, %q) = %q, want %q", tt.key, tt.value, result, tt.expected)
}
})
}
}
func TestMaskSensitiveValue_NoLeakage(t *testing.T) {
// Ensure sensitive values are never fully exposed
sensitiveKeys := []string{"API_KEY", "api_key", "AUTH_TOKEN", "SECRET", "access_token", "MYAPIKEY"}
longValue := "this-is-a-very-long-secret-value-that-should-be-masked"
for _, key := range sensitiveKeys {
t.Run(key, func(t *testing.T) {
masked := maskSensitiveValue(key, longValue)
// Should not contain the full value
if masked == longValue {
t.Errorf("key %q: value was not masked", key)
}
// Should contain mask marker
if !strings.Contains(masked, "****") {
t.Errorf("key %q: masked value %q does not contain ****", key, masked)
}
// First 4 chars should be visible
if !strings.HasPrefix(masked, longValue[:4]) {
t.Errorf("key %q: masked value should start with first 4 chars", key)
}
// Last 4 chars should be visible
if !strings.HasSuffix(masked, longValue[len(longValue)-4:]) {
t.Errorf("key %q: masked value should end with last 4 chars", key)
}
})
}
}
func TestMaskSensitiveValue_NonSensitivePassthrough(t *testing.T) {
// Non-sensitive keys should pass through unchanged
nonSensitiveKeys := []string{
"ANTHROPIC_BASE_URL",
"BASE_URL",
"MODEL",
"BACKEND",
"WORKDIR",
"HOME",
"PATH",
}
value := "any-value-here-12345"
for _, key := range nonSensitiveKeys {
t.Run(key, func(t *testing.T) {
result := maskSensitiveValue(key, value)
if result != value {
t.Errorf("key %q: expected passthrough but got %q", key, result)
}
})
}
}
// TestClaudeBackendEnv tests that ClaudeBackend.Env returns correct env vars
func TestClaudeBackendEnv(t *testing.T) {
tests := []struct {
name string
baseURL string
apiKey string
expectKeys []string
expectNil bool
}{
{
name: "both base_url and api_key",
baseURL: "https://api.custom.com",
apiKey: "sk-test-key-12345",
expectKeys: []string{"ANTHROPIC_BASE_URL", "ANTHROPIC_AUTH_TOKEN"},
},
{
name: "only base_url",
baseURL: "https://api.custom.com",
apiKey: "",
expectKeys: []string{"ANTHROPIC_BASE_URL"},
},
{
name: "only api_key",
baseURL: "",
apiKey: "sk-test-key-12345",
expectKeys: []string{"ANTHROPIC_AUTH_TOKEN"},
},
{
name: "both empty",
baseURL: "",
apiKey: "",
expectNil: true,
},
{
name: "whitespace only",
baseURL: " ",
apiKey: " ",
expectNil: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := backend.ClaudeBackend{}
env := b.Env(tt.baseURL, tt.apiKey)
if tt.expectNil {
if env != nil {
t.Errorf("expected nil env, got %v", env)
}
return
}
if env == nil {
t.Fatal("expected non-nil env")
}
for _, key := range tt.expectKeys {
if _, ok := env[key]; !ok {
t.Errorf("expected key %q in env", key)
}
}
// Verify values are correct
if tt.baseURL != "" && strings.TrimSpace(tt.baseURL) != "" {
if env["ANTHROPIC_BASE_URL"] != strings.TrimSpace(tt.baseURL) {
t.Errorf("ANTHROPIC_BASE_URL = %q, want %q", env["ANTHROPIC_BASE_URL"], strings.TrimSpace(tt.baseURL))
}
}
if tt.apiKey != "" && strings.TrimSpace(tt.apiKey) != "" {
if env["ANTHROPIC_AUTH_TOKEN"] != strings.TrimSpace(tt.apiKey) {
t.Errorf("ANTHROPIC_AUTH_TOKEN = %q, want %q", env["ANTHROPIC_AUTH_TOKEN"], strings.TrimSpace(tt.apiKey))
}
}
})
}
}
// TestEnvLoggingIntegration tests that env vars are properly masked in logs
func TestEnvLoggingIntegration(t *testing.T) {
b := backend.ClaudeBackend{}
baseURL := "https://api.minimaxi.com/anthropic"
apiKey := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.longjwttoken"
env := b.Env(baseURL, apiKey)
if env == nil {
t.Fatal("expected non-nil env")
}
// Verify that when we log these values, sensitive ones are masked
for k, v := range env {
masked := maskSensitiveValue(k, v)
if k == "ANTHROPIC_BASE_URL" {
// URL should not be masked
if masked != v {
t.Errorf("BASE_URL should not be masked: got %q, want %q", masked, v)
}
}
if k == "ANTHROPIC_AUTH_TOKEN" {
// API key should be masked
if masked == v {
t.Errorf("API_KEY should be masked, but got original value")
}
if !strings.Contains(masked, "****") {
t.Errorf("masked API_KEY should contain ****: got %q", masked)
}
// Should still show first 4 and last 4 chars
if !strings.HasPrefix(masked, v[:4]) {
t.Errorf("masked value should start with first 4 chars of original")
}
if !strings.HasSuffix(masked, v[len(v)-4:]) {
t.Errorf("masked value should end with last 4 chars of original")
}
}
}
}
// TestGeminiBackendEnv tests GeminiBackend.Env for comparison
func TestGeminiBackendEnv(t *testing.T) {
b := backend.GeminiBackend{}
env := b.Env("https://custom.api", "gemini-api-key-12345")
if env == nil {
t.Fatal("expected non-nil env")
}
// Check that GEMINI env vars are set
if _, ok := env["GOOGLE_GEMINI_BASE_URL"]; !ok {
t.Error("expected GOOGLE_GEMINI_BASE_URL in env")
}
if _, ok := env["GEMINI_API_KEY"]; !ok {
t.Error("expected GEMINI_API_KEY in env")
}
// Verify masking works for Gemini keys too
for k, v := range env {
masked := maskSensitiveValue(k, v)
if strings.Contains(strings.ToLower(k), "key") {
if masked == v && len(v) > 0 {
t.Errorf("key %q should be masked", k)
}
}
}
}
// TestCodexBackendEnv tests CodexBackend.Env
func TestCodexBackendEnv(t *testing.T) {
b := backend.CodexBackend{}
env := b.Env("https://custom.api", "codex-api-key-12345")
if env == nil {
t.Fatal("expected non-nil env for codex")
}
// Check for OPENAI env vars
if _, ok := env["OPENAI_BASE_URL"]; !ok {
t.Error("expected OPENAI_BASE_URL in env")
}
if _, ok := env["OPENAI_API_KEY"]; !ok {
t.Error("expected OPENAI_API_KEY in env")
}
}

View File

@@ -0,0 +1,133 @@
package executor
import (
"context"
"errors"
"io"
"os"
"path/filepath"
"strings"
"testing"
config "codeagent-wrapper/internal/config"
)
type fakeCmd struct {
env map[string]string
}
func (f *fakeCmd) Start() error { return nil }
func (f *fakeCmd) Wait() error { return nil }
func (f *fakeCmd) StdoutPipe() (io.ReadCloser, error) {
return io.NopCloser(strings.NewReader("")), nil
}
func (f *fakeCmd) StderrPipe() (io.ReadCloser, error) {
return nil, errors.New("fake stderr pipe error")
}
func (f *fakeCmd) StdinPipe() (io.WriteCloser, error) {
return nil, errors.New("fake stdin pipe error")
}
func (f *fakeCmd) SetStderr(io.Writer) {}
func (f *fakeCmd) SetDir(string) {}
func (f *fakeCmd) SetEnv(env map[string]string) {
if len(env) == 0 {
return
}
if f.env == nil {
f.env = make(map[string]string, len(env))
}
for k, v := range env {
f.env[k] = v
}
}
func (f *fakeCmd) Process() processHandle { return nil }
func TestEnvInjection_LogsToStderrAndMasksKey(t *testing.T) {
// Arrange ~/.codeagent/models.json via HOME override.
tmpDir := t.TempDir()
configDir := filepath.Join(tmpDir, ".codeagent")
if err := os.MkdirAll(configDir, 0o755); err != nil {
t.Fatal(err)
}
const baseURL = "https://api.minimaxi.com/anthropic"
const apiKey = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.test"
models := `{
"agents": {
"explore": {
"backend": "claude",
"model": "MiniMax-M2.1",
"base_url": "` + baseURL + `",
"api_key": "` + apiKey + `"
}
}
}`
if err := os.WriteFile(filepath.Join(configDir, "models.json"), []byte(models), 0o644); err != nil {
t.Fatal(err)
}
oldHome := os.Getenv("HOME")
if err := os.Setenv("HOME", tmpDir); err != nil {
t.Fatal(err)
}
defer func() { _ = os.Setenv("HOME", oldHome) }()
config.ResetModelsConfigCacheForTest()
defer config.ResetModelsConfigCacheForTest()
// Capture stderr (RunCodexTaskWithContext prints env injection lines there).
r, w, err := os.Pipe()
if err != nil {
t.Fatal(err)
}
oldStderr := os.Stderr
os.Stderr = w
defer func() { os.Stderr = oldStderr }()
readDone := make(chan string, 1)
go func() {
defer r.Close()
b, _ := io.ReadAll(r)
readDone <- string(b)
}()
var cmd *fakeCmd
restoreRunner := SetNewCommandRunner(func(ctx context.Context, name string, args ...string) CommandRunner {
cmd = &fakeCmd{}
return cmd
})
defer restoreRunner()
// Act: force an early return right after env injection by making StderrPipe fail.
_ = RunCodexTaskWithContext(
context.Background(),
TaskSpec{Task: "hi", WorkDir: ".", Backend: "claude", Agent: "explore"},
nil,
"claude",
nil,
nil,
false,
false,
1,
)
_ = w.Close()
got := <-readDone
// Assert: env was injected into the command and logging is present with masking.
if cmd == nil || cmd.env == nil {
t.Fatalf("expected cmd env to be set, got cmd=%v env=%v", cmd, nil)
}
if cmd.env["ANTHROPIC_BASE_URL"] != baseURL {
t.Fatalf("ANTHROPIC_BASE_URL=%q, want %q", cmd.env["ANTHROPIC_BASE_URL"], baseURL)
}
if cmd.env["ANTHROPIC_AUTH_TOKEN"] != apiKey {
t.Fatalf("ANTHROPIC_AUTH_TOKEN=%q, want %q", cmd.env["ANTHROPIC_AUTH_TOKEN"], apiKey)
}
if !strings.Contains(got, "Env: ANTHROPIC_BASE_URL="+baseURL) {
t.Fatalf("stderr missing base URL env log; stderr=%q", got)
}
if !strings.Contains(got, "Env: ANTHROPIC_AUTH_TOKEN=eyJh****test") {
t.Fatalf("stderr missing masked API key log; stderr=%q", got)
}
}

View File

@@ -40,7 +40,7 @@ const (
stdoutCloseReasonWait = "wait-done"
stdoutCloseReasonDrain = "drain-timeout"
stdoutCloseReasonCtx = "context-cancel"
stdoutDrainTimeout = 100 * time.Millisecond
stdoutDrainTimeout = 500 * time.Millisecond
)
// Hook points (tests can override inside this package).
@@ -1067,6 +1067,12 @@ func RunCodexTaskWithContext(parentCtx context.Context, taskSpec TaskSpec, backe
}
if injected := envBackend.Env(baseURL, apiKey); len(injected) > 0 {
cmd.SetEnv(injected)
// Log injected env vars with masked API keys (to file and stderr)
for k, v := range injected {
msg := fmt.Sprintf("Env: %s=%s", k, maskSensitiveValue(k, v))
logInfoFn(msg)
fmt.Fprintln(os.Stderr, " "+msg)
}
}
}
@@ -1449,3 +1455,19 @@ func terminateCommand(cmd commandRunner) *forceKillTimer {
return &forceKillTimer{timer: timer, done: done}
}
// maskSensitiveValue masks sensitive values like API keys for logging.
// Values containing "key", "token", or "secret" (case-insensitive) are masked.
// For values longer than 8 chars: shows first 4 + **** + last 4.
// For shorter values: shows only ****.
func maskSensitiveValue(key, value string) string {
keyLower := strings.ToLower(key)
if strings.Contains(keyLower, "key") || strings.Contains(keyLower, "token") || strings.Contains(keyLower, "secret") {
if len(value) > 8 {
return value[:4] + "****" + value[len(value)-4:]
} else if len(value) > 0 {
return "****"
}
}
return value
}

View File

@@ -0,0 +1,43 @@
#!/bin/bash
# Benchmark script for Claude CLI stability test
# Tests if the stdoutDrainTimeout fix resolves intermittent failures
set -euo pipefail
RUNS=${1:-100}
FAIL_COUNT=0
SUCCESS_COUNT=0
TIMEOUT_COUNT=0
echo "Running $RUNS iterations..."
echo "---"
for i in $(seq 1 $RUNS); do
result=$(timeout 30 codeagent --backend claude --skip-permissions 'say OK' 2>&1) || true
if echo "$result" | grep -q 'without agent_message'; then
((FAIL_COUNT++))
echo "[$i] FAIL: without agent_message"
elif echo "$result" | grep -q 'timeout'; then
((TIMEOUT_COUNT++))
echo "[$i] TIMEOUT"
elif echo "$result" | grep -q 'OK\|ok'; then
((SUCCESS_COUNT++))
printf "\r[$i] OK "
else
((FAIL_COUNT++))
echo "[$i] FAIL: unexpected output"
echo "$result" | head -3
fi
done
echo ""
echo "---"
echo "Results ($RUNS runs):"
echo " Success: $SUCCESS_COUNT ($(echo "scale=1; $SUCCESS_COUNT * 100 / $RUNS" | bc)%)"
echo " Fail: $FAIL_COUNT ($(echo "scale=1; $FAIL_COUNT * 100 / $RUNS" | bc)%)"
echo " Timeout: $TIMEOUT_COUNT ($(echo "scale=1; $TIMEOUT_COUNT * 100 / $RUNS" | bc)%)"
if [ $FAIL_COUNT -gt 0 ]; then
exit 1
fi

View File

@@ -0,0 +1,90 @@
# requirements - Requirements-Driven Workflow
Lightweight requirements-to-code pipeline with interactive quality gates.
## Installation
```bash
python install.py --module requirements
```
## Usage
```bash
/requirements-pilot <FEATURE_DESCRIPTION> [OPTIONS]
```
### Options
| Option | Description |
|--------|-------------|
| `--skip-tests` | Skip testing phase entirely |
| `--skip-scan` | Skip initial repository scanning |
## Workflow Phases
| Phase | Description | Output |
|-------|-------------|--------|
| 0 | Repository scanning | `00-repository-context.md` |
| 1 | Requirements confirmation | `requirements-confirm.md` (90+ score required) |
| 2 | Implementation | Code + `requirements-spec.md` |
## Quality Scoring (100-point system)
| Category | Points | Focus |
|----------|--------|-------|
| Functional Clarity | 30 | Input/output specs, success criteria |
| Technical Specificity | 25 | Integration points, constraints |
| Implementation Completeness | 25 | Edge cases, error handling |
| Business Context | 20 | User value, priority |
## Sub-Agents
| Agent | Role |
|-------|------|
| `requirements-generate` | Create technical specifications |
| `requirements-code` | Implement functionality |
| `requirements-review` | Code quality evaluation |
| `requirements-testing` | Test case creation |
## Approval Gate
One mandatory stop point after Phase 1:
- Requirements must achieve 90+ quality score
- User must explicitly approve before implementation begins
## Testing Decision
After code review passes (≥90%):
- `--skip-tests`: Complete without testing
- No option: Interactive prompt with smart recommendations based on task complexity
## Output Structure
```
.claude/specs/{feature_name}/
├── 00-repository-context.md
├── requirements-confirm.md
└── requirements-spec.md
```
## When to Use
- Quick prototypes
- Well-defined features
- Smaller scope tasks
- When full BMAD workflow is overkill
## Directory Structure
```
requirements-driven-workflow/
├── README.md
├── commands/
│ └── requirements-pilot.md
└── agents/
├── requirements-generate.md
├── requirements-code.md
├── requirements-review.md
└── requirements-testing.md
```

View File

@@ -1,6 +1,6 @@
# do
# do - Feature Development Orchestrator
7-phase feature development workflow, orchestrating multiple agents via codeagent-wrapper.
7-phase feature development workflow orchestrating multiple agents via codeagent-wrapper.
## Installation
@@ -24,30 +24,141 @@ Examples:
/do implement order export to CSV
```
## Workflow Phases
## 7-Phase Workflow
| Phase | Name | Goal |
|-------|------|------|
| 1 | Discovery | Understand requirements |
| 2 | Exploration | Explore codebase |
| 3 | Clarification | Resolve ambiguities (mandatory) |
| 4 | Architecture | Design approach |
| 5 | Implementation | Build (requires approval) |
| 6 | Review | Code review |
| 7 | Summary | Document results |
| Phase | Name | Goal | Key Actions |
|-------|------|------|-------------|
| 1 | Discovery | Understand requirements | AskUserQuestion + code-architect draft |
| 2 | Exploration | Map codebase patterns | 2-3 parallel code-explorer tasks |
| 3 | Clarification | Resolve ambiguities | **MANDATORY** - must answer before proceeding |
| 4 | Architecture | Design implementation | 2 parallel code-architect approaches |
| 5 | Implementation | Build the feature | **Requires approval** - develop agent |
| 6 | Review | Catch defects | 2-3 parallel code-reviewer tasks |
| 7 | Summary | Document results | code-reviewer summary |
## Agents
- `code-explorer` - Code tracing, architecture mapping
- `code-architect` - Design approaches, file planning
- `code-reviewer` - Code review, simplification suggestions
- `develop` - Implement code, run tests
| Agent | Purpose | Prompt Location |
|-------|---------|----------------|
| `code-explorer` | Code tracing, architecture mapping | `agents/code-explorer.md` |
| `code-architect` | Design approaches, file planning | `agents/code-architect.md` |
| `code-reviewer` | Code review, simplification | `agents/code-reviewer.md` |
| `develop` | Implement code, run tests | global config |
Agent prompts are in the `agents/` directory. To customize, create same-named files in `~/.codeagent/agents/` to override.
To customize agents, create same-named files in `~/.codeagent/agents/` to override.
## Hard Constraints
1. **Never write code directly** - delegate all changes to codeagent-wrapper agents
2. **Phase 3 is mandatory** - do not proceed until questions are answered
3. **Phase 5 requires approval** - stop after Phase 4 if not approved
4. **Pass complete context forward** - every agent gets the Context Pack
5. **Parallel-first** - run independent tasks via `codeagent-wrapper --parallel`
6. **Update state after each phase** - keep `.claude/do.{task_id}.local.md` current
## Context Pack Template
```text
## Original User Request
<verbatim request>
## Context Pack
- Phase: <1-7 name>
- Decisions: <requirements/constraints/choices>
- Code-explorer output: <paste or "None">
- Code-architect output: <paste or "None">
- Code-reviewer output: <paste or "None">
- Develop output: <paste or "None">
- Open questions: <list or "None">
## Current Task
<specific task>
## Acceptance Criteria
<checkable outputs>
```
## Loop State Management
When triggered via `/do <task>`, initializes `.claude/do.{task_id}.local.md` with:
- `active: true`
- `current_phase: 1`
- `max_phases: 7`
- `completion_promise: "<promise>DO_COMPLETE</promise>"`
After each phase, update frontmatter:
```yaml
current_phase: <next phase number>
phase_name: "<next phase name>"
```
When all 7 phases complete, output:
```
<promise>DO_COMPLETE</promise>
```
To abort early, set `active: false` in the state file.
## Stop Hook
A Stop hook is registered after installation:
1. Creates `.claude/do.{task_id}.local.md` state file
2. Updates `current_phase` after each phase
3. Stop hook checks state, blocks exit if incomplete
4. Outputs `<promise>DO_COMPLETE</promise>` when finished
Manual exit: Set `active` to `false` in the state file.
## Parallel Execution Examples
### Phase 2: Exploration (3 parallel tasks)
```bash
codeagent-wrapper --parallel <<'EOF'
---TASK---
id: p2_similar_features
agent: code-explorer
workdir: .
---CONTENT---
Find similar features, trace end-to-end.
---TASK---
id: p2_architecture
agent: code-explorer
workdir: .
---CONTENT---
Map architecture for relevant subsystem.
---TASK---
id: p2_conventions
agent: code-explorer
workdir: .
---CONTENT---
Identify testing patterns and conventions.
EOF
```
### Phase 4: Architecture (2 approaches)
```bash
codeagent-wrapper --parallel <<'EOF'
---TASK---
id: p4_minimal
agent: code-architect
workdir: .
---CONTENT---
Propose minimal-change architecture.
---TASK---
id: p4_pragmatic
agent: code-architect
workdir: .
---CONTENT---
Propose pragmatic-clean architecture.
EOF
```
## ~/.codeagent/models.json Configuration
Optional. Uses codeagent-wrapper built-in config by default. To customize agent models:
Optional. Uses codeagent-wrapper built-in config by default. To customize:
```json
{
@@ -68,17 +179,6 @@ Optional. Uses codeagent-wrapper built-in config by default. To customize agent
}
```
## Loop Mechanism
A Stop hook is registered after installation. When `/do` runs:
1. Creates `.claude/do.local.md` state file
2. Updates `current_phase` after each phase
3. Stop hook checks state, blocks exit if incomplete
4. Outputs `<promise>DO_COMPLETE</promise>` when finished
Manual exit: Set `active` to `false` in the state file.
## Uninstall
```bash

View File

@@ -16,7 +16,7 @@ When triggered via `/do <task>`, **first** initialize the loop state:
"${SKILL_DIR}/scripts/setup-do.sh" "<task description>"
```
This creates `.claude/do.local.md` with:
This creates `.claude/do.{task_id}.local.md` with:
- `active: true`
- `current_phase: 1`
- `max_phases: 7`
@@ -24,7 +24,7 @@ This creates `.claude/do.local.md` with:
## Loop State Management
After each phase, update `.claude/do.local.md` frontmatter:
After each phase, update `.claude/do.{task_id}.local.md` frontmatter:
```yaml
current_phase: <next phase number>
phase_name: "<next phase name>"
@@ -44,7 +44,7 @@ To abort early, set `active: false` in the state file.
3. **Phase 5 (Implementation) requires explicit approval.** Stop after Phase 4 if not approved.
4. **Pass complete context forward.** Every agent invocation includes the Context Pack.
5. **Parallel-first.** Run independent tasks via `codeagent-wrapper --parallel`.
6. **Update state after each phase.** Keep `.claude/do.local.md` current.
6. **Update state after each phase.** Keep `.claude/do.{task_id}.local.md` current.
## Agents

View File

@@ -26,9 +26,13 @@ json_escape() {
}
project_dir="${CLAUDE_PROJECT_DIR:-$PWD}"
state_file="${project_dir}/.claude/do.local.md"
state_dir="${project_dir}/.claude"
if [ ! -f "$state_file" ]; then
shopt -s nullglob
state_files=("${state_dir}"/do.*.local.md)
shopt -u nullglob
if [ ${#state_files[@]} -eq 0 ]; then
exit 0
fi
@@ -38,7 +42,7 @@ if [ ! -t 0 ]; then
fi
frontmatter_get() {
local key="$1"
local file="$1" key="$2"
awk -v k="$key" '
BEGIN { in_fm=0 }
NR==1 && $0=="---" { in_fm=1; next }
@@ -52,72 +56,96 @@ frontmatter_get() {
exit
}
}
' "$state_file"
' "$file"
}
active_raw="$(frontmatter_get active || true)"
active_lc="$(printf "%s" "$active_raw" | tr '[:upper:]' '[:lower:]')"
case "$active_lc" in
true|1|yes|on) ;;
*) exit 0 ;;
esac
check_state_file() {
local state_file="$1"
current_phase_raw="$(frontmatter_get current_phase || true)"
max_phases_raw="$(frontmatter_get max_phases || true)"
phase_name="$(frontmatter_get phase_name || true)"
completion_promise="$(frontmatter_get completion_promise || true)"
local active_raw active_lc
active_raw="$(frontmatter_get "$state_file" active || true)"
active_lc="$(printf "%s" "$active_raw" | tr '[:upper:]' '[:lower:]')"
case "$active_lc" in
true|1|yes|on) ;;
*) return 0 ;;
esac
current_phase=1
if [[ "${current_phase_raw:-}" =~ ^[0-9]+$ ]]; then
current_phase="$current_phase_raw"
fi
local current_phase_raw max_phases_raw phase_name completion_promise
current_phase_raw="$(frontmatter_get "$state_file" current_phase || true)"
max_phases_raw="$(frontmatter_get "$state_file" max_phases || true)"
phase_name="$(frontmatter_get "$state_file" phase_name || true)"
completion_promise="$(frontmatter_get "$state_file" completion_promise || true)"
max_phases=7
if [[ "${max_phases_raw:-}" =~ ^[0-9]+$ ]]; then
max_phases="$max_phases_raw"
fi
local current_phase=1
if [[ "${current_phase_raw:-}" =~ ^[0-9]+$ ]]; then
current_phase="$current_phase_raw"
fi
if [ -z "${phase_name:-}" ]; then
phase_name="$(phase_name_for "$current_phase")"
fi
local max_phases=7
if [[ "${max_phases_raw:-}" =~ ^[0-9]+$ ]]; then
max_phases="$max_phases_raw"
fi
if [ -z "${completion_promise:-}" ]; then
completion_promise="<promise>DO_COMPLETE</promise>"
fi
if [ -z "${phase_name:-}" ]; then
phase_name="$(phase_name_for "$current_phase")"
fi
phases_done=0
if [ "$current_phase" -ge "$max_phases" ]; then
phases_done=1
fi
if [ -z "${completion_promise:-}" ]; then
completion_promise="<promise>DO_COMPLETE</promise>"
fi
promise_met=0
if [ -n "$completion_promise" ]; then
if [ -n "$stdin_payload" ] && printf "%s" "$stdin_payload" | grep -Fq -- "$completion_promise"; then
promise_met=1
else
body="$(
awk '
BEGIN { in_fm=0; body=0 }
NR==1 && $0=="---" { in_fm=1; next }
in_fm==1 && $0=="---" { body=1; in_fm=0; next }
body==1 { print }
' "$state_file"
)"
if [ -n "$body" ] && printf "%s" "$body" | grep -Fq -- "$completion_promise"; then
local phases_done=0
if [ "$current_phase" -ge "$max_phases" ]; then
phases_done=1
fi
local promise_met=0
if [ -n "$completion_promise" ]; then
if [ -n "$stdin_payload" ] && printf "%s" "$stdin_payload" | grep -Fq -- "$completion_promise"; then
promise_met=1
else
local body
body="$(
awk '
BEGIN { in_fm=0; body=0 }
NR==1 && $0=="---" { in_fm=1; next }
in_fm==1 && $0=="---" { body=1; in_fm=0; next }
body==1 { print }
' "$state_file"
)"
if [ -n "$body" ] && printf "%s" "$body" | grep -Fq -- "$completion_promise"; then
promise_met=1
fi
fi
fi
fi
if [ "$phases_done" -eq 1 ] && [ "$promise_met" -eq 1 ]; then
if [ "$phases_done" -eq 1 ] && [ "$promise_met" -eq 1 ]; then
rm -f "$state_file"
return 0
fi
local reason
if [ "$phases_done" -eq 0 ]; then
reason="do loop incomplete: current phase ${current_phase}/${max_phases} (${phase_name}). Continue with remaining phases; update ${state_file} current_phase/phase_name after each phase. Include completion_promise in final output when done: ${completion_promise}. To exit early, set active to false."
else
reason="do reached final phase (current_phase=${current_phase} / max_phases=${max_phases}, phase_name=${phase_name}), but completion_promise not detected: ${completion_promise}. Please include this marker in your final output (or write it to ${state_file} body), then finish; to force exit, set active to false."
fi
printf "%s" "$reason"
}
blocking_reasons=()
for state_file in "${state_files[@]}"; do
reason="$(check_state_file "$state_file")"
if [ -n "$reason" ]; then
blocking_reasons+=("$reason")
fi
done
if [ ${#blocking_reasons[@]} -eq 0 ]; then
exit 0
fi
if [ "$phases_done" -eq 0 ]; then
reason="do loop incomplete: current phase ${current_phase}/${max_phases} (${phase_name}). Continue with remaining phases; update ${state_file} current_phase/phase_name after each phase. Include completion_promise in final output when done: ${completion_promise}. To exit early, set active to false."
else
reason="do reached final phase (current_phase=${current_phase} / max_phases=${max_phases}, phase_name=${phase_name}), but completion_promise not detected: ${completion_promise}. Please include this marker in your final output (or write it to ${state_file} body), then finish; to force exit, set active to false."
fi
printf '{"decision":"block","reason":"%s"}\n' "$(json_escape "$reason")"
combined_reason="${blocking_reasons[*]}"
printf '{"decision":"block","reason":"%s"}\n' "$(json_escape "$combined_reason")"
exit 0

View File

@@ -81,7 +81,9 @@ fi
project_dir="${CLAUDE_PROJECT_DIR:-$PWD}"
state_dir="${project_dir}/.claude"
state_file="${state_dir}/do.local.md"
task_id="$(date +%s)-$$-$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n')"
state_file="${state_dir}/do.${task_id}.local.md"
mkdir -p "$state_dir"
@@ -107,5 +109,6 @@ $prompt
EOF
echo "Initialized: $state_file"
echo "task_id: $task_id"
echo "phase: 1/$max_phases ($phase_name)"
echo "completion_promise: $completion_promise"

View File

@@ -1,14 +1,14 @@
# OmO Multi-Agent Orchestration
# omo - Multi-Agent Orchestration
OmO (Oh-My-OpenCode) is a multi-agent orchestration skill that delegates tasks to specialized agents based on routing signals.
OmO is a multi-agent orchestration skill that routes tasks to specialized agents based on risk signals.
## Installation
```bash
python3 install.py --module omo
python install.py --module omo
```
## Quick Start
## Usage
```
/omo <your task>
@@ -18,59 +18,107 @@ python3 install.py --module omo
| Agent | Role | Backend | Model |
|-------|------|---------|-------|
| oracle | Technical advisor | claude | claude-opus-4-5-20251101 |
| librarian | External research | claude | claude-sonnet-4-5-20250929 |
| explore | Codebase search | opencode | opencode/grok-code |
| develop | Code implementation | codex | gpt-5.2 |
| frontend-ui-ux-engineer | UI/UX specialist | gemini | gemini-3-pro-preview |
| document-writer | Documentation | gemini | gemini-3-flash-preview |
| `oracle` | Technical advisor | claude | claude-opus-4-5 |
| `librarian` | External research | claude | claude-sonnet-4-5 |
| `explore` | Codebase search | opencode | grok-code |
| `develop` | Code implementation | codex | gpt-5.2 |
| `frontend-ui-ux-engineer` | UI/UX specialist | gemini | gemini-3-pro |
| `document-writer` | Documentation | gemini | gemini-3-flash |
## How It Works
## Routing Signals (Not Fixed Pipeline)
1. `/omo` analyzes your request via routing signals
2. Based on task type, it either:
- Answers directly (analysis/explanation tasks - no code changes)
- Delegates to specialized agents (implementation tasks)
- Fires parallel agents (exploration + research)
This skill is **routing-first**, not a mandatory conveyor belt.
| Signal | Add Agent |
|--------|----------|
| Code location/behavior unclear | `explore` |
| External library/API usage unclear | `librarian` |
| Risky change (multi-file, public API, security, perf) | `oracle` |
| Implementation required | `develop` / `frontend-ui-ux-engineer` |
| Documentation needed | `document-writer` |
### Skipping Heuristics
- Skip `explore` when exact file path + line number is known
- Skip `oracle` when change is local + low-risk (single area, clear fix)
- Skip implementation agents when user only wants analysis
## Common Recipes
| Task | Recipe |
|------|--------|
| Explain code | `explore` |
| Small fix with known location | `develop` directly |
| Bug fix, location unknown | `explore → develop` |
| Cross-cutting refactor | `explore → oracle → develop` |
| External API integration | `explore + librarian → oracle → develop` |
| UI-only change | `explore → frontend-ui-ux-engineer` |
| Docs-only change | `explore → document-writer` |
## Context Pack Template
Every agent invocation includes:
```text
## Original User Request
<original request>
## Context Pack (include anything relevant; write "None" if absent)
- Explore output: <...>
- Librarian output: <...>
- Oracle output: <...>
- Known constraints: <tests to run, time budget, repo conventions>
## Current Task
<specific task description>
## Acceptance Criteria
<clear completion conditions>
```
## Agent Invocation
```bash
codeagent-wrapper --agent <agent_name> - <workdir> <<'EOF'
## Original User Request
...
## Context Pack
...
## Current Task
...
## Acceptance Criteria
...
EOF
```
Timeout: 2 hours.
## Examples
```bash
# Refactoring
/omo Help me refactor this authentication module
# Analysis only
/omo how does this function work?
# → explore
# Feature development
/omo I need to add a new payment feature with frontend UI and backend API
# Bug fix with unknown location
/omo fix the authentication bug
# → explore → develop
# Research
/omo What authentication scheme does this project use?
```
# Feature with external API
/omo add Stripe payment integration
# → explore + librarian → oracle → develop
## Agent Delegation
Delegates via codeagent-wrapper with full Context Pack:
```bash
codeagent-wrapper --agent oracle - . <<'EOF'
## Original User Request
Analyze the authentication architecture and recommend improvements.
## Context Pack (include anything relevant; write "None" if absent)
- Explore output: [paste explore output if available]
- Librarian output: None
- Oracle output: None
## Current Task
Review auth architecture, identify risks, propose minimal improvements.
## Acceptance Criteria
Output: recommendation, action plan, risk assessment, effort estimate.
EOF
# UI change
/omo redesign the dashboard layout
# → explore → frontend-ui-ux-engineer
```
## Configuration
Agent-model mappings are configured in `~/.codeagent/models.json`:
Agent-model mappings in `~/.codeagent/models.json`:
```json
{
@@ -80,34 +128,28 @@ Agent-model mappings are configured in `~/.codeagent/models.json`:
"oracle": {
"backend": "claude",
"model": "claude-opus-4-5-20251101",
"description": "Technical advisor",
"yolo": true
},
"librarian": {
"backend": "claude",
"model": "claude-sonnet-4-5-20250929",
"description": "Researcher",
"yolo": true
},
"explore": {
"backend": "opencode",
"model": "opencode/grok-code",
"description": "Code search"
"model": "opencode/grok-code"
},
"frontend-ui-ux-engineer": {
"backend": "gemini",
"model": "gemini-3-pro-preview",
"description": "Frontend engineer"
"model": "gemini-3-pro-preview"
},
"document-writer": {
"backend": "gemini",
"model": "gemini-3-flash-preview",
"description": "Documentation"
"model": "gemini-3-flash-preview"
},
"develop": {
"backend": "codex",
"model": "gpt-5.2",
"description": "codex develop",
"yolo": true,
"reasoning": "xhigh"
}
@@ -115,6 +157,14 @@ Agent-model mappings are configured in `~/.codeagent/models.json`:
}
```
## Hard Constraints
1. **Never write code yourself** - delegate to implementation agents
2. **Always pass context forward** - include original request + prior outputs
3. **No direct grep/glob for non-trivial exploration** - use `explore`
4. **No external docs guessing** - use `librarian`
5. **Use fewest agents possible** - skipping is normal
## Requirements
- codeagent-wrapper with `--agent` support

View File

@@ -1,96 +1,169 @@
# SPARV - Unified Development Workflow (Simplified)
# sparv - SPARV Workflow
[![Skill Version](https://img.shields.io/badge/version-1.0.0-blue.svg)]()
[![Claude Code](https://img.shields.io/badge/Claude%20Code-Compatible-green.svg)]()
Minimal 5-phase workflow: **S**pecify → **P**lan → **A**ct → **R**eview → **V**ault.
**SPARV** is an end-to-end development workflow: maximize delivery quality with minimal rules while avoiding "infinite iteration + self-rationalization."
```
S-Specify → P-Plan → A-Act → R-Review → V-Vault
Clarify Plan Execute Review Archive
```
## Key Changes (Over-engineering Removed)
- External memory merged from 3 files into 1 `.sparv/journal.md`
- Specify scoring simplified from 100-point to 10-point scale (threshold `>=9`)
- Reboot Test reduced from 5 questions to 3 questions
- Removed concurrency locks (Claude is single-threaded; locks only cause failures)
Completes "requirements → verifiable delivery" in one pass with external memory.
## Installation
SPARV is installed at `~/.claude/skills/sparv/`.
Install from ZIP:
```bash
unzip sparv.zip -d ~/.claude/skills/
python install.py --module sparv
```
## Quick Start
Installs to `~/.claude/skills/sparv/`.
Run in project root:
## Usage
```
/sparv <task description>
```
## Core Rules (Mandatory)
| Rule | Description |
|------|-------------|
| **10-Point Specify Gate** | Spec score 0-10; must be >=9 to enter Plan |
| **2-Action Save** | Append to `.sparv/journal.md` every 2 tool calls |
| **3-Failure Protocol** | Stop and escalate after 3 consecutive failures |
| **EHRB** | Explicit confirmation for high-risk (production/sensitive/destructive/billing/security) |
| **Fixed Phase Names** | `specify|plan|act|review|vault` in `state.yaml` |
## 5-Phase Workflow
### Phase 1: Specify (10-Point Scale)
Each dimension scores 0/1/2, total 0-10:
| Dimension | Focus |
|-----------|-------|
| Value | Why do it, verifiable benefits/metrics |
| Scope | MVP + what's out of scope |
| Acceptance | Testable acceptance criteria |
| Boundaries | Error/performance/compatibility/security limits |
| Risk | EHRB/dependencies/unknowns + handling |
- `score < 9`: Keep asking questions; do not enter Plan
- `score >= 9`: Write `completion_promise`, then enter Plan
### Phase 2: Plan
- Break into atomic tasks (2-5 minute granularity)
- Each task has verifiable output/test point
- Write plan to `.sparv/journal.md`
### Phase 3: Act
- **TDD Rule**: No failing test → no production code
- Auto-write journal every 2 actions (PostToolUse hook)
- 3-Failure Protocol enforced
### Phase 4: Review
- Two stages: Spec conformance → Code quality
- Maximum 3 fix rounds; escalate if exceeded
- Run 3-question reboot test before session ends
### Phase 5: Vault
- Archive current session to `.sparv/history/`
- Update knowledge base `.sparv/kb.md`
## Enhanced Rules (v1.1)
### Uncertainty Declaration (G3)
When any Specify dimension scores < 2:
```
UNCERTAIN: <what> | ASSUMPTION: <fallback>
UNCERTAIN: deployment target | ASSUMPTION: Docker container
UNCERTAIN: auth method | OPTIONS: JWT / OAuth2 / Session
```
### Requirement Routing
| Mode | Condition | Flow |
|------|-----------|------|
| **Quick** | score >= 9 AND <= 3 files AND no EHRB | Specify → Act → Review |
| **Full** | otherwise | Specify → Plan → Act → Review → Vault |
### Knowledge Base Maintenance
During Vault phase, update `.sparv/kb.md`:
- **Patterns**: Reusable code patterns discovered
- **Decisions**: Architectural choices + rationale
- **Gotchas**: Common pitfalls + solutions
### CHANGELOG Update
For non-trivial changes:
```bash
~/.claude/skills/sparv/scripts/changelog-update.sh --type <Added|Changed|Fixed|Removed> --desc "..."
```
## External Memory
Initialize (run in project root):
```bash
~/.claude/skills/sparv/scripts/init-session.sh --force
```
Creates:
```
.sparv/
├── state.yaml
├── journal.md
── history/
├── state.yaml # State machine
├── journal.md # Unified log
── kb.md # Knowledge base
└── history/ # Archive directory
```
## External Memory System (Two Files)
- `state.yaml`: State (minimum fields: `session_id/current_phase/action_count/consecutive_failures`)
- `journal.md`: Unified log (Plan/Progress/Findings all go here)
After archiving:
```
.sparv/history/<session_id>/
├── state.yaml
└── journal.md
```
| File | Purpose |
|------|--------|
| `state.yaml` | session_id, current_phase, action_count, consecutive_failures |
| `journal.md` | Plan/Progress/Findings unified log |
| `kb.md` | patterns/decisions/gotchas |
| `history/` | Archived sessions |
## Key Numbers
| Number | Meaning |
|--------|---------|
|--------|--------|
| **9/10** | Specify score passing threshold |
| **2** | Write to journal every 2 tool calls |
| **3** | Failure retry limit / Review fix limit |
| **3** | Reboot Test question count |
| **12** | Default max iterations (optional safety valve) |
## Script Tools
| Script | Purpose |
|--------|--------|
| `init-session.sh` | Initialize `.sparv/`, generate state + journal |
| `save-progress.sh` | Maintain action_count, append journal |
| `check-ehrb.sh` | Scan diff/text, output ehrb_flags |
| `failure-tracker.sh` | Maintain consecutive_failures |
| `reboot-test.sh` | 3-question self-check |
| `archive-session.sh` | Archive to history/ |
| `changelog-update.sh` | Update CHANGELOG.md |
## Auto Hooks
Configured in `hooks/hooks.json`:
- **PostToolUse**: `save-progress.sh` (2-Action save)
- **PreToolUse**: `check-ehrb.sh --diff --dry-run` (prompt only)
- **Stop**: `reboot-test.sh --strict` (3-question self-check)
## Failure Tracking
```bash
~/.claude/skills/sparv/scripts/init-session.sh --force
~/.claude/skills/sparv/scripts/save-progress.sh "Edit" "done"
~/.claude/skills/sparv/scripts/check-ehrb.sh --diff --fail-on-flags
~/.claude/skills/sparv/scripts/failure-tracker.sh fail --note "tests are flaky"
~/.claude/skills/sparv/scripts/reboot-test.sh --strict
~/.claude/skills/sparv/scripts/archive-session.sh
# Record failure
~/.claude/skills/sparv/scripts/failure-tracker.sh fail --note "short blocker"
# Reset counter
~/.claude/skills/sparv/scripts/failure-tracker.sh reset
```
## Hooks
## Uninstall
Hooks defined in `hooks/hooks.json`:
- PostToolUse: 2-Action auto-write to `journal.md`
- PreToolUse: EHRB risk prompt (default dry-run)
- Stop: 3-question reboot test (strict)
## References
- `SKILL.md`: Skill definition (for agent use)
- `references/methodology.md`: Methodology quick reference
---
*Quality over speed—iterate until truly complete.*
```bash
python install.py --uninstall --module sparv
```