# How to Start a New Task in the Swarm Forge Dashboard: A Step-by-Step Guide

> Learn how to start a new task in the Swarm Forge dashboard. Follow our easy step-by-step guide to create and manage your tasks efficiently.

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

---

**You can start a new task in the Swarm Forge dashboard by clicking the New Task button in the global toolbar or on any project band, then filling in the task name and description and clicking OK.**

The Swarm Forge dashboard provides two entry points for creating tasks, depending on whether you want to associate the task with a specific project upfront. All interaction logic is implemented in [`swarmforge/scripts/pack/dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html), a single-file HTML/JS application that handles the entire workflow from button click to API submission.

## Two Ways to Open the New Task Dialog

The dashboard exposes **New Task** buttons in two distinct locations, as defined in the source code:

- **Global toolbar button** (`#btn-new-task`) — creates a task without pre-selecting a project
- **Project band button** (`.btn-primary.btn-sm`) — creates a task automatically scoped to that project

Both buttons trigger the same `openNewTask()` function, but the project band variant passes the project name as an argument.

### Opening from the Toolbar

The toolbar button is defined at [line 48](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html#L48) of [`dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/dashboard.html). Clicking it invokes `openNewTask()` with no arguments:

```javascript
document.getElementById('btn-new-task').click();   // opens the "New Task" dialog

```

This presents a blank form where you manually specify the project affiliation or leave it unassigned.

### Opening from a Project Band

Each project rendered on the dashboard receives its own **New Task** button. The `projectBand()` function creates this button at [line 44](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html#L44):

```javascript
function projectBand(proj) {
  // ...
  const nt = document.createElement('button');
  nt.className = 'btn btn-primary btn-sm';
  nt.textContent = 'New Task';
  nt.onclick = () => openNewTask(proj.name);   // dialog pre-scoped to project
  // ...
}

```

Clicking this sets the `taskProject` variable internally, so the submitted task automatically links to `proj.name`.

## The New Task Dialog and Form Fields

The dialog markup occupies [lines 31-44](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html#L31-L44) of [`dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/dashboard.html). It collects two required fields:

| Field | Purpose | Input Element |
|-------|---------|---------------|
| **Name** | Short task title | `input#nt-name` |
| **Task** | Detailed description | `textarea#nt-text` |

The `openNewTask(project?)` function at [line 25](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html#L25) displays this dialog and stores the optional project name in closure state:

```javascript
let taskProject = null;   // tracks project context across dialog lifecycle

function openNewTask(project = null) {
  taskProject = project;  // null when opened from toolbar
  $('nt-name').value = '';
  $('nt-text').value = '';
  show('new-task-dialog');
  $('nt-name').focus();
}

```

## Submitting the Task via POST /api/tasks

When you click **OK**, the `submitNewTask()` function at [lines 66-76](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html#L66-L76) serializes the form data and transmits it to the backend:

```javascript
async function submitNewTask() {
  const name = $('nt-name').value.trim();          // task name
  const text = $('nt-text').value;                 // task description
  const payload = { name, text };
  
  if (taskProject) payload.project = taskProject;  // include project if scoped

  const res = await fetch('/api/tasks', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload)
  });

  if (!res.ok) {
    // Error handling omitted for brevity
    return;
  }
  
  // Reset UI state and refresh board
  closeNewTask();
  await loadState();
}

```

On success, the function clears the form, closes the dialog, and invokes `loadState()` to fetch the updated board state. The new task appears as a card in the **Master** lane.

## Backend Routing and API Contract

The frontend's `POST /api/tasks` request reaches the Clojure backend through the routing defined in `swarmforge/scripts/pack_web.bb`. The endpoint expects a JSON payload with:

- `name` (string, required): Task title
- `text` (string, required): Task description
- `project` (string, optional): Project name for automatic association

The server creates the task record, persists it, and returns a success response that triggers the UI refresh.

## Testing the New Task Workflow

The Playwright test suite in [`test/dashboard/dashboard.spec.js`](https://github.com/unclebob/swarm-forge/blob/main/test/dashboard/dashboard.spec.js) validates this functionality:

```javascript
// Verify toolbar button presence
await expect(page.locator(".pack-actions #btn-new-task")).toHaveCount(1);

// Verify task creation flow
await page.locator('#btn-new-task').click();
await page.fill('#nt-name', 'Test Task');
await page.fill('#nt-text', 'Test description');
await page.click('text=OK');
await expect(page.locator('.task-card:has-text("Test Task")')).toBeVisible();

```

These tests confirm both the DOM structure and the end-to-end integration with the backend API.

## Summary

- **Two entry points**: Use the toolbar for unscoped tasks or a project band for pre-associated tasks
- **Two form fields**: Provide a **Name** and **Task** description
- **Single API call**: `POST /api/tasks` with optional `project` field
- **Automatic refresh**: Successful submission updates the **Master** lane via `loadState()`
- **Source location**: All UI logic resides in [`swarmforge/scripts/pack/dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/swarmforge/scripts/pack/dashboard.html)

## Frequently Asked Questions

### Can I create a task without selecting a project first?

Yes. Click the **New Task** button in the global toolbar (`#btn-new-task`). The dialog opens with `taskProject` set to `null`, and you can submit the task without project association. You can later assign it to a project using other dashboard controls.

### What happens if the POST /api/tasks request fails?

The `submitNewTask()` function checks `res.ok` and aborts the UI reset if the server returns an error status. The dialog remains open with your input preserved, allowing you to retry or cancel. Specific error handling logic would depend on additional code not shown in the analyzed source.

### Is the New Task dialog modal or modeless?

The implementation uses a custom dialog shown via `show('new-task-dialog')`. Based on the source structure, this appears to be a modal overlay that blocks interaction with the board until you submit or cancel, though the exact modality depends on the CSS definitions in [`dashboard.html`](https://github.com/unclebob/swarm-forge/blob/main/dashboard.html).

### Where can I find the backend handler for /api/tasks?

The routing is defined in `swarmforge/scripts/pack_web.bb`, which maps `/api/tasks` to Clojure handler functions. The actual task creation logic—database insertion, ID generation, and response formatting—would reside in the corresponding namespace imported by that routing file.