Add PACE to an Existing Project
This tutorial walks you through adding PACE to a repository that already has production code. Unlike the Quickstart, which assumes a mostly greenfield setup, this path is for teams that want to run PACE sprints on top of existing work.
What makes an existing project different?
When you initialise PACE on an existing codebase, two things are different from a greenfield start:
-
SCRIBE already has material to work with. Your existing source files, README, CI workflows, and architecture docs give SCRIBE real facts to write into
engineering.md,security.md, anddevops.md. The context documents it produces will be specific and accurate from Day 1, rather than mostly stubs. -
Your sprint plan targets features, not foundations.
plan.yamlshould describe work that builds on top of what already exists — new endpoints, extended functionality, refactored modules — not setting up project infrastructure that is already in place.
Step 1: Install PACE
Copy the pace/ directory and .github/workflows/pace.yml into your repository root. This is identical to the Quickstart:
cp -r pace-framework-starter/pace ./pacecp -r pace-framework-starter/.github ./.githubcp -r pace-framework-starter/.pace ./.paceDo not replace your existing src/, tests, CI workflows, or any application code.
Step 2: Configure pace.config.yaml
Open pace/pace.config.yaml and fill in the fields that describe your existing project:
product: name: "Payments API" description: > A REST API for processing card payments. Handles authorisation, capture, refunds, and webhook delivery. Python 3.12 / FastAPI. github_org: "my-org"
sprint: duration_days: 30
source: dirs: # List the directories FORGE is allowed to write into. # For an existing project, include only the directories you want PACE to modify. - name: "api" path: "src/api/" language: "Python" description: "FastAPI route handlers and middleware" - name: "services" path: "src/services/" language: "Python" description: "Business logic and external integrations"
# Optional: point SCRIBE to an external documentation folder. # Useful if your team maintains architecture docs, ADRs, or product specs # outside the code repository (e.g. a separate docs repo or wiki export). # docs_dir: "../my-product-docs" docs_dir: null
tech: primary_language: "Python 3.12" ci_system: "GitHub Actions" test_command: "pytest -v --tb=short" build_command: null
platform: ci: github
llm: provider: anthropic model: claude-sonnet-4-6Step 3: Point SCRIBE to your existing docs (optional)
If your team maintains product, architecture, or security documentation outside the code repo (a separate docs/ repo, a Notion export, an ADR folder), set docs_dir in pace.config.yaml:
source: docs_dir: "../my-product-docs"SCRIBE will read from both the code repo and this folder when generating context documents. It specifically looks for files named:
| Document | What SCRIBE looks for in docs_dir |
|---|---|
product.md | Files with mvp, vision, persona, roadmap, strategy in the name |
engineering.md | Files with architecture, tech_stack, api, contracts, adr |
security.md | Files with security, threat, stride, compliance, audit |
devops.md | Files with ci, deployment, devops, runbook, onboarding |
The path can be relative (resolved from the repository root’s parent) or absolute.
Step 4: Run SCRIBE to generate context documents
SCRIBE runs automatically the first time the orchestrator runs (Day 1), but you can also trigger it manually before your first sprint to review what it produces:
cd pacepython -c "from agents.scribe import run_scribe; run_scribe()"Review the four files SCRIBE writes to .pace/context/:
.pace/context/ product.md ← vision, personas, MVP scope, success metrics engineering.md ← module map, tech stack, architecture, test patterns security.md ← sensitive data inventory, threat model, security requirements devops.md ← CI/CD topology, env vars, deployment, runbookRead each file. If SCRIBE missed something important (a subtle security invariant, a non-obvious deployment step, a data-privacy constraint), edit the file directly. These are living documents — you own them and can edit them at any time. To regenerate a specific document from scratch, delete it and re-run the orchestrator.
Step 5: Write plan.yaml for your existing codebase
plan.yaml targets work that extends your existing system. Write stories that assume the current code is already there:
release: "sprint-4"
stories: - id: story-1 title: "Idempotency key support on POST /authorise" status: pending acceptance_criteria: - "POST /authorise accepts X-Idempotency-Key header" - "Duplicate requests with same key return cached response within 24h TTL" - "Keys are stored in Redis with configurable TTL" - "pytest exits 0"
- id: story-2 title: "Rate limiting on POST /authorise" status: pending acceptance_criteria: - "POST /authorise enforces 100 req/min per API key via slowapi" - "Exceeding limit returns 429 with Retry-After header" - "pytest exits 0"
- id: story-3 title: "Webhook retry queue with exponential backoff" status: pending acceptance_criteria: - "Failed webhook deliveries retry up to 5 times with exponential backoff" - "Exhausted retries move webhook to dead-letter queue" - "pytest exits 0"
- id: story-4 title: "Advisory clearance" status: pending human_gate: true acceptance_criteria: - "All open SENTINEL advisories resolved or escalated with justification" - "All open CONDUIT advisories resolved or escalated with justification"
- id: story-5 title: "Partial-capture refund support" status: pending acceptance_criteria: - "POST /refund accepts amount less than or equal to captured amount" - "Partial refund updates payment record with remaining capturable balance" - "pytest exits 0"Note that story-1 says “add idempotency key support to POST /authorise” — it assumes the route already exists. PRIME will read engineering.md to understand where the route lives before generating the story card. FORGE will read it to know which file to modify.
Step 6: Handle your existing CI with CONDUIT
CONDUIT reviews your CI/CD configuration on every day. If your existing CI has patterns it flags (pinned to @master, missing dependency caching, test steps that aren’t pinned), it will raise advisories. On Day 1 this may generate several findings about pre-existing issues.
This is intentional. You can handle them in one of two ways:
- Fix them on Day 1 before running PACE — run through your CI config and address any obvious pinning or configuration issues first.
- Let them accumulate to the first clearance day — CONDUIT advisories are non-blocking. They’ll appear in the advisory backlog and must be cleared on the clearance day (every 7th day by default, or any day you mark in
plan.yaml).
Step 7: Run Day 1
Set the required environment variables and trigger the workflow:
# LocallyPACE_DAY=1 ANTHROPIC_API_KEY=your-key python pace/orchestrator.py
# Or push to main to trigger .github/workflows/pace.yml# (set ANTHROPIC_API_KEY in repository secrets)On Day 1, the orchestrator will:
- Preflight: check for context documents. Since this is Day 1, SCRIBE runs (unless you already ran it manually in Step 4).
- PRIME: read
product.mdand the sprint plan to generate a story card for Day 1’s target. - FORGE: read
engineering.mdto understand the module map, then implement the story using a tool-calling loop. - GATE: run your existing test suite (
tech.test_command) and evaluate each acceptance criterion. - SENTINEL: review the implementation against
security.md. - CONDUIT: review CI configuration against
devops.md.
Regenerating context documents mid-sprint
You can force SCRIBE to regenerate any context document at any time:
# Regenerate engineering.md after a significant refactorrm .pace/context/engineering.mdPACE_DAY=<next-day> python pace/orchestrator.py# SCRIBE runs automatically during preflightOr regenerate all four documents:
rm .pace/context/*.mdpython -c "from agents.scribe import run_scribe; run_scribe()"Regenerating context does not reset the sprint or advisory backlog — only the context documents are affected.
Common issues on existing projects
FORGE modifies the wrong files. Tighten source.dirs in pace.config.yaml to restrict FORGE’s working directory to only the areas you want it to touch.
GATE fails because the test suite is slow or requires services. Set a focused test_command that runs only the tests relevant to the sprint (e.g. pytest tests/api/ -v --tb=short). Full integration tests that require a running database should be in a separate CI step, not the one GATE evaluates.
SCRIBE generates generic sections for security.md because there are no security docs. Edit .pace/context/security.md manually and add your actual threat model. SENTINEL uses this file to calibrate what it checks.
CONDUIT flags many pre-existing CI issues on Day 1. Either fix them before starting (recommended) or accept that they’ll accumulate as advisories and be force-cleared on your first clearance day.