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

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, 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 of dashboard.html. Clicking it invokes openNewTask() with no arguments:

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:

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 of 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 displays this dialog and stores the optional project name in closure state:

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 serializes the form data and transmits it to the backend:

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 validates this functionality:

// 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

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.

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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →