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
4.9 KiB
Handler — mobile app
A remote control for Handler: run many Claude Code agents across many projects, each isolated, each leaving a checkmark (current state) and an entry in the global log.
This is the React Native + Expo (iOS) implementation of the
Handler Mobile.dc.html design (turn 2a, the version the user committed to:
"Commit to 1a, wire-up the real screens"). It reproduces the interactive
prototype as a real app — six wired screens with the exact state logic from
the design.
Run it
cd app
npm install
npm run ios # opens the iOS simulator (requires Xcode)
# or: npm start then scan the QR code with Expo Go on a device
Screens
| Screen | File | What it does |
|---|---|---|
| Fleet (home) | src/screens/FleetScreen.tsx |
Tappable stat cards → filtered agent list, "Waiting on you" → Answer, "Recent checkmarks" → detail |
| Agent list | src/screens/AgentListScreen.tsx |
Every agent (checkmark or not) with All / Running / Waiting / Done filters → detail |
| Agent detail | src/screens/AgentDetailScreen.tsx |
Checkmark / Events / Log segmented control, live headless run event stream, meta table (incl. model backend + worker), Answer / Kill |
| Answer | src/screens/AnswerScreen.tsx |
Question, tappable quick replies, reply field + Send & resume |
| Spawn | src/screens/SpawnScreen.tsx |
Project select, model backend select, task field, Spawn |
| Schedules | src/screens/SchedulesScreen.tsx |
Recurring agent spawns: list, create (interval / role / model), pause, delete |
| Memory | src/screens/MemoryScreen.tsx |
The agent-memory note graph: kind filters, expandable notes, note authoring + deletion |
| Log | src/screens/LogScreen.tsx |
All / per-project / Errors filters over the global feed |
| Settings | src/screens/SettingsScreen.tsx |
Server info, Manage + Account entries, notification toggles, Sign out |
| Connect | src/screens/ConnectScreen.tsx |
Email sign-in (/auth/login), first-run admin setup, forgot-password, API-token fallback |
Management screens (Settings → Manage)
The full admin surface — everything the web dashboard can do, under
src/screens/manage/:
| Screen | What it does |
|---|---|
| Models | Model-backend CRUD: base URL, model ids, claude/pi harness, write-only API keys (set/clear), enable toggles |
| Skills | Create / toggle / delete managed skills, read SKILL.md, install-from-prompt via the command queue |
| Connectors | stdio / http / sse MCP servers with args, env, and header entry |
| Plugins | Marketplace plugins pinned to their repo |
| Permissions | Default permission mode + allow/deny/ask rules over the read-only env baseline |
| Claude login | Drive the worker's claude /login (authorize in browser, paste the code back) |
| Activity | The control-command queue: status filters, worker attribution, result/error detail, 5s auto-refresh |
| Repositories | Register repos (git-server or manual mode, optional mise-init bootstrap), sync, delete |
| Git servers | Forge hosts: encrypted tokens, generated deploy keys (public half copyable) |
| Approvals | Record operator approve / reject verdicts per project + branch |
| Shared context | Browse and set the cross-agent key/value store |
| Users | Invite (shareable links), promote / disable, mint reset links, delete |
| Account | Signed-in identity, change password, sign out (revokes the session server-side) |
The prototype navigates by swapping a single screen value (with working back
/ close controls) rather than a native stack, mirroring the design. Answering
agt-7a1d flips it Waiting → Running everywhere and clears it from the
Fleet waiting list — that cross-screen behavior lives in one shared store
(src/state/AppState.tsx, a direct port of the design's renderVals()).
Design system
The Leeworks tokens (project/_ds/.../tokens/*.css) are ported to typed RN
values in src/theme/tokens.ts; the components used by these screens
(Button, Badge, Icon, Switch, Select, Input, segmented control,
chip) are reimplemented in src/components/ from the design-system bundle.
- Fonts: Outfit (display), Figtree (body), Spline Sans Mono (data) via
@expo-google-fonts/*. - Colors: the warm-neutral ink ramp + muted status colors, light and dark.
Intentional deviations from the HTML prototype
The prototype drew a phone frame to make an HTML mock look like a device. A real iOS app is the device, so:
- The fake status bar (
9:41, signal, battery) and the home-indicator pill are dropped — the OS draws those. Screens use safe-area insets andexpo-status-barinstead. - Dark mode was a design-time prop; here it follows the system appearance
(
useColorScheme,userInterfaceStyle: "automatic"). - The
Selectuses a bottom-sheet picker (native<select>has no cross-platform styling in RN) — same field, real picking behavior.
All copy, spacing, colors, and interactions otherwise match the 2a design.