Skip to content
Back to work

Agentic engineering system

Automated Agentic SDLC

A Codex-only Python orchestrator that runs a deterministic SDLC state machine from one JSON file, with phase gates and verification remediation.

A single state file per repo drives a deterministic 8-phase run across 27 role-based tasks, with gate-before-advance, a bounded repair loop on DEV, and a per-task prompt contract every role honors.

Phases
8
Tasks
27
Agents
10
Features shipped
16
Auto-remediations
3
01 /

What this is

A small Python orchestrator that drives the entire software development lifecycle of a single product repo by sequencing codex exec invocations against role-based prompts. The orchestrator owns a single JSON state file per repo (state/flow_state.json); every Codex invocation reads it, runs the task it prescribes, and the orchestrator validates the result, advances the phase machine, and auto-commits the scoped diff before the next task.

The goal was to make a long, multi-agent SDLC resumable, auditable, and replayable from one file. There is no parallel scheduling, no separate agent runtime, and no SDK dependency. Just one CLI tool, one state machine, and a few hundred lines of Python that enforce the contract every role has to honor.

02 /

The state machine

Eight phases. Each phase has a small set of canonical tasks; the orchestrator dispatches them in order, gates the transition to the next phase on artifact completeness, and rewinds the machine to Phase 5 if verification finds a gap.

ADMIN_*
Human-in-the-loop approval gate. Only ADMIN tasks can ask the user questions or request approval.
AUDIT_PHASE_*
Automated post-phase audit. Checks the phase's outputs meet standards before the phase can close.
*_DRAFT
An agent generates the artifact (PRD, ARCH, DESIGN, PLAN).
QA_PREP / QA_VERIFY
Quality assurance: test-plan prep, then verify the implementation against it.
DEV_IMPLEMENT
The actual code change for one feature. Gets a 2-attempt repair loop on gate failure.
F-XXX
A single feature ID (e.g. F-001, F-016). The Phase 5 BUILD loop runs once per F-XXX in backlog order.
VERIFY_PRD / VERIFY_ARCH
Post-build verification: does the shipped product match the original PRD and architecture?
ADMIN_SIGNOFF
Final human signoff that closes the run. Nothing runs after this.
stateDiagram-v2
  direction TB
  [*] --> INTAKE
  INTAKE: Phase 0 · INTAKE
  INTAKE: ADMIN_INTAKE → AUDIT_PHASE_0
  PRD: Phase 1 · PRD
  PRD: PRD_DRAFT → ADMIN_REVIEW_PRD → AUDIT_PHASE_1
  ARCH: Phase 2 · ARCH
  ARCH: ARCH_DRAFT → ADMIN_REVIEW_ARCH → AUDIT_PHASE_2
  DESIGN: Phase 3 · DESIGN
  DESIGN: DESIGN_DRAFT → ADMIN_REVIEW_DESIGN → AUDIT_PHASE_3
  PLAN: Phase 4 · PLAN
  PLAN: PLAN_DRAFT → ADMIN_REVIEW_PLAN → AUDIT_PHASE_4
  BUILD: Phase 5 · BUILD
  BUILD: SELECT_FEATURE → QA_PREP → DEV_IMPLEMENT → QA_VERIFY → AUDIT_FEATURE → ADMIN_CLOSE_FEATURE
  VERIFY: Phase 6 · VERIFY
  VERIFY: VERIFY_PRD → VERIFY_ARCH → ADMIN_REVIEW_VERIFY → AUDIT_PHASE_6
  SIGNOFF: Phase 7 · SIGNOFF
  SIGNOFF: ADMIN_SIGNOFF
  INTAKE --> PRD
  PRD --> ARCH
  ARCH --> DESIGN
  DESIGN --> PLAN
  PLAN --> BUILD
  BUILD --> VERIFY: backlog empty
  BUILD --> BUILD: next F-XXX
  VERIFY --> BUILD: gap → new F-XXX
  VERIFY --> SIGNOFF: approved
  SIGNOFF --> [*]
          
03 /

One real run, end-to-end

A single orchestrator run produced a luxury-hotel Next.js site. The orchestrator itself ran for about 6 hours of wall-clock time across 24 sessions over 12 calendar days (planning phases preceded the first run). The audit trail is the state/flow_state.json file itself, replayable from any point.

  1. Phases 0–4 — planning. Five artifacts were generated and user-approved in sequence: use case, PRD, architecture, UI spec, and implementation plan. Each one gated the next phase from starting.
  2. Phase 5 — build. Based on the plan, the orchestrator created 16 feature tasks (F-001 to F-016) and ran them in backlog order through the SELECT_FEATURE → QA_PREP → DEV_IMPLEMENT → QA_VERIFY → AUDIT_FEATURE → ADMIN_CLOSE_FEATURE loop.
  3. F-001 to F-003 shipped the app shell, media handling, and SEO base. F-001 went through one QA_FAIL → fix → QA_PASS cycle.
  4. F-004 added the mock data layer and read-only /api/* routes. A sandbox-level EPERM on the loopback interface forced module-level Playwright as the equivalent verification path, recorded as a decision in docs/audit/decision_log.md.
  5. F-005 to F-010 built the guest-facing pages: home, rooms list/detail, booking intent, amenities, experiences, and dining/wellness/offers.
  6. F-011 to F-013 wrapped up the content layer with gallery, reviews, and contact pages.
  7. F-014 was a verification remediation. After all 13 features shipped, Phase 6 ran and ADMIN_REVIEW_VERIFY withheld approval over the gallery media boundary (YouTube removed; Unsplash/Pexels only). The orchestrator queued this F-ID, rewound to Phase 5, and the QA loop re-ran the fix.
  8. F-015 and F-016 closed out the BUILD loop with route metadata for /booking and /gallery, plus room-detail JSON-LD.
  9. Phase 6 — verification and signoff. With all 16 features built, the run re-ran VERIFY_PRD → VERIFY_ARCH → ADMIN_REVIEW_VERIFY → AUDIT_PHASE_6 → ADMIN_SIGNOFF. Every artifact approved; run_state: IDLE. Final runtime: 5.95 hours of orchestrator time across 24 sessions.
05 /

How it works

Three small Python modules do the whole job. Each is a single-purpose function with no hidden state; together they form a transparent, resumable loop.

a /

The outer loop

workflow.py · run_until_blocked()

Each tick of the loop: load the state file, derive the next task, dispatch it to Codex, gate the result against the current task's success criteria, advance the state machine, and auto-commit the scoped diff. A file lock (state/orchestrator.lock) prevents concurrent runs. The loop exits on an open BLOCKER, an open approval, or when the planner returns nothing (run_state: IDLE). On DEV_IMPLEMENT gate failure, the loop tries a bounded 2-attempt repair before surfacing the failure to the user.

b /

The planner

planner.py · derive_next_task()

A pure function over state: given the current phase and the last completed task, it returns the next Task from a 27-entry registry. No hidden Python state, no side effects; that's what makes the run fully deterministic and resumable from any point in flow_state.json. Each phase has the same shape: a *_DRAFT task, an *_REVIEW approval, and an AUDIT_PHASE_* gate. Phase 5 is the per-feature BUILD loop; phases 6 and 7 are the final verification and signoff.

c /

The prompt contract

executor.py · build_agent_prompt()

Every Codex invocation gets the same prompt template, regardless of role. The function injects four things: the current task, the role's .md contract, the current feature, and a fixed set of non-negotiable orchestrator rules (don't touch flow_state.json, stay within the allowed write paths, keep diffs minimal, surface blockers as questions). The agent's final response must be valid JSON matching agent_result.schema.json the orchestrator gates on that, not on free-form text.

06 /

Design choices and evidence

Why these choices

  • One state file per repo. The entire SDLC is replayable from a single JSON file. Diffable in code review. Resumable from any point. The orchestrator owns it; every role reads it but never writes it.
  • Pure-function task dispatch. derive_next_task(state) is a pure function. No hidden Python state, so the run is fully deterministic from the JSON.
  • Gate-before-advance. Phase transitions require doc front-matter, QA status match, npm run lint, npm run build, and per-feature Playwright. The main branch is always coherent.
  • proposed_questions buffer. Non-ADMIN agents propose BLOCKER questions into a buffer; ADMIN triages. The user is only ever asked by ADMIN, and only the smallest necessary set.
  • 2-attempt repair loop on DEV only. Bounded retry prevents worker loops. Other roles fail fast and surface the gate failure to ADMIN.
  • Manual git push only. The orchestrator auto-commits scoped diffs but never publishes. Pushes are queued as pending_approvals[] and drained manually.
  • Verification remediation rewind. When ADMIN_REVIEW_VERIFY doesn't approve, the orchestrator queues a new F-ID for the gap and rewinds to Phase 5. The run never idles on an open blocker.

Evidence

The full run is on disk. The state file is the live ledger; the audit directory is the trail of decisions; the orchestrator source is the eight modules that enforce the contract. None of these are public, but the same code is what the excerpts above are drawn from.

  • state/flow_state.json — live ledger (459 KB; 16 features, 13 commits per feature, 614,358 tokens across 5 final-session runs, 5.95 h orchestrator runtime across 24 sessions)
  • docs/audit/journal.md — full audit trail across all phases and features
  • docs/audit/decision_log.md — every “why we did it this way” decision
  • docs/06_verification/final_signoff_summary.md — the closing artifact
  • agentic_orchestrator/orchestrator/{workflow,planner,executor,gates,state,runlog,documents,git_ops}.py — ~1,500 LOC across 8 modules
  • agentops-kit/agents/*.md — 10 role contracts

© 2026 Abhishek Yadav