아카이브 / 개발

codex-autodev — PRD 기반 멀티 에이전트 개발 오케스트레이터

유형개발
기간2026.04 — 2026.05
역할설계·구현
구분개인 프로젝트
언어JavaScript (Node.js)
주요 기술Codex CLI · Claude CLI · git worktree · node:test

목차프로젝트 요약 · 담당 범위 · 문제와 구현 접근 · 이 작업에서 한 일 · 결과물과 원문 · 구현 상세

프로젝트 요약

대상 저장소의 PRD·인수 조건·규칙을 읽고, Codex CLI(선택적으로 Claude CLI) 에이전트로 계획·구현·검증·수리·리뷰를 반복하는 로컬 Node.js 개발 오케스트레이터.

담당 범위

설계·구현을 맡은 개인 프로젝트다. 공개 저장소에 코드와 사용 방법을 남겼다.

문제와 구현 접근

requirements.yaml의 열린 인수 조건이나 PRD 문서의 소제목에서 작업을 만들고, 개인정보·보안·데이터 무결성 항목을 먼저, 사람의 입력이 필요한 항목을 마지막에 두도록 위험도 순으로 정렬한다. 작업은 프론트엔드·백엔드·API·데이터베이스·보안 같은 도메인별 전문 에이전트 역할로 나눠 맡긴다.

작업마다 별도 git worktree에서 구현하고 설정된 검증 명령을 돌린다. 실패 로그는 정해진 횟수 안에서 수리 에이전트에 넘기고, 리뷰 에이전트가 마지막으로 규칙을 점검한다. marathon 모드는 검증을 통과한 작업만 통합 worktree에 병합하고, push는 명시적으로 켰을 때만 최종 검증을 거쳐 실행한다.

모델 호출을 코드에 넣지 않고 에이전트 CLI를 실행하는 방식으로 두었다. 실행 기록 조회 명령, 읽기 전용 대시보드(API 라우트 탐지와 OpenAPI 출력), 작업 중인 worktree를 따라 미리보기 서버를 다시 띄우는 감시 명령, macOS LaunchAgent로 설치하는 자동 운영 워치독을 함께 만들었다.

이 작업에서 한 일

아이디어를 실제로 작동하는 코드로 만들고, 다른 사람이 설치하고 사용할 수 있도록 설명서를 함께 작성했다.

결과물과 원문

관련 등록공보·논문·저장소는 아래 링크에서 볼 수 있다.

구현 상세

README공개 저장소의 구조·기능·실행 문서

codex-autodev

codex-autodev is a general-purpose autonomous development orchestrator. It reads a target repository's PRDs, specs, acceptance criteria, and repo-local rules, then coordinates multiple coding agents to plan, implement, verify, repair, and review code changes.

It is a local Node.js CLI. It does not embed model calls: every LLM-backed step shells out to an agent CLI (Codex CLI by default, Claude CLI optionally), and every task runs in an isolated Git worktree so the target repo's working tree is not modified by default.

What It Does

  • Plans tasks from a user goal, from a machine-readable docs/autodev/requirements.yaml, or from PRD headings, and orders open acceptance criteria by risk (privacy/security/data-integrity first, human-input items last).
  • Routes each task to engineering domains (frontend, backend, API, database, agent, DevOps, test, security, docs) and to specialist agent roles.
  • Runs specialist agents in a per-task worktree, then runs deterministic verification commands, feeds failure logs to a repair agent within a bounded retry count, and finishes with a review agent.
  • In marathon mode, keeps working through the backlog and merges only verified tasks into a cumulative integration worktree.
  • Records events, agent outputs, command logs, and reports in a per-run blackboard under state/.
  • Provides run inspection commands, a read-only local dashboard, a preview dev-server watcher, and an auto-ops watchdog that can be installed as a macOS LaunchAgent.

Requirements

  • Node.js 22 or newer
  • Git
  • Codex CLI, installed locally by npm install (@openai/codex is a dependency), logged in with OAuth
  • Optional: Claude CLI, if you configure it as an agent runtime
  • macOS only for ops install-launchagent; the other commands are plain Node.js

Core Constraint

Model access goes through Codex CLI OAuth login. This project does not call the OpenAI API directly and does not require OPENAI_API_KEY.

The runner invokes:

codex exec ...

or the local package equivalent:

node_modules/.bin/codex exec ...

Model selection and reasoning effort are inherited from Codex CLI defaults unless a project overrides them. Set them in the machine user's Codex config, for example:

model = "gpt-5.5"
model_reasoning_effort = "xhigh"
approval_policy = "never"

The runner also passes --ask-for-approval never to Codex CLI by default. It does not default to --dangerously-bypass-approvals-and-sandbox; task execution stays inside the configured sandbox unless a project explicitly sets codex.bypassApprovalsAndSandbox.

For long autonomous runs, reasoning can be adaptive per agent call instead of always using the CLI default. codex.reasoningPolicy.mode = "adaptive" makes the runner pass per-call overrides such as -c model_reasoning_effort="high":

{
  "codex": {
    "reasoningPolicy": {
      "mode": "adaptive",
      "default": "medium",
      "byRole": {
        "architect": "xhigh",
        "frontend-engineer": "medium",
        "api-engineer": "high",
        "database-engineer": "high",
        "security-reviewer": "xhigh",
        "repair": "xhigh"
      }
    }
  }
}

The adaptive policy keeps cheap/simple work at medium, regular API/database/test work at high, and reserves xhigh for architecture, security, agent orchestration, repairs, and critical P0 API/database/backend changes. plan --with-reasoning shows the effort that would be selected for each planned role.

Quick Start

git clone <this-repo> codex-autodev
cd codex-autodev
npm install

# Create a starter config for your target repository
node bin/codex-autodev.js init --target <path-to-target-repo> --name my-app --out configs/my-app.json

Or copy configs/example.json and edit name, targetRepo, worktreeRoot, docs, hardRules, and verification. Keep project configs one level deep inside this repo (for example in configs/): the runner takes the parent of the config's directory as the codex-autodev root and resolves stateDir from there. configs/generated.json and configs/*.local.json are git-ignored if you want to keep machine-specific paths out of commits.

Check readiness and authenticate:

node bin/codex-autodev.js doctor --config configs/my-app.json
node bin/codex-autodev.js auth login --config configs/my-app.json --device
node bin/codex-autodev.js auth status --config configs/my-app.json
node bin/codex-autodev.js auth smoke --config configs/my-app.json   # tiny live model call

Plan without changing anything:

node bin/codex-autodev.js plan --config configs/my-app.json --max-tasks 3 --with-reasoning
node bin/codex-autodev.js run --config configs/my-app.json --dry-run --max-tasks 3

Run one real implementation loop:

node bin/codex-autodev.js run \
  --config configs/my-app.json \
  --goal "Implement the next highest-value PRD task" \
  --max-tasks 1

Keep going through the PRD backlog with marathon mode:

node bin/codex-autodev.js marathon \
  --config configs/my-app.json \
  --include-server-checks \
  --continue-on-failure

The npm run doctor, npm run dry-run, npm run dry-marathon, npm run dashboard, and npm run runs scripts run the same commands against configs/example.json.

Project Config

A project config is JSON or YAML. The schema is in schemas/project-config.schema.json; configs/example.json is a minimal starting point. The main keys:

KeyPurpose
name, targetRepoProject name and path to the target Git repository
workspaceMode, worktreeRootworktree (default) or direct, and where task worktrees are created
stateDirWhere run state is written, relative to the codex-autodev root
docs, hardRulesTarget-repo documents given to agents, and rules every agent must follow
verificationCommands with id, command, timeoutMs, required, and optional needsServer
serverHow to start the target's dev server for needsServer checks (command, port, healthUrl, env, ...)
agents, agentRuntimesSpecialist mode and cap, default runtime, per-role runtime mapping
codex, claudeCLI commands, sandbox, approval, and reasoning policy
marathonmaxCycles, maxTasksPerCycle, stopOnFailure, and includeServerChecks (run needsServer checks without passing the flag)
publishOptional push of verified results (disabled unless publish.enabled is true)
opsWatchdog timeouts and cooldown, plus the optional capture and taskIntents coordination described under Auto-Ops Watchdog
dashboardDefaults for the dashboard preview link (previewUrl) and for preview-watch (previewHost, previewPort)
Structured requirements

When you pass --goal, that goal becomes the task. Otherwise, if the target repo contains docs/autodev/requirements.yaml, the planner reads it first. Features with an open status (partial, not_implemented, stub, needs_human_input) become tasks: one per unresolved acceptance criterion, or one follow-up task for the feature when no criterion is open:

features:
  - id: F4
    title: Reports
    phase: P0
    status: partial
    source_docs: [docs/PRD.md]
    acceptance_criteria:
      - id: F4.AC1
        description: Export the monthly report as CSV
        status: not_implemented
        verification: vitest

Without that file, the planner falls back to ##/### headings in the PRD documents listed in docs. --ai-plan asks the agent CLI (read-only sandbox, schema-constrained JSON output) to write the plan from the same documents, and falls back to the deterministic plan if that call fails or returns invalid JSON.

Run Modes

run executes a bounded task set. By default each task gets its own worktree and does not merge back automatically. Use direct mode only when you intentionally want the agent to edit the target path in place:

node bin/codex-autodev.js run --config configs/my-app.json --direct --max-tasks 1

marathon is the long-running PRD implementation mode. It repeatedly plans unfinished tasks, creates isolated task branches from the current integration branch, verifies them, and merges successful branches into an integration worktree under:

<worktreeRoot>/<run-id>/integration

For each task, the marathon loop:

  1. Plans the next unfinished PRD/spec task from the target repo docs.
  2. Creates an isolated task worktree from the current integration branch.
  3. Asks specialist agents to implement only their part of the task.
  4. Runs the required verification gates.
  5. If a required gate fails, passes the logs to RepairAgent and reruns the same gates.
  6. Commits the task branch only after required gates pass.
  7. Merges the task branch into the integration worktree.

When a marathon finishes with no failed tasks and publishing is enabled, it runs final verification on the integration worktree and pushes only if that passes. Failed task branches stay isolated so later tasks continue from the last successful integration state.

Parallel independent tasks

marathon.maxTasksPerCycle (or --max-tasks-per-cycle) controls how many tasks are selected per cycle. When more than one task is selected, each gets its own worktree from the integration branch, the tasks run concurrently, and a tasks.parallel.started event is recorded. Successful results are then committed and merged into the integration worktree one by one. While tasks run in parallel, runs monitor, the dashboard, preview-watch, and the watchdog follow the first of them; the dashboard's /api/state also lists all of them in run.progress.inProgressTasks.

Resume and retry

If a marathon run stops, pass --resume <run-id> or --resume latest-marathon to continue from the saved integration worktree and completed/failed task sets. Use plain latest only when you intentionally want to resume the newest run of any mode. If tasks failed because of a runner or environment problem that has since been fixed, add --retry-failed:

node bin/codex-autodev.js marathon \
  --config configs/my-app.json \
  --resume latest-marathon \
  --include-server-checks \
  --retry-failed \
  --continue-on-failure

Progress is continuously written to reports/marathon-progress.json in the run directory, which powers runs monitor and the dashboard.

Agent Loop

The runner includes these agents:

  • PlannerAgent: turns PRD/spec/autodev docs into executable tasks.
  • SpecialistAgent: calls the agent CLI for domain roles: architect, frontend-engineer, backend-engineer, api-engineer, database-engineer, agent-engineer, devops-engineer, test-engineer, security-reviewer, product-reviewer.
  • VerifierAgent: runs configured deterministic checks.
  • RepairAgent: calls the agent CLI with failure logs and a bounded retry count.
  • ReviewerAgent: performs a final rule/contract review.

Agents communicate through a run blackboard stored as JSON and JSONL artifacts under state/runs/<run-id>/. Agent stdout/stderr is stored under state/runs/<run-id>/commands/; JSONL events keep compact tails so long model sessions do not make the event log unusable.

agents.maxImplementationSpecialists caps the implementation roles per task (eight in configs/example.json and init output, four if unset). Specialists run sequentially by default. Projects that can tolerate same-workspace concurrent edits may opt into agents.mode = "specialist-parallel": the architect still runs first, then implementation specialists are dispatched together and a specialists.parallel.started event is recorded.

Claude CLI runtime

Codex CLI is the default runtime. A project can define additional runtimes in agentRuntimes and choose them globally (agents.defaultRuntime) or per role (agents.runtimeByRole):

{
  "agentRuntimes": {
    "claude": {
      "provider": "claude",
      "command": "claude",
      "model": "<model-name>"
    }
  },
  "agents": {
    "defaultRuntime": "codex",
    "runtimeByRole": { "frontend-engineer": "claude" }
  }
}

The Claude runtime runs claude -p --output-format json with the prompt on stdin and passes the selected reasoning effort as --effort. Optional runtime keys (permissionMode, tools, allowedTools, disallowedTools, outputFormat, ...) are listed in the config schema. doctor checks --version and auth status for every configured Claude runtime.

The Codex sandbox setting, including the read-only sandbox used for planning and review calls, is not applied to Claude CLI. What a Claude agent may do is controlled only by the permissionMode and tool lists you set for that runtime.

Verification And Publish Gates

Before a task can be committed, it must pass the required commands in verification. A typical web project might use:

"verification": [
  { "id": "lint", "command": "npm run lint", "timeoutMs": 600000, "required": true },
  { "id": "test", "command": "npm test", "timeoutMs": 600000, "required": true },
  { "id": "build", "command": "npm run build", "timeoutMs": 900000, "required": true },
  { "id": "e2e", "command": "npx playwright test", "timeoutMs": 1200000, "required": true, "needsServer": true }
]

A needsServer check is more than a command. With --include-server-checks, the runner starts the target's dev server on a free port (by default npm run dev -- -H <host> -p <port>), waits for the health URL (default <baseUrl>/api/health), injects PORT, PLAYWRIGHT_BASE_URL, and AUTODEV_SERVER_BASE_URL, runs the check, records server stdout/stderr, and stops the server. If the server never becomes healthy, that is a verification failure and RepairAgent receives the server logs.

verify runs the configured checks on their own:

node bin/codex-autodev.js verify --config configs/my-app.json --include-server-checks

Publishing is off unless publish.enabled is true. When enabled, the publisher fetches and merges publish.targetBranch from publish.remote into the integration worktree, reruns final verification, then pushes:

  • the integration branch (autodev/<run-id>/integration by default; publish.pushIntegrationBranch, publish.integrationBranch),
  • the target branch, unless publish.pushTargetBranch is false,
  • and fast-forwards the local target checkout if it is clean, unless publish.updateLocalTarget is false.

Set publish.pushTargetBranch = false to push only the verified integration branch and merge it by hand after review. Completed historical runs are not auto-published unless publish.publishCompletedRuns is enabled.

When it commits a task, the runner never stages .env or .env.* files at any depth (templates such as .env.example included) or anything under a node_modules directory. It also skips the root-level .next, coverage, playwright-report, and test-results folders and its own dev-server pid, port, and log files. Other generated files are kept out only by the target repo's .gitignore.

Inspecting Runs

node bin/codex-autodev.js runs list    --config configs/my-app.json --limit 10
node bin/codex-autodev.js runs status  --config configs/my-app.json --run latest
node bin/codex-autodev.js runs monitor --config configs/my-app.json --run latest
node bin/codex-autodev.js runs tail    --config configs/my-app.json --run latest --limit 20
node bin/codex-autodev.js runs patch   --config configs/my-app.json --run latest
node bin/codex-autodev.js runs prune   --config configs/my-app.json --keep 30

runs monitor adds an attention list (failed tasks, stale in-progress tasks, runtime blockers, needs-human outcomes) and redacts token-like values from process lines and event payloads. runs patch writes a reviewable patch from the integration worktree without touching the target repo. runs prune is a dry run by default; pass --apply to delete old completed run directories. Incomplete runs are kept unless --include-incomplete is also passed.

Dashboard

node bin/codex-autodev.js dashboard --config configs/my-app.json --host 127.0.0.1 --port 8765

A read-only HTTP server built on node:http. It serves:

  • /: a status page for the selected run (default latest-marathon) with panels for the app preview, current work, command timeline, recent events, API routes, related processes, and recent runs. An API capture panel is added when ops.capture.statusPath or ops.capture.requestPath is configured.
  • /api/state: the same snapshot as JSON.
  • /openapi.json and /api-docs: an OpenAPI document generated from the API routes found in the active worktree, and a Swagger UI page for it (Swagger UI assets load from unpkg).
  • /healthz

Route discovery covers Next.js pages/api/ and app/api//route.* files, Express-style app.get(...)/router.post(...) declarations, and FastAPI decorators with APIRouter(prefix=...). Each route is tagged with a heuristic security note, for example a sensitive namespace or mutating method with no auth evidence found in the file or in framework middleware.

The dashboard binds to 127.0.0.1 by default. It has no authentication, so bind it to other interfaces only on a network you trust.

Preview Watch

node bin/codex-autodev.js preview-watch --config configs/my-app.json --port 3054

Keeps one preview server pointed at the worktree the current run is working in (the in-progress task, else the integration worktree, else the target repo). It runs npm run dev -- -H <host> -p <port> (Next.js-style flags) in that workspace, so the workspace needs a dev script. Host and port default to dashboard.previewHost/dashboard.previewPort, then 127.0.0.1:3054. When the active worktree changes, it stops the old server and starts a new one. --once aligns once and exits. The dashboard shows the preview state; pass --preview-url to the dashboard (or set dashboard.previewUrl) to link it.

Before it starts a server, preview-watch stops any process that is listening on the chosen port (found with lsof) and deletes the .next folder in the workspace it is about to serve. With no run in progress, that workspace is the target repo itself. Use a port that nothing else needs.

Auto-Ops Watchdog

ops once runs one watchdog cycle; on macOS, ops install-launchagent installs a LaunchAgent that runs ops once --start-if-idle --self-repair --live-auth-check on an interval (use --no-start-if-idle, --no-self-repair, or --no-live-auth-check to drop a flag):

node bin/codex-autodev.js ops install-launchagent \
  --config configs/my-app.json \
  --label com.codex-autodev.autoops.my-app \
  --interval 300 \
  --load

The watchdog is intentionally conservative. It tracks latest-marathon, so ad-hoc verify runs do not accidentally trigger a new marathon. If a marathon or agent CLI process for this project is active, it only records status. With --start-if-idle, when the runner is idle after an incomplete or failed marathon run, it starts marathon --resume latest-marathon --retry-failed --continue-on-failure in the background (adding --include-server-checks when marathon.includeServerChecks is true, and --live-auth-check when that flag was given). It also starts one after a successful run if the deterministic planner still finds open tasks in the target docs. With --self-repair, if it sees a known runner-level failure, such as git add trying to stage ignored .env or node_modules symlinks, it first runs Codex CLI against the codex-autodev repo itself, then runs npm run lint and npm test before restarting the marathon. With self-repair on, a run that stays idle and incomplete also gets a stall diagnosis from Codex CLI in a read-only sandbox, with a cooldown between attempts. If a newly completed run has publishing enabled, the watchdog runs the final verification gates before pushing.

Manual one-shot cycle:

node bin/codex-autodev.js ops once \
  --config configs/my-app.json \
  --run latest-marathon \
  --resume latest-marathon \
  --start-if-idle \
  --self-repair \
  --live-auth-check

Each cycle also writes a situation summary (current task, primary mode, risks, recommendations). Optionally, ops.capture.statusPath and ops.taskIntents let the watchdog compare a separate helper process's status file with the hints declared for the current task, and write a desired_target.json request next to it when they diverge. Without that config, this step does nothing.

Auto-ops logs are written under:

state/supervisor/autoops.jsonl
state/supervisor/autoops-latest.json
state/supervisor/autoops.stdout.log
state/supervisor/autoops.stderr.log

Human Questions

The runner does not stop to ask ordinary implementation questions. Agents run non-interactively and report anything unresolved in the openQuestions field (or a needs-human status) of their JSON result, which is stored with the run. docs/HUMAN_QUESTIONS.md is a file the operator maintains by hand: keep questions that truly need a human there, together with the defaults you have decided on. No code reads or writes it. Separately, the planner classifies acceptance criteria that depend on credentials, manual approval, or evidence from external services (English or Korean wording) as needs_human_input and schedules them last.

Image Generation

The runner invokes agents through terminal/filesystem workflows, so they do not get a raster image-generation tool. For autonomous repo work, prefer code-native assets such as SVG, CSS, canvas, or existing project assets. Note tasks that need generated raster images in docs/HUMAN_QUESTIONS.md and handle them by hand.

Development

npm run lint   # node --check on every source and test file
npm test       # node:test suite

More design detail is in docs/PRD.md and docs/ARCHITECTURE.md.

Status And Limitations

  • Personal project, built in April and May 2026 and exercised against real target repositories. Version 0.1.0; the CLI and config format may still change.
  • Depends on Codex CLI ^0.125.0. Agent quality, cost, and speed depend on the model and effort settings of your CLI login.
  • Agents run with --ask-for-approval never inside the configured sandbox, and marathon mode commits and merges task branches automatically. Point it at repositories where that is acceptable, and review integration branches before merging.
  • The planner's risk and human-input classification, and the dashboard's route security notes, are keyword heuristics, not proofs.
  • The LaunchAgent installer is macOS-only. On other systems, run ops once from cron or another scheduler.

GitHub에서 최신 문서 보기 ↗