Generate runnable AI agent projects from markdown specs in the agent-deployments repo.
Project description
agent-scaffold
agent-scaffold generates runnable AI agent projects from markdown specs. It fetches the agent-deployments catalog at runtime (one URL hardcoded, overridable via --catalog-url) and falls back to an embedded snapshot when offline — pick a recipe, target language, and framework, and the CLI assembles the relevant docs, asks Claude to emit a complete project, validates the response, and writes the files atomically into your destination of choice.
The three-repo ecosystem
This repo is one of three that work together as a single pipeline:
agent-blueprints → agent-deployments → agent-scaffold
(architecture) (specs) (generator)
"how to think" "what to build" "build it for me"
patterns + tradeoffs 9 production-shaped reads spec, asks LLM,
framework-agnostic markdown blueprints writes runnable project
- agent-blueprints — framework-agnostic patterns, tradeoffs, and design guidance. Start here if you want to design before you build.
- agent-deployments — opinionated, production-shaped markdown specs for nine concrete agents (Python + TypeScript tracks).
- agent-scaffold (this repo) — a CLI that consumes a deployment spec, asks Claude to emit a complete project, and writes the files atomically to disk.
Install
The package is published on PyPI as agent-scaffold-cli and installs two equivalent binaries: agent-scaffold (long form) and scaffold (short, claude-style). Bare scaffold (no subcommand) drops you straight into the interactive REPL; everything else (scaffold new, scaffold doctor, scaffold --help, …) mirrors the agent-scaffold subcommands.
One-line install (recommended). Installs the CLI, adds it to your PATH, and offers to store your Anthropic key — the way claude's installer works:
curl -fsSL https://raw.githubusercontent.com/jagguvarma15/agent-scaffold/main/install.sh | sh
Or install manually. A plain pip install can't put the binaries on your PATH (wheels run no code at install time), so use pipx/uv tool and run their one-time PATH step:
pipx install agent-scaffold-cli && pipx ensurepath
# or
uv tool install agent-scaffold-cli && uv tool update-shell
# or, for one-off use (no install, no PATH change):
uvx --from agent-scaffold-cli scaffold --help
Either way, restart your shell afterward, then store your Anthropic key once with scaffold auth login (the one-line installer prompts for it during setup). scaffold won't start without a key.
Local development
git clone https://github.com/jagguvarma15/agent-scaffold
cd agent-scaffold
uv sync
make install-dev # exposes `scaffold` + `agent-scaffold` on PATH (editable)
Quickstart
export ANTHROPIC_API_KEY=sk-ant-...
agent-scaffold scaffold # interactive shell — recommended
# or, one-shot:
agent-scaffold new
One command to a running stack
By default, agent-scaffold new (interactive) chains into the full lifecycle: generation → up (install deps, start docker, run migrations, seed data, launch the frontend dev server) → welcome panel → open the frontend in your browser. The screencast looks like:
$ agent-scaffold new
... (generation)
✓ Files written: 46
✓ Validation passed (static)
─── Provisioning ─────────────────────────────────────
→ install_deps ✓ done
→ docker_up ✓ 5 services up + healthy
→ wire_credentials ✓ all keys resolved
→ migrations ✓ alembic upgrade head
→ seed ✓ 50 restaurants, 80 reservations
→ emit_deploy_configs ✓ vercel.json written
→ launch_frontend ✓ http://localhost:3000
╭── Ready — local URLs ──────────────────╮
│ Frontend: http://localhost:3000 │
│ Backend: http://localhost:8000 │
│ Grafana: http://localhost:3002 │
│ ... │
╰────────────────────────────────────────╯
Opening http://localhost:3000 in your browser…
Escape hatches when you want the staged-by-hand flow instead:
--no-autorun— generate only, then print the legacy "Next steps" hints.--no-open-browser— autorun completes but doesn't launch a browser tab.--non-interactive(the CI shape) — autorun is implicitly off so generation-only CI scripts keep their one-shot behavior.
In the REPL, the same default applies: /generate runs the full chain. Toggle with /autorun off (per session) for the staged flow.
Interactive shell
agent-scaffold scaffold opens a persistent REPL. Make selections with
slash commands, refine the plan with free text, see the cost estimate,
generate when you're ready, then start the next project — all without
re-launching the CLI.
scaffold › /recipe restaurant-rebooking
scaffold › /language python
scaffold › /framework langgraph
scaffold › /name demo
scaffold › /plan
[renders the generation plan with token + cost estimate]
scaffold › swap to sonnet and skip the smoke test
✓ applied refinement
Δ model: claude-opus-4-7 → claude-sonnet-4-6
Δ steps: -smoke_test
scaffold › /generate
[runs the generation pipeline]
scaffold › /exit
Type /help inside the shell for the full command list. Free-text
input ("use Sonnet, add Redis") is interpreted by a tiny Haiku call
(~$0.002) into a typed patch over the plan. Run /help refine for the
full list of accepted refinement keys.
By default, the CLI auto-fetches the latest main commit from
agent-deployments and
agent-blueprints,
caches each by commit SHA under ~/.cache/agent-scaffold/, and rewrites
blueprint URLs in deployments docs so the LLM actually reads the
canonical pattern content. Offline fallback chain: cached catalog at
~/.cache/agent-scaffold/catalog/ → embedded _embedded_catalog.json
shipped in the wheel. Blueprint links are silently skipped when the
blueprints repo can't be fetched.
To use a local checkout instead (typical for repo development):
export AGENT_SCAFFOLD_DEPLOYMENTS_PATH=/path/to/agent-deployments
export AGENT_SCAFFOLD_BLUEPRINTS_PATH=/path/to/agent-blueprints
agent-scaffold new
# or per-invocation:
agent-scaffold new --deployments-path . --blueprints-path ../agent-blueprints
The interactive new flow walks you through:
- A recipe from
docs/recipes/*.md. - A target language (Python or TypeScript).
- A framework (e.g.
pydantic_ai,langgraph,vercel_ai_sdk, ornone). - A project name and destination directory.
You'll see the resolved source labels, a context summary, a generation step, a static validation pass, and a "next steps" footer with the smoke-check command.
Configuration
| Source | Variable / key | Purpose |
|---|---|---|
| Env | ANTHROPIC_API_KEY |
Required. The Anthropic API key used by the generator. |
| Env | AGENT_SCAFFOLD_DEPLOYMENTS_PATH |
Local-checkout override for agent-deployments (defaults to auto-fetch from GitHub). |
| Env | AGENT_SCAFFOLD_BLUEPRINTS_PATH |
Local-checkout override for agent-blueprints (defaults to auto-fetch from GitHub). |
| Env | AGENT_SCAFFOLD_DEPLOYMENTS_SOURCE |
auto only (default). bundled mode was removed in v0.3 — the catalog + on-disk fetch cache replaces it. |
| Env | AGENT_SCAFFOLD_BLUEPRINTS_SOURCE |
auto (default) or skip (no fetch; drop blueprint URLs from context). |
| Env | AGENT_SCAFFOLD_CATALOG_URL |
Override the catalog URL. Default: raw.githubusercontent.com/jagguvarma15/agent-deployments/main/catalog.yaml. |
| Env | AGENT_SCAFFOLD_MODEL |
Override the model (default claude-opus-4-7). |
| Env | AGENT_SCAFFOLD_THINKING_BUDGET |
Extended-thinking token budget. Omit to disable. |
| Env | AGENT_SCAFFOLD_EFFORT |
Default effort preset (low / medium / high). |
| Env | AGENT_SCAFFOLD_CACHE_DIR |
Override the cache root (default ~/.cache/agent-scaffold). |
| Env | AGENT_SCAFFOLD_CONFIG_PATH |
Override the TOML fallback location. |
| TOML | ~/.config/agent-scaffold/config.toml |
Fallback for deployments_path, model, and thinking_budget. |
Run agent-scaffold config (or scaffold config) to print the resolved configuration (the API key is masked).
A typical config file:
deployments_path = "/Users/me/code/agent-deployments"
model = "claude-opus-4-7"
Generation effort
--effort picks a preset bundle of model + token budget + extended-thinking budget + prompt strictness:
| Effort | Model | max_tokens | Thinking | Strict prompt |
|---|---|---|---|---|
| low | Haiku 4.5 | 16,000 | off | no |
| medium | Sonnet 4.6 | 32,000 | 8,000 | no |
| high | Opus 4.7 | 64,000 | 16,000 | yes |
Explicit --model, --max-tokens, --thinking, and --strict override preset values. Precedence: preset → explicit flag → env / TOML.
Strict mode (--strict or --effort high) loads system_strict.md, which instructs the LLM to emit Docker / docker-compose / GitHub Actions / structured-logging / three-tier tests when the spec references those components.
Where docs come from
The CLI resolves two sources before assembling the LLM context:
- agent-deployments — recipes + cross-cutting / framework / pattern / stack docs.
- agent-blueprints — canonical pattern overviews referenced by deployments docs.
Resolution order for each repo (highest priority first):
--deployments-path/--blueprints-pathflag onagent-scaffold new.AGENT_SCAFFOLD_DEPLOYMENTS_PATH/AGENT_SCAFFOLD_BLUEPRINTS_PATHenv var.deployments_path/blueprints_pathin~/.config/agent-scaffold/config.toml.- Auto-fetch from GitHub (default) — pulls the latest
maincommit, caches by SHA under~/.cache/agent-scaffold/{deployments,blueprints}/<sha>/. Uses ETag-conditional GET so unchanged refs don't consume rate-limit quota. - Offline fallback — catalog falls through cached → embedded JSON (frozen at wheel-build time). Blueprints is skipped with a warning (blueprint URLs in deployments docs drop out of context).
Override the auto-fetch behavior per-invocation:
# Skip network for blueprints (deployments still fetches; the cache or
# embedded catalog serves offline runs after the first fetch).
agent-scaffold new --blueprints-source skip
# Use my local fork of deployments, auto-fetch blueprints.
agent-scaffold new --deployments-path ~/code/my-deployments
Recipe frontmatter
Recipes are markdown files with optional YAML frontmatter:
---
status: blueprint
languages: [python, typescript]
required_files:
- Dockerfile
- docker-compose.yml
- .github/workflows/ci.yml
---
status— free-form label shown in the recipe picker (e.g.validated,blueprint).languages— supported target languages; intersected with the available language hints.required_files— additional paths that the generated project MUST contain. These are enforced by the contract validator on top of the built-in four (manifest, entry point,README.md,.env.example). Paths follow the same safety rules as generated files (relative, no.., no leading/); unsafe entries are warned about and dropped during discovery.
recipe_dependencies (optional)
Per-language extra dependencies the recipe needs. Merged into pinned_dependencies from the language hints before being shown to the LLM. Use when a recipe references infrastructure clients (Redis, Postgres drivers), observability (structlog, langfuse), or framework adjuncts not in the default language profile.
---
recipe_dependencies:
python:
redis: ">=5.0.0"
structlog: ">=24.1.0"
typescript:
ioredis: "^5.4.0"
pino: "^9.0.0"
---
Recipe-declared versions win over language-default versions on conflict. Malformed entries (non-mapping shape) are warned about and ignored during discovery.
external_services (optional)
The infrastructure the recipe depends on. agent-scaffold doctor --recipe <slug> probes each entry; agent-scaffold new --plan renders a per-service ✓/✗ readiness row before the LLM call.
---
external_services:
- id: anthropic
env_vars: [ANTHROPIC_API_KEY]
probe: anthropic_list_models
explain: anthropic
- id: redis
required: true
env_vars: [REDIS_URL]
default_local: redis://localhost:6379
docker_service: redis
probe: redis_ping
explain: redis
- id: langfuse
required: false
env_vars: [LANGFUSE_HOST]
probe: langfuse_health
explain: langfuse
---
Per-entry fields:
| Field | Default | Meaning |
|---|---|---|
id |
— | Short stable slug (anthropic, redis, postgres, ...). Required. |
required |
true |
Whether the service must be present for the recipe to work. |
env_vars |
[] |
Env vars that may carry the connection URL / credentials, in priority order. |
default_local |
none | Used when no env_vars entry is set. |
docker_service |
none | Name of the matching service in a bundled docker-compose.yml (consumed by the upcoming up orchestrator). |
probe |
none | Registered probe name. See the table below. |
migrations |
none | Migration tool (alembic, prisma, ...). |
explain |
none | Slug under docs/getting-started/<slug>.md for --explain. |
mock_available |
false |
A fallback mock adapter exists if the real service is unreachable. |
Bundled probes:
probe value |
What it does | Address from |
|---|---|---|
anthropic_list_models |
models.list(limit=1) via the resolved key |
auth resolution (env → keyring → file) |
redis_ping |
Raw-socket Redis PING/PONG |
first env var, else default_local |
postgres_select_one |
psycopg.connect(...).cursor().execute("SELECT 1") (TCP-only fallback if psycopg not installed) |
first env var, else default_local |
langfuse_health |
GET {host}/api/public/health |
first env var, else default_local |
kafka_metadata |
TCP connect + kafka-python metadata (TCP-only fallback if not installed) |
first env var, else default_local |
Unknown probe names log a warning and produce a SKIP at runtime instead of crashing the audit.
Adding a new target language
Drop a YAML file into src/agent_scaffold/languages/ modeled after python.yaml or typescript.yaml. Required keys:
language,package_manager,project_layout,entry_point,manifestrequired_tools(formatter / type_checker / test)pinned_dependencies,framework_dependenciesforbidden,smoke_check
The CLI reads them on demand; no code changes needed unless you also want a language-specific static-validation tier (see src/agent_scaffold/validator.py).
Troubleshooting
Contract parse failures
If Claude returns malformed JSON, agent-scaffold:
- Saves the raw response to
~/.cache/agent-scaffold/failures/<timestamp>.json. - Prints a warning and asks Claude to repair the response.
- If the repair still fails, saves that raw response too and aborts with file pointers.
You can re-run agent-scaffold new with AGENT_SCAFFOLD_CACHE_DIR set to inspect failures elsewhere.
--write-mode choices
| Mode | Behavior |
|---|---|
abort (default) |
Refuse to write into a non-empty destination. |
skip |
Keep existing files, write only new ones. |
diff |
Show a unified diff per file and prompt before overwriting. |
overwrite |
Replace everything. |
All writes stage to a sibling temp directory and os.replace into place, so a failure mid-generation leaves the destination untouched.
Re-running validation
agent-scaffold validate /path/to/generated --tier static|build|smoke reruns one of the post-generation tiers without re-invoking the LLM.
CLI commands
| Command | Purpose |
|---|---|
agent-scaffold new |
Interactive project generator. |
agent-scaffold up [project_dir] |
Provision a generated project: install deps, start docker services, prompt for missing API keys, run alembic migrations, seed dev data, run smoke tests, launch the frontend dev server in the background, and (opt-in) commit/push + open $EDITOR. Ends with a welcome panel listing every live local URL. --plan to preview, --yes for CI, --resume / --retry / --skip / --force / --only for re-runs, --yes --confirm-commit-push to fully automate the opt-in commit step. |
agent-scaffold update [project_dir] |
Re-run the recipe and 3-way-merge template changes against your edits. Copier-style: snapshots the generated tree on new, uses it as the merge base, writes <<<<<<< user / ======= / >>>>>>> template markers on conflicts. --dry-run previews the plan, --continue finalises after manual resolution. |
agent-scaffold down --cwd <project> |
Stop the local stack: kills the frontend dev server (SIGTERM the process group), then docker compose down. -v also removes named volumes (destroys local Postgres / Qdrant / Redis state — requires confirmation). |
agent-scaffold logs <service> --cwd <project> |
Tail container logs. The reserved name frontend tails the dev server's log file at .scaffold/frontend.log instead of going through docker. -f/--no-follow, --tail N. |
agent-scaffold eval --cwd <project> |
Run the project's eval suite via the matching eval.* capability's plugin (default: Promptfoo via npx). Exits 1 if the total score drops below the baseline (stored in manifest.answers["eval_baseline"] by the bootstrap_evals step during up). --update-baseline persists the new total and exits 0. --json for machine-readable output. Recipes without an eval.* capability exit 0 with a friendly note. |
agent-scaffold regenerate <project> <file> |
Re-prompt the model for a single file in an existing project. |
agent-scaffold validate <project> --tier ... |
Re-run a post-generation validation tier. |
agent-scaffold doctor |
Read-only audit of local tools (python, uv, docker, ruff). --recipe <slug> adds Authentication + per-external_services rows. --no-probes skips network probes. --timeout N (1–30s) caps each probe. --json for machine-readable output. --explain <topic> opens the matching getting-started doc. |
agent-scaffold auth login |
Capture an Anthropic key (browser or paste), validate it via models.list(), and store it. |
agent-scaffold auth status |
Show the active credential backend, stored credentials (masked), and the resolution order. --json for machine-readable output. |
agent-scaffold auth logout |
Remove a stored credential from every backend it lives in (--all to wipe everything). |
agent-scaffold auth setup-token <name> |
Store a long-lived CI token in the mode-0600 file backend (--stdin for piped input). |
agent-scaffold secrets list |
Inventory every credential the CLI knows about, masked. --json for machine output. |
agent-scaffold secrets purge |
Survey + wipe every stored credential (keyring + file + ./.env.local). --yes for CI; --keep-env-local to preserve project secrets. |
agent-scaffold config |
Print the resolved configuration. |
Step orchestrator
Provisioning verbs (up, update) plug into a state-tracked step framework: each step has a detect() (read-only) and an apply() (idempotent), with progress recorded in <project>/.scaffold/state.json. From that one design, the flag set --only / --skip / --force / --retry / --resume and --plan-before-build all fall out naturally.
See docs/design/orchestrator.md for the contract, state-file shape, decision table, and the anti-patterns to avoid when authoring new steps.
Credentials
agent-scaffold resolves the Anthropic API key in this order:
ANTHROPIC_API_KEYenvironment variablepython-keyring(macOS Keychain / Windows Credential Manager / Linux Secret Service / KDE Wallet)- INI file at
$XDG_CONFIG_HOME/agent-scaffold/credentials(mode0600)
The plaintext keyring backend is refused: if keyring.get_keyring() reports PlaintextKeyring (or any non-OS-native backend), auth login falls back to the mode-0600 file backend with a warning. Pass --use-file or --use-env to override the default.
agent-scaffold auth login # browser flow
agent-scaffold auth login --no-browser # paste flow (headless / SSH)
agent-scaffold auth status # show what's stored where
agent-scaffold auth logout --all # nuke every stored credential
echo "$TOKEN" | agent-scaffold auth setup-token ci-prod --stdin
# Cross-backend revocation (keyring + file + ./.env.local in one go)
agent-scaffold secrets list
agent-scaffold secrets purge --yes
Security model
The CLI follows a nine-point hardening checklist for secret handling:
no secrets in argv, getpass instead of input, SecretStr typing,
shell=False, mode-0600 credential files, plaintext-keyring refusal,
output redaction, enforced .gitignore, and first-class revocation via
secrets purge. Each rule is locked in by an audit test under
tests/security/ so regressions block CI.
See docs/design/security.md for the full
rationale and per-rule references.
License
MIT (see LICENSE).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file agent_scaffold_cli-0.3.556a1.tar.gz.
File metadata
- Download URL: agent_scaffold_cli-0.3.556a1.tar.gz
- Upload date:
- Size: 694.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c2346191eecc2dfbf7c8fac8e3bfe600875915623071914b5418d922ac3f5ead
|
|
| MD5 |
52d40b1894bed3f7cd89c51471cb7f6f
|
|
| BLAKE2b-256 |
7671984588a64d451a7af6f982ba6c428b15c268bd568e30df910d27ef555765
|
Provenance
The following attestation bundles were made for agent_scaffold_cli-0.3.556a1.tar.gz:
Publisher:
publish.yml on jagguvarma15/agent-scaffold
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_scaffold_cli-0.3.556a1.tar.gz -
Subject digest:
c2346191eecc2dfbf7c8fac8e3bfe600875915623071914b5418d922ac3f5ead - Sigstore transparency entry: 1908360209
- Sigstore integration time:
-
Permalink:
jagguvarma15/agent-scaffold@2562fe0f67145b9b8b1a9051ae327713dd57384e -
Branch / Tag:
refs/tags/v0.3.556a1 - Owner: https://github.com/jagguvarma15
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2562fe0f67145b9b8b1a9051ae327713dd57384e -
Trigger Event:
release
-
Statement type:
File details
Details for the file agent_scaffold_cli-0.3.556a1-py3-none-any.whl.
File metadata
- Download URL: agent_scaffold_cli-0.3.556a1-py3-none-any.whl
- Upload date:
- Size: 405.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1de484d0647e2e83dba39e601ff2c6f4f23a8eee270da63eafc4556843dfb61e
|
|
| MD5 |
02d59a63ac1e057008682fbcde98914b
|
|
| BLAKE2b-256 |
4e75388254710cb97aa5120561ac39ae59af7122af798cbc4f3f19683289da40
|
Provenance
The following attestation bundles were made for agent_scaffold_cli-0.3.556a1-py3-none-any.whl:
Publisher:
publish.yml on jagguvarma15/agent-scaffold
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
agent_scaffold_cli-0.3.556a1-py3-none-any.whl -
Subject digest:
1de484d0647e2e83dba39e601ff2c6f4f23a8eee270da63eafc4556843dfb61e - Sigstore transparency entry: 1908360529
- Sigstore integration time:
-
Permalink:
jagguvarma15/agent-scaffold@2562fe0f67145b9b8b1a9051ae327713dd57384e -
Branch / Tag:
refs/tags/v0.3.556a1 - Owner: https://github.com/jagguvarma15
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2562fe0f67145b9b8b1a9051ae327713dd57384e -
Trigger Event:
release
-
Statement type: