feat(installer): add Codex CLI + Codex Web modes, generate AGENTS.md, inject npm scripts, and docs (#529)
This commit is contained in:
committed by
GitHub
parent
052e84dd4a
commit
05736fa069
16
README.md
16
README.md
@@ -243,3 +243,19 @@ BMAD™ and BMAD-METHOD™ are trademarks of BMad Code, LLC. All rights reserved
|
||||
[](https://github.com/bmadcode/bmad-method/graphs/contributors)
|
||||
|
||||
<sub>Built with ❤️ for the AI-assisted development community</sub>
|
||||
|
||||
#### Codex (CLI & Web)
|
||||
|
||||
- Two modes are supported:
|
||||
- Codex (local only): `npx bmad-method install -f -i codex -d .` — keeps `.bmad-core/` ignored via `.gitignore` for local development.
|
||||
- Codex Web Enabled: `npx bmad-method install -f -i codex-web -d .` — ensures `.bmad-core/` is tracked (not ignored) so it can be committed for Codex Web.
|
||||
- For Codex Web, commit both `.bmad-core/` and `AGENTS.md` to the repository.
|
||||
- Codex CLI: run `codex` at your project root; reference agents naturally, e.g., “As dev, implement …”.
|
||||
- Codex Web: open your repo in Codex and prompt the same way — it reads `AGENTS.md` automatically.
|
||||
- Refresh after changes: rerun the appropriate install command (`codex` or `codex-web`) to regenerate the BMAD section inside `AGENTS.md`.
|
||||
|
||||
If a `package.json` exists in your project, the installer will add helpful scripts:
|
||||
|
||||
- `bmad:refresh` → `bmad-method install -f -i codex`
|
||||
- `bmad:list` → `bmad-method list:agents`
|
||||
- `bmad:validate` → `bmad-method validate`
|
||||
|
||||
@@ -187,6 +187,32 @@ If you want to do the planning on the web with Claude (Sonnet 4 or Opus), Gemini
|
||||
npx bmad-method install
|
||||
```
|
||||
|
||||
### Codex (CLI & Web)
|
||||
|
||||
BMAD integrates with OpenAI Codex via `AGENTS.md` and committed core agent files.
|
||||
|
||||
- Two installation modes:
|
||||
- Codex (local only): keeps `.bmad-core/` ignored for local dev.
|
||||
- `npx bmad-method install -f -i codex -d .`
|
||||
- Codex Web Enabled: ensures `.bmad-core/` is tracked so you can commit it for Codex Web.
|
||||
- `npx bmad-method install -f -i codex-web -d .`
|
||||
|
||||
- What gets generated:
|
||||
- `AGENTS.md` at the project root with a BMAD section containing
|
||||
- How-to-use with Codex (CLI & Web)
|
||||
- Agent Directory (Title, ID, When To Use)
|
||||
- Detailed per‑agent sections with source path, when-to-use, activation phrasing, and YAML
|
||||
- Tasks with quick usage notes
|
||||
- If a `package.json` exists, helpful scripts are added:
|
||||
- `bmad:refresh`, `bmad:list`, `bmad:validate`
|
||||
|
||||
- Using Codex:
|
||||
- CLI: run `codex` in the project root and prompt naturally, e.g., “As dev, implement …”.
|
||||
- Web: commit `.bmad-core/` and `AGENTS.md`, then open the repo in Codex and prompt the same way.
|
||||
|
||||
- Refresh after changes:
|
||||
- Re-run the appropriate install mode (`codex` or `codex-web`) to update the BMAD block in `AGENTS.md`.
|
||||
|
||||
## Special Agents
|
||||
|
||||
There are two BMad agents — in the future they'll be consolidated into a single BMad-Master.
|
||||
|
||||
@@ -49,7 +49,7 @@ program
|
||||
.option('-d, --directory <path>', 'Installation directory')
|
||||
.option(
|
||||
'-i, --ide <ide...>',
|
||||
'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, other)',
|
||||
'Configure for specific IDE(s) - can specify multiple (cursor, claude-code, windsurf, trae, roo, kilo, cline, gemini, qwen-code, github-copilot, codex, codex-web, other)',
|
||||
)
|
||||
.option(
|
||||
'-e, --expansion-packs <packs...>',
|
||||
|
||||
@@ -121,3 +121,25 @@ ide-configurations:
|
||||
# 2. It concatenates all agent files into a single QWEN.md file.
|
||||
# 3. Simply mention the agent in your prompt (e.g., "As *dev, ...").
|
||||
# 4. The Qwen Code CLI will automatically have the context for that agent.
|
||||
|
||||
codex:
|
||||
name: Codex CLI
|
||||
format: project-memory
|
||||
file: AGENTS.md
|
||||
instructions: |
|
||||
# To use BMAD agents with Codex CLI:
|
||||
# 1. The installer updates/creates AGENTS.md at your project root with BMAD agents and tasks.
|
||||
# 2. Run `codex` in your project. Codex automatically reads AGENTS.md as project memory.
|
||||
# 3. Mention agents in your prompt (e.g., "As dev, please implement ...") or reference tasks.
|
||||
# 4. You can further customize global Codex behavior via ~/.codex/config.toml.
|
||||
|
||||
codex-web:
|
||||
name: Codex Web Enabled
|
||||
format: project-memory
|
||||
file: AGENTS.md
|
||||
instructions: |
|
||||
# To enable BMAD agents for Codex Web (cloud):
|
||||
# 1. The installer updates/creates AGENTS.md and ensures `.bmad-core` is NOT ignored by git.
|
||||
# 2. Commit `.bmad-core/` and `AGENTS.md` to your repository.
|
||||
# 3. Open the repo in Codex Web and reference agents naturally (e.g., "As dev, ...").
|
||||
# 4. Re-run this installer to refresh agent sections when the core changes.
|
||||
|
||||
@@ -74,6 +74,12 @@ class IdeSetup extends BaseIdeSetup {
|
||||
case 'qwen-code': {
|
||||
return this.setupQwenCode(installDir, selectedAgent);
|
||||
}
|
||||
case 'codex': {
|
||||
return this.setupCodex(installDir, selectedAgent, { webEnabled: false });
|
||||
}
|
||||
case 'codex-web': {
|
||||
return this.setupCodex(installDir, selectedAgent, { webEnabled: true });
|
||||
}
|
||||
default: {
|
||||
console.log(chalk.yellow(`\nIDE ${ide} not yet supported`));
|
||||
return false;
|
||||
@@ -81,6 +87,175 @@ class IdeSetup extends BaseIdeSetup {
|
||||
}
|
||||
}
|
||||
|
||||
async setupCodex(installDir, selectedAgent, options) {
|
||||
options = options ?? { webEnabled: false };
|
||||
// Codex reads AGENTS.md at the project root as project memory (CLI & Web).
|
||||
// Inject/update a BMAD section with guidance, directory, and details.
|
||||
const filePath = path.join(installDir, 'AGENTS.md');
|
||||
const startMarker = '<!-- BEGIN: BMAD-AGENTS -->';
|
||||
const endMarker = '<!-- END: BMAD-AGENTS -->';
|
||||
|
||||
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
||||
const tasks = await this.getAllTaskIds(installDir);
|
||||
|
||||
// Build BMAD section content
|
||||
let section = '';
|
||||
section += `${startMarker}\n`;
|
||||
section += `# BMAD-METHOD Agents and Tasks\n\n`;
|
||||
section += `This section is auto-generated by BMAD-METHOD for Codex. Codex merges this AGENTS.md into context.\n\n`;
|
||||
section += `## How To Use With Codex\n\n`;
|
||||
section += `- Codex CLI: run \`codex\` in this project. Reference an agent naturally, e.g., "As dev, implement ...".\n`;
|
||||
section += `- Codex Web: open this repo and reference roles the same way; Codex reads \`AGENTS.md\`.\n`;
|
||||
section += `- Commit \`.bmad-core\` and this \`AGENTS.md\` file to your repo so Codex (Web/CLI) can read full agent definitions.\n`;
|
||||
section += `- Refresh this section after agent updates: \`npx bmad-method install -f -i codex\`.\n\n`;
|
||||
|
||||
section += `### Helpful Commands\n\n`;
|
||||
section += `- List agents: \`npx bmad-method list:agents\`\n`;
|
||||
section += `- Reinstall BMAD core and regenerate AGENTS.md: \`npx bmad-method install -f -i codex\`\n`;
|
||||
section += `- Validate configuration: \`npx bmad-method validate\`\n\n`;
|
||||
|
||||
// Agents directory table
|
||||
section += `## Agents\n\n`;
|
||||
section += `### Directory\n\n`;
|
||||
section += `| Title | ID | When To Use |\n|---|---|---|\n`;
|
||||
const agentSummaries = [];
|
||||
for (const agentId of agents) {
|
||||
const agentPath = await this.findAgentPath(agentId, installDir);
|
||||
if (!agentPath) continue;
|
||||
const raw = await fileManager.readFile(agentPath);
|
||||
const yamlMatch = raw.match(/```ya?ml\r?\n([\s\S]*?)```/);
|
||||
const yamlBlock = yamlMatch ? yamlMatch[1].trim() : null;
|
||||
const title = await this.getAgentTitle(agentId, installDir);
|
||||
const whenToUse = yamlBlock?.match(/whenToUse:\s*"?([^\n"]+)"?/i)?.[1]?.trim() || '';
|
||||
agentSummaries.push({ agentId, title, whenToUse, yamlBlock, raw, path: agentPath });
|
||||
section += `| ${title} | ${agentId} | ${whenToUse || '—'} |\n`;
|
||||
}
|
||||
section += `\n`;
|
||||
|
||||
// Detailed agent sections
|
||||
for (const { agentId, title, whenToUse, yamlBlock, raw, path: agentPath } of agentSummaries) {
|
||||
const relativePath = path.relative(installDir, agentPath).replaceAll('\\', '/');
|
||||
section += `### ${title} (id: ${agentId})\n`;
|
||||
section += `Source: ${relativePath}\n\n`;
|
||||
if (whenToUse) section += `- When to use: ${whenToUse}\n`;
|
||||
section += `- How to activate: Mention "As ${agentId}, ..." or "Use ${title} to ..."\n\n`;
|
||||
if (yamlBlock) {
|
||||
section += '```yaml\n' + yamlBlock + '\n```\n\n';
|
||||
} else {
|
||||
section += '```md\n' + raw.trim() + '\n```\n\n';
|
||||
}
|
||||
}
|
||||
|
||||
// Tasks
|
||||
if (tasks && tasks.length > 0) {
|
||||
section += `## Tasks\n\n`;
|
||||
section += `These are reusable task briefs you can reference directly in Codex.\n\n`;
|
||||
for (const taskId of tasks) {
|
||||
const taskPath = await this.findTaskPath(taskId, installDir);
|
||||
if (!taskPath) continue;
|
||||
const raw = await fileManager.readFile(taskPath);
|
||||
const relativePath = path.relative(installDir, taskPath).replaceAll('\\', '/');
|
||||
section += `### Task: ${taskId}\n`;
|
||||
section += `Source: ${relativePath}\n`;
|
||||
section += `- How to use: "Use task ${taskId} with the appropriate agent" and paste relevant parts as needed.\n\n`;
|
||||
section += '```md\n' + raw.trim() + '\n```\n\n';
|
||||
}
|
||||
}
|
||||
|
||||
section += `${endMarker}\n`;
|
||||
|
||||
// Write or update AGENTS.md
|
||||
let finalContent = '';
|
||||
if (await fileManager.pathExists(filePath)) {
|
||||
const existing = await fileManager.readFile(filePath);
|
||||
if (existing.includes(startMarker) && existing.includes(endMarker)) {
|
||||
// Replace existing BMAD block
|
||||
const pattern = String.raw`${startMarker}[\s\S]*?${endMarker}`;
|
||||
const replaced = existing.replace(new RegExp(pattern, 'm'), section);
|
||||
finalContent = replaced;
|
||||
} else {
|
||||
// Append BMAD block to existing file
|
||||
finalContent = existing.trimEnd() + `\n\n` + section;
|
||||
}
|
||||
} else {
|
||||
// Create fresh AGENTS.md with a small header and BMAD block
|
||||
finalContent += '# Project Agents\n\n';
|
||||
finalContent += 'This file provides guidance and memory for Codex CLI.\n\n';
|
||||
finalContent += section;
|
||||
}
|
||||
|
||||
await fileManager.writeFile(filePath, finalContent);
|
||||
console.log(chalk.green('✓ Created/updated AGENTS.md for Codex CLI integration'));
|
||||
console.log(
|
||||
chalk.dim(
|
||||
'Codex reads AGENTS.md automatically. Run `codex` in this project to use BMAD agents.',
|
||||
),
|
||||
);
|
||||
|
||||
// Optionally add helpful npm scripts if a package.json exists
|
||||
try {
|
||||
const pkgPath = path.join(installDir, 'package.json');
|
||||
if (await fileManager.pathExists(pkgPath)) {
|
||||
const pkgRaw = await fileManager.readFile(pkgPath);
|
||||
const pkg = JSON.parse(pkgRaw);
|
||||
pkg.scripts = pkg.scripts || {};
|
||||
const updated = { ...pkg.scripts };
|
||||
if (!updated['bmad:refresh']) updated['bmad:refresh'] = 'bmad-method install -f -i codex';
|
||||
if (!updated['bmad:list']) updated['bmad:list'] = 'bmad-method list:agents';
|
||||
if (!updated['bmad:validate']) updated['bmad:validate'] = 'bmad-method validate';
|
||||
const changed = JSON.stringify(updated) !== JSON.stringify(pkg.scripts);
|
||||
if (changed) {
|
||||
const newPkg = { ...pkg, scripts: updated };
|
||||
await fileManager.writeFile(pkgPath, JSON.stringify(newPkg, null, 2) + '\n');
|
||||
console.log(chalk.green('✓ Added npm scripts: bmad:refresh, bmad:list, bmad:validate'));
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
console.log(
|
||||
chalk.yellow('⚠︎ Skipped adding npm scripts (package.json not writable or invalid)'),
|
||||
);
|
||||
}
|
||||
|
||||
// Adjust .gitignore behavior depending on Codex mode
|
||||
try {
|
||||
const gitignorePath = path.join(installDir, '.gitignore');
|
||||
const ignoreLines = ['# BMAD (local only)', '.bmad-core/', '.bmad-*/'];
|
||||
const exists = await fileManager.pathExists(gitignorePath);
|
||||
if (options.webEnabled) {
|
||||
if (exists) {
|
||||
let gi = await fileManager.readFile(gitignorePath);
|
||||
// Remove lines that ignore BMAD dot-folders
|
||||
const updated = gi
|
||||
.split(/\r?\n/)
|
||||
.filter((l) => !/^\s*\.bmad-core\/?\s*$/.test(l) && !/^\s*\.bmad-\*\/?\s*$/.test(l))
|
||||
.join('\n');
|
||||
if (updated !== gi) {
|
||||
await fileManager.writeFile(gitignorePath, updated.trimEnd() + '\n');
|
||||
console.log(chalk.green('✓ Updated .gitignore to include .bmad-core in commits'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Local-only: add ignores if missing
|
||||
let base = exists ? await fileManager.readFile(gitignorePath) : '';
|
||||
const haveCore = base.includes('.bmad-core/');
|
||||
const haveStar = base.includes('.bmad-*/');
|
||||
if (!haveCore || !haveStar) {
|
||||
const sep = base.endsWith('\n') || base.length === 0 ? '' : '\n';
|
||||
const add = [!haveCore || !haveStar ? ignoreLines.join('\n') : '']
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
const out = base + sep + add + '\n';
|
||||
await fileManager.writeFile(gitignorePath, out);
|
||||
console.log(chalk.green('✓ Added .bmad-core/* to .gitignore for local-only Codex setup'));
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
console.log(chalk.yellow('⚠︎ Could not update .gitignore (skipping)'));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async setupCursor(installDir, selectedAgent) {
|
||||
const cursorRulesDir = path.join(installDir, '.cursor', 'rules', 'bmad');
|
||||
const agents = selectedAgent ? [selectedAgent] : await this.getAllAgentIds(installDir);
|
||||
|
||||
Reference in New Issue
Block a user