Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ export default tseslint.config(
},
},
{
ignores: ["dist/", "node_modules/"],
ignores: ["dist/", "node_modules/", "coverage/"],
},
);
34 changes: 34 additions & 0 deletions specs/016-codex-ai-tool/checklists/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Specification Quality Checklist: Codex CLI as a Selectable AI Tool

**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2026-04-24
**Feature**: [spec.md](../spec.md)

## Content Quality

- [x] No implementation details (languages, frameworks, APIs) — only file-shape constraints, no language references in user stories
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders — file names appear because they are the user-facing contract of a scaffolder
- [x] All mandatory sections completed

## Requirement Completeness

- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic — no perf numbers, only count + leakage assertions
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded (Out of Scope section)
- [x] Dependencies and assumptions identified

## Feature Readiness

- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows (Claude / Codex / None)
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification

## Notes

This is a CLI-scaffolder feature, so artifact filenames (`CLAUDE.md`, `AGENTS.md`, `.codex/config.toml`, etc.) appear in functional requirements — they are the **user-visible contract** of the tool, not implementation details. Treat them as part of the spec.
115 changes: 115 additions & 0 deletions specs/016-codex-ai-tool/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Implementation Plan: Codex CLI as a Selectable AI Tool

**Branch**: `016-codex-ai-tool` | **Date**: 2026-04-24 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `/specs/016-codex-ai-tool/spec.md`

## Summary

Replace the existing `claudeCode: boolean` flag in `ProjectConfig` with `aiTool: 'claude' | 'codex' | 'none'`, branch the generator dispatcher on it, add a new `CodexGenerator` that emits `AGENTS.md` + `.codex/config.toml` + `.codex/rules/{backend,frontend}.md`, and parameterize the existing `speckit` generator so `specify init` receives the correct `--ai` flag for each tool. Skip the `speckitPreset` prompt for Codex.

## Technical Context

**Language/Version**: TypeScript 5.9 / Node.js ≥20
**Primary Dependencies**: Commander 14, Inquirer 8, Handlebars 4 (existing — no new deps)
**Storage**: N/A (CLI scaffolder; reads/writes filesystem only)
**Testing**: Vitest 4 + @vitest/coverage-v8 (existing)
**Target Platform**: Local developer machines (macOS, Linux, Windows via Node)
**Project Type**: CLI tool (single project, single module tree)
**Performance Goals**: N/A (one-shot scaffolding; existing constraints apply: parallel I/O per Constitution §10)
**Constraints**: Must follow ForgeKit Constitution (single layer per generator, fail-fast rollback, no speculative abstractions)
**Scale/Scope**: ~5 modified files + ~5 new files; ~3 new vitest suites or expanded suites

## Constitution Check

*GATE: Must pass before implementation. Re-check after Phase 1 design.*

| Constitution Rule | Compliance |
|---|---|
| §1 — One layer per generator | ✅ `CodexGenerator` writes only `AGENTS.md` + `.codex/`. `ClaudeCodeGenerator` unchanged. `speckit.ts` continues owning `.specify/`. |
| §2 — Templates contain zero logic | ✅ All branching (per-stack rules, presence of MCP) lives in `CodexGenerator`. Handlebars templates receive a flat data object. |
| §3 — ProjectConfig is single source of truth | ✅ `aiTool` flows top-down. No filesystem probing inside generators. |
| §4 — Fail fast, rollback completely | ✅ Existing rollback in `commands/new.ts` already wraps generators. Codex generator integrates into the same try/catch. |
| §5 — Network failures silent | ✅ No new network calls. Codex generator has no version-fetch path. |
| §6 — No speculative abstractions | ✅ Per-stack rule rendering has only 2 callsites (Claude, Codex). No shared module extracted. |
| §7 — Tests declare all fixture fields | ✅ All Claude tests will be updated to swap `claudeCode: true` → `aiTool: 'claude'`. New Codex tests follow same rule. |
| §8 — CLI detection synchronous + early | ✅ New `isCodexInstalled()` mirrors `isClaudeInstalled()`: `spawnSync` with `stdio: 'ignore'` and `--help`. |
| §9 — Release only via pipeline | ✅ No release-script changes. |
| §10 — I/O parallelized | ✅ `AGENTS.md`, `.codex/config.toml`, `.codex/rules/backend.md`, `.codex/rules/frontend.md` are independent → `Promise.all`. |

**No violations. Complexity Tracking section omitted.**

## Project Structure

### Documentation (this feature)

```text
specs/016-codex-ai-tool/
├── plan.md # This file
├── spec.md # Feature spec
├── qa-summary.md # Confirmed scope from Q&A
├── checklists/
│ └── requirements.md # Spec-quality checklist
└── tasks.md # Phase 2 output (sk:tasks)
```

`research.md`, `data-model.md`, and `contracts/` are intentionally **not generated** (plan-detail=low + no genuine technical unknowns + no entity model + no external wire contract).

### Source Code (repository root)

```text
src/
├── types.ts [MODIFY: add AITool, swap claudeCode → aiTool]
├── prompts/
│ └── project.ts [MODIFY: list-prompt for aiTool, conditional preset]
├── utils/
│ └── (cli-detect helper file) [MODIFY: add isCodexInstalled]
├── commands/
│ └── new.ts [MODIFY: branch on aiTool]
├── generators/
│ ├── claude-code/
│ │ ├── index.ts [MODIFY: gate on aiTool === 'claude' externally]
│ │ └── __tests__/claude-code.test.ts [MODIFY: fixtures use aiTool: 'claude']
│ ├── codex/
│ │ ├── index.ts [NEW: CodexGenerator]
│ │ └── __tests__/codex.test.ts [NEW: vitest suite]
│ └── speckit.ts [MODIFY: forward --ai based on aiTool]
└── templates/
└── codex/
├── AGENTS.md.hbs [NEW]
├── config.toml.hbs [NEW]
└── rules/
├── backend.md.hbs [NEW]
└── frontend.md.hbs [NEW]
```

**Structure Decision**: Single Node project, existing `src/` layout. New work confined to `src/generators/codex/` and `src/templates/codex/`. No top-level reshuffling.

## Implementation Phases (high level)

Following `cfg`: `tdd=false, verification=minimal, code-review=false, security-review=auto, subagents=false, fast-mode=true`. Per-task loop: write impl → write tests → `npm run lint && npm run typecheck`. Full `npm test` runs once in Phase 3.

### Phase 2 — Direct implementation (per-task loop, no subagents)

1. **Type migration** — `src/types.ts`: add `AITool`, replace `claudeCode` with `aiTool`. Mechanical rename across the codebase.
2. **CLI detection** — locate `isClaudeInstalled` (likely in `src/utils/`), add sibling `isCodexInstalled`. Same shape: `spawnSync('codex', ['--help'], { stdio: 'ignore' })`.
3. **Prompt rewiring** — `src/prompts/project.ts`: replace the Claude checkbox with a single `list` question for `aiTool`. Re-gate `workflowMode` on `aiTool !== 'none'` and `speckitPreset` on `aiTool === 'claude' && workflowMode === 'speckit'`.
4. **Dispatch update** — `src/commands/new.ts`: replace `if (config.claudeCode)` with `if (config.aiTool === 'claude')` and add an `else if (config.aiTool === 'codex')` branch invoking the new generator.
5. **Speckit generator** — `src/generators/speckit.ts`: forward `--ai claude` or `--ai codex` based on `config.aiTool`. Skip when `aiTool === 'none'`.
6. **Codex generator** — `src/generators/codex/index.ts`: new class extending `BaseGenerator`. Renders the four templates via `Promise.all`.
7. **Codex templates** — write the four `.hbs` files. Embed per-stack rule text in `AGENTS.md.hbs` since Codex does not read sub-files reliably. Keep `.codex/rules/*.md` for human/IDE convention.
8. **Update Claude tests** — swap `claudeCode: true` → `aiTool: 'claude'` everywhere. Add a "no Claude artifacts when aiTool !== 'claude'" case.
9. **Codex tests** — new suite asserting file presence per stack, content shape, no Claude leakage, and proper `--ai codex` forwarding to speckit.
10. **Smoke build** — `npm run build && npm run lint && npm run typecheck`.

### Phase 3 — Verification & ship

- Run full `npm test` once. Must be green.
- Security review (auto): touches no auth/input/secrets/external APIs → **skip** per cfg.
- Code review (cfg=false) → skip.
- `commit-commands:commit-push-pr` with title `feat(cli): add Codex CLI as AI tool option`.

## Risks / Unknowns (still open)

- The exact module path of `isClaudeInstalled` was not pinned in research; resolve at impl time via `grep -r "isClaudeInstalled" src/`.
- `BaseGenerator` is reportedly minimal (constructor + abstract `generate()`); confirm the constructor signature before subclassing.
- Old preset/JSON config files (if any exist in the wild) carrying `claudeCode: true` will break loudly. The spec accepts this.
28 changes: 28 additions & 0 deletions specs/016-codex-ai-tool/qa-summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Q&A Summary — Codex CLI as AI tool option

Confirmed by user before spec generation:

## 1. ProjectConfig field shape
**Decision:** Replace `claudeCode: boolean` with an enum `aiTool: 'claude' | 'codex' | 'none'`.
- Hard rename — no compat shim, no parallel boolean.
- `AITool` type added to `src/types.ts`.

## 2. Codex generator scope
**Decision:** Generate three artifacts when `aiTool === 'codex'`:
- `AGENTS.md` at project root — prose instructions with stack-specific conventions embedded inline (since Codex's `project_doc` discovery only reads `AGENTS.md` itself, not subfiles).
- `.codex/config.toml` — minimal TOML with `sandbox_mode`, `approval_policy`, optional MCP block.
- `.codex/rules/{backend,frontend}.md` — explicit user choice: keep a `rules/` directory as a human/IDE convention, even though Codex CLI does not natively read it. Risk acknowledged.

**Not generated** for Codex: hooks, skills, slash commands, hookify files, `.claude/settings.json` equivalent — none of these exist as concepts in Codex CLI.

## 3. Speckit + Codex
**Decision:** `specify init --ai codex --no-git` runs the same way as for Claude. Constitution template (`.specify/memory/constitution.md`) is generated identically. **The `speckitPreset` prompt is skipped** when `aiTool === 'codex'` because presets translate into a `.claude/settings.json` speckit block, which Codex cannot read.

## 4. "None" option
**Decision:** Keep `aiTool: 'none'` as a valid choice, preserving the current `claudeCode: false` behavior (no AI tooling files emitted at all).

## Out of scope
- No backward-compat shim for the renamed field.
- No support for additional AI tools (Cursor, Gemini, etc.) in this iteration.
- No refactor of the BaseGenerator pattern.
- No extraction of shared rules-rendering module — only 2 callsites (Claude + Codex), per Constitution §6.
Loading
Loading