A schedule is a time trigger, and only the first step of a pipeline is really
waiting on time — every later step waits on the previous step's result. Modeling
"watch a source -> write a spec -> implement it" as three schedules made each fire
blind: on a quiet day the coding agent still spawned, paid a full model run to find
there was nothing to do, and left an empty run in Activity.
So an agent can start the next step itself. `dispatch_agent` (a tool on the bundled
MCP server, and on the pi bridge through the same --call seam) enqueues an ordinary
spawn command in the agent's own project, tagged requested_by=agent:<id> — so a
handoff is visible in Activity with no new surface to build.
- Project-scoped by construction: project_id is read from the spawn environment and
never from the tool arguments.
- Bounded rather than gated: MAX_DISPATCH_PER_RUN counts the command rows the agent
already wrote; MAX_DISPATCH_DEPTH rides in the spawn payload and is recovered by
spawn._dispatch_depth, so a chain keeps its place across a resume and a cycle
terminates instead of fanning out.
- New scout and planner roles, with built-in skills (handler-scout, handler-planner,
handler-dispatch) carrying the judgment code can't: dedupe against a memory-note
watermark, treat "nothing new" as a complete run, and write a task the receiving
cold-start agent can act on.
- A scout ending on a clean tree skips the test gate and records the new
tests_status='skipped' (migration 0017, additive CHECK widening). The gate promises
`done` means tests passed for the work that shipped; nothing shipped.
Rejected a `condition` field on schedules: "is this paper new and does it matter
here?" is a semantic judgment, so it belongs to a model, not a scheduler column. The
scout is the condition; dispatch is how it reports true — one mechanism that covers
future pipelines too.
426 tests (14 new for dispatch, 3 for the gate exemption).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HcbDevyMcJWE6qPA56C7mZ
The Running / Waiting / Done cards now navigate to a new agent-list
screen pre-filtered to that bucket, using exactly the same grouping as
the counts so the number tapped is the number listed. The list shows
every agent row the API knows — an agent that hasn't dropped a
checkmark yet is visible the moment it spawns, with a status badge, its
age, and a live last-output line while it works. Rows open the agent
detail screen, whose back button now returns to wherever the detail was
opened from (fleet or the list).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Settings → Manage → Activity lists every control command with status
filter chips, when/where it ran (project, agent, claiming worker or
'unclaimed'), and tap-to-expand result/error text; a Sweep CI button
enqueues the global poll. The list auto-refreshes every 5s while open,
so a login_start or spawn can be watched to completion — this was the
one web dashboard page missing from the phone, and exactly the view
needed to diagnose a stuck command.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Settings → Manage now opens the entire admin control surface on the
phone, mirroring the web dashboard page for page:
- Models: full CRUD for model backends incl. write-only API keys
(set/clear), harness selection (claude/pi), enable toggles.
- Skills: create, toggle, delete, expand to read SKILL.md, and
install-from-prompt driven through the command queue.
- Connectors: stdio/http/sse MCP servers with args/env/header parsing.
- Plugins: marketplace plugins pinned to their repo.
- Permissions: default mode + allow/deny/ask rules over the read-only
env baseline.
- Repositories: register in git-server or manual mode (incl. the
mise-init bootstrap), sync, delete.
- Git servers: forge hosts with encrypted tokens and generated deploy
keys (public half selectable for copying).
- Approvals: record operator approve/reject verdicts per branch.
- Shared context: browse and set the cross-agent key/value store.
- Users: invite (with shareable invite links), promote/disable, mint
reset links, delete — the user-accounts feature that just landed.
- Claude login: drive the worker's claude /login flow from the phone.
- Account (Settings): who you're signed in as, change password,
sign out with server-side session revocation.
The connect screen gains the matching gate: email sign-in via
/auth/login (session token stored like the legacy env token),
first-run setup when the server has zero accounts, forgot-password,
and the API-token method as fallback (auto-selected for pre-accounts
servers). Memory gains note authoring + deletion via a new
reloadMemory hook.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Groundwork for the full admin surface on mobile: the API client gains
the user-account and Claude-management types (skills, connectors,
plugins, permissions, users/auth, owner fields) plus an unauthenticated
authApi helper; AppState exposes the client and the new management
screen names; ManageShell/Field/ErrorNotice and a useResource hook give
the subscreens one shared page/fetch pattern; Settings gains Manage and
Account rows leading to the new hub.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
A new Memory tab loads /memory/graph when opened and lists the
distilled notes newest-first with kind filter chips
(fact/decision/gotcha/runbook); tapping a note expands its body, tags,
and both directions of its links, resolved to note titles. Read-only by
design — authoring stays with the web dashboard's admin surface and the
agents' own MCP server.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
A new Schedules tab lists every schedule across projects with its
interval, prompt, next/last run, and role/model badges; the operator
can create one (project, name prefix, interval, role, model backend,
prompt), pause/resume with a switch, and delete with confirmation.
Mirrors the web dashboard's Schedules page, including the model picker
added there. New clock/brain icons join the Lucide subset and the tab
bar grows to four tabs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Add an Events tab between Checkmark and Log: while the detail (or
answer) screen is open the store polls the cursor-paged
/agents/{name}/events endpoint every 3s and renders the stream-json
events the way the web dashboard does — assistant text as prose, tool
calls as badges, results as a turns/cost footer, worker notices as
danger callouts, raw lines verbatim. The meta card now also shows the
agent's model backend and supervising worker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Fetch the registered model backends (/claude/models) alongside the
fleet poll and offer the enabled ones in a Model select on the spawn
form, defaulting to the Claude subscription — the mobile counterpart of
the web dashboard's per-spawn dropdown. The select is hidden when no
backends are registered, and Select itself now takes value/label pairs
as well as bare strings.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Port the schema additions the backend gained since the last mobile
release: headless-runner fields on Agent (model_id, session_id,
worker_id) plus the AgentEvent row, model_id on Schedule, the
ClaudeModel backend registry row, and the agent-memory note/link/graph
shapes. Mirrors frontend/lib/api.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01731mKtVzsfeT4Vi3TvkR48
Wire the mobile app to the real Handler API instead of the transcribed
prototype data:
- src/api/client.ts: typed client ported from frontend/lib/api.ts (bearer
auth, AuthError/ApiError, base URL param, allow401 for admin-only resume)
- src/api/format.ts: relative-time + status label/tone/color helpers
- src/state/ServerConfig.tsx: endpoint+token persisted to AsyncStorage
- src/screens/ConnectScreen.tsx: first-open config, validated via
/health then /projects
- src/state/AppState.tsx: data-driven store polling projects -> agents ->
checkmarks -> logs every 10s with per-item failure isolation; derives
fleet counts, waiting list, recent checkmarks, merged log; answer+resume,
spawn, kill mutations; 401 routes back to ConnectScreen
- screens render live data; detail meta is Started/Status/Tests/Build;
Pause removed (no endpoint); Kill confirms; log filters are per-project
- delete src/data/mock.ts
tsc clean; Hermes bundle builds (200).
- .github/workflows/mobile-release.yml: validate (npm ci + tsc) on every
run with no secrets, plus an EAS Build job gated on workflow_dispatch or
a `mobile-v*` tag. Requires only the EXPO_TOKEN secret.
- app/eas.json: development / preview (iOS simulator, no Apple account) /
production (signed, EAS-managed Apple credentials) build profiles.
Build the committed 2a interactive prototype from Handler Mobile.dc.html as
a real Expo app: six wired screens (Fleet, Agent detail, Answer, Spawn, Log,
Settings) with the exact state logic ported from the design's renderVals().
- Port Leeworks tokens (colors light/dark, typography, spacing, radii,
shadows) to typed RN values in src/theme.
- Reimplement the design-system components used by the screens (Button,
Badge, Icon, Switch, Select, TextField, segmented control, chip, tab bar).
- Shared store mirrors the prototype's single-screen navigation and the
Waiting -> Running flip when agt-7a1d is answered.
- Real OS status bar / home indicator (safe-area insets) replace the mock
phone chrome; dark mode follows system appearance.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdF2hHVQ4UUBFPtpeMQ81o