Code Generation
Generate runnable, framework-specific agent code from a single agent.yaml manifest.
Overview
@agentspec/codegen reads your agent.yaml manifest, selects an LLM provider, and produces a complete, ready-to-run project — source files, dependencies, environment templates, and a README. You never write boilerplate by hand; the manifest is the source of truth.
1. Quick Start
# Generate a LangGraph agent from your manifest
agentspec generate agent.yaml --framework langgraph
# Output lands in ./generated/ by default
cd generated && pip install -r requirements.txt && python server.pyNo configuration needed if you have the Claude CLI installed and logged in. AgentSpec auto-detects your auth.
2. How It Works
agent.yaml
│
▼
┌─────────────────────────────────┐
│ @agentspec/codegen │
│ │
│ resolveProvider() │◄── Claude subscription / Anthropic API key / OpenAI-compatible
│ loadSkill('langgraph') │◄── src/skills/langgraph.md
│ buildContext(manifest) │
│ provider.stream(system, user) │
│ extractGeneratedAgent(result) │
└─────────────────────────────────┘
│
▼
{ files: { 'agent.py': '...', 'requirements.txt': '...', ... } }
│
▼
agentspec generate --output ./generated/Step by step:
- Resolve provider - auto-detects Claude subscription (CLI), an OpenAI-compatible endpoint, or an Anthropic API key
- Load skill — reads a framework-specific Markdown guide (e.g.,
langgraph.md) that tells the LLM how to generate code - Build context — serializes the manifest JSON + any context files into a prompt
- Stream — sends the prompt to the provider and streams back the response
- Parse — extracts the JSON file map from the LLM response and writes files to disk
This approach covers all manifest fields without exhaustive TypeScript templates. When the schema evolves, the skill file captures it in plain Markdown, not code.
3. Providers
AgentSpec supports three codegen providers. Auto-detection tries them in order:
| Provider | Env vars needed | How it works |
|---|---|---|
| Claude subscription | None - uses claude CLI | First priority. Free with Pro/Max plan. |
| OpenAI-compatible | AGENTSPEC_LLM_API_KEY, AGENTSPEC_LLM_MODEL, optional AGENTSPEC_LLM_BASE_URL | Works with any OpenAI-compatible endpoint (OpenAI, OpenRouter, Groq, Together, Ollama, Nvidia NIM). |
| Anthropic API | ANTHROPIC_API_KEY | Direct API call. Pay per token. |
Force a specific provider
# Via CLI flag
agentspec generate agent.yaml --framework langgraph --provider anthropic-api
# Via env var
export AGENTSPEC_CODEGEN_PROVIDER=claude-sub # force subscription
export AGENTSPEC_CODEGEN_PROVIDER=anthropic-api # force Anthropic API key
export AGENTSPEC_CODEGEN_PROVIDER=openai-compatible # force OpenAI-compatible endpointCheck your auth status
agentspec provider-statusSee the Provider Authentication guide for full details, CI setup, and overrides.
4. Available Frameworks
| Framework | Language | Generated files | Status |
|---|---|---|---|
langgraph | Python | agent.py, tools.py, guardrails.py, server.py, eval_runner.py, requirements.txt, .env.example, README.md | Available |
crewai | Python | crew.py, tools.py, guardrails.py, requirements.txt, .env.example, README.md | Available |
mastra | TypeScript | src/agent.ts, src/tools.ts, mastra.config.ts, package.json, .env.example, README.md | Available |
autogen | Python | agent.py, tools.py, guardrails.py, requirements.txt, .env.example, README.md | Available |
# Pick your framework
agentspec generate agent.yaml --framework langgraph
agentspec generate agent.yaml --framework crewai
agentspec generate agent.yaml --framework mastra
# Preview without writing files
agentspec generate agent.yaml --framework langgraph --dry-run
# Custom output directory
agentspec generate agent.yaml --framework langgraph --output ./my-agent/
# Override model
export ANTHROPIC_MODEL=claude-sonnet-4-6
agentspec generate agent.yaml --framework langgraphSee the per-framework docs for generated file details:
5. The Skill File
Each framework is a single Markdown file in packages/codegen/src/skills/:
src/skills/
├── langgraph.md # Python LangGraph — complete field mapping guide
├── crewai.md # Python CrewAI — crew.py, tools.py, guardrails.py
├── mastra.md # TypeScript Mastra — src/agent.ts, src/tools.ts
├── helm.md # Helm chart generation
└── scan.md # Source code scanning (used by agentspec scan)Adding a new framework means writing one .md file — not a new TypeScript package. The file describes:
- Output format — the exact JSON shape the LLM must return
- File map — which files to generate and under what conditions
- Manifest-to-code mappings — tables mapping
agent.yamlfields to framework-specific code patterns - Reference syntax resolution — how to handle
$env:,$secret:,$file:,$func:in the generated code - Quality checklist — invariants the LLM must verify before returning output
Add a new framework
# 1. Create the skill
touch packages/codegen/src/skills/autogen.md
# 2. Rebuild to copy it to dist/
pnpm --filter @agentspec/codegen build
# 3. Use it immediately
agentspec generate agent.yaml --framework autogenSee packages/codegen/src/skills/langgraph.md for a comprehensive reference implementation.
6. The GeneratedAgent Output
All generation returns the same GeneratedAgent shape from @agentspec/sdk:
interface GeneratedAgent {
framework: string // which framework produced this
files: Record<string, string> // filename → file contents
installCommands: string[] // ordered setup commands
envVars: string[] // env vars the generated code requires
readme: string // README contents
}files is a flat map. Keys are output filenames and values are complete file contents. The CLI writes each key/value pair to --output <dir>.
7. Programmatic Usage
Use @agentspec/codegen directly from TypeScript:
import { generateCode, resolveProvider } from '@agentspec/codegen'
import { loadManifest } from '@agentspec/sdk'
const { manifest } = loadManifest('./agent.yaml')
const provider = resolveProvider() // auto-detect
const result = await generateCode(manifest, {
framework: 'langgraph',
provider,
onChunk: (chunk) => {
if (chunk.type === 'delta') {
process.stdout.write(chunk.text) // stream progress
}
},
})
console.log(Object.keys(result.files)) // ['agent.py', 'tools.py', ...]Custom provider
import { AnthropicApiProvider } from '@agentspec/codegen'
const provider = new AnthropicApiProvider(
process.env.ANTHROPIC_API_KEY!,
process.env.ANTHROPIC_BASE_URL, // optional proxy
)
const result = await generateCode(manifest, {
framework: 'crewai',
provider,
})8. Static Adapters (SDK)
The FrameworkAdapter interface in @agentspec/sdk is available for deterministic, offline adapters:
import { registerAdapter, type FrameworkAdapter } from '@agentspec/sdk'
const myAdapter: FrameworkAdapter = {
framework: 'my-framework',
version: '0.1.0',
generate(manifest) {
return {
framework: 'my-framework',
files: { 'agent.py': generateAgentPy(manifest) },
installCommands: ['pip install -r requirements.txt'],
envVars: manifest.spec.requires?.envVars ?? [],
readme: '...',
}
},
}
registerAdapter(myAdapter)Static adapters are useful for:
- Deterministic output (no API call, no token cost)
- Offline environments
- Narrow/well-defined manifest subsets
9. Field Mapping Reference
Every manifest field maps to a concept in generated code. Exact class names vary by framework; skill files contain the full per-framework tables.
agent.yaml field | Generated code concept |
|---|---|
spec.model.provider + spec.model.id | LLM client instantiation |
spec.model.apiKey | os.environ.get("VAR_NAME") — never embedded as a literal |
spec.model.parameters.temperature | LLM temperature setting |
spec.model.parameters.maxTokens | LLM max tokens |
spec.model.fallback | Fallback LLM chain |
spec.prompts.system ($file:) | System prompt loaded from file at runtime |
spec.prompts.variables[] | Prompt template variable injection |
spec.tools[] | Tool functions bound to the LLM |
spec.memory.shortTerm.backend | Memory / checkpointer backend |
spec.guardrails.input[] | Input validation middleware |
spec.guardrails.output[] | Output validation middleware |
spec.observability.tracing.backend | Tracing / callback setup |
spec.evaluation.* | Eval harness generation |
spec.api.* | FastAPI / HTTP server generation |
spec.requires.envVars[] | Startup env var validation |
spec.subagents[] | Sub-agent invocation stubs |
Reference prefix resolution
| Manifest value | Generated code |
|---|---|
$env:GROQ_API_KEY | os.environ.get("GROQ_API_KEY") |
$secret:my-key | os.environ.get("AGENTSPEC_SECRET_MY_KEY") |
$file:prompts/system.md | Open the file at runtime |
$func:now_iso | datetime.utcnow().isoformat() |
See also
- Provider Authentication — subscription vs API key, CI setup, overrides
- LangGraph adapter — generated files and manifest mapping
- CrewAI adapter — generated files and manifest mapping
- Mastra adapter — generated files and manifest mapping
- The agent.yaml manifest — manifest structure and reference syntax
- agentspec generate CLI reference