# How to Approve a Handoff in the SwarmForge Dashboard: A Complete Guide

> Learn how to approve a handoff in the SwarmForge dashboard using our complete guide. Approve easily via the UI or programmatically with the API.

- Repository: [Robert C. Martin/swarm-forge](https://github.com/unclebob/swarm-forge)
- Tags: how-to-guide
- Published: 2026-08-29

---

**Click the Approve button in Attention → Approvals, or POST to `/api/approvals/<id>/approve` to approve a handoff programmatically.**

SwarmForge is an open-source AI-assisted development framework created by Uncle Bob (Robert C. Martin). Approving handoffs is a core workflow step that moves completed work between team members or AI agents. This guide covers both the dashboard UI and the underlying API implementation in the `unclebob/swarm-forge` repository.

## Locating Pending Handoffs in the Dashboard

Pending handoffs appear in the **Attention → Approvals** section of the SwarmForge UI.

The dashboard structure follows this hierarchy:

- `#attention` — the top-level gray "Attention" box
  - `#attention-approvals` — pending handoffs awaiting your review
  - `#attention-clarifications` — items needing additional information

Each handoff row displays:
- An **"Approval"** pill label
- The project and task identifier
- **Documents** and **Approve** action buttons

## Reviewing Before Approval

Click the **Documents** button on any handoff row to inspect the associated source files. This triggers the `viewDoc` function defined at `pack_web.bb` lines 24–27.

**Critical check:** If the handoff has unresolved remedial comments, the **Approve** button will be disabled. The UI enforces this via `hasRemedialComments` at `pack_web.bb` line 7010. You must resolve all comments before proceeding.

## Approving a Handoff in the UI

The approval button is created by `approvalButton` at `pack_web.bb` lines 8000–8006. When clicked:

1. The handler calls `postApproval(item.id, "approve")` (lines 8484–8486)
2. A POST request fires to the backend
3. `loadState()` refreshes the UI (lines 8485–8487)
4. The handoff disappears from Approvals and moves to the appropriate workflow lane

## Programmatic Approval via REST API

The same endpoint powers automation and CI/CD pipelines.

```bash

# Approve a handoff by ID (replace <ID> with the actual identifier)

curl -X POST http://localhost:8000/api/approvals/<ID>/approve

```

The JavaScript implementation used by the dashboard:

```javascript
// pack_web.bb – lines 8484-8487
async function postApproval(id, action) {
  await fetch("/api/approvals/" + encodeURIComponent(id) + "/" + action, {
    method: "POST"
  });
  loadState();  // Refresh dashboard state
}

```

## Server-Side Approval Implementation

The backend handler resides at `pack_web.bb` lines 1258–1266. It delegates to the `approve!` helper:

```clojure
;; pack_web.bb – lines 1065-1071
(defn approve! [root id]
  (let [src (str (fs/path root ".swarmforge/handoffs/outbox/" id ".handoff"))
        dest (str (fs/path root ".swarmforge/handoffs/outbox/" id ".handoff"))]
    (spit dest (with-approved (slurp src)))))

```

This writes `approved: true` into the handoff file located at `.swarmforge/handoffs/outbox/<id>.handoff`.

## Key Source Files

| Component | Path | Purpose |
|-----------|------|---------|
| Dashboard HTML | [`swarmforge/scripts/pack/dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html) | Renders the Attention → Approvals pane |
| UI Logic | `swarmforge/scripts/pack_web.bb` | Button creation, comment checks, API calls |
| Approval Endpoint | `swarmforge/scripts/pack_web.bb` (lines 1258–1266) | POST handler for `/api/approvals/<id>/approve` |
| Approval Helper | `swarmforge/scripts/pack_web.bb` (lines 1065–1071) | Writes `approved: true` to handoff files |
| Tests | `test/swarmforge/pack_ui_test.clj` (lines 750–765) | Verifies approval flow and UI updates |

## Summary

- **Dashboard path:** Attention → Approvals → click **Approve** button (class `btn-approve`)
- **API endpoint:** `POST /api/approvals/<hand-off-id>/approve`
- **Blocking condition:** Unresolved remedial comments disable the Approve button
- **Backend effect:** Sets `approved: true` in the handoff file at `.swarmforge/handoffs/outbox/`
- **Key files:** `pack_web.bb` for UI and server logic; [`pack/dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/pack/dashboard.html) for structure

## Frequently Asked Questions

### What happens if the Approve button is grayed out?

The **Approve** button is disabled when `hasRemedialComments` returns true (line 7010 in `pack_web.bb`). Open the Documents view, resolve all remedial comments on the handoff, and refresh the dashboard. The button will re-enable automatically.

### Can I approve handoffs without using the dashboard?

Yes. Send a POST request directly to `/api/approvals/<id>/approve` as shown in the curl example above. This is useful for automation, scripted workflows, or integrating SwarmForge with external CI systems.

### Where are approved handoffs stored?

Approved handoffs remain in `.swarmforge/handoffs/outbox/` with `approved: true` written to the file. The dashboard filters them out of the Approvals pane after `loadState()` refreshes, but the files persist for audit trails.

### How do I verify a handoff was actually approved?

Check the handoff file directly: `cat .swarmforge/handoffs/outbox/<id>.handoff | grep approved`. The line `approved: true` confirms approval. Alternatively, refresh the dashboard—the handoff should no longer appear in Attention → Approvals.