Skip to content

DartAI Loop Snapshot: Single-Call Queue Aggregation

Single-call aggregation tailored for the dartai adversarial cooperation loop. Returns the claimable queue, workspace assignees and statuses, runner-claimed tasks, and blocked tasks in one response — replacing three sequential calls (get_config(['assignees']) + list_tasks(...) + client-side filter) at loop startup.

Designed for the /dartai:start command in the Ralph Wiggum loop, but usable by any agent harness that needs a fast read of “what can I work on right now?” against a Dart dartboard.

ParameterTypeRequiredDescription
dartboardstringYesDartboard name (e.g. "Personal/agnt") or dart_id. Resolved against configCache by name first, then by ID.
runner_dart_idstringNoWhen provided, populates runner_claimed with In-Progress tasks assigned to this runner. Omit on the first call when the runner ID has not yet been resolved.
queue_limitintegerNoMaximum number of claimable tasks to return in queue (default: 20).
FieldTypeDescription
dartboard_idstringResolved dart_id of the requested dartboard.
config.statusesstring[]Available status names for the workspace.
config.assignees{ dart_id, email }[]Workspace assignees, projected to ID + email pairs.
queueTaskSummary[]Claimable tasks (status='Todo', no loop-blocked tag, no claimed:* tag), capped at queue_limit.
runner_claimedTaskSummary[]Tasks status='In Progress' whose assignees include runner_dart_id. Empty when runner_dart_id is omitted.
blockedTaskSummary[]Tasks tagged loop-blocked.
fetched_atstringISO-8601 timestamp the snapshot was assembled.

TaskSummary is a token-minimal projection of DartTask:

interface TaskSummary {
dart_id: string;
title: string;
status: string;
tags: string[];
assignees: string[];
}

Tasks are partitioned in this order — first match wins:

  1. blockedtags includes 'loop-blocked'.
  2. runner_claimedrunner_dart_id is set, task assignees includes it, status === 'In Progress'.
  3. queuestatus === 'Todo' and no tag starts with 'claimed:'.
  4. Otherwise dropped (e.g. Done tasks, In-Progress tasks not assigned to this runner).

The handler issues exactly one outbound listTasks call (limited to queue_limit * 3 to cover the three buckets) plus one cached configCache.get(). Partitioning is client-side.

Cold start — runner_dart_id not yet resolved:

dartai_loop_snapshot({
dartboard: "Personal/agnt",
queue_limit: 20
})

Returns config + queue + blocked, with runner_claimed: []. Resolve runner_dart_id from result.config.assignees by matching the runner’s git email, then pass it on subsequent calls.

Warm iteration — runner identity cached:

dartai_loop_snapshot({
dartboard: "Personal/agnt",
runner_dart_id: "uS3rD4rt1d",
queue_limit: 20
})

Now runner_claimed is populated, allowing the loop driver to detect interrupted In-Progress work and decide between resume-vs-orphan-warn before claiming new tasks.

PathOutbound callsNotes
Loop start (this tool)1 listTasks + 1 cached configOne round-trip to the Dart API
Equivalent with primitivesget_config + list_tasks + client filterTwo round-trips, more tokens

For a typical 20-task queue, response size is roughly 4–8 KB depending on tag/assignee density.

  • Requires DART_TOKEN in the environment. Missing token throws a DartAPIError with statusCode: 401 and a link to retrieve the token.
  • Throws Error('dartboard "{name}" not found') if the dartboard name or ID does not match any entry in configCache.dartboards.
  • Throws if the config cache is empty — call get_config once at startup to prime it.
  • get_config — primes the cache used by this tool
  • list_tasks — lower-level alternative when full task detail is needed
  • execute_dartql — preferred path for bulk writes after the loop has chosen a task