Skip to content
Open
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
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ Our research and experimentation focus on:
## 🔧 Prerequisites

- **Linux/macOS** (or WSL2 on Windows)
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), or [Cursor](https://cursor.sh/)
- AI coding agent: [Claude Code](https://www.anthropic.com/claude-code), [GitHub Copilot](https://code.visualstudio.com/), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Codex CLI](https://github.com/openai/codex) or [Cursor](https://cursor.sh/)
- [uv](https://docs.astral.sh/uv/) for package management
- [Python 3.11+](https://www.python.org/downloads/)
- [Git](https://git-scm.com/downloads)
Expand Down Expand Up @@ -200,16 +200,24 @@ You will be prompted to select the AI agent you are using. You can also proactiv
specify init <project_name> --ai claude
specify init <project_name> --ai gemini
specify init <project_name> --ai copilot
specify init <project_name> --ai codex
# Or in current directory:
specify init --here --ai claude
specify init --here --ai codex
```

The CLI will check if you have Claude Code or Gemini CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:
The CLI will check if you have Claude Code, Gemini CLI, or Codex CLI installed. If you do not, or you prefer to get the templates without checking for the right tools, use `--ignore-agent-tools` with your command:

```bash
specify init <project_name> --ai claude --ignore-agent-tools
```

> [!NOTE]
> Codex CLI specifics
> - When you run `specify init --ai codex`, the CLI ensures a `commands/` directory exists. If packaged templates are not available, it bootstraps minimal command files (`specify.md`, `plan.md`, `tasks.md`).
> - Codex reads project memory from `AGENTS.md`. If it does not exist yet, run `codex /init` inside the project.
> - To allow the bundled scripts under `scripts/` to run from Codex slash commands, open `codex /approvals` and enable “Run shell commands”.
### **STEP 1:** Bootstrap the project

Go to the project folder and run your AI agent. In our example, we're using `claude`.
Expand Down
5 changes: 3 additions & 2 deletions scripts/bash/update-agent-context.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ REPO_ROOT=$(git rev-parse --show-toplevel)
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
FEATURE_DIR="$REPO_ROOT/specs/$CURRENT_BRANCH"
NEW_PLAN="$FEATURE_DIR/plan.md"
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"; GEMINI_FILE="$REPO_ROOT/GEMINI.md"; COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md"
CLAUDE_FILE="$REPO_ROOT/CLAUDE.md"; GEMINI_FILE="$REPO_ROOT/GEMINI.md"; COPILOT_FILE="$REPO_ROOT/.github/copilot-instructions.md"; AGENTS_FILE="$REPO_ROOT/AGENTS.md"
AGENT_TYPE="$1"
[ -f "$NEW_PLAN" ] || { echo "ERROR: No plan.md found at $NEW_PLAN"; exit 1; }
echo "=== Updating agent context files for feature $CURRENT_BRANCH ==="
Expand Down Expand Up @@ -50,8 +50,9 @@ fi; mv "$temp_file" "$target_file" 2>/dev/null || true; echo "✅ $agent_name co
case "$AGENT_TYPE" in
claude) update_agent_file "$CLAUDE_FILE" "Claude Code" ;;
gemini) update_agent_file "$GEMINI_FILE" "Gemini CLI" ;;
codex) update_agent_file "$AGENTS_FILE" "Codex" ;;
copilot) update_agent_file "$COPILOT_FILE" "GitHub Copilot" ;;
"") [ -f "$CLAUDE_FILE" ] && update_agent_file "$CLAUDE_FILE" "Claude Code"; [ -f "$GEMINI_FILE" ] && update_agent_file "$GEMINI_FILE" "Gemini CLI"; [ -f "$COPILOT_FILE" ] && update_agent_file "$COPILOT_FILE" "GitHub Copilot"; if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$COPILOT_FILE" ]; then update_agent_file "$CLAUDE_FILE" "Claude Code"; fi ;;
"") [ -f "$CLAUDE_FILE" ] && update_agent_file "$CLAUDE_FILE" "Claude Code"; [ -f "$GEMINI_FILE" ] && update_agent_file "$GEMINI_FILE" "Gemini CLI"; [ -f "$AGENTS_FILE" ] && update_agent_file "$AGENTS_FILE" "Codex"; [ -f "$COPILOT_FILE" ] && update_agent_file "$COPILOT_FILE" "GitHub Copilot"; if [ ! -f "$CLAUDE_FILE" ] && [ ! -f "$GEMINI_FILE" ] && [ ! -f "$AGENTS_FILE" ] && [ ! -f "$COPILOT_FILE" ]; then update_agent_file "$CLAUDE_FILE" "Claude Code"; fi ;;
*) echo "ERROR: Unknown agent type '$AGENT_TYPE'"; exit 1 ;;
esac
echo; echo "Summary of changes:"; [ -n "$NEW_LANG" ] && echo "- Added language: $NEW_LANG"; [ -n "$NEW_FRAMEWORK" ] && echo "- Added framework: $NEW_FRAMEWORK"; [ -n "$NEW_DB" ] && [ "$NEW_DB" != "N/A" ] && echo "- Added database: $NEW_DB"; echo; echo "Usage: $0 [claude|gemini|copilot]"
6 changes: 4 additions & 2 deletions scripts/powershell/update-agent-context.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ if (-not (Test-Path $newPlan)) { Write-Error "ERROR: No plan.md found at $newPla

$claudeFile = Join-Path $repoRoot 'CLAUDE.md'
$geminiFile = Join-Path $repoRoot 'GEMINI.md'
$agentsFile = Join-Path $repoRoot 'AGENTS.md'
$copilotFile = Join-Path $repoRoot '.github/copilot-instructions.md'

Write-Output "=== Updating agent context files for feature $currentBranch ==="
Expand Down Expand Up @@ -68,12 +69,13 @@ function Update-AgentFile($targetFile, $agentName) {
switch ($AgentType) {
'claude' { Update-AgentFile $claudeFile 'Claude Code' }
'gemini' { Update-AgentFile $geminiFile 'Gemini CLI' }
'codex' { Update-AgentFile $agentsFile 'Codex' }
'copilot' { Update-AgentFile $copilotFile 'GitHub Copilot' }
'' {
foreach ($pair in @(@{file=$claudeFile; name='Claude Code'}, @{file=$geminiFile; name='Gemini CLI'}, @{file=$copilotFile; name='GitHub Copilot'})) {
foreach ($pair in @(@{file=$claudeFile; name='Claude Code'}, @{file=$geminiFile; name='Gemini CLI'}, @{file=$agentsFile; name='Codex'}, @{file=$copilotFile; name='GitHub Copilot'})) {
if (Test-Path $pair.file) { Update-AgentFile $pair.file $pair.name }
}
if (-not (Test-Path $claudeFile) -and -not (Test-Path $geminiFile) -and -not (Test-Path $copilotFile)) {
if (-not (Test-Path $claudeFile) -and -not (Test-Path $geminiFile) -and -not (Test-Path $agentsFile) -and -not (Test-Path $copilotFile)) {
Write-Output 'No agent context files found. Creating Claude Code context file by default.'
Update-AgentFile $claudeFile 'Claude Code'
}
Expand Down
106 changes: 102 additions & 4 deletions src/specify_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,59 @@
"copilot": "GitHub Copilot",
"claude": "Claude Code",
"gemini": "Gemini CLI",
"cursor": "Cursor"
"cursor": "Cursor",
"codex": "Codex CLI",
}
# Add script type choices
SCRIPT_TYPE_CHOICES = {"sh": "POSIX Shell (bash/zsh)", "ps": "PowerShell"}

# Claude CLI local installation path after migrate-installer
CLAUDE_LOCAL_PATH = Path.home() / ".claude" / "local" / "claude"

# Embedded fallback command templates for Codex (used only if templates/commands is not found)
CODEX_CMD_SPECIFY = """---
name: specify
description: "Start a new feature by creating a specification and feature branch."
---
Start a new feature by creating a specification and feature branch.
Given the feature description provided as an argument, do this:
1. Run the script `scripts/create-new-feature.sh --json "{ARGS}"` from the repo root and parse its JSON for BRANCH_NAME and SPEC_FILE. All future paths must be absolute.
2. Load `templates/spec-template.md` and create the initial specification at SPEC_FILE, filling in the placeholders with concrete details derived from the arguments while preserving headings/order.
3. Report completion with the new branch name and spec file path.
"""

CODEX_CMD_PLAN = """---
name: plan
description: "Plan how to implement the specified feature."
---
Plan how to implement the specified feature.
Given the implementation details provided as an argument, do this:
1. Run `scripts/setup-plan.sh --json` from the repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. Use absolute paths in all steps.
2. Read the feature specification (FEATURE_SPEC) and `memory/constitution.md`.
3. Copy `templates/plan-template.md` to IMPL_PLAN if not already present and fill in all sections using the specification and {ARGS} as Technical Context.
4. Ensure the plan includes phases and produces research.md, data-model.md (if needed), contracts/, quickstart.md as appropriate.
5. Report results with BRANCH and generated artifact paths.
"""

CODEX_CMD_TASKS = """---
name: tasks
description: "Break down the plan into executable tasks."
---
Break down the plan into executable tasks.
1. Run `scripts/check-task-prerequisites.sh --json` and parse FEATURE_DIR and AVAILABLE_DOCS.
2. Read plan.md and any available docs to derive concrete tasks.
3. Use `templates/tasks-template.md` as the base, generating numbered tasks (T001, T002, …) with clear file paths and dependency notes. Mark tasks that can run in parallel with [P].
4. Write the result to FEATURE_DIR/tasks.md.
"""

# ASCII Art Banner
BANNER = """
███████╗██████╗ ███████╗ ██████╗██╗███████╗██╗ ██╗
Expand Down Expand Up @@ -443,12 +488,21 @@ def download_template_from_github(ai_assistant: str, download_dir: Path, *, scri
console.print(Panel(str(e), title="Fetch Error", border_style="red"))
raise typer.Exit(1)

# Find the template asset for the specified AI assistant
# Find the template asset for the specified AI assistant, with fallback for 'new assistant' -> 'copilot'
pattern = f"spec-kit-template-{ai_assistant}-{script_type}"
assets = release_data.get("assets", [])
matching_assets = [
asset for asset in release_data.get("assets", [])
if pattern in asset["name"] and asset["name"].endswith(".zip")
]

if not matching_assets and not ai_assistant == "copilot":
fallback_pattern = "spec-kit-template-copilot"
fallback_assets = [a for a in assets if fallback_pattern in a["name"] and a["name"].endswith(".zip")]
if fallback_assets:
matching_assets = fallback_assets
if verbose:
console.print(f"[yellow]No '{ai_assistant}' template found; falling back to 'copilot' template.[/yellow]")

if not matching_assets:
console.print(f"[red]No matching release asset found[/red] for pattern: [bold]{pattern}[/bold]")
Expand Down Expand Up @@ -735,7 +789,7 @@ def init(
This command will:
1. Check that required tools are installed (git is optional)
2. Let you choose your AI assistant (Claude Code, Gemini CLI, GitHub Copilot, or Cursor)
2. Let you choose your AI assistant (Claude Code, Gemini CLI, GitHub Copilot, Codex, or Cursor)
3. Download the appropriate template from GitHub
4. Extract the template to a new project directory or current directory
5. Initialize a fresh git repository (if not --no-git and no existing repo)
Expand All @@ -746,9 +800,11 @@ def init(
specify init my-project --ai claude
specify init my-project --ai gemini
specify init my-project --ai copilot --no-git
specify init my-project --ai codex
specify init my-project --ai cursor
specify init --ignore-agent-tools my-project
specify init --here --ai claude
specify init --here --ai codex
specify init --here
"""
# Show banner first
Expand Down Expand Up @@ -825,6 +881,10 @@ def init(
if not check_tool("gemini", "Install from: https://github.com/google-gemini/gemini-cli"):
console.print("[red]Error:[/red] Gemini CLI is required for Gemini projects")
agent_tool_missing = True
elif selected_ai == "codex":
if not check_tool("codex", "Install from: https://github.com/openai/codex"):
console.print("[red]Error:[/red] Codex CLI is required for Codex projects")
agent_tool_missing = True

if agent_tool_missing:
console.print("\n[red]Required AI tool is missing![/red]")
Expand Down Expand Up @@ -873,6 +933,9 @@ def init(
("final", "Finalize")
]:
tracker.add(key, label)
# Codex only: show progress for auto-adding commands/
if selected_ai == "codex":
tracker.add("commands", "Add commands directory")

# Use transient so live tree is replaced by the final static render (avoids duplicate output)
with Live(tracker.render(), console=console, refresh_per_second=8, transient=True) as live:
Expand All @@ -888,6 +951,34 @@ def init(
# Ensure scripts are executable (POSIX)
ensure_executable_scripts(project_path, tracker=tracker)

# Codex only: if commands/ is missing, copy from template or bootstrap minimal ones
if selected_ai == "codex":
tracker.start("commands")
try:
target_cmds = project_path / "commands"
if not target_cmds.exists():
# Search for templates/commands within the running package/repo
commands_src = None
for ancestor in Path(__file__).resolve().parents:
cand = ancestor / "templates" / "commands"
if cand.exists() and cand.is_dir():
commands_src = cand
break
if commands_src is not None:
shutil.copytree(commands_src, target_cmds, dirs_exist_ok=True)
tracker.complete("commands", "added")
else:
# Fallback: embed minimal commands
target_cmds.mkdir(parents=True, exist_ok=True)
(target_cmds / "specify.md").write_text(CODEX_CMD_SPECIFY, encoding="utf-8")
(target_cmds / "plan.md").write_text(CODEX_CMD_PLAN, encoding="utf-8")
(target_cmds / "tasks.md").write_text(CODEX_CMD_TASKS, encoding="utf-8")
tracker.complete("commands", "bootstrapped")
else:
tracker.skip("commands", "already present")
except Exception as e:
tracker.error("commands", str(e))

# Git step
if not no_git:
tracker.start("git")
Expand Down Expand Up @@ -950,6 +1041,12 @@ def init(
steps_lines.append(" - See GEMINI.md for all available commands")
elif selected_ai == "copilot":
steps_lines.append(f"{step_num}. Open in Visual Studio Code and use [bold cyan]/specify[/], [bold cyan]/plan[/], [bold cyan]/tasks[/] commands with GitHub Copilot")
elif selected_ai == "codex":
steps_lines.append(f"{step_num}. Use / commands with Codex CLI")
steps_lines.append(" - Run codex /specify to create specifications")
steps_lines.append(" - Run codex /plan to create implementation plans")
steps_lines.append(" - Run codex /tasks to generate task list")
steps_lines.append(" - See AGENTS.md for available commands")

# Removed script variant step (scripts are transparent to users)
step_num += 1
Expand Down Expand Up @@ -982,6 +1079,7 @@ def check():
git_ok = check_tool_for_tracker("git", "https://git-scm.com/downloads", tracker)
claude_ok = check_tool_for_tracker("claude", "https://docs.anthropic.com/en/docs/claude-code/setup", tracker)
gemini_ok = check_tool_for_tracker("gemini", "https://github.com/google-gemini/gemini-cli", tracker)
codex_ok = check_tool_for_tracker("codex", "https://github.com/openai/codex", tracker)
# Check for VS Code (code or code-insiders)
code_ok = check_tool_for_tracker("code", "https://code.visualstudio.com/", tracker)
if not code_ok:
Expand All @@ -997,7 +1095,7 @@ def check():
# Recommendations
if not git_ok:
console.print("[dim]Tip: Install git for repository management[/dim]")
if not (claude_ok or gemini_ok):
if not (claude_ok or gemini_ok or codex_ok):
console.print("[dim]Tip: Install an AI assistant for the best experience[/dim]")


Expand Down
2 changes: 1 addition & 1 deletion templates/plan-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
→ Update Progress Tracking: Initial Constitution Check
4. Execute Phase 0 → research.md
→ If NEEDS CLARIFICATION remain: ERROR "Resolve unknowns"
5. Execute Phase 1 → contracts, data-model.md, quickstart.md, agent-specific template file (e.g., `CLAUDE.md` for Claude Code, `.github/copilot-instructions.md` for GitHub Copilot, or `GEMINI.md` for Gemini CLI).
5. Execute Phase 1 → contracts, data-model.md, quickstart.md, agent-specific template file (e.g., `CLAUDE.md` for Claude Code, `.github/copilot-instructions.md` for GitHub Copilot, `AGENTS.md` for Codex, or `GEMINI.md` for Gemini CLI).
6. Re-evaluate Constitution Check section
→ If new violations: Refactor design, return to Phase 1
→ Update Progress Tracking: Post-Design Constitution Check
Expand Down