Skip to content

feat(launcher): UI-driven agent launcher with reusable profiles (gated by ORCHESTRATOR_ENABLED)#140

Open
kqb wants to merge 65 commits into
hoangsonww:masterfrom
kqb:feat/agent-launcher
Open

feat(launcher): UI-driven agent launcher with reusable profiles (gated by ORCHESTRATOR_ENABLED)#140
kqb wants to merge 65 commits into
hoangsonww:masterfrom
kqb:feat/agent-launcher

Conversation

@kqb

@kqb kqb commented May 6, 2026

Copy link
Copy Markdown

Summary

Extends the orchestrator surface introduced in a6343be (PWA + mobile orchestrator) to expose every session-launch CLI flag from code.claude.com/docs/en/cli-reference through a UI form, persists configurations as reusable Profiles (SQLite, JSON export/import), and adds a send composer to the existing Conversation tab so any session — live or imported — can be continued from the dashboard. The previous 6-flag preset is replaced by a strict ProfileConfig shape that the spawner validates before invoking claude.

All new surface stays gated behind ORCHESTRATOR_ENABLED=1. Default behavior of the dashboard (observe-only) is preserved — every new route 404s when the flag is unset, no schema or UI changes for users who don't opt in.

What ships

Server (8 new modules)

  • server/lib/profile-schema.js — flag table + JSON validator + buildArgsFromConfig (drives spawn argv).
  • server/lib/stream-json-parser.js — newline-delimited JSON line buffer.
  • server/lib/spawner.js — full rewrite: stdin pipe, full flag mapping, stream-json broadcast over WS, concurrency cap (ORCHESTRATOR_MAX_CONCURRENT), sendMessage(), resume support.
  • server/lib/profiles.js, server/lib/cwds.js, server/lib/launches.js, server/lib/launcher-secrets.js.
  • server/routes/profiles.js, server/routes/cwds.js.
  • Three new SQLite tables: launcher_profiles, launcher_allowed_cwds, launcher_launches (audit log; env values are never recorded — only names).

Client

  • New /launcher page with a sectioned form (15 sections covering every applicable flag) + live argv preview + dangerous-flag highlighting.
  • Settings → Agent Profiles tab with list / edit / duplicate / import-export.
  • SendComposer mounted at the bottom of the existing ConversationView — pipes follow-up messages to live agents (POST /agents/:id/message) or runs claude --resume <session-id> for historical sessions. Cmd/Ctrl+Enter to send.
  • useProfiles, useCwds, extended useOrchestrator (now sendMessage-aware).
  • MobileChat refactored as a thin SendComposer wrapper.
  • New WSMessage variant: agent_input_ack.
  • New nav entry across Sidebar.tsx, BottomTabNav.tsx, plus i18n (en/vi/zh).

Docs

  • docs/superpowers/specs/2026-05-05-agent-launcher-design.md — design spec (brainstorming output).
  • docs/superpowers/plans/2026-05-05-agent-launcher.md — 26-task TDD implementation plan.
  • docs/launcher.md — user-facing feature guide.
  • README + ARCHITECTURE + .env.example cross-references.

Architecture (one-pass)

Launcher form / Conversation send composer
  → POST /api/orchestrator/spawn  or  /agents/:id/message
    → server validates body against ProfileConfig schema
    → server checks cwd against launcher_allowed_cwds (security gate)
    → server checks concurrency cap
    → spawnAgent() builds argv, spawns `claude` with cleanSpawnEnv()
      → child stdout (stream-json) → parseStreamJson() → broadcast WS agent_stream
      → spawned `claude` fires hooks → POST /api/hooks/event → existing dashboard ingestion
    → response { id, pid, status, startedAt }

Spawned claude processes ride the existing observation pipeline — Sessions, Conversation, Workflows, Cost Tracking all "just work" for orchestrator-launched sessions on day one.

Safety

  • Every new HTTP route 404s unless ORCHESTRATOR_ENABLED=1.
  • The cwd allowlist is enforced server-side in the spawn handler — UI dropdowns are convenience, not security. Even a hand-crafted request with cwd: "/etc" is rejected.
  • Default permission mode is acceptEdits (never bypassPermissions implicit).
  • Dangerous flags (--bare, --dangerously-skip-permissions, --allow-dangerously-skip-permissions, --dangerously-load-development-channels) live behind a collapsed red banner in the editor.
  • Hook handlers always exit 0 (project gotcha Feature: Interactive Session Replay with Timeline Scrubber #2 preserved).
  • Argv is recorded in launcher_launches.argv_json with env values redacted — only the names that were injected are kept. Secrets resolve at spawn from ~/.claude/launcher/secrets.env (gitignored) or process.env.
  • Concurrency-capped via ORCHESTRATOR_MAX_CONCURRENT (default 5).
  • Profile validation runs twice — at the lib boundary (DB) and again at the spawner — so a hand-edited row or future MCP tool can't slip a bad config into a child process.

Test Plan

  • npm run test:server241 / 241 (was 186 baseline → +55 launcher tests).
  • npm run test:client159 / 159 (was 139 baseline → +20 launcher tests).
  • cd client && npx tsc --noEmit — clean.
  • All new HTTP routes 404 when ORCHESTRATOR_ENABLED is unset (test profiles route first case + cwds route smoke).
  • Spawner concurrency limit, env-stripping, sendMessage rejection on non-running, agent_stream broadcast, agent_input_ack on stdin write — all covered in spawner-extended.test.js.
  • Profile + cwd + audit CRUD round-trips covered (profiles-lib.test.js, cwds.test.js, launches.test.js).
  • secrets.env parser covers ENOENT-only swallowing + EACCES rethrow (launcher-secrets.test.js).
  • Manual smoke (recommended for review): set ORCHESTRATOR_ENABLED=1, npm run dev, visit /launcher, save a profile, launch an agent, see it stream via the existing Conversation tab; type into a historical session's send box and confirm claude --resume runs.

Backwards compatibility

  • The previous 6-field preset shape is a strict subset of ProfileConfig; the spawner validator accepts it and the new route translates configOverride into the same merged config path. Existing callers continue to work.
  • WSMessage extension is additive — agent_input_ack is a new variant; existing variants unchanged.
  • No schema migrations against existing tables; only CREATE TABLE IF NOT EXISTS additions.
  • The ConversationView component gained two optional props (sessionCwd, sessionLiveHandleId); both default to "no composer rendered." Existing parents that don't pass them continue to render the read-only view.

Phased delivery (33 commits)

  1. Server foundation — flag table, line parser, spawner rewrite, secrets reader.
  2. Persistence — schema, profiles + cwds + launches libs, HTTP routes.
  3. Spawn integration — extended /spawn body, /agents/:id/message, sub-router mounts, liveHandle on session detail, agent_input_ack WS type.
  4. Launcher form UI — types, hooks, CommandPreview, ProfileEditor + 14 sections, LauncherView page, route mount.
  5. Profile manager — Settings → Agent Profiles tab.
  6. Send composeruseOrchestrator.sendMessage, SendComposer (mode: "resume" | "fresh"), ConversationView mount, MobileChat refactor.
  7. Polishdocs/launcher.md, README/ARCHITECTURE/.env cross-refs.

References

  • docs/superpowers/specs/2026-05-05-agent-launcher-design.md — full design.
  • docs/superpowers/plans/2026-05-05-agent-launcher.md — TDD task breakdown.
  • docs/launcher.md — user guide.
  • Built atop a6343be (PWA + mobile orchestrator) and docs/orchestration-research/10-pwa-on-dashboard-design.md Phase 2 "preset shape" decision.

🤖 Generated with Claude Code

kqb and others added 30 commits May 5, 2026 04:36
12-file research corpus exploring orchestration architecture options
for the Claude Code Agent Monitor dashboard. Builds the design rationale
for the Phase 0-6 implementation in commit 2/2.

Files:
- README.md           index + decision tree
- 01-current-architecture.md   dashboard's observe-only contract
- 02-claude-orchestration-options.md   SDK / Task tool / CLI subprocess
- 03-third-party-orchestrators.md   9-repo deep survey
- 04-architecture-patterns.md   10 topology patterns with mermaid
- 05-runtime-comparison.md   local LLM vs API vs CLI session
- 06-agentic-pattern-archetypes.md   26 pattern catalog + decision tree
- 07-claude-code-hidden-features.md   v2.1.128 feature tour
- 08-claudeclaw-deep-dive.md   four-axis claudeclaw analysis
- 09-memory-and-rag.md   memory system + RAG analysis
- 10-pwa-on-dashboard-design.md   design that this build implements
- 11-build-summary.md   build-orchestration metrics + handoff notes

Total: 4,643 lines across 12 markdown files. All mermaid diagrams
validated against the Mermaid 11 parser.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…RATOR_ENABLED)

Implements docs/orchestration-research/10-pwa-on-dashboard-design.md
Phases 0-6. Total ~7,300 lines across 33 new files + 8 additive edits.

All new functionality lives behind ORCHESTRATOR_ENABLED=1. Default
behavior unchanged: every new route returns 404 when the flag is unset.
The dashboard's observe-only contract is preserved; existing tests pass
with no regression.

Phase 0/1: PWA + responsive mobile shell
- vite-plugin-pwa with injectManifest strategy (custom service worker
  in client/src/sw.ts that combines workbox precache + the dashboard's
  push/notificationclick handlers from the previous public/sw.js)
- Manifest, 192/512px icons, standalone display, theme color matched
  to existing dark palette
- client/src/features/mobile/: MobileShell, BottomTabNav (Dashboard/
  Sessions/Chat/Settings), useMediaQuery hook (768px breakpoint)
- App.tsx wraps existing Layout in MobileShell; desktop unchanged
- Offline cache for /api/sessions and /api/agents (NetworkFirst, 60s)

Phase 2: Orchestrator backend + mobile chat
- POST /api/orchestrator/spawn — env-stripping claude subprocess (the
  claudeclaw daemon trick from docs/orchestration-research/08-)
- GET/DELETE /api/orchestrator/agents/:id
- Preset shape: effort/permissionMode/maxBudgetUsd/model/allowedTools/
  appendSystemPrompt. Default permission mode: acceptEdits (never
  bypassPermissions implicit)
- /chat mobile page: prompt textbox, streaming response via existing WS
- WSMessage extended additively to discriminated union with
  agent_stream / agent_status variants

Phases 3-4: Read-only management viewers
- GET /api/memory/* — auto-memory + CLAUDE.md across all projects
- GET /api/channels/* — configured channels with secret-redaction
- GET /api/skills/* — skills + subagents + plugins + marketplaces
- GET /api/hooks-mgmt/* — hooks across user/project/local scopes
- GET /api/context/* — compaction events + per-session token budget
- All endpoints validate path-traversal via strict regex + path.resolve
  containment checks (Round 2/3/4 agents added 51 tests covering the
  validation paths)

Phase 5: Push notifications
- usePushSubscription hook + PushSubscribeButton in Settings
- server/lib/push-dispatcher.js — fan-out via existing sendPushToAll
- Hook events Stop/Notification/SubagentStop trigger pushes
  (fire-and-forget; preserves the hook handler's always-exit-0 contract)

Tests: 459/459 pass (186 server + 139 client + 134 MCP). Production
build clean. TypeScript clean across all surfaces.

Build was orchestrated using docs/orchestration-research/06-'s
Supervisor + Worker fan-out pattern: 4 rounds × 2 parallel agents on
non-overlapping file scopes, with sequential wiring of shared files
(server/index.js, App.tsx) by the parent session between rounds.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Validated brainstorming output. Extends the orchestrator surface from
a6343be to expose every session-launch CLI flag, persists configs as
SQLite-backed Profiles with JSON export/import, and adds a send composer
to the existing Conversation tab so any session (live or imported via
--resume) can be continued from the dashboard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
26 TDD tasks across 7 phases (server foundation → persistence →
spawn integration → launcher UI → profile manager → send composer →
docs). Phases 4-6 parallelize after phase 3 lands. Each task is
fully self-contained: failing test, expected fail output, complete
implementation code, expected pass, commit step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds server/lib/profile-schema.js as the foundational module for the
Agent Launcher feature: flagTable (37 CLI flags with shapes/enums/
constraints), validateProfileConfig(), and buildArgsFromConfig().
Covered by 13 new tests in server/__tests__/profile-schema.test.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…Names entries) + clarify camelCase flags

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ge, WS broadcast, concurrency cap

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… shim

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…unches tables

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds append-only audit log over launcher_launches: record() writes one row
at spawn with argv+envNames (env values are never stored), complete()
updates exit_code/status/ended_at, attachSessionId() backfills session_id
once the first hook event reports it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds HTTP surface for the cwd allowlist gated by ORCHESTRATOR_ENABLED.
GET lists entries, POST adds (400 on missing dir), DELETE removes by path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ofile + cwd subrouters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extend GET /api/sessions/:id to include a liveHandle field containing
{ id, pid, status } when ORCHESTRATOR_ENABLED=1 and an orchestrator
agent is actively attached (status running or spawning). Returns null
otherwise, preserving full backward compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Thin React hooks wrapping the /api/orchestrator/profiles and /api/orchestrator/cwds
HTTP endpoints, with loading/error state, auto-refresh on mount, and mutations
(create, update, remove, duplicate, importJson / add, remove).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the ProfileEditor shell (collapsible MUI Accordion per section) and
all 14 controlled section components covering every ProfileConfig field.
Installs @mui/material v7 + @emotion peers as client deps. Both tests pass,
tsc --noEmit clean, full 148-test suite green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… getByRole

Restore accurate CLI flag names and mode strings in PermissionsSection,
ToolsSection, and DangerousSection. Tighten ProfileEditor test selectors
to use getByRole("button") with anchored regex to target accordion headers
only, avoiding false matches against MenuItem/chip field text inside sections.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wires ProfileEditor + CommandPreview + Save/Launch actions into a two-column
page layout. Launch calls useOrchestrator.spawn({prompt, cwd}); T21 will
extend the hook to pass editor.config as configOverride.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wires LauncherView to the router and adds Launcher nav entries to the
desktop sidebar (Rocket icon, nav:launcher i18n key) and mobile bottom
tab bar (inline SVG rocket icon). Translation keys added for en/vi/zh.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…export

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the old OrchestratorPreset-based SpawnArgs with the new shape
({prompt, cwd, profileId?, config?, resumeSessionId?, forkSession?}) that
matches the server's /spawn body. Adds sendMessage(id, text) for continuing
live agent sessions via POST /agents/:id/message. MobileChat.tsx updated
to pass cwd:"" as a minimal shim (T24 will rewrite that component).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
kqb and others added 16 commits May 6, 2026 15:32
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…electors

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds ComposerActions, ComposerTextarea, and ComposerToolbar; textarea test covers Cmd+Enter submit and slash-trigger detection. MUI v9 adjustments: alignItems/flexWrap moved into sx prop on Stack, regex capture group typed with nullish coalesce.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…u + actions)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- docs/launcher.md: replace minimal "Continue any conversation" section
  with the Composer feature description (toolbar, slash menu, file/photo
  pickers, drag-and-drop, mid-session respawn semantics, .launcher-uploads/
  + auto-gitignore behavior).
- .env.example: document LAUNCHER_MAX_UPLOAD_MB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add a project-wide MUI ThemeProvider with a dark palette matching
  the dashboard's existing #0c0c14 / #15151f / #e4e4ed colors. Until
  this commit, every MUI component (Composer, LauncherView,
  SettingsProfiles, ProfileEditor) rendered with light defaults
  against the dashboard's dark background — invisible text on
  invisible surfaces.
- Add bottom margin on the Composer for xs viewports equal to
  56px + safe-area-inset-bottom so the BottomTabNav doesn't cover
  the Send/Stop buttons on mobile.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…list recovery

Initial-value fix:
- GET /api/sessions/:id now returns currentModel / currentMode /
  currentProfileId derived (in priority order) from the live orchestrator
  handle's profile → most recent launcher_launches argv → session.model.
- ConversationView accepts defaultModel / defaultMode / defaultProfileId
  and forwards them to the Composer.
- useComposerState seeds its model/mode state from those defaults instead
  of always starting null. The pickers now show what the session is
  actually running with when the page loads.

Send-error visibility fix:
- Move the error Alert from below the Send button to ABOVE the toolbar so
  failures are unmissable on mobile.
- Recognize the most common /spawn failure ("cwd not in allowlist") and
  render a "Add cwd & retry" inline button that calls POST /cwds and
  re-sends. One-click recovery instead of "send did nothing — figure out
  why."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…orchestrator

The Composer V2 plan added server/routes/uploads.js and
server/routes/slash-commands.js but the orchestrator.js mount was
left as the original two-mount form (profiles + cwds). Browser
validation caught the gap: GET /api/orchestrator/slash-commands
404'd, the SlashMenu silently rendered an empty popover (no items
to filter). Adding the two missing router.use() lines wires the
new endpoints under the gated /api/orchestrator namespace exactly
like profiles and cwds.

Caught via Playwright validation against http://localhost:5173/
after restarting the dev server.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hoangsonww hoangsonww added enhancement New feature or request help wanted Extra attention is needed good first issue Good for newcomers question Further information is requested labels May 7, 2026
@hoangsonww hoangsonww moved this from Backlog to In progress in Claude Code AI Agents Monitor Project Board May 7, 2026
kqb and others added 5 commits May 7, 2026 14:42
Two issues blocked end-to-end live updates from the Conversation tab.

1. Spawner hung. `claude -p PROMPT --input-format stream-json` is a
   contradictory combo — claude waits for additional stdin input even
   though the prompt is on argv, so no assistant chunk ever streams. Drop
   `-p` from argv and write the initial prompt to stdin as a stream-json
   user message (same path sendMessage already uses).

2. ConversationView never wired up agent_stream. The JSONL → new_event
   path eventually catches the response, but `--resume` forks the
   session-id, so live tokens are stranded unless the UI subscribes to
   the spawner's broadcast directly. Add a subscription gated on
   liveHandleId; also default useComposerState to mode="resume" so
   callers (like ConversationView) that don't pass the prop still
   continue the existing session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ity ring

Conversation tab UX overhaul, all in the React client:

- Drop the standalone "LIVE" panel. agent_stream messages are converted to
  TranscriptMessage shape and concatenated into the same MessageList as
  JSONL-derived messages, so the user sees one continuous conversation.
- Optimistic user bubble — render the message immediately on Send with a
  dimmed "Sending…" treatment, snap to normal once the spawn POST resolves.
  When the agent's stream-json echoes the user prompt back, we drop the
  pending bubble so it doesn't double with the live echo.
- Assistant "thinking…" placeholder — three pulsing dots until the first
  agent_stream chunk lands or the agent terminates (completed | error |
  killed; killed was missing on the first cut and would strand the spinner
  on Stop).
- Dedupe live vs JSONL — when the JSONL catch-up surfaces the same text
  the agent already streamed, the JSONL version (with model + tokens) wins
  and the live entry is dropped from unifiedMessages. Bounded N×M dedup
  over a sliding window of recent messages.
- Reset live/result/pending state when sessionId or selectedTranscript
  changes so a transcript switch doesn't carry stale chunks.
- New ContextRingButton next to the upload buttons — a small circular
  progress ring (green <70%, amber 70-90%, red >90%) that shows current
  context usage (preferring the latest result chunk's modelUsage, falling
  back to the session cost endpoint, falling back to a per-model default
  window). Clicking it sends `/compact` through the existing send path.
- useComposerState.send() now takes an optional overrideText so /compact
  can be sent without clobbering the user's draft. setText is async, so
  the prior approach (setText then send) raced and sent the old draft.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… transcript view

Conversation tab UX overhaul to match Claude Code Desktop:

- Bottom status bar replaces the prominent Model/Mode/Profile dropdown row.
  Left chip = current permission mode (yellow for bypassPermissions/dontAsk).
  Right chip = "Opus 4.7 1M · Extra high"-style model+effort label, opens a
  Models / Effort / Fast mode popover with kbd shortcuts. Effort respawns
  the live agent like model/mode does. Fast mode is a UI-only stub for v1.
- Single + button opens a popup with Add files or photos / Take a photo /
  Slash commands. Existing file-input wiring preserved.
- Mic button — Web Speech API dictation with pulse animation, graceful
  fallback when unsupported. Adjacent chevron stub for future language
  picker.
- Inline submit icon at the right end of the textarea (ArrowUp / Stop)
  replaces the separate Send/Stop row. Placeholder is now "Type / for
  commands."
- Context-capacity ring sits between + and mic, stays standalone with the
  same /compact wiring.
- Transcript view picker in the Conversation header — Normal / Thinking /
  Verbose / Summary plus three Aa font-size controls. Persists to
  localStorage. MessageList accepts viewMode + fontSize and filters
  content blocks before render.

Stubs / TODOs:
- Fast mode toggle is UI-only.
- Mic language picker is a no-op chevron with "coming soon" tooltip.
- Older ComposerActions / ModePicker / ProfilePicker / UploadButtons are
  unused but left in place for a follow-up cleanup pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New "Routines" feature mirroring Claude Code Desktop's Routines panel.

Backend
- Two new tables (routines, routine_runs) added as additive CREATE
  TABLE IF NOT EXISTS migrations in server/db.js.
- server/lib/routines.js: CRUD + pure computeNextRun helper covering
  manual / hourly / daily / weekdays / weekly schedules.
- server/lib/routine-scheduler.js: in-process tick (default 60s) wakes
  due routines, jitters fire by up to ~5min, calls spawnAgent directly
  (no HTTP loopback), and watches the child for exit so it can record
  the run's status, exit code, and a 500-char output_summary.
- server/routes/routines.js: CRUD + POST :id/run + POST :id/webhook
  (constant-time hex token compare via crypto.timingSafeEqual) + status
  toggle. Whole router gated on ORCHESTRATOR_ENABLED=1 and bound to the
  cwd allowlist. webhookToken is only revealed via GET :id; redacted
  from list/create/update responses.

Frontend
- Sidebar nav entry "Routines" (Lucide Zap), gated by a one-shot probe
  of /api/orchestrator/.
- /routines list page with banner, All/Calendar tabs, "Include
  completed" toggle, "New routine" CTA. Calendar tab is a stub.
- /routines/:id detail page with description / status toggle / folder /
  schedule / instructions / webhook URL (token reveal-on-click) / run
  history / Run now / Edit / Delete.
- RoutineEditor modal (dual-purpose Create + Edit) with embedded
  permissions / model / folder / worktree controls and the
  Manual/Hourly/Daily/Weekdays/Weekly schedule tab strip.

Stubs / follow-ups
- Calendar tab is a "coming soon" empty state.
- Mobile bottom-tab nav unchanged (5 tabs already, didn't fit a new one).
- Detail page doesn't subscribe to routine_run_updated WS broadcasts —
  refetches via Run now button. Backend already publishes the events.

Tests: 16 new server (278 total) + 5 new client (214 total). All pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every desktop destination is now reachable on mobile.

- Add a 5th primary tab "Routines" (gated on the orchestrator flag, same
  policy as the desktop Sidebar) plus a "More" tab that opens a slide-up
  sheet listing the rest of the desktop sidebar in the same order:
  Kanban Board, Activity Feed, Analytics, Workflows, Settings, Launcher.
- The More sheet locks body scroll while open, dismisses on backdrop tap,
  ESC key, or any nav-link tap. Backdrop is a real <button> so it's
  keyboard-reachable.
- Pull the existing /api/orchestrator/ flag probe out of Sidebar.tsx into
  a shared useOrchestratorEnabled() hook so the two nav surfaces stay in
  sync without duplicating the fetch logic.
- Replace the static `grid-template-columns: repeat(4, 1fr)` (already a
  pre-existing mismatch with the 5 tabs the file rendered) with a
  CSS-variable-driven `repeat(var(--tab-count, 5), 1fr)` so the grid
  adapts to whether Routines is shown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hoangsonww hoangsonww moved this from In progress to Backlog in Claude Code AI Agents Monitor Project Board May 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request good first issue Good for newcomers help wanted Extra attention is needed question Further information is requested

Projects

Development

Successfully merging this pull request may close these issues.

2 participants