

In the era of AI-native software engineering, we are moving away from "Chat-and-Code" toward Spec-Driven Agentic Development (SDAD). Instead of asking an LLM to "write a function," SDAD focuses on defining a formal, machine-readable specification (the "Spec") that acts as the single source of truth for a swarm of specialized agents (Architect, Coder, Tester, and Reviewer).
This guide provides a production-ready implementation of an SDAD orchestration layer.
Before implementing the SDAD framework, ensure you have the following:
gpt-4o or Anthropic claude-3-5-sonnet are highly recommended for spec parsing).pip for Python and npm or pnpm for JavaScript.# Create a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install core dependencies
pip install openai pydantic python-dotenv loguru
# Initialize project
mkdir sdad-agent && cd sdad-agent
npm init -y
# Install dependencies
npm install openai zod dotenv typescript ts-node @types/node
# Initialize TypeScript
npx tsc --init
The core of SDAD is the Specification Object. We will implement a system where a "Spec" is passed to an agentic loop that validates code against that spec.
import os
import json
from typing import List, Dict, Any
from pydantic import BaseModel, Field
from openai import OpenAI
from dotenv import load_dotenv
from loguru import logger
# Load environment variables
load_dotenv()
# 1. Define the formal Specification Schema
class SoftwareSpec(BaseModel):
component_name: str
functionality: str
input_schema: Dict[str, Any]
output_schema: Dict[str, Any]
constraints: List[str]
# 2. Define the Agentic Response Schema
class AgentResponse(BaseModel):
code: str
explanation: str
unit_tests: str
compliance_score: float = Field(description="Score from 0 to 1 on how well code matches spec")
class SDADOrchestrator:
def __init__(self):
self.client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
logger.info("SDAD Orchestrator Initialized")
def execute_sdad_loop(self, spec: SoftwareSpec) -> AgentResponse:
"""
The Agentic Loop: Takes a formal spec and generates compliant code.
"""
logger.info(f"Starting SDAD loop for component: {spec.component_name}")
prompt = f"""
You are an AI Software Engineer following the SDAD (Spec-Driven Agentic Development) protocol.
TARGET SPECIFICATION:
- Component: {spec.component_name}
- Functionality: {spec.functionality}
- Inputs: {json.dumps(spec.input_schema)}
- Outputs: {json.dumps(spec.output_schema)}
- Constraints: {', '.join(spec.constraints)}
TASK:
1. Generate production-ready code.
2. Ensure strict adherence to input/output schemas.
3. Provide comprehensive unit tests.
4. Self-evaluate compliance.
Return ONLY a JSON object matching this structure:
{{ "code": "string", "explanation": "string", "unit_tests": "string", "compliance_score": float }}
"""
try:
response = self.client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "system", "content": "You are a strict SDAD Agent."},
{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
# Parse the structured output
raw_content = response.choices[0].message.content
data = json.loads(raw_content)
return AgentResponse(**data)
except Exception as e:
logger.error(f"SDAD Loop Failed: {str(e)}")
raise
# --- Execution Example ---
if __name__ == "__main__":
# Define a formal spec for a Calculator component
my_spec = SoftwareSpec(
component_name="ArithmeticEngine",
functionality="Performs addition and subtraction on integers.",
input_schema={"a": "int", "b": "int", "op": "str"},
output_schema={"result": "int"},
constraints=["Must handle zero division if division is added later", "No floating point"]
)
orchestrator = SDADOrchestrator()
try:
result = orchestrator.execute_sdad_loop(my_spec)
print("\n--- GENERATED CODE ---")
print(result.code)
print("\n--- COMPLIANCE SCORE ---")
print(f"{result.compliance_score * 100}%")
except Exception as err:
print(f"Error: {err}")
import OpenAI from 'openai';
import { z } from 'zod';
import 'dotenv/config';
// 1. Define the Spec using Zod for runtime validation
const SpecSchema = z.object({
componentName: z.string(),
functionality: z.string(),
inputSchema: z.record(z.string()),
constraints: z.array(z.string()),
});
type SoftwareSpec = z.infer<typeof SpecSchema>;
// 2. Define the Agentic Output Schema
const AgentOutputSchema = z.object({
code: z.string(),
explanation: z.string(),
complianceScore: z.number().min(0).max(1),
});
class SDADAgent {
private openai: OpenAI;
constructor() {
this.openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
}
async generateFromSpec(spec: SoftwareSpec) {
console.log(`🚀 SDAD: Processing ${spec.componentName}...`);
const prompt = `
SDAD PROTOCOL ACTIVATED.
Spec: ${JSON.stringify(spec)}
Generate code that strictly follows this spec.
Return JSON format.
`;
try {
const completion = await this.openai.chat.completions.create({
model: "gpt-4o",
messages: [{ role: "user", content: prompt }],
response_format: { type: "json_object" },
});
const content = completion.choices[0].message.content;
if (!content) throw new Error("Empty response from AI");
// Validate the AI's output against our schema
const parsed = JSON.parse(content);
return AgentOutputSchema.parse(parsed);
} catch (error) {
console.error("❌ SDAD Agent Error:", error);
throw error;
}
}
}
// --- Execution Example ---
async function run() {
const agent = new SDADAgent();
const mySpec: SoftwareSpec = {
componentName: "DataTransformer",
functionality: "Converts snake_case strings to camelCase.",
inputSchema: { input: "string" },
constraints: ["Must handle empty strings", "Must be idempotent"],
};
try {
const result = await agent.generateFromSpec(mySpec);
console.log("✅ Implementation Successful:");
console.log(result.code);
console.log(`Compliance: ${result.complianceScore * 100}%`);
} catch (err) {
console.error("Failed to complete SDAD cycle.");
}
}
run();
Create a .env file in your root directory. Never commit this file to version control.
# API Keys
OPENAI_API_KEY=sk-proj-your-actual-key-here
# Agent Behavior Settings
AGENT_TEMPERATURE=0.2 # Low temperature is critical for SDAD to ensure spec adherence
AGENT_MODEL=gpt-4o
In production, one agent generates code, and a second agent (the "Critic") validates it against the spec. If the score is $< 0.9$, the code is sent back to the first agent for a rewrite.
# Pseudo-code pattern for Refinement
def refinement_loop(spec, max_retries=3):
current_code = None
for i in range(max_retries):
current_code = coder_agent.generate(spec)
score = critic_agent.evaluate(spec, current_code)
if score > 0.9:
return current_code
raise Exception("Agent failed to meet spec after max retries")
| Error | Cause | Fix |
|---|---|---|
JSONDecodeError | The LLM returned conversational text instead of raw JSON. | Ensure response_format: { "type": "json_object" } is set and the prompt explicitly requests JSON. |
ValidationError (Pydantic/Zod) | The agent generated code that doesn't match the required output schema. | Increase the "strictness" in the prompt or use a more capable model (e.g., move from GPT-3.5 to GPT-4o). |
RateLimitError | Too many agentic loops running in parallel. | Implement an exponential backoff strategy or use a task queue like Celery/BullMQ. |
temperature set to 0 or near 0? (High temperature destroys spec adherence).Source: arXiv AI
Follow ICARAX for more AI insights and tutorials.
