- Move from top-level domain-skills/tasksquad.ai/ to the canonical agent-workspace/domain-skills/tasksquad-ai/ location, switching to kebab-case to match sibling dirs (booking-com, dev-to, archive-org). - Replace find_text_coords(...) with self-contained inline Python helpers (_coords_by_text, _coords_by_selector) that wrap querySelector + getBoundingClientRect. find_text_coords does not exist in the harness or agent_helpers — every call site was a NameError waiting to happen. - Fix the compose-task snippet: drop the dead subject_input = js(...) line, focus the subject input via _coords_by_selector before typing, and add a placeholder click for the agent dropdown item. - Fix the polling-interval contradiction: the inbox section now defers to the gotchas, and the gotchas list the Free (5s) / Pro (2s) cadence in one place.
6.3 KiB
TaskSquad — Task Inbox
Field-tested against tasksquad.ai on 2026-05-03 using a logged-in Chrome session.
URL
https://tasksquad.ai/dashboard # Inbox (default view)
https://tasksquad.ai/dashboard/<taskId> # Task thread (individual task)
Inbox view
The inbox is the default view after sign-in. It shows a list of tasks assigned to agents in the currently selected project.
Task list
Tasks are rendered as rows. Each row shows:
- Subject line
- Agent name
- Status badge
- Relative timestamp
Status values
| Status | Meaning |
|---|---|
pending |
Queued for the agent daemon |
queued |
Agent is busy — task is waiting in line |
running |
Agent is actively working |
waiting_input |
Agent needs a reply from the user |
done |
Completed successfully |
failed |
Ended with an error |
scheduled |
Will start at a future scheduled_at time |
wrapping_up |
Running post-completion close steps |
Filters
Two dropdowns appear above the task list:
Status (left): All / Pending / Queued / Running / Waiting / Done / Failed / Scheduled
Origin (right): All / System / Mine / From Note / Critique / Scheduled
- "System" = tasks created by automated conveyors
- "Mine" = tasks you composed yourself
- "From Note" = tasks spawned from Notes
- "Critique" = tasks that are note critiques
Both dropdowns use shadcn <Select>. Click the trigger to open, then click the item by text.
Refresh
A RefreshCw icon button sits next to the "Inbox" heading. Click it to reload the task list without full navigation. Alternatively, wait_for_load() after any state change — the app auto-polls when active tasks exist (interval depends on plan; see Gotchas).
Composing a new task
Click the "New message" button (top-right of Inbox). A dialog opens.
Dialog fields
| Field | Type | Notes |
|---|---|---|
| Agent | <Select> |
Required. Dropdown of agents in the current project. |
| Subject | <input> |
Required. Short description of the task. |
| Message | <textarea> |
Optional. Task body / detailed instructions. |
Optional advanced toggles (revealed via UI controls):
- Schedule: set a future delivery time
- Auto-close: task closes automatically when the agent finishes
- Save tokens: compress the task context (lite / full / ultra)
- Close steps: newline-separated post-completion steps
Submit with the "Send" button inside the dialog.
import json
def _coords_by_text(label, tag="button"):
"""Find an element by exact innerText and return click coords, or raise."""
sel = json.dumps(tag)
txt = json.dumps(label)
result = js(f"""
var el = Array.from(document.querySelectorAll({sel}))
.find(e => (e.innerText || "").trim() === {txt});
if (!el) return null;
var r = el.getBoundingClientRect();
return JSON.stringify({{x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)}});
""")
if result is None:
raise RuntimeError(f"{tag!r} with text {label!r} not found")
p = json.loads(result)
return p["x"], p["y"]
def _coords_by_selector(selector):
"""Find an element by CSS selector and return click coords, or raise."""
sel = json.dumps(selector)
result = js(f"""
var el = document.querySelector({sel});
if (!el) return null;
var r = el.getBoundingClientRect();
return JSON.stringify({{x: Math.round(r.x + r.width/2), y: Math.round(r.y + r.height/2)}});
""")
if result is None:
raise RuntimeError(f"selector not found: {selector!r}")
p = json.loads(result)
return p["x"], p["y"]
# Open the compose dialog
click_at_xy(*_coords_by_text("New message"))
wait(1.0) # let the dialog mount; agents may still be loading
# Open the agent <Select> trigger and pick an agent.
# The trigger renders the placeholder "Select agent…" until an agent is chosen.
click_at_xy(*_coords_by_text("Select agent…"))
wait(0.5)
# Then click the agent name from the opened dropdown:
click_at_xy(*_coords_by_text("YOUR_AGENT_NAME"))
# Focus the subject input, then type
click_at_xy(*_coords_by_selector('input[id="subject"]'))
type_text("Check the build status")
# (Optional) focus the message textarea and type the body
# click_at_xy(*_coords_by_selector('textarea'))
# type_text("Detailed instructions go here.")
# Submit
click_at_xy(*_coords_by_text("Send"))
Task thread
Clicking a task row opens the thread at /dashboard/<taskId>.
The thread is an email-style conversation. Messages alternate between:
- User messages (right-aligned or labeled with sender name)
- Agent messages (left-aligned)
Replying
When a task is in waiting_input status, a reply box appears at the bottom. Type your reply and press Enter or click the send button.
A scheduled reply pending delivery blocks the reply box — a cancel option appears.
Task actions
Actions available from the thread view (usually via icon buttons or a menu):
- Close — mark the task done manually
- Delete — permanently remove the task
- Forward — reassign to a different agent (appears as "Forward to agent" with agent selector and optional instructions)
Gotchas
- Inbox auto-polls while active tasks exist (
pending/running/waiting_input). Free plan polls every 5 s, Pro every 2 s. For scraping, add await_for_load()between reads if statuses are changing. queuedis a derived client-side status — the server returnspending, but the UI showsqueuedwhen the target agent is itselfrunningorwaiting_input. Filter accordingly.- Task list is per-project. Switching projects (teams) reloads the list. The active project is stored in
localStorageastsq_team_id. - Dialog does not open until agents are loaded. If "Select agent…" placeholder is missing after clicking "New message", the agents list is still fetching — retry after a short wait.
- Free plan project limit: free accounts have a project limit (currently 1).