mirror of
https://github.com/itme-brain/agent-team.git
synced 2026-05-08 11:40:12 -04:00
feat: template-based dual-target generator for Claude + Codex
Replace generate-codex.sh with unified generate.sh that produces both
claude/ and codex/ output from template source files.
Agent bodies use ${PLANS_DIR}, ${WEB_SEARCH}, ${SEARCH_TOOLS} placeholders
expanded per-target via envsubst. Skills and rules made tool-agnostic
(no Claude tool names or .claude/ paths). Orchestrate skill stays
Claude-only.
install.sh now symlinks from claude/agents/ instead of agents/ directly.
flake.nix adds gettext (envsubst) to devShell.
This commit is contained in:
parent
37ec0fd7ec
commit
b9d8b03895
17 changed files with 687 additions and 211 deletions
338
.claude/plans/template-based-dual-target-generator.md
Normal file
338
.claude/plans/template-based-dual-target-generator.md
Normal file
|
|
@ -0,0 +1,338 @@
|
||||||
|
---
|
||||||
|
date: 2026-04-02
|
||||||
|
task: template-based dual-target generator
|
||||||
|
tier: 2
|
||||||
|
status: active
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plan: Template-based dual-target generator
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Refactor agent-team from "Claude source of truth with a Codex converter" to "tool-agnostic templates with a generator that produces both Claude and Codex output." Agent bodies gain `${VAR}` placeholders for tool-specific references. Skills and rules are made tool-agnostic by replacing Claude-specific tool names and paths with generic language. A new `generate.sh` replaces `generate-codex.sh` and produces both `claude/` and `codex/` output directories. `install.sh` changes to symlink from the generated `claude/` directory. The orchestrate skill stays Claude-only since it is deeply tied to Claude's Agent tool dispatch model.
|
||||||
|
|
||||||
|
## Out of Scope
|
||||||
|
|
||||||
|
- Changing agent frontmatter schema (YAML fields stay as-is; the generator handles YAML-to-TOML conversion)
|
||||||
|
- Adding new agents or skills
|
||||||
|
- Changing the orchestrate skill's content (it stays Claude-only, not templated)
|
||||||
|
- Changing conventions skill content (already tool-agnostic)
|
||||||
|
- Modifying the message-schema envelope format
|
||||||
|
- Codex config.toml generation (the current `generate-codex.sh` logic for mapping model/effort/sandbox is preserved, not redesigned)
|
||||||
|
- README content updates beyond what's needed to reflect the new structure
|
||||||
|
|
||||||
|
## Research Findings
|
||||||
|
|
||||||
|
**envsubst scoping:** `envsubst '${PLANS_DIR} ${WEB_SEARCH}'` substitutes only the listed variables, leaving other `$` references untouched. Safe for use in files with YAML frontmatter and bash-like content.
|
||||||
|
|
||||||
|
**Codex path conventions:** Codex has no `.claude/plans/` equivalent -- plans are regular files at `plans/` (project-relative). No `.claude/memory/` -- use `memory/` or omit. Skills are discovered from `~/.agents/skills/` via `SKILL.md` auto-matching or `skills.config` in agent TOML. Skills are NOT inlined into `developer_instructions`.
|
||||||
|
|
||||||
|
**Skill strategy:** Option B (make skills tool-agnostic) for most skills. Orchestrate stays Claude-only. Tool name references like "Use Read/Glob/Grep" add marginal value and can be replaced with generic language like "Search the codebase."
|
||||||
|
|
||||||
|
## Codebase Analysis
|
||||||
|
|
||||||
|
### Files to modify
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|---|---|
|
||||||
|
| `agents/architect.md` | Replace `.claude/plans/` (lines 19, 106) with `${PLANS_DIR}` |
|
||||||
|
| `agents/reviewer.md` | Replace `via WebFetch/WebSearch` (line 33) with `${WEB_SEARCH}` |
|
||||||
|
| `agents/debugger.md` | Replace `Use Grep` (line 25) with `${SEARCH_TOOLS}` |
|
||||||
|
| `agents/documenter.md` | Replace `Use Read/Glob/Grep` (line 29) with `${SEARCH_TOOLS}` |
|
||||||
|
| `skills/message-schema/SKILL.md` | Replace `.claude/plans/` (lines 155, 205) with `${PLANS_DIR}` |
|
||||||
|
| `skills/project/SKILL.md` | Replace `.claude/skills/project.md` (lines 7, 9) with `${PROJECT_SKILL_PATH}` |
|
||||||
|
| `skills/worker-protocol/SKILL.md` | Replace `Read/Glob/Grep` (line 50) with generic language |
|
||||||
|
| `skills/qa-checklist/SKILL.md` | Replace `Read/Grep` (line 13) with generic language |
|
||||||
|
| `rules/01-session.md` | Replace `.claude/memory/` (lines 3, 9, 12) with `${MEMORY_DIR}` |
|
||||||
|
| `rules/04-tools.md` | Replace `suggest /clear` (line 17) with `${CLEAR_CMD}` |
|
||||||
|
| `generate-codex.sh` | **Delete** -- replaced by `generate.sh` |
|
||||||
|
| `generate.sh` | **New** -- produces both `claude/` and `codex/` |
|
||||||
|
| `install.sh` | Rewire Claude symlinks to point at `claude/` output directory |
|
||||||
|
| `.gitignore` | Add `claude/` to exclusions |
|
||||||
|
| `flake.nix` | Add `envsubst` (from `gettext`) to devShell packages |
|
||||||
|
|
||||||
|
### Files for context (read-only)
|
||||||
|
|
||||||
|
| File | Why |
|
||||||
|
|---|---|
|
||||||
|
| `agents/worker.md` | Confirm no Claude-specific references in body (clean) |
|
||||||
|
| `agents/auditor.md` | Confirm no Claude-specific references in body (clean) |
|
||||||
|
| `agents/researcher.md` | Confirm no Claude-specific references in body (clean) |
|
||||||
|
| `skills/orchestrate/SKILL.md` | Confirm Claude-only decision (deeply coupled) |
|
||||||
|
| `skills/conventions/SKILL.md` | Confirm already tool-agnostic (clean) |
|
||||||
|
| `rules/02-responses.md` through `rules/07-research.md` | Confirm no Claude-specific references (clean, except 04-tools.md) |
|
||||||
|
| `codex/config.toml` | Understand current generated output (reference only) |
|
||||||
|
|
||||||
|
### Current patterns
|
||||||
|
|
||||||
|
- **Shell scripts** use `set -euo pipefail`, `SCRIPT_DIR` idiom, echo-based progress reporting
|
||||||
|
- **yq** (yq-go) is the YAML/JSON processor -- used for frontmatter extraction and settings parsing
|
||||||
|
- **Generated output** is committed to `codex/` but gitignored; `claude/` will follow the same pattern
|
||||||
|
- **Symlink strategy** in install.sh: directory symlinks for agents/skills/rules, file symlinks for individual config files; backup-on-conflict pattern
|
||||||
|
- **Agent markdown** uses YAML frontmatter with specific schema fields (`name`, `description`, `model`, `effort`, `permissionMode`, `tools`, `disallowedTools`, `maxTurns`, `skills`, `isolation`, `background`, `memory`)
|
||||||
|
|
||||||
|
## Interface Contracts
|
||||||
|
|
||||||
|
### Module ownership
|
||||||
|
|
||||||
|
- `generate.sh`: owned by Step 5 (Wave 3), responsible for template expansion + output generation
|
||||||
|
- `agents/*.md` templates: owned by Steps 1-2 (Wave 1), responsible for adding `${VAR}` placeholders
|
||||||
|
- `skills/` tool-agnostic edits: owned by Step 3 (Wave 1), responsible for removing tool-specific language
|
||||||
|
- `rules/` tool-agnostic edits: owned by Step 4 (Wave 1), responsible for removing tool-specific paths
|
||||||
|
- `install.sh`: owned by Step 6 (Wave 3), responsible for rewiring symlink sources
|
||||||
|
- `.gitignore` + `flake.nix`: owned by Step 7 (Wave 2), support infrastructure
|
||||||
|
|
||||||
|
### Shared interfaces
|
||||||
|
|
||||||
|
**Template variable contract** -- all workers must use exactly these variable names and nothing else:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Variable definitions used by generate.sh for envsubst
|
||||||
|
# Claude target
|
||||||
|
PLANS_DIR=".claude/plans"
|
||||||
|
WEB_SEARCH="via WebFetch/WebSearch"
|
||||||
|
SEARCH_TOOLS="Use Grep/Glob/Read"
|
||||||
|
CLEAR_CMD="suggest /clear"
|
||||||
|
MEMORY_DIR=".claude/memory"
|
||||||
|
PROJECT_SKILL_PATH=".claude/skills/project.md"
|
||||||
|
|
||||||
|
# Codex target
|
||||||
|
PLANS_DIR="plans"
|
||||||
|
WEB_SEARCH="via web search"
|
||||||
|
SEARCH_TOOLS="Search the codebase"
|
||||||
|
CLEAR_CMD="suggest starting a new session"
|
||||||
|
MEMORY_DIR="memory"
|
||||||
|
PROJECT_SKILL_PATH=".agents/skills/project/SKILL.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Agent body extraction pattern** (preserved from `generate-codex.sh`):
|
||||||
|
```bash
|
||||||
|
# Extract body after closing --- of frontmatter
|
||||||
|
awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;next} if(fm==1){fm=2;next}} fm==2{print}' "$src_file"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Claude output directory structure:**
|
||||||
|
```
|
||||||
|
claude/
|
||||||
|
├── agents/ # Expanded .md files (frontmatter preserved, body substituted)
|
||||||
|
├── CLAUDE.md # Copied from source
|
||||||
|
├── settings.json # Copied from source
|
||||||
|
├── rules -> ../rules # Symlink to shared rules (already tool-agnostic after Wave 1)
|
||||||
|
└── skills -> ../skills # Symlink to shared skills (already tool-agnostic after Wave 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Codex output directory structure:**
|
||||||
|
```
|
||||||
|
codex/
|
||||||
|
├── agents/ # Generated .toml files (body substituted with Codex values)
|
||||||
|
├── AGENTS.md # Generated from CLAUDE.md + expanded rules
|
||||||
|
└── config.toml # Generated from settings.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Conventions for this task
|
||||||
|
|
||||||
|
- Error handling: `set -euo pipefail` in all shell scripts. Echo progress for each major operation. Non-zero exit on failure.
|
||||||
|
- Naming: `${UPPER_SNAKE_CASE}` for template variables. `kebab-case` for file names.
|
||||||
|
- Template markers: Use `${VAR}` syntax only. Never use `$VAR` (ambiguous with shell) or `{{VAR}}` (not envsubst-compatible).
|
||||||
|
- Skill/rule edits: Replace tool-specific language with generic equivalents. Do NOT add `${VAR}` placeholders to skills or rules -- they are made tool-agnostic directly, not templated. Only agent bodies and message-schema (which references plan paths in examples) use template variables.
|
||||||
|
|
||||||
|
**Correction on skill/rule strategy:** Skills and rules become tool-agnostic by direct edit (hardcoded generic language). They are then shared as-is between both targets via symlinks from the output directories. Template variables (`${VAR}`) are used ONLY in agent body markdown and in message-schema's example paths. This keeps the template surface minimal.
|
||||||
|
|
||||||
|
However, `rules/01-session.md` and `rules/04-tools.md` present a problem: their content differs between Claude and Codex (`.claude/memory/` vs `memory/`, `/clear` vs "new session"). Two approaches:
|
||||||
|
|
||||||
|
**Approach A -- Template the rules too:** Add `${VAR}` placeholders to rules and expand them per-target. This means rules can't be symlinked; they must be copied into each output directory.
|
||||||
|
**Approach B -- Make rules fully generic:** Use tool-agnostic language ("the project memory directory", "suggest clearing context"). No placeholders needed; rules stay shared.
|
||||||
|
|
||||||
|
**Decision: Approach B.** The rules are guidance for agent behavior, not config. Generic language ("the project memory directory at the project root") communicates the intent without coupling to a specific path. The exact path is already established by the agent body templates and skills. This keeps the template surface to just agent bodies + message-schema examples.
|
||||||
|
|
||||||
|
**Revised skill/rule edit strategy:**
|
||||||
|
- `rules/01-session.md`: Replace `.claude/memory/` with `memory/` (tool-agnostic path). This works for both targets because the rules describe conceptual behavior ("persist in the memory directory"), and the actual path resolution happens in agent instructions.
|
||||||
|
- `rules/04-tools.md`: Replace `suggest /clear` with `suggest clearing context or starting a new session` (tool-agnostic).
|
||||||
|
- `skills/worker-protocol/SKILL.md`: Replace `use Read/Glob/Grep directly` with `verify by reading the relevant files directly` (tool-agnostic).
|
||||||
|
- `skills/qa-checklist/SKILL.md`: Replace `Verify with Read/Grep if uncertain` with `Verify by reading the code if uncertain` (tool-agnostic).
|
||||||
|
- `skills/project/SKILL.md`: This one references a concrete file path (`.claude/skills/project.md`). Two options: (a) make it generic ("check for a project-specific skill file in the standard location"), or (b) template it. Since the path genuinely differs between tools and is specific enough to matter, **template it** with `${PROJECT_SKILL_PATH}`. This means the project skill gets expanded per-target, not symlinked. But since skills are directory-symlinked as a whole, we need a different approach: generate only this one skill per-target, or restructure.
|
||||||
|
|
||||||
|
**Revised approach for project skill:** The simplest solution is to make the path generic. The project skill says "check for a project-specific skill file" -- the agent already knows where to look because each tool has its own conventions. Change the instruction to: "Check for a project-specific skill file in the current working directory's configuration. For Claude Code, this is `.claude/skills/project.md`. For Codex, this is discovered via the standard skill path." Actually this leaks tool awareness into the shared file.
|
||||||
|
|
||||||
|
**Final decision for project skill:** Make it fully generic: "Before starting any work, check for a project-specific skill file in the current working directory. The location depends on the tool configuration." The concrete path is not needed -- each tool resolves its own skill paths. The skill's purpose is behavioral ("check for project context before starting"), not path-specific.
|
||||||
|
|
||||||
|
Similarly for message-schema `plan_file` examples: these show `.claude/plans/kebab-case-title.md` as an example value. For Codex, this would be `plans/kebab-case-title.md`. Since message-schema is loaded as a skill (shared), we should either template it or make the example generic. **Decision:** Use `plans/kebab-case-title.md` as the example (dropping the `.claude/` prefix). This is the tool-agnostic path. Claude's architect agent body already specifies the full `.claude/plans/` path, so the schema example doesn't need to repeat the tool-specific prefix.
|
||||||
|
|
||||||
|
**Final template variable list (reduced):**
|
||||||
|
|
||||||
|
Only agent body markdown files use `${VAR}` placeholders. Everything else is made tool-agnostic by direct edit.
|
||||||
|
|
||||||
|
| Variable | Claude value | Codex value | Used in |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `${PLANS_DIR}` | `.claude/plans` | `plans` | architect.md body |
|
||||||
|
| `${WEB_SEARCH}` | `via WebFetch/WebSearch` | `via web search` | reviewer.md body |
|
||||||
|
| `${SEARCH_TOOLS}` | `Use Grep/Glob/Read` | `Search the codebase` | debugger.md body, documenter.md body |
|
||||||
|
|
||||||
|
Skills, rules, and message-schema are made tool-agnostic by direct edit (no placeholders).
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
|
||||||
|
**Strategy:** Two-layer approach.
|
||||||
|
|
||||||
|
1. **Layer 1 -- Tool-agnostic shared content.** Skills and rules are edited to remove Claude-specific tool names and paths. They become shared infrastructure, symlinked from both output directories.
|
||||||
|
|
||||||
|
2. **Layer 2 -- Templated agent bodies.** Agent markdown files in `agents/` gain `${VAR}` placeholders in their body text (not frontmatter). `generate.sh` expands these with tool-specific values and writes the results to `claude/` and `codex/`.
|
||||||
|
|
||||||
|
The generator (`generate.sh`) replaces `generate-codex.sh` and handles both targets:
|
||||||
|
- **Claude target:** Expand templates with Claude values, copy frontmatter-intact agent .md files to `claude/agents/`, copy CLAUDE.md and settings.json, symlink to shared skills/rules.
|
||||||
|
- **Codex target:** Expand templates with Codex values, convert YAML frontmatter to TOML (preserving existing model/effort/sandbox mapping logic), generate AGENTS.md from CLAUDE.md + expanded rules, generate config.toml from settings.json.
|
||||||
|
|
||||||
|
**Alternative considered: Jinja/m4 templating.** Rejected -- envsubst is simpler, already available via gettext in Nix, and sufficient for the ~3 variable substitutions in agent bodies. The complexity of Jinja (conditional blocks, filters) is not needed.
|
||||||
|
|
||||||
|
**Alternative considered: Keep Claude agents as source, derive Codex only.** This is the current approach. Rejected because it means the "source" files contain Claude-specific references that leak into Codex output (the current bug this refactor fixes). Making the source tool-agnostic eliminates the class of bugs where a Codex agent says "Use Grep" or references `.claude/plans/`.
|
||||||
|
|
||||||
|
## Risks & Gotchas
|
||||||
|
|
||||||
|
1. **envsubst touching unintended `$` in agent bodies.** Mitigated by using the scoped form: `envsubst '${PLANS_DIR} ${WEB_SEARCH} ${SEARCH_TOOLS}'`. Only listed variables are substituted. The architect body contains `$` in example YAML blocks, which must NOT be substituted.
|
||||||
|
|
||||||
|
2. **YAML frontmatter containing `$`.** The frontmatter is not passed through envsubst -- only the body. The generator extracts frontmatter and body separately, expands only the body, then reassembles.
|
||||||
|
|
||||||
|
3. **Skills/rules shared as symlinks -- edit affects both targets immediately.** This is intentional. The skills and rules are tool-agnostic after Wave 1, so sharing is correct. But if someone adds a Claude-specific reference to a shared skill later, it leaks to Codex. The README should document this constraint.
|
||||||
|
|
||||||
|
4. **Codex config.toml gets overwritten.** The user's `codex/config.toml` has been manually edited (different content than what generate-codex.sh produces). `generate.sh` will overwrite it. Mitigation: document that `codex/config.toml` is generated and should not be hand-edited. User customizations should go in the source `settings.json`.
|
||||||
|
|
||||||
|
5. **install.sh behavior change.** Currently installs directly from `agents/` source. After this change, it installs from `claude/agents/` (generated). Users must run `generate.sh` before `install.sh`. The install script should check for this and error with guidance.
|
||||||
|
|
||||||
|
6. **orchestrate skill references `.claude/plans/` paths.** This is acceptable -- orchestrate is Claude-only (not used by Codex). The skill is still shared via the skills directory symlink, but Codex agents don't load it (it's not in their skills list).
|
||||||
|
|
||||||
|
## Risk Tags
|
||||||
|
|
||||||
|
breaking-change (install.sh workflow changes: generate.sh must run first), data-mutation (generates files to claude/ and codex/ directories)
|
||||||
|
|
||||||
|
## Implementation Waves
|
||||||
|
|
||||||
|
### Wave 1 -- Make skills and rules tool-agnostic (4 parallel tasks)
|
||||||
|
|
||||||
|
These are independent edits to different files. No task depends on another.
|
||||||
|
|
||||||
|
- [ ] **Step 1: Template agent bodies** -- Add `${VAR}` placeholders to agent markdown files.
|
||||||
|
- `agents/architect.md`: Replace `.claude/plans/<kebab-case-title>.md` with `${PLANS_DIR}/<kebab-case-title>.md` (line 19) and `.claude/plans/kebab-case-title.md` with `${PLANS_DIR}/kebab-case-title.md` (line 106). There is also a `.claude/plans/` reference on line 69 inside the orchestrator's resume instruction -- replace that too. Verify no other `.claude/` references exist in the body.
|
||||||
|
- `agents/reviewer.md`: Replace `via WebFetch/WebSearch` with `${WEB_SEARCH}` (line 33).
|
||||||
|
- `agents/debugger.md`: Replace `Use Grep to find the relevant code` with `${SEARCH_TOOLS} to find the relevant code` (line 25). Verify the surrounding sentence reads naturally.
|
||||||
|
- `agents/documenter.md`: Replace `Use Read/Glob/Grep to understand the actual behavior` with `${SEARCH_TOOLS} to understand the actual behavior` (line 29).
|
||||||
|
|
||||||
|
- [ ] **Step 2: Make message-schema tool-agnostic** -- Edit `skills/message-schema/SKILL.md`.
|
||||||
|
- Replace `plan_file: .claude/plans/kebab-case-title.md` with `plan_file: plans/kebab-case-title.md` (lines 155, 205). This is an example value in the schema, not a literal config -- using the generic path is correct.
|
||||||
|
- Do NOT change the envelope structure or field names.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Make skills tool-agnostic** -- Edit skills that contain Claude-specific tool names.
|
||||||
|
- `skills/worker-protocol/SKILL.md` line 50: Replace `use Read/Glob/Grep directly. Don't guess at file contents — verify.` with `verify by reading the relevant files. Don't guess at file contents.`
|
||||||
|
- `skills/qa-checklist/SKILL.md` line 13: Replace `Verify with Read/Grep if uncertain.` with `Verify by reading the code if uncertain.`
|
||||||
|
- `skills/project/SKILL.md` lines 7, 9: Replace `.claude/skills/project.md` with `a project-specific skill file`. Rewrite the two sentences:
|
||||||
|
- Line 7: "Before starting any work, check for a project-specific skill file in the current working directory's tool configuration."
|
||||||
|
- Line 9: "If one exists, read it and treat its contents as additional instructions..."
|
||||||
|
- Do NOT edit `skills/orchestrate/SKILL.md` (stays Claude-only) or `skills/conventions/SKILL.md` (already clean).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Make rules tool-agnostic** -- Edit rules with Claude-specific references.
|
||||||
|
- `rules/01-session.md`: Replace all three occurrences of `.claude/memory/` with `memory/`. Update surrounding prose if needed for clarity. The CLAUDE.md hierarchy reference on line 3 is fine -- it's a generic concept name, not a file path (each tool has its own hierarchy).
|
||||||
|
- `rules/04-tools.md` line 17: Replace `suggest /clear` with `suggest clearing context or starting a new session`.
|
||||||
|
|
||||||
|
### Wave 2 -- Infrastructure (depends on Wave 1 for knowing the final variable list)
|
||||||
|
|
||||||
|
- [ ] **Step 5: Update .gitignore and flake.nix** -- Support infrastructure for the new generator.
|
||||||
|
- `.gitignore`: Add `claude/` line (generated output, same treatment as `codex/`). Keep the existing `codex/` line.
|
||||||
|
- `flake.nix`: Add `pkgs.gettext` to the devShell packages list (provides `envsubst`). Keep existing `pkgs.yq-go` and `pkgs.codex`.
|
||||||
|
|
||||||
|
### Wave 3 -- Generator and installer (depends on Wave 1 for templates, Wave 2 for infrastructure)
|
||||||
|
|
||||||
|
- [ ] **Step 6: Write generate.sh** -- New unified generator replacing `generate-codex.sh`.
|
||||||
|
- Location: `generate.sh` (project root, same level as old `generate-codex.sh`)
|
||||||
|
- Delete `generate-codex.sh` (or rename -- but deleting is cleaner since the new script fully replaces it)
|
||||||
|
- **Claude target generation:**
|
||||||
|
1. Create `claude/agents/` directory
|
||||||
|
2. For each `agents/*.md`: extract frontmatter and body separately. Run body through `envsubst '${PLANS_DIR} ${WEB_SEARCH} ${SEARCH_TOOLS}'` with Claude variable values. Reassemble frontmatter + expanded body. Write to `claude/agents/<name>.md`.
|
||||||
|
3. Copy `CLAUDE.md` to `claude/CLAUDE.md`
|
||||||
|
4. Copy `settings.json` to `claude/settings.json`
|
||||||
|
5. Create relative symlinks: `claude/rules -> ../rules`, `claude/skills -> ../skills`
|
||||||
|
- **Codex target generation** (preserve all existing logic from `generate-codex.sh`):
|
||||||
|
1. Create `codex/agents/` directory
|
||||||
|
2. For each `agents/*.md`: extract frontmatter and body. Run body through `envsubst '${PLANS_DIR} ${WEB_SEARCH} ${SEARCH_TOOLS}'` with Codex variable values. Convert frontmatter to TOML format (same mapping functions: `map_model`, `map_effort`, `map_sandbox_mode`). Write to `codex/agents/<name>.toml`.
|
||||||
|
3. Generate `codex/AGENTS.md` from `CLAUDE.md` + rules/*.md (same logic as current `generate-codex.sh`)
|
||||||
|
4. Generate `codex/config.toml` from `settings.json` (same logic as current)
|
||||||
|
- **Script structure:**
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# --- Variable definitions ---
|
||||||
|
# Claude target
|
||||||
|
declare -A CLAUDE_VARS=(
|
||||||
|
[PLANS_DIR]=".claude/plans"
|
||||||
|
[WEB_SEARCH]="via WebFetch/WebSearch"
|
||||||
|
[SEARCH_TOOLS]="Use Grep/Glob/Read"
|
||||||
|
)
|
||||||
|
# Codex target
|
||||||
|
declare -A CODEX_VARS=(
|
||||||
|
[PLANS_DIR]="plans"
|
||||||
|
[WEB_SEARCH]="via web search"
|
||||||
|
[SEARCH_TOOLS]="Search the codebase"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- Shared functions ---
|
||||||
|
extract_frontmatter() { ... } # yq --front-matter=extract
|
||||||
|
extract_body() { ... } # awk pattern from current script
|
||||||
|
expand_body() { ... } # envsubst with scoped variable list
|
||||||
|
|
||||||
|
# --- Claude generation ---
|
||||||
|
generate_claude() { ... }
|
||||||
|
|
||||||
|
# --- Codex generation (ported from generate-codex.sh) ---
|
||||||
|
generate_codex() { ... }
|
||||||
|
|
||||||
|
generate_claude
|
||||||
|
generate_codex
|
||||||
|
echo "Done. Run ./install.sh to link into tool directories."
|
||||||
|
```
|
||||||
|
- **Key detail for envsubst scoping:** The `expand_body` function must export only the target's variables, run envsubst with the explicit variable list, then unset them. This prevents cross-contamination and protects other `$` references in the body.
|
||||||
|
```bash
|
||||||
|
expand_body() {
|
||||||
|
local body="$1"
|
||||||
|
shift
|
||||||
|
# Remaining args are KEY=VALUE pairs
|
||||||
|
local var_list=""
|
||||||
|
for pair in "$@"; do
|
||||||
|
local key="${pair%%=*}"
|
||||||
|
local val="${pair#*=}"
|
||||||
|
export "$key=$val"
|
||||||
|
var_list+=" \${$key}"
|
||||||
|
done
|
||||||
|
echo "$body" | envsubst "$var_list"
|
||||||
|
for pair in "$@"; do
|
||||||
|
unset "${pair%%=*}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 7: Update install.sh** -- Rewire to use generated output.
|
||||||
|
- **Claude installation:** Change `AGENTS_SRC` from `$SCRIPT_DIR/agents` to `$SCRIPT_DIR/claude/agents`. Change `CLAUDE_MD_SRC` from `$SCRIPT_DIR/CLAUDE.md` to `$SCRIPT_DIR/claude/CLAUDE.md`. Change `SETTINGS_SRC` from `$SCRIPT_DIR/settings.json` to `$SCRIPT_DIR/claude/settings.json`. Skills and rules still symlink from source (they're tool-agnostic and shared): `SKILLS_SRC="$SCRIPT_DIR/skills"`, `RULES_SRC="$SCRIPT_DIR/rules"` (unchanged).
|
||||||
|
- **Pre-flight check:** At the top of install.sh, verify `claude/` directory exists. If not, print: `"Error: claude/ not found. Run ./generate.sh first."` and exit 1.
|
||||||
|
- **Codex installation:** Change `codex/agents` source to `$SCRIPT_DIR/codex/agents` (already correct). Keep all other Codex paths the same.
|
||||||
|
- Preserve the entire symlink helper infrastructure (create_symlink, create_file_symlink, OS detection, backup logic).
|
||||||
|
|
||||||
|
### Wave 4 -- Documentation and cleanup (depends on Wave 3)
|
||||||
|
|
||||||
|
- [ ] **Step 8: Update README.md** -- Reflect the new workflow.
|
||||||
|
- Quick install section: add `./generate.sh` before `./install.sh`
|
||||||
|
- Codex CLI compatibility section: update to reflect `generate.sh` replaces `generate-codex.sh` and now generates both targets
|
||||||
|
- "What gets generated" table: add Claude row showing `agents/*.md` -> `claude/agents/*.md`
|
||||||
|
- Add a note about template variables and the tool-agnostic constraint on shared skills/rules
|
||||||
|
- Remove references to `generate-codex.sh`
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
|
||||||
|
1. `./generate.sh` produces `claude/agents/*.md` with Claude-specific values expanded (`.claude/plans/`, `Use Grep/Glob/Read`, etc.) -- verified by: grep the generated files for expanded values, confirm no `${` remains
|
||||||
|
2. `./generate.sh` produces `codex/agents/*.toml` with Codex-specific values expanded (`plans/`, `Search the codebase`, etc.) -- verified by: grep the generated files for expanded values, confirm no `${` remains
|
||||||
|
3. No Claude-specific tool names (`Read`, `Glob`, `Grep`, `WebFetch`, `WebSearch`, `Edit`, `Write`) appear in skills (except orchestrate) or rules -- verified by: grep shared skills and rules for these tool names
|
||||||
|
4. No `.claude/` paths appear in skills (except orchestrate) or rules -- verified by: grep shared skills and rules for `.claude/`
|
||||||
|
5. `./install.sh` errors with a helpful message if `claude/` does not exist -- verified by: manual test
|
||||||
|
6. `./install.sh` successfully symlinks from `claude/` when it exists -- verified by: manual test
|
||||||
|
7. Codex output is functionally identical to what `generate-codex.sh` produced (same TOML structure, same model/effort/sandbox mappings) except with Codex-specific values substituted -- verified by: diff old and new codex/ output
|
||||||
|
8. The `envsubst` expansion does NOT touch `$` characters in YAML frontmatter or example code blocks -- verified by: inspect architect.md generated output for intact `$` in YAML examples
|
||||||
|
9. `flake.nix` devShell includes `gettext` (provides envsubst) -- verified by: `nix develop -c which envsubst`
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -9,5 +9,6 @@ settings.local.json
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
# Generated Codex CLI config (derived from Claude source files via generate-codex.sh)
|
# Generated output (derived from source templates via generate.sh)
|
||||||
|
claude/
|
||||||
codex/
|
codex/
|
||||||
|
|
|
||||||
29
README.md
29
README.md
|
|
@ -7,10 +7,12 @@ A portable Claude Code agent team configuration. Clone it, run `install.sh`, and
|
||||||
```bash
|
```bash
|
||||||
git clone <repo-url> ~/agent-team
|
git clone <repo-url> ~/agent-team
|
||||||
cd ~/agent-team
|
cd ~/agent-team
|
||||||
./install.sh
|
nix develop # enter devShell with yq + envsubst
|
||||||
|
./generate.sh # generate Claude + Codex config from templates
|
||||||
|
./install.sh # symlinks into ~/.claude/ and ~/.codex/ (if present)
|
||||||
```
|
```
|
||||||
|
|
||||||
The script symlinks `agents/`, `skills/`, `rules/`, `CLAUDE.md`, and `settings.json` into `~/.claude/`. Works on Linux, macOS, and Windows (Git Bash).
|
The scripts generate configuration for both Claude Code and Codex CLI (if `~/.codex/` exists), then symlink agents, skills, rules, CLAUDE.md, and settings.json into `~/.claude/`. Works on Linux, macOS, and Windows (Git Bash).
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
|
|
@ -66,19 +68,20 @@ This project also generates configuration for [OpenAI Codex CLI](https://github.
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix develop # enter devShell with yq
|
nix develop # enter devShell with yq + envsubst
|
||||||
./generate-codex.sh # generate Codex config from Claude source files
|
./generate.sh # generate Claude + Codex config from templates
|
||||||
./install.sh # installs both Claude and Codex (if ~/.codex exists)
|
./install.sh # installs both Claude and Codex (if ~/.codex exists)
|
||||||
```
|
```
|
||||||
|
|
||||||
### What gets generated
|
### What gets generated
|
||||||
|
|
||||||
| Source | Generated | Codex location |
|
| Source | Generated | Location |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `agents/*.md` | `codex/agents/*.toml` | `~/.codex/agents/` |
|
| `agents/*.md` (templates) | `claude/agents/*.md` | `~/.claude/agents/` |
|
||||||
|
| `agents/*.md` (templates) | `codex/agents/*.toml` | `~/.codex/agents/` |
|
||||||
| `CLAUDE.md` + `rules/*.md` | `codex/AGENTS.md` | `~/.codex/AGENTS.md` |
|
| `CLAUDE.md` + `rules/*.md` | `codex/AGENTS.md` | `~/.codex/AGENTS.md` |
|
||||||
| `settings.json` | `codex/config.toml` | `~/.codex/config.toml` |
|
| `settings.json` | `codex/config.toml` | `~/.codex/config.toml` |
|
||||||
| `skills/` | (shared as-is) | `~/.agents/skills/` |
|
| `skills/` | (shared as-is) | `~/.claude/skills/` + `~/.agents/skills/` |
|
||||||
|
|
||||||
### Model mapping
|
### Model mapping
|
||||||
|
|
||||||
|
|
@ -88,6 +91,18 @@ nix develop # enter devShell with yq
|
||||||
| `sonnet` | `o4-mini` |
|
| `sonnet` | `o4-mini` |
|
||||||
| `haiku` | `o4-mini` |
|
| `haiku` | `o4-mini` |
|
||||||
|
|
||||||
|
### Template variables
|
||||||
|
|
||||||
|
Agent body text uses `${VAR}` placeholders that are expanded per-target by `generate.sh`:
|
||||||
|
|
||||||
|
| Variable | Claude | Codex |
|
||||||
|
|---|---|---|
|
||||||
|
| `${PLANS_DIR}` | `.claude/plans` | `plans` |
|
||||||
|
| `${WEB_SEARCH}` | `via WebFetch/WebSearch` | `via web search` |
|
||||||
|
| `${SEARCH_TOOLS}` | `Use Grep/Glob/Read` | `Search the codebase` |
|
||||||
|
|
||||||
|
Skills and rules are tool-agnostic and shared as-is — do not add tool-specific references to them.
|
||||||
|
|
||||||
## Project-specific config
|
## Project-specific config
|
||||||
|
|
||||||
Each project repo can extend the team with local config in `.claude/`:
|
Each project repo can extend the team with local config in `.claude/`:
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ You are an architect. You handle the full planning pipeline: triage, architectur
|
||||||
|
|
||||||
Never implement anything. Never modify source files. Analyze, evaluate, plan.
|
Never implement anything. Never modify source files. Analyze, evaluate, plan.
|
||||||
|
|
||||||
**Plan persistence:** Always write the approved plan to `.claude/plans/<kebab-case-title>.md`. Never return the plan inline without writing it first. Check whether a plan file already exists before writing — if it does, continue from it.
|
**Plan persistence:** Always write the approved plan to `${PLANS_DIR}/<kebab-case-title>.md`. Never return the plan inline without writing it first. Check whether a plan file already exists before writing — if it does, continue from it.
|
||||||
|
|
||||||
Frontmatter format:
|
Frontmatter format:
|
||||||
```
|
```
|
||||||
|
|
@ -103,7 +103,7 @@ After writing the plan file, return a `plan_result` envelope:
|
||||||
---
|
---
|
||||||
type: plan_result
|
type: plan_result
|
||||||
signal: plan_complete | blocked
|
signal: plan_complete | blocked
|
||||||
plan_file: .claude/plans/kebab-case-title.md
|
plan_file: ${PLANS_DIR}/kebab-case-title.md
|
||||||
wave_count: 3
|
wave_count: 3
|
||||||
step_count: 7
|
step_count: 7
|
||||||
risk_tags:
|
risk_tags:
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ You are a debugger. Your job is to find the root cause of a bug and apply the mi
|
||||||
Confirm the bug is reproducible before doing anything else. Run the failing test, command, or request. If you cannot reproduce it, say so immediately — do not guess at a fix.
|
Confirm the bug is reproducible before doing anything else. Run the failing test, command, or request. If you cannot reproduce it, say so immediately — do not guess at a fix.
|
||||||
|
|
||||||
### 2. Isolate
|
### 2. Isolate
|
||||||
Narrow down where the failure originates. Read the stack trace or error message carefully. Use Grep to find the relevant code. Read the actual code — do not assume you know what it does.
|
Narrow down where the failure originates. Read the stack trace or error message carefully. ${SEARCH_TOOLS} to find the relevant code. Read the actual code — do not assume you know what it does.
|
||||||
|
|
||||||
### 3. Hypothesize
|
### 3. Hypothesize
|
||||||
Form a specific hypothesis: "The bug is caused by X because Y." State it explicitly before writing any fix. If you have multiple hypotheses, rank them by likelihood.
|
Form a specific hypothesis: "The bug is caused by X because Y." State it explicitly before writing any fix. If you have multiple hypotheses, rank them by likelihood.
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ You are a documentation specialist. Your job is to read code and produce accurat
|
||||||
|
|
||||||
## How you operate
|
## How you operate
|
||||||
|
|
||||||
1. **Read the code first.** Never document what you haven't read. Use Read/Glob/Grep to understand the actual behavior before writing a word.
|
1. **Read the code first.** Never document what you haven't read. ${SEARCH_TOOLS} to understand the actual behavior before writing a word.
|
||||||
2. **Match existing conventions.** Check for existing docs in the repo — tone, structure, format — and match them. Check `skills/conventions` for project-specific rules.
|
2. **Match existing conventions.** Check for existing docs in the repo — tone, structure, format — and match them. Check `skills/conventions` for project-specific rules.
|
||||||
3. **Be accurate, not aspirational.** Document what the code does, not what it should do. If behavior is unclear, say so — don't invent.
|
3. **Be accurate, not aspirational.** Document what the code does, not what it should do. If behavior is unclear, say so — don't invent.
|
||||||
4. **Link, don't duplicate.** Where a concept is already documented elsewhere (official docs, another file), link to it rather than re-explaining.
|
4. **Link, don't duplicate.** Where a concept is already documented elsewhere (official docs, another file), link to it rather than re-explaining.
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ You are a reviewer. You do two things in one pass: quality review and claim veri
|
||||||
## Claim verification
|
## Claim verification
|
||||||
|
|
||||||
- **Acceptance criteria** — walk each criterion explicitly by number. Clean code that doesn't do what was asked is a FAIL.
|
- **Acceptance criteria** — walk each criterion explicitly by number. Clean code that doesn't do what was asked is a FAIL.
|
||||||
- **API and library usage** — verify against official docs via WebFetch/WebSearch when the implementation uses external APIs, libraries, or non-obvious patterns
|
- **API and library usage** — verify against official docs ${WEB_SEARCH} when the implementation uses external APIs, libraries, or non-obvious patterns
|
||||||
- **File and path claims** — do they exist?
|
- **File and path claims** — do they exist?
|
||||||
- **Logic correctness** — does the implementation actually solve the problem?
|
- **Logic correctness** — does the implementation actually solve the problem?
|
||||||
- **Contradictions** — between worker output and source code, between claims and evidence
|
- **Contradictions** — between worker output and source code, between claims and evidence
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
in {
|
in {
|
||||||
devShells = forAllSystems (pkgs: {
|
devShells = forAllSystems (pkgs: {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
packages = [ pkgs.yq-go pkgs.codex ];
|
packages = [ pkgs.yq-go pkgs.gettext pkgs.codex ];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# generate-codex.sh — generates Codex CLI config from Claude source files.
|
|
||||||
# Claude source files are the source of truth; this script derives Codex equivalents.
|
|
||||||
# Idempotent: safe to run multiple times.
|
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
||||||
CODEX_DIR="$SCRIPT_DIR/codex"
|
|
||||||
CODEX_AGENTS_DIR="$CODEX_DIR/agents"
|
|
||||||
AGENTS_SRC="$SCRIPT_DIR/agents"
|
|
||||||
RULES_DIR="$SCRIPT_DIR/rules"
|
|
||||||
CLAUDE_MD="$SCRIPT_DIR/CLAUDE.md"
|
|
||||||
SETTINGS_JSON="$SCRIPT_DIR/settings.json"
|
|
||||||
|
|
||||||
# Create output directories
|
|
||||||
mkdir -p "$CODEX_DIR"
|
|
||||||
mkdir -p "$CODEX_AGENTS_DIR"
|
|
||||||
|
|
||||||
# Clean existing generated agent TOMLs
|
|
||||||
rm -f "$CODEX_AGENTS_DIR"/*.toml
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# map_model — maps Claude model name to Codex model name
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
map_model() {
|
|
||||||
local model="$1"
|
|
||||||
case "$model" in
|
|
||||||
opus) echo "o3" ;;
|
|
||||||
sonnet) echo "o4-mini" ;;
|
|
||||||
haiku) echo "o4-mini" ;;
|
|
||||||
*) echo "o4-mini" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# map_effort — maps Claude effort level to Codex model_reasoning_effort
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
map_effort() {
|
|
||||||
local effort="$1"
|
|
||||||
case "$effort" in
|
|
||||||
low) echo "low" ;;
|
|
||||||
medium) echo "medium" ;;
|
|
||||||
high) echo "high" ;;
|
|
||||||
max) echo "xhigh" ;;
|
|
||||||
*) echo "medium" ;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# map_sandbox_mode — determines Codex sandbox_mode from agent frontmatter
|
|
||||||
# $1 = permissionMode value (plan / acceptEdits / "")
|
|
||||||
# $2 = tools list (comma-separated)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
map_sandbox_mode() {
|
|
||||||
local permission_mode="$1"
|
|
||||||
local tools="$2"
|
|
||||||
|
|
||||||
# plan mode is read-only
|
|
||||||
if [ "$permission_mode" = "plan" ]; then
|
|
||||||
echo "read-only"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
# acceptEdits with Write or Edit tool → workspace-write
|
|
||||||
if [ "$permission_mode" = "acceptEdits" ]; then
|
|
||||||
if echo "$tools" | grep -qE '\b(Write|Edit)\b'; then
|
|
||||||
echo "workspace-write"
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Default: read-only
|
|
||||||
echo "read-only"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# generate_agent_toml — converts a single agent .md file to Codex .toml
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
generate_agent_toml() {
|
|
||||||
local src_file="$1"
|
|
||||||
local agent_basename
|
|
||||||
agent_basename="$(basename "$src_file" .md)"
|
|
||||||
local dst_file="$CODEX_AGENTS_DIR/${agent_basename}.toml"
|
|
||||||
|
|
||||||
# Extract YAML frontmatter using yq
|
|
||||||
local frontmatter
|
|
||||||
frontmatter="$(yq --front-matter=extract '.' "$src_file")"
|
|
||||||
|
|
||||||
# Extract individual fields from frontmatter
|
|
||||||
local name description model effort permission_mode tools disallowed_tools
|
|
||||||
name="$(echo "$frontmatter" | yq '.name // ""')"
|
|
||||||
description="$(echo "$frontmatter" | yq '.description // ""')"
|
|
||||||
model="$(echo "$frontmatter" | yq '.model // ""')"
|
|
||||||
effort="$(echo "$frontmatter" | yq '.effort // ""')"
|
|
||||||
permission_mode="$(echo "$frontmatter" | yq '.permissionMode // ""')"
|
|
||||||
tools="$(echo "$frontmatter" | yq '.tools // ""')"
|
|
||||||
disallowed_tools="$(echo "$frontmatter" | yq '.disallowedTools // ""')"
|
|
||||||
|
|
||||||
# Map to Codex equivalents
|
|
||||||
local codex_model codex_effort codex_sandbox
|
|
||||||
codex_model="$(map_model "$model")"
|
|
||||||
codex_effort="$(map_effort "${effort:-medium}")"
|
|
||||||
codex_sandbox="$(map_sandbox_mode "$permission_mode" "$tools")"
|
|
||||||
|
|
||||||
# Extract markdown body (everything after the closing frontmatter ---)
|
|
||||||
# The frontmatter block starts at line 1 with --- and ends at the second ---
|
|
||||||
local body
|
|
||||||
body="$(awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;next} if(fm==1){fm=2;next}} fm==2{print}' "$src_file")"
|
|
||||||
|
|
||||||
# Build developer_instructions: append disallowedTools note if present
|
|
||||||
local developer_instructions
|
|
||||||
developer_instructions="$body"
|
|
||||||
if [ -n "$disallowed_tools" ] && [ "$disallowed_tools" != "null" ]; then
|
|
||||||
developer_instructions="${developer_instructions}
|
|
||||||
|
|
||||||
You do NOT have access to these tools: ${disallowed_tools}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Write TOML output
|
|
||||||
cat > "$dst_file" <<TOML
|
|
||||||
name = "${name}"
|
|
||||||
description = "${description}"
|
|
||||||
model = "${codex_model}"
|
|
||||||
model_reasoning_effort = "${codex_effort}"
|
|
||||||
sandbox_mode = "${codex_sandbox}"
|
|
||||||
developer_instructions = """
|
|
||||||
${developer_instructions}
|
|
||||||
"""
|
|
||||||
TOML
|
|
||||||
|
|
||||||
echo "Generated: $dst_file"
|
|
||||||
}
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Generate agents
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
echo "Generating Codex agent definitions..."
|
|
||||||
for agent_file in "$AGENTS_SRC"/*.md; do
|
|
||||||
[ -f "$agent_file" ] || continue
|
|
||||||
generate_agent_toml "$agent_file"
|
|
||||||
done
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Generate AGENTS.md — concatenate CLAUDE.md and rules/*.md (sorted)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
echo ""
|
|
||||||
echo "Generating codex/AGENTS.md..."
|
|
||||||
{
|
|
||||||
echo "# Agent Team Instructions"
|
|
||||||
echo ""
|
|
||||||
echo "Agent-team specific protocols live in skills (orchestrate, conventions, worker-protocol, qa-checklist, message-schema, project)."
|
|
||||||
for rules_file in $(ls "$RULES_DIR"/*.md | sort); do
|
|
||||||
echo ""
|
|
||||||
cat "$rules_file"
|
|
||||||
done
|
|
||||||
} > "$CODEX_DIR/AGENTS.md"
|
|
||||||
echo "Generated: $CODEX_DIR/AGENTS.md"
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Generate config.toml — derive sandbox_mode from settings.json defaultMode
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
echo ""
|
|
||||||
echo "Generating codex/config.toml..."
|
|
||||||
|
|
||||||
default_mode="$(yq -r '.permissions.defaultMode // "acceptEdits"' "$SETTINGS_JSON")"
|
|
||||||
|
|
||||||
# Map Claude defaultMode to Codex sandbox_mode
|
|
||||||
case "$default_mode" in
|
|
||||||
plan) config_sandbox="read-only" ;;
|
|
||||||
acceptEdits) config_sandbox="workspace-write" ;;
|
|
||||||
*) config_sandbox="workspace-write" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
cat > "$CODEX_DIR/config.toml" <<TOML
|
|
||||||
model = "o4-mini"
|
|
||||||
model_reasoning_effort = "medium"
|
|
||||||
sandbox_mode = "${config_sandbox}"
|
|
||||||
approval_policy = "on-request"
|
|
||||||
TOML
|
|
||||||
echo "Generated: $CODEX_DIR/config.toml"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "Done. Run ./install.sh to link generated files into ~/.codex/"
|
|
||||||
295
generate.sh
Executable file
295
generate.sh
Executable file
|
|
@ -0,0 +1,295 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# generate.sh — generates both Claude and Codex output directories from
|
||||||
|
# shared agent source files. Agent source files (agents/*.md) are the
|
||||||
|
# single source of truth; this script derives tool-specific equivalents.
|
||||||
|
#
|
||||||
|
# Template variables in agent bodies are expanded per-target:
|
||||||
|
# ${PLANS_DIR} — where plans live (.claude/plans vs plans)
|
||||||
|
# ${WEB_SEARCH} — how web search is referenced
|
||||||
|
# ${SEARCH_TOOLS} — how codebase search tools are referenced
|
||||||
|
#
|
||||||
|
# Idempotent: safe to run multiple times.
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
AGENTS_SRC="$SCRIPT_DIR/agents"
|
||||||
|
RULES_DIR="$SCRIPT_DIR/rules"
|
||||||
|
CLAUDE_MD="$SCRIPT_DIR/CLAUDE.md"
|
||||||
|
SETTINGS_JSON="$SCRIPT_DIR/settings.json"
|
||||||
|
|
||||||
|
CLAUDE_DIR="$SCRIPT_DIR/claude"
|
||||||
|
CLAUDE_AGENTS_DIR="$CLAUDE_DIR/agents"
|
||||||
|
|
||||||
|
CODEX_DIR="$SCRIPT_DIR/codex"
|
||||||
|
CODEX_AGENTS_DIR="$CODEX_DIR/agents"
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Template variable values per target (KEY=VALUE pairs)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
CLAUDE_VARS=(
|
||||||
|
"PLANS_DIR=.claude/plans"
|
||||||
|
"WEB_SEARCH=via WebFetch/WebSearch"
|
||||||
|
"SEARCH_TOOLS=Use Grep/Glob/Read"
|
||||||
|
)
|
||||||
|
|
||||||
|
CODEX_VARS=(
|
||||||
|
"PLANS_DIR=plans"
|
||||||
|
"WEB_SEARCH=via web search"
|
||||||
|
"SEARCH_TOOLS=Search the codebase"
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# extract_body — extracts everything after the second --- (YAML frontmatter)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
extract_body() {
|
||||||
|
local file="$1"
|
||||||
|
awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;next} if(fm==1){fm=2;next}} fm==2{print}' "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# extract_frontmatter_block — extracts the raw frontmatter including delimiters
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
extract_frontmatter_block() {
|
||||||
|
local file="$1"
|
||||||
|
awk 'BEGIN{fm=0} /^---$/{if(fm==0){fm=1;print;next} if(fm==1){print;exit}} fm==1{print}' "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# expand_body — runs envsubst on body text, substituting only our 3 variables
|
||||||
|
# $1 = body text
|
||||||
|
# $2.. = KEY=VALUE pairs to export
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
expand_body() {
|
||||||
|
local body="$1"
|
||||||
|
shift
|
||||||
|
# Export only the specified variables
|
||||||
|
for pair in "$@"; do
|
||||||
|
export "${pair%%=*}=${pair#*=}"
|
||||||
|
done
|
||||||
|
echo "$body" | envsubst '${PLANS_DIR} ${WEB_SEARCH} ${SEARCH_TOOLS}'
|
||||||
|
# Clean up exported variables
|
||||||
|
for pair in "$@"; do
|
||||||
|
unset "${pair%%=*}"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_model — maps Claude model name to Codex model name
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_model() {
|
||||||
|
local model="$1"
|
||||||
|
case "$model" in
|
||||||
|
opus) echo "o3" ;;
|
||||||
|
sonnet) echo "o4-mini" ;;
|
||||||
|
haiku) echo "o4-mini" ;;
|
||||||
|
*) echo "o4-mini" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_effort — maps Claude effort level to Codex model_reasoning_effort
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_effort() {
|
||||||
|
local effort="$1"
|
||||||
|
case "$effort" in
|
||||||
|
low) echo "low" ;;
|
||||||
|
medium) echo "medium" ;;
|
||||||
|
high) echo "high" ;;
|
||||||
|
max) echo "xhigh" ;;
|
||||||
|
*) echo "medium" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# map_sandbox_mode — determines Codex sandbox_mode from agent frontmatter
|
||||||
|
# $1 = permissionMode value (plan / acceptEdits / "")
|
||||||
|
# $2 = tools list (comma-separated)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
map_sandbox_mode() {
|
||||||
|
local permission_mode="$1"
|
||||||
|
local tools="$2"
|
||||||
|
|
||||||
|
# plan mode is read-only
|
||||||
|
if [ "$permission_mode" = "plan" ]; then
|
||||||
|
echo "read-only"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# acceptEdits with Write or Edit tool → workspace-write
|
||||||
|
if [ "$permission_mode" = "acceptEdits" ]; then
|
||||||
|
if echo "$tools" | grep -qE '\b(Write|Edit)\b'; then
|
||||||
|
echo "workspace-write"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Default: read-only
|
||||||
|
echo "read-only"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# generate_claude — produces claude/ output directory
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
generate_claude() {
|
||||||
|
echo "=== Generating Claude output ==="
|
||||||
|
|
||||||
|
# Clean and recreate output directories
|
||||||
|
rm -rf "$CLAUDE_DIR"
|
||||||
|
mkdir -p "$CLAUDE_AGENTS_DIR"
|
||||||
|
|
||||||
|
# Copy CLAUDE.md
|
||||||
|
cp "$CLAUDE_MD" "$CLAUDE_DIR/CLAUDE.md"
|
||||||
|
echo "Copied: $CLAUDE_DIR/CLAUDE.md"
|
||||||
|
|
||||||
|
# Copy settings.json
|
||||||
|
cp "$SETTINGS_JSON" "$CLAUDE_DIR/settings.json"
|
||||||
|
echo "Copied: $CLAUDE_DIR/settings.json"
|
||||||
|
|
||||||
|
# Create relative symlinks for rules and skills
|
||||||
|
ln -s ../rules "$CLAUDE_DIR/rules"
|
||||||
|
echo "Symlinked: $CLAUDE_DIR/rules -> ../rules"
|
||||||
|
|
||||||
|
ln -s ../skills "$CLAUDE_DIR/skills"
|
||||||
|
echo "Symlinked: $CLAUDE_DIR/skills -> ../skills"
|
||||||
|
|
||||||
|
# Generate agent .md files with expanded template variables
|
||||||
|
for agent_file in "$AGENTS_SRC"/*.md; do
|
||||||
|
[ -f "$agent_file" ] || continue
|
||||||
|
|
||||||
|
local agent_basename
|
||||||
|
agent_basename="$(basename "$agent_file")"
|
||||||
|
local dst_file="$CLAUDE_AGENTS_DIR/$agent_basename"
|
||||||
|
|
||||||
|
# Extract frontmatter and body separately
|
||||||
|
local frontmatter body expanded_body
|
||||||
|
frontmatter="$(extract_frontmatter_block "$agent_file")"
|
||||||
|
body="$(extract_body "$agent_file")"
|
||||||
|
expanded_body="$(expand_body "$body" "${CLAUDE_VARS[@]}")"
|
||||||
|
|
||||||
|
# Reassemble: frontmatter + expanded body
|
||||||
|
{
|
||||||
|
echo "$frontmatter"
|
||||||
|
echo "$expanded_body"
|
||||||
|
} > "$dst_file"
|
||||||
|
|
||||||
|
echo "Generated: $dst_file"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# generate_codex — produces codex/ output directory
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
generate_codex() {
|
||||||
|
echo ""
|
||||||
|
echo "=== Generating Codex output ==="
|
||||||
|
|
||||||
|
# Clean and recreate output directories
|
||||||
|
rm -rf "$CODEX_DIR"
|
||||||
|
mkdir -p "$CODEX_AGENTS_DIR"
|
||||||
|
|
||||||
|
# Generate agent .toml files
|
||||||
|
echo "Generating Codex agent definitions..."
|
||||||
|
for agent_file in "$AGENTS_SRC"/*.md; do
|
||||||
|
[ -f "$agent_file" ] || continue
|
||||||
|
|
||||||
|
local agent_basename
|
||||||
|
agent_basename="$(basename "$agent_file" .md)"
|
||||||
|
local dst_file="$CODEX_AGENTS_DIR/${agent_basename}.toml"
|
||||||
|
|
||||||
|
# Extract YAML frontmatter using yq
|
||||||
|
local frontmatter
|
||||||
|
frontmatter="$(yq --front-matter=extract '.' "$agent_file")"
|
||||||
|
|
||||||
|
# Extract individual fields from frontmatter
|
||||||
|
local name description model effort permission_mode tools disallowed_tools
|
||||||
|
name="$(echo "$frontmatter" | yq '.name // ""')"
|
||||||
|
description="$(echo "$frontmatter" | yq '.description // ""')"
|
||||||
|
model="$(echo "$frontmatter" | yq '.model // ""')"
|
||||||
|
effort="$(echo "$frontmatter" | yq '.effort // ""')"
|
||||||
|
permission_mode="$(echo "$frontmatter" | yq '.permissionMode // ""')"
|
||||||
|
tools="$(echo "$frontmatter" | yq '.tools // ""')"
|
||||||
|
disallowed_tools="$(echo "$frontmatter" | yq '.disallowedTools // ""')"
|
||||||
|
|
||||||
|
# Map to Codex equivalents
|
||||||
|
local codex_model codex_effort codex_sandbox
|
||||||
|
codex_model="$(map_model "$model")"
|
||||||
|
codex_effort="$(map_effort "${effort:-medium}")"
|
||||||
|
codex_sandbox="$(map_sandbox_mode "$permission_mode" "$tools")"
|
||||||
|
|
||||||
|
# Extract and expand body with Codex variable values
|
||||||
|
local body expanded_body
|
||||||
|
body="$(extract_body "$agent_file")"
|
||||||
|
expanded_body="$(expand_body "$body" "${CODEX_VARS[@]}")"
|
||||||
|
|
||||||
|
# Build developer_instructions: append disallowedTools note if present
|
||||||
|
local developer_instructions
|
||||||
|
developer_instructions="$expanded_body"
|
||||||
|
if [ -n "$disallowed_tools" ] && [ "$disallowed_tools" != "null" ]; then
|
||||||
|
developer_instructions="${developer_instructions}
|
||||||
|
|
||||||
|
You do NOT have access to these tools: ${disallowed_tools}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Write TOML output
|
||||||
|
cat > "$dst_file" <<TOML
|
||||||
|
name = "${name}"
|
||||||
|
description = "${description}"
|
||||||
|
model = "${codex_model}"
|
||||||
|
model_reasoning_effort = "${codex_effort}"
|
||||||
|
sandbox_mode = "${codex_sandbox}"
|
||||||
|
developer_instructions = """
|
||||||
|
${developer_instructions}
|
||||||
|
"""
|
||||||
|
TOML
|
||||||
|
|
||||||
|
echo "Generated: $dst_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Generate AGENTS.md — concatenate rules/*.md with tool-agnostic header
|
||||||
|
echo ""
|
||||||
|
echo "Generating codex/AGENTS.md..."
|
||||||
|
{
|
||||||
|
echo "# Agent Team Instructions"
|
||||||
|
echo ""
|
||||||
|
echo "Agent-team specific protocols live in skills (orchestrate, conventions, worker-protocol, qa-checklist, message-schema, project)."
|
||||||
|
for rules_file in $(ls "$RULES_DIR"/*.md | sort); do
|
||||||
|
echo ""
|
||||||
|
cat "$rules_file"
|
||||||
|
done
|
||||||
|
} > "$CODEX_DIR/AGENTS.md"
|
||||||
|
echo "Generated: $CODEX_DIR/AGENTS.md"
|
||||||
|
|
||||||
|
# Generate config.toml — derive sandbox_mode from settings.json defaultMode
|
||||||
|
echo ""
|
||||||
|
echo "Generating codex/config.toml..."
|
||||||
|
|
||||||
|
local default_mode
|
||||||
|
default_mode="$(yq -r '.permissions.defaultMode // "acceptEdits"' "$SETTINGS_JSON")"
|
||||||
|
|
||||||
|
# Map Claude defaultMode to Codex sandbox_mode
|
||||||
|
local config_sandbox
|
||||||
|
case "$default_mode" in
|
||||||
|
plan) config_sandbox="read-only" ;;
|
||||||
|
acceptEdits) config_sandbox="workspace-write" ;;
|
||||||
|
*) config_sandbox="workspace-write" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
cat > "$CODEX_DIR/config.toml" <<TOML
|
||||||
|
model = "o4-mini"
|
||||||
|
model_reasoning_effort = "medium"
|
||||||
|
sandbox_mode = "${config_sandbox}"
|
||||||
|
approval_policy = "on-request"
|
||||||
|
TOML
|
||||||
|
echo "Generated: $CODEX_DIR/config.toml"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Main
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
generate_claude
|
||||||
|
generate_codex
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done."
|
||||||
19
install.sh
19
install.sh
|
|
@ -6,15 +6,15 @@ set -euo pipefail
|
||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
CLAUDE_DIR="$HOME/.claude"
|
CLAUDE_DIR="$HOME/.claude"
|
||||||
AGENTS_SRC="$SCRIPT_DIR/agents"
|
AGENTS_SRC="$SCRIPT_DIR/claude/agents"
|
||||||
SKILLS_SRC="$SCRIPT_DIR/skills"
|
SKILLS_SRC="$SCRIPT_DIR/skills"
|
||||||
RULES_SRC="$SCRIPT_DIR/rules"
|
RULES_SRC="$SCRIPT_DIR/rules"
|
||||||
AGENTS_DST="$CLAUDE_DIR/agents"
|
AGENTS_DST="$CLAUDE_DIR/agents"
|
||||||
SKILLS_DST="$CLAUDE_DIR/skills"
|
SKILLS_DST="$CLAUDE_DIR/skills"
|
||||||
RULES_DST="$CLAUDE_DIR/rules"
|
RULES_DST="$CLAUDE_DIR/rules"
|
||||||
CLAUDE_MD_SRC="$SCRIPT_DIR/CLAUDE.md"
|
CLAUDE_MD_SRC="$SCRIPT_DIR/claude/CLAUDE.md"
|
||||||
CLAUDE_MD_DST="$CLAUDE_DIR/CLAUDE.md"
|
CLAUDE_MD_DST="$CLAUDE_DIR/CLAUDE.md"
|
||||||
SETTINGS_SRC="$SCRIPT_DIR/settings.json"
|
SETTINGS_SRC="$SCRIPT_DIR/claude/settings.json"
|
||||||
SETTINGS_DST="$CLAUDE_DIR/settings.json"
|
SETTINGS_DST="$CLAUDE_DIR/settings.json"
|
||||||
|
|
||||||
# Detect OS
|
# Detect OS
|
||||||
|
|
@ -30,6 +30,12 @@ echo "Source: $SCRIPT_DIR"
|
||||||
echo "Target: $CLAUDE_DIR"
|
echo "Target: $CLAUDE_DIR"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# Pre-flight: require generated claude/ output before proceeding
|
||||||
|
if [ ! -d "$SCRIPT_DIR/claude" ]; then
|
||||||
|
echo "Error: claude/ not found. Run ./generate.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Ensure ~/.claude exists
|
# Ensure ~/.claude exists
|
||||||
mkdir -p "$CLAUDE_DIR"
|
mkdir -p "$CLAUDE_DIR"
|
||||||
|
|
||||||
|
|
@ -130,6 +136,11 @@ if [ -d "$CODEX_DIR" ]; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "Codex CLI detected at $CODEX_DIR"
|
echo "Codex CLI detected at $CODEX_DIR"
|
||||||
|
|
||||||
|
# Warn if generated codex/ output is missing
|
||||||
|
if [ ! -d "$SCRIPT_DIR/codex" ]; then
|
||||||
|
echo "Warning: codex/ not found. Run ./generate.sh first to generate Codex output."
|
||||||
|
fi
|
||||||
|
|
||||||
# Skills shared via ~/.agents/skills/ (Codex discovery path)
|
# Skills shared via ~/.agents/skills/ (Codex discovery path)
|
||||||
mkdir -p "$CODEX_AGENTS_DIR"
|
mkdir -p "$CODEX_AGENTS_DIR"
|
||||||
create_symlink "$SKILLS_SRC" "$CODEX_AGENTS_DIR/skills" "codex skills"
|
create_symlink "$SKILLS_SRC" "$CODEX_AGENTS_DIR/skills" "codex skills"
|
||||||
|
|
@ -138,7 +149,7 @@ if [ -d "$CODEX_DIR" ]; then
|
||||||
if [ -d "$SCRIPT_DIR/codex/agents" ]; then
|
if [ -d "$SCRIPT_DIR/codex/agents" ]; then
|
||||||
create_symlink "$SCRIPT_DIR/codex/agents" "$CODEX_DIR/agents" "codex agents"
|
create_symlink "$SCRIPT_DIR/codex/agents" "$CODEX_DIR/agents" "codex agents"
|
||||||
else
|
else
|
||||||
echo "Run ./generate-codex.sh first to generate Codex agent definitions"
|
echo "Run ./generate.sh first to generate Codex agent definitions"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Generated AGENTS.md (symlink to project root for Codex discovery)
|
# Generated AGENTS.md (symlink to project root for Codex discovery)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
# Session Behavior
|
# Session Behavior
|
||||||
|
|
||||||
- Treat each session as stateless — do not assume context from prior sessions
|
- Treat each session as stateless — do not assume context from prior sessions
|
||||||
- The CLAUDE.md hierarchy and `.claude/memory/` are the only sources of persistent context
|
- The instruction hierarchy and `memory/` are the only sources of persistent context
|
||||||
- If something needs to carry forward across sessions, persist it in the appropriate file — not in session memory
|
- If something needs to carry forward across sessions, persist it in the appropriate file — not in session memory
|
||||||
|
|
||||||
# Project Memory
|
# Project Memory
|
||||||
|
|
||||||
- Project-specific memory lives in `.claude/memory/` at the project root
|
- Project-specific memory lives in `memory/` at the project root
|
||||||
- Use `MEMORY.md` in that directory as the index (one line per entry pointing to a file)
|
- Use `MEMORY.md` in that directory as the index (one line per entry pointing to a file)
|
||||||
- Memory files use frontmatter: `name`, `description`, `type` (user/feedback/project/reference)
|
- Memory files use frontmatter: `name`, `description`, `type` (user/feedback/project/reference)
|
||||||
- Commit `.claude/memory/` with the repo so memory persists across machines and sessions
|
- Commit `memory/` with the repo so memory persists across machines and sessions
|
||||||
|
|
|
||||||
|
|
@ -14,4 +14,4 @@
|
||||||
|
|
||||||
- Use subagents for exploratory reads and investigations to keep the main context clean
|
- Use subagents for exploratory reads and investigations to keep the main context clean
|
||||||
- Prefer scoped file reads (offset/limit) over reading entire large files
|
- Prefer scoped file reads (offset/limit) over reading entire large files
|
||||||
- When a task is complete or the topic shifts significantly, suggest /clear
|
- When a task is complete or the topic shifts significantly, suggest clearing context or starting a new session
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ Emitted by: architect (Phase 2)
|
||||||
---
|
---
|
||||||
type: plan_result
|
type: plan_result
|
||||||
signal: plan_complete | blocked
|
signal: plan_complete | blocked
|
||||||
plan_file: .claude/plans/kebab-case-title.md
|
plan_file: plans/kebab-case-title.md
|
||||||
wave_count: 3
|
wave_count: 3
|
||||||
step_count: 7
|
step_count: 7
|
||||||
risk_tags:
|
risk_tags:
|
||||||
|
|
@ -202,7 +202,7 @@ Sent to: worker, debugger, documenter
|
||||||
type: task_assignment
|
type: task_assignment
|
||||||
signal: execute
|
signal: execute
|
||||||
task: "short task title"
|
task: "short task title"
|
||||||
plan_file: .claude/plans/kebab-case-title.md
|
plan_file: plans/kebab-case-title.md
|
||||||
wave: 1
|
wave: 1
|
||||||
step: 2
|
step: 2
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ description: Instructs agents to check for and ingest a project-specific skill f
|
||||||
when_to_use: Loaded by all agents. Checks for .claude/skills/project.md in the working directory and ingests project-local conventions.
|
when_to_use: Loaded by all agents. Checks for .claude/skills/project.md in the working directory and ingests project-local conventions.
|
||||||
---
|
---
|
||||||
|
|
||||||
Before starting any work, check for a project-specific skill file at `.claude/skills/project.md` in the current working directory.
|
Before starting any work, check for a project-specific skill file in the current working directory's configuration.
|
||||||
|
|
||||||
If it exists, read it and treat its contents as additional instructions — project conventions, architecture notes, domain context, or anything else the project maintainer has defined. These instructions take precedence over general defaults where they conflict.
|
If it exists, read it and treat its contents as additional instructions — project conventions, architecture notes, domain context, or anything else the project maintainer has defined. These instructions take precedence over general defaults where they conflict.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ when_to_use: Loaded by all agents that produce output envelopes. Run before retu
|
||||||
Before returning your output, validate against every item below. If you find a violation, fix it — don't just note it.
|
Before returning your output, validate against every item below. If you find a violation, fix it — don't just note it.
|
||||||
|
|
||||||
### Factual accuracy
|
### Factual accuracy
|
||||||
- Every file path, function name, class name, and line number you reference — does it actually exist? Verify with Read/Grep if uncertain. Never guess paths or signatures.
|
- Every file path, function name, class name, and line number you reference — does it actually exist? Verify by reading the code if uncertain. Never guess paths or signatures.
|
||||||
- Every version number, API endpoint, or external reference — is it correct? If you can't verify, say "unverified" explicitly.
|
- Every version number, API endpoint, or external reference — is it correct? If you can't verify, say "unverified" explicitly.
|
||||||
- No invented specifics. If you don't know something, say so.
|
- No invented specifics. If you don't know something, say so.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ Before returning your output, run the `qa-checklist` skill against your work. Fi
|
||||||
## Cost sensitivity
|
## Cost sensitivity
|
||||||
|
|
||||||
- Keep responses tight. Result only.
|
- Keep responses tight. Result only.
|
||||||
- Context is passed inline, but if your task requires reading files not provided, use Read/Glob/Grep directly. Don't guess at file contents — verify. Keep it targeted.
|
- Context is passed inline, but if your task requires reading files not provided, verify by reading the relevant files. Don't guess at file contents. Keep it targeted.
|
||||||
|
|
||||||
## Commits
|
## Commits
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue