Skip to content

Codex

SpecForge’s Codex support is a committed bundle — dist/agents/codex/ — that ports the same spec-driven lifecycle to OpenAI’s Codex CLI: the $specforge-* skills, repo-wide instructions, and a real pre-tool gate. It’s generated from the same neutral step source as the Claude Code plugin, so the workflow and artifacts (specforge/spec.md, plan.md, tasks.md, state.md, …) are identical; only the invocation syntax and hook transport differ.

Path Purpose
.agents/skills/specforge-<n>/SKILL.md 15 skill files, invoked as $specforge-<n> in Codex
.codex/hooks.json A PreToolUse hook registering the gate shim
AGENTS.md Repo-wide instructions telling Codex the gate exists and not to route around it
.specforge/gate/{codex-gate.sh,decide.sh,common.sh} The gate: a Codex-specific shim over the same transport-agnostic decision logic Claude Code, Copilot, Cursor, and Gemini use
.specforge/scripts/{new-feature.sh,ralph-loop.sh} Helper scripts the $specforge-* skills reference
pre-commit An agent-independent git hook — the backstop described below
install.sh Copies the above into your repo (see Install)

install.sh needs the rest of the bundle sitting beside it — it copies .agents/, .codex/, and .specforge/ from its own directory, and it detects your repo root by running git rev-parse --show-toplevel from wherever you invoke it. That means it can’t be safely piped through curl | sh: it has to be run from inside your target repo, pointed at a real copy of the bundle. Get the bundle, then run its installer from inside your project:

Terminal window
# From inside your project repo:
git clone --depth 1 https://github.com/pooyagolchian/specforge /tmp/specforge
/tmp/specforge/dist/agents/codex/install.sh
# then in Codex: $specforge-init

This is safe to re-run. If AGENTS.md or a git pre-commit hook already exists and differs from SpecForge’s version, install.sh backs up the existing file (.bak) before installing rather than silently overwriting it. .agents/skills/ and .codex/ are merged (cp -r into an existing directory), so any other skills or hook config you already have there are preserved.

Command Phase What it does
$specforge-init setup Scaffold the specforge/ workspace + input templates
$specforge-constitution inception Set project principles (soft gates)
$specforge-reverse-engineer inception Seed specs from an existing codebase (brownfield)
$specforge-specify inception Write the spec (WHAT/WHY) → spec.md
$specforge-clarify inception Resolve unknowns via a questions-in-a-file flow
$specforge-plan construction Design the HOW → plan.md + companions
$specforge-tasks construction Break the plan into an ordered, traceable checklist
$specforge-analyze construction Cross-check spec ↔ plan ↔ tasks for gaps (read-only)
$specforge-approve <stage> gate Record human approval — specify + plan opens the gate
$specforge-implement construction Build it, under the gate
$specforge-loop construction Autonomously work the approved task list — gated Ralph loop
$specforge-operate operations Deploy plan, runbook, observability, rollback, handoff
$specforge-quick escape hatch Audited fast-track for a trivial change
$specforge-status any Show progress + gate state
$specforge-resume any Continue after a context reset

SpecForge’s differentiator is that approval is enforced, not advisory. Here’s the honest picture for Codex:

Tier Mechanism Status
Claude Code Real-time PreToolUse hook — blocks the edit at the moment it’s attempted Full (the flagship)
Codex PreToolUse hook (.codex/hooks.jsoncodex-gate.sh) Matcher and deny-response shape match Codex’s documented schemanot yet tested against a live Codex install
Any agent, or a human editing directly git pre-commit hook (installed by install.sh) Agent-independent backstop — fires at commit time regardless of which AI (or no AI) made the edit

The pre-commit hook is the honest floor: even where the PreToolUse hook is misconfigured, disabled, or not wired up, an unapproved code change staged for commit is still caught locally, before it’s committed. It reuses the same decide.sh decision logic as the Codex hook, so its verdict is always consistent. Note this is a local git hook, not a CI/PR check — the bundle doesn’t ship a CI workflow for your repo; if you want enforcement at PR time too, you can wire decide.sh into your own CI job the same way pre-commit does.

Caveat — apply_patch parsing: .codex/hooks.json registers a PreToolUse hook with matcher apply_patch|Edit|Write, matching Codex’s documented schema. Codex’s own file-editing tool is apply_patch, and unlike every other adapter’s edit tool, it has no clean file-path field: tool_input.command (or, as a fallback, tool_input.input) carries the raw patch text, and the file paths live in that patch’s header lines (*** Add File: <path>, *** Update File: <path>, *** Delete File: <path>). codex-gate.sh parses those header lines out with a portable (sed -E, works on both BSD and GNU sed) regex to recover every path the patch touches, and runs the gate decision against each one — a patch touching even one gate-blocked file is denied. Edit and Write (also matched by this hook, in case Codex ever routes through them) are tried first via a direct tool_input.file_path / tool_input.path field, before falling back to patch parsing. On a deny, it emits Codex’s documented {"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny",...}} shape. None of this has been exercised against a live Codex install — it’s built and tested against Codex’s documented schema and a scripted stand-in for the hook contract (see tests/codex-gate.test.sh and tests/e2e-codex.test.sh), not verified end-to-end with the real CLI. The shim fails open on anything it can’t parse — an unparseable patch, a missing script, or a crash all resolve to “allow,” never to “incorrectly block a legitimate edit.” A schema mismatch downgrades this tier to “not enforced by this hook,” always caught anyway by the pre-commit backstop at commit time. Verify against your Codex version.