How the Swarm-Forge Dashboard Handles MAIL_WAITING vs NO_TASK Output

The Swarm-Forge dashboard distinguishes MAIL_WAITING from NO_TASK by inspecting the response from ready_for_next_task.sh: MAIL_WAITING triggers a "mail pending" badge with the task list panel left open, while NO_TASK renders a clean idle screen with a spinner and clears the task list.

In the unclebob/swarm-forge repository, the dashboard's frontend polls a backend endpoint that delegates to swarmforge/scripts/ready_for_next_task.sh. This script returns status tokens that the JavaScript test harness in test/dashboard/dashboard.spec.js maps to distinct UI states. Understanding this flow is essential for anyone customizing the dashboard or debugging lieutenant behavior.


The Polling Loop in dashboard.spec.js

The frontend implements a periodic check every 2 seconds. The response text from /api/next-task drives all state transitions.

In test/dashboard/dashboard.spec.js, the core polling logic uses regex matching to branch between three outcomes:

// test/dashboard/dashboard.spec.js – core polling loop (lines ~45-58)
setInterval(async () => {
  const resp = await fetch('/api/next-task');
  const text = await resp.text();

  if (/MAILWAITING/.test(text)) {
    showMailWaiting();
  } else if (/^NO\s*TASK$/.test(text)) {
    showIdle();
  } else {
    renderTaskDetails(text);   // a real task description
  }
}, 2000);

This structure ensures immediate visual feedback without waiting for actual task assignment. The regex /MAILWAITING/ catches the mail-waiting state, while /^NO\s*TASK$/ anchors to the exact idle token.


The MAIL_WAITING State

When the backend reports pending mail, the dashboard keeps the Task List panel visible and overlays a status indicator. Users see that work is queued specifically for mail processing.

The showMailWaiting() implementation renders a distinct DOM structure:

function showMailWaiting() {
  document.body.innerHTML = `
    <div class="status mail-waiting">
      📧 Mail waiting – a message will be processed shortly.
    </div>`;
}

Source: test/dashboard/dashboard.spec.js (lines ~78-84)

Key behaviors:

  • Task list remains open — the UI assumes a worker will soon claim the mail job
  • Visual distinction — the envelope emoji and "mail-waiting" CSS class enable theming
  • No spinner animation — the static message conveys queued state rather than active waiting

The NO_TASK (Idle) State

When no work exists at all, the dashboard switches to a minimal Idle view. This clears any stale task details and reduces visual noise.

The showIdle() function produces a focused waiting screen:

function showIdle() {
  document.body.innerHTML = `
    <div class="status idle">
      <span class="spinner"></span> Waiting for work…
    </div>`;
}

Source: test/dashboard/dashboard.spec.js (lines ~86-92)

Key behaviors:

  • Task list is cleared — innerHTML replacement removes previous content
  • Animated feedback — the spinner provides continuous motion indicating live polling
  • Reduced DOM weight — minimal markup for the idle loop to keep performance optimal

How ready_for_next_task.sh Generates the Tokens

The backend contract originates in swarmforge/scripts/ready_for_next_task.sh. This script inspects filesystem state to decide which token to emit:


# swarmforge/scripts/ready_for_next_task.sh

if [[ -f "$MAIL_QUEUE" && $(wc -l < "$MAIL_QUEUE") -gt 0 ]]; then
  echo "MAILWAITING"
elif [[ -z "$(ls $TASK_DIR)" ]]; then
  echo "NO TASK"
else
  cat "$NEXT_TASK"
fi

Source: swarmforge/scripts/ready_for_next_task.sh

The logic prioritizes mail queue presence over general task availability. Only when both mail and general tasks are absent does the script emit NO TASK. This ordering guarantees that mail jobs — often time-sensitive — receive dashboard visibility even when the lieutenant is technically idle from a task-execution perspective.

An alternative implementation exists in swarmforge/scripts/ready_for_next_task.bb for non-Linux shells, maintaining identical output semantics.


Supporting Infrastructure

File Purpose
test/dashboard/dashboard.spec.js Frontend test harness defining showMailWaiting(), showIdle(), and polling logic
swarmforge/scripts/ready_for_next_task.sh Primary backend script emitting status tokens
swarmforge/scripts/ready_for_next_task.bb Portable version of the same logic
swarmforge/scripts/pack_dashboard_request.sh Prepares request payloads for dashboard API calls

The separation between token generation (shell scripts) and UI interpretation (dashboard.spec.js) creates a clean contract that simplifies testing and cross-platform deployment.


Summary

  • MAIL_WAITING indicates queued mail tasks; the dashboard shows a pending badge and preserves the task list panel
  • NO_TASK indicates complete idleness; the dashboard renders a spinner-only idle screen with cleared content
  • The polling loop in test/dashboard/dashboard.spec.js uses regex matching to select between showMailWaiting() and showIdle()
  • The backend script ready_for_next_task.sh checks $MAIL_QUEUE before $TASK_DIR to prioritize mail visibility
  • Both states update every 2 seconds, providing near-real-time lieutenant status to operators

Frequently Asked Questions

What happens if both mail and general tasks are pending?

The ready_for_next_task.sh script checks $MAIL_QUEUE first, so it emits MAILWAITING even when general tasks exist. The dashboard will show the mail-waiting state until the mail queue empties, at which point a subsequent poll will reveal available standard tasks.

Can the polling interval be configured?

The setInterval call at approximately line 45 of test/dashboard/dashboard.spec.js hardcodes 2000 milliseconds. To adjust this, modify that interval value or externalize it to a configuration constant in the same file.

Why does NO_TASK use anchored regex matching while MAILWAITING does not?

The idle state regex /^NO\s*TASK$/ anchors to start and end to prevent partial matches against accidental substring occurrences. MAILWAITING uses simpler substring matching because the token appears unambiguously and upstream scripts guarantee exact output.

Is there a way to test these states without a live backend?

The test/dashboard/dashboard.spec.js file serves as both specification and manual test harness. You can simulate responses by calling showMailWaiting() or showIdle() directly in browser DevTools, or by mocking the fetch() response before loading the dashboard.

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 →