Building an Iterative Dev Feedback Loop

Set up a sustainable rhythm: branch strategy, how to chain tasks, how to refine prompts when the agent misses, and when to break work into subtasks.

Building an Iterative Dev Feedback Loop

What you'll learn

Set up a sustainable working rhythm with Paperclip: branch strategy, chaining tasks, refining prompts when the agent misses, and breaking large features into agent-sized pieces.


The core loop

┌─────────────────────────────────────────────────────────────┐
│                                                             │
│   Write issue  →  Trigger heartbeat  →  Agent works        │
│         ↑                                       ↓          │
│   Refine prompt                          Review diff        │
│   (if reject)                                   ↓          │
│                                          Accept → commit    │
│                                          Reject → discard   │
│                                          Revise → follow-up │
└─────────────────────────────────────────────────────────────┘

Most developers find this loop becomes second nature after 3–5 tasks.


Branch strategy

Keep agent work isolated with a clear branch pattern:

# One branch per feature or ticket
git checkout -b paperclip/add-user-profile-api

# Do all agent tasks for this feature on this branch
# (create issues, trigger heartbeats, commit accepted changes)

# When the feature is done, merge or PR into main
git checkout main
git merge --no-ff paperclip/add-user-profile-api

Using the paperclip/ prefix makes it easy to spot agent branches in your git log.


Chaining tasks — building a feature in steps

For anything bigger than an S task, break it into a chain:

Feature: User profile API with avatar upload

Task 1: Add users table migration (schema only)
        ↓ accept ↓
Task 2: Add GET /api/users/:id profile endpoint
        ↓ accept ↓
Task 3: Add PATCH /api/users/:id update endpoint
        ↓ accept ↓
Task 4: Add POST /api/users/:id/avatar upload endpoint
        ↓ accept ↓
Task 5: Add integration tests covering all four endpoints

Create Task 2 only after Task 1 is accepted and committed — the agent for Task 2 will read the migration file that Task 1 created.

# After accepting and committing Task 1:
git diff HEAD~1 --stat
# db/migrations/0005_add_users.ts    +45

# Now create Task 2 with context about what Task 1 added
curl -X POST $BASE/companies/$COMPANY_ID/issues \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Add GET /api/users/:id profile endpoint",
    "description": "## Context\nMigration `db/migrations/0005_add_users.ts` was just added with a `users` table containing: id, name, email, avatar_url, created_at.\n\n## Task\nAdd the profile endpoint...",
    ...
  }'

Refining prompts when the agent misses

When an agent produces the wrong result, resist the urge to just retry the same prompt. Diagnose first:

Symptom Root cause Fix
Agent used a different pattern to the rest of the code No example provided Add "See src/routes/orders.ts for the pattern to follow"
Agent modified files outside scope Scope was implicit Add explicit "Do not change" section
Agent created the right code but in the wrong file File path not specified Give exact file paths
Agent wrote tests but they don't run Test runner not mentioned Add "Run npm test to verify" to acceptance criteria
Agent solution is correct but uses a package not in package.json No constraint on packages Add "Do not add new npm packages"

Example improvement:

Before:
"Add input validation to the registration endpoint"

After:
"Add input validation to the POST /api/auth/register endpoint in `src/routes/auth.ts`.
Use the existing `zod` package (already in package.json) — see `src/routes/products.ts`
line 12 for an example of how we use zod validation on this route.
Return 400 with `{ error: 'Invalid input', details: [...] }` on validation failure.
Do not change the success response shape."

Using CLAUDE.md to reduce prompt boilerplate

If you find yourself repeating the same context in every issue ("use Drizzle ORM, not raw SQL", "follow the pattern in src/routes/orders.ts"), move it to CLAUDE.md:

<!-- CLAUDE.md additions -->
## Code standards for Paperclip agents
- Always use Drizzle ORM for database queries — no raw SQL
- Follow the pattern in `src/routes/orders.ts` for new route files
- Every new endpoint needs a test — run `npm test` before finishing
- Do not add new npm packages without checking with the team first
- TypeScript strict mode: no `any`, no non-null assertions without a comment

Once this is in CLAUDE.md, you don't need to repeat it in every issue.


Velocity tips

Work on one task at a time. The heartbeat can process multiple issues in parallel, but for dev tasks you want to review and commit each one before the next agent run reads the updated codebase.

# After committing Task 1:
curl -X POST $BASE/heartbeat/run -d '{"company_id": "'$COMPANY_ID'"}'
# This now picks up Task 2, which can see the files Task 1 created

Use the agent's result as documentation. The structured result text is a natural commit message, PR description, or changelog entry:

# Get the result text
curl -s $BASE/companies/$COMPANY_ID/issues/$ISSUE_ID | \
  python3 -c "import sys,json; print(json.load(sys.stdin)['result'])"

Keep a task backlog. Write 5–10 issues in advance (they'll sit as open). The heartbeat will pick them up in priority order.


Checkpoint ✓

Sign in for progress tracking & Q&A →