Auto-trigger agent when task moves to in progress#182
Conversation
Greptile SummaryThis PR adds auto-triggering of assigned agents when a task card is dragged to the "In Progress" column, eliminating the manual "Send" button step. It also introduces a new Key observations:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
actor User
participant KanbanUI as Kanban Board (page.tsx)
participant API as TinyClaw API
participant MsgBus as Message Bus (sendMessage)
participant Agent as Assigned Agent (invoke.ts)
User->>KanbanUI: Drag task → In Progress column
KanbanUI->>KanbanUI: Compute newlyInProgress<br/>(tasks not in prevInProgress with assignee)
KanbanUI->>API: reorderTasks(colMap)
API-->>KanbanUI: OK
KanbanUI->>MsgBus: sendMessage(@agent title [task:ID])
MsgBus-->>KanbanUI: OK (errors silently swallowed)
KanbanUI->>KanbanUI: refresh()
MsgBus->>Agent: Deliver @agent message
Agent->>Agent: invokeAgent(...)<br/>env: TINYCLAW_AGENT_ID=agentId<br/>(⚠️ lost for custom providers)
Agent->>Agent: Work on task
Agent->>API: tasks.sh update TASK_ID --status done
API-->>Agent: OK
Note over User, KanbanUI: Alternative: User clicks "Send" button (backlog tasks only)
User->>KanbanUI: Click Send button
KanbanUI->>MsgBus: sendMessage(@agent title [task:ID])
KanbanUI->>API: updateTask(id, {status: in_progress})
KanbanUI->>KanbanUI: refresh()
|
| const newlyInProgress = (newColumns.in_progress ?? []).filter( | ||
| (t) => !prevInProgress.has(t.id) && t.assignee | ||
| ); |
There was a problem hiding this comment.
Agent re-triggered on any in-progress transition, not just from backlog
The current check fires whenever a task is newly present in in_progress — regardless of which column it came from. This means dragging a task from review → in_progress or done → in_progress (e.g., reopening a finished task) will also silently dispatch an @agent message, potentially spamming the agent or restarting already-completed work.
To restrict triggering to the intended case — moving a task from backlog to in_progress — you should also verify the task's previous column:
// Build a quick lookup of previous column for each task
const prevColumnOf = new Map<string, string>();
for (const [status, items] of Object.entries(columns)) {
for (const t of (items as Task[])) {
prevColumnOf.set(t.id, status as string);
}
}
const prevInProgress = new Set((columns.in_progress ?? []).map((t) => t.id));
const newlyInProgress = (newColumns.in_progress ?? []).filter(
(t) => !prevInProgress.has(t.id) && t.assignee && prevColumnOf.get(t.id) === "backlog"
);
Without this guard, reopening a reviewed or completed task re-triggers the assigned agent unexpectedly.
|
@greptileai review new changes |
| if [[ -n "$filter_status" ]]; then | ||
| jq_filter="${jq_filter} | map(select(.status == \"${filter_status}\"))" | ||
| fi |
There was a problem hiding this comment.
Unvalidated --status value interpolated into jq filter
filter_status is passed directly from the command-line argument into a jq expression with no prior validation. The update sub-command validates its --status input against an allowlist, but list does not. A value containing " or jq operators (e.g., in_progress" | @base64) could break the generated filter or produce unexpected output.
Add the same allowlist guard used in cmd_update:
| if [[ -n "$filter_status" ]]; then | |
| jq_filter="${jq_filter} | map(select(.status == \"${filter_status}\"))" | |
| fi | |
| if [[ -n "$filter_status" ]]; then | |
| case "$filter_status" in | |
| backlog|in_progress|review|done) ;; | |
| *) die "Invalid status: $filter_status. Must be one of: backlog, in_progress, review, done" ;; | |
| esac | |
| jq_filter="${jq_filter} | map(select(.status == \"${filter_status}\"))" | |
| fi |
mczabca-boop
left a comment
There was a problem hiding this comment.
Overall direction makes sense, but I found two functional issues and one rollout gap that should be addressed before merge.
-
Existing agents do not automatically receive the new
tasksskill, so the feature does not work for already-provisioned workspaces. The new task flow depends on agents understanding[task:ID], but older agent workspaces are only updated on first provisioning, not when new default skills are added. In local testing, an existing Claude-based agent ignored task semantics untiltaskswas manually copied into both.agents/skills/tasksand.claude/skills/tasks. That means this PR works for newly created agents, but not reliably for existing ones. Relevant code:src/lib/agent.ts,src/server/routes/agents.ts. -
Custom-provider agents lose
TINYCLAW_AGENT_ID, which breaks the new task skill behavior.invokeAgent()initializesenvOverrideswithTINYCLAW_AGENT_ID, but in thecustom:provider branch it replaces the object instead of merging into it. That meanstasks.sh list --mineand the default self-assignment path stop working for custom-provider agents. Relevant code:src/lib/invoke.ts. -
Dragging a task into
in_progressupdates task state before notification is guaranteed, so tasks can appear active even if no agent was actually notified. In the new drag path,reorderTasks()is committed first andsendMessage()failures are swallowed. By contrast, the existing send-button flow sends first and only then updates status. This creates an inconsistent and potentially misleading state transition. Relevant code:tinyoffice/src/app/tasks/page.tsx.
I also manually verified that:
- The web UI changes do work: dragging to
in_progressdoes auto-enqueue a task message. - The
tasks.shscript itself works correctly against the local API. - The main gap is rollout/discovery of the new skill for existing agents, not the script implementation itself.
When a task is dragged to the in progress column on the kanban board, automatically send a message to the assigned agent to start working on it, matching the behavior of the manual "Send" button. Also add yarn.lock to .gitignore and pin TypeScript version. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Agents can now list, update, and create tasks via a new skill. Messages dispatched from the task board include a [task:ID] tag so agents know which task to mark done. TINYCLAW_AGENT_ID env var is passed to agent processes to support --mine filtering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Preserve TINYCLAW_AGENT_ID when building env overrides for custom providers by using property assignment instead of object replacement. Reorder drag-to-in-progress flow to send agent message before updating task status, matching the send-button pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
42c466e to
6b2c044
Compare
Summary
When a task is dragged to the "In Progress" column on the kanban board, the assigned agent is now automatically triggered to start working on it. Previously, users had to click the "Send" button after moving the task, adding an extra step.
Changes
@agentmessage for each task with an assigneeType of Change
Testing
Checklist