feat(electron): mobile-capture auto-run pipeline#203
Merged
Conversation
…asks Desktop half of the mobile-capture → auto-run flow. Mobile companion writes captures into Supabase; CodeFire desktop picks them up, extracts tasks with per-task confidence scores, and (when shipIntent='ship_and_start' and confidence clears the threshold) fires Claude at the task automatically. - v54 migration: shipIntent + autoRunConfidence + autoRunState + autoRunSessionId on taskItems, partial index on the dispatch candidates. Swift v42 mirror. - CaptureIntakeService.extractTasks asks the model for a 0..1 confidence per task; stamps session.shipIntent onto every created task. - New AutoRunDispatcher: polls eligible tasks, spawns ClaudeAgentSession in autoEdits mode, persists the transcript to a chatConversations thread so the run is resumable from AgentChat. - Pause/resume handshake: approval-gate fires → autoRunState= 'paused_for_human', synthetic system message logged in the thread, Kanban Resume button reopens the project window + AgentChat thread. - 'shipped' added to CaptureStatus. - New ConfigStore keys autoRunEnabled (default false) + autoRunConfidenceThreshold (default 0.8) — auto-run is opt-in. - Dev-only capture:devSeedSession IPC + DevSeedPanel in CapturesView for testing without the mobile companion (gated by app.isPackaged + DEV). - "Ship & start" / "Create only" chips on CapturesView; auto-run state badges (Running, Resume, Auto-ran, Retry) on Kanban cards. - .codefire/ added to .gitignore for the seed harness fixtures. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e + CAPTURE pill Four issues found while testing the auto-run pipeline against a real mobile capture (task #800): 1. Kanban not refreshing on auto-run state transitions. Dispatcher only emitted the custom `tasks:autoRunChanged` event; the renderer's useTasks hook subscribes to `tasks:updated`. broadcastTaskChanged now emits both. 2. Idle agents stranded as 'running'. Claude's -p streaming subprocess sits at phase=ready between turns, so an agent that finishes its wrap-up message never emits phase=ended. Dispatcher now schedules a 15s idle-completion timer on every phase=ready event; cleared by any new message or status event, fires finishRun(completed) on expiry. 3. Bypass-mode option for fully autonomous runs. New autoRunPermissionMode config key (default 'autoEdits', alternative 'bypass'). autoEdits keeps Bash gated by the approval server (which triggers pause-for-human); bypass skips approval entirely so tasks needing shell can complete without intervention. Trade-off documented in the runbook note. 4. "CAPTURE" source pill on Kanban cards. mobile-capture tasks now render an orange CAPTURE badge alongside the priority/labels row so you can see at a glance which tasks came from the phone. Verified end-to-end against capture session 440a319a → task #800: agent ran autonomously in autoEdits mode, wrote CAPTURE_PIPELINE_E2E_TEST.md at repo root with a complete pipeline-stage walkthrough, then sat idle at phase=ready (which is what the idle-completion timer now catches). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…sk #800) This file was created by Claude Code running autonomously as the first real end-to-end test of the mobile-capture → auto-run pipeline. The capture originated on the CodeFire Capture phone app, propagated through Supabase (session 440a319a), got extracted into local task #800, and was auto-dispatched by AutoRunDispatcher running on commit 056f90a. The agent itself wrote the contents, including the pipeline-stage walkthrough and the run metadata header. Kept as a regression marker so future pipeline changes can be diffed against a known-good autonomous run. Safe to delete if it becomes stale. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ain page The home-view CodeFireChat was landing on whichever conversation had the freshest updatedAt — including empty rows created by clicking "+ New Chat" without sending a message — so users saw the "Ask anything" empty state instead of their last real thread. Mirror the project-page AgentChatPanel behavior by skipping empty conversations during auto-select. - chat:listConversations now returns messageCount via a correlated subquery - ChatConversation.messageCount added as optional field - CodeFireChat mount effect picks list.find(c => messageCount > 0), falling back to list[0] when every conversation is empty Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n columns Add bg-[var(--bg-subtle)] to ProjectTaskSummary and all RecentEmails states so Home cards sit on the subtle surface, and lift kanban column .cf-kcolumn-surface to --bg-elevated (hover #2a2a2a) so columns read as elevated above the card surface behind them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
File was a one-shot proof artifact for the mobile-capture -> auto-run pipeline (task #800) and was explicitly marked safe to delete after review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The top-right account icon was always pulling from the remote Supabase avatar_url, ignoring the photo a user uploaded via Settings → Me. Now we read profileAvatarUrl from AppConfig (refreshed on settings:changed) and prefer it over user.avatarUrl across loading, signed-out, and signed-in states. The display name falls back to the local profileName first as well. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PASSIVE checkpoints flush frames into the DB but never shrink the WAL file's on-disk size — SQLite reuses space inside the WAL but the OS file size only ever grows to the high-water mark. After a heavy day of agent activity (session/audit/chat writes), the WAL file ends up pinned at multi-GB even though almost no frames are actually unflushed. Switch the periodic checkpoint to TRUNCATE on a dedicated connection with a short (500ms) busy_timeout. The dedicated connection prevents the short timeout from leaking into the main connection's 30s setting, and bounds main-thread stalls during heavy writes. Interval tightened from 5 min to 1 min so quiet moments are caught sooner. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each Activity row now has two click targets: the avatar/name opens a new UserProfileSheet wired to premium.sendTeamMessage, and the event description opens the matching modal for openable event kinds (tasks → TaskDetailSheet, notes → NoteSheet). Other event types (sessions, commits, reviews, docs, team) stay as plain text. Remote `entity_id`s from activity_events are resolved back to local DB rows via a new SyncEngine.getLocalIdByRemoteId helper exposed as `premium:resolveLocalEntity`, so the modals work for any task/note that has been synced on this device. UserAvatar prefers the locally-set profile avatar/name (Settings → Me) over the remote avatarUrl for the signed-in user, matching the same preference already used by AccountMenu, and reacts to settings:changed so the avatar updates live. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
shipIntent='ship_and_start'and high extractor confidence are now picked up by a newAutoRunDispatcherand run through Claude automatically; everything else (low confidence,create_only, or paused at the agent's approval gate) lands in the Kanban for human review.taskItemsgainsshipIntent,autoRunConfidence,autoRunState,autoRunSessionId(Electron v54 + Swift v42 mirror, partial index for the dispatch query). LocalshipIntentdefaults to'ship_and_start'to mirror the Supabase column.Ship & start/Create onlychips on CapturesView; per-cardRunning/Resume/Auto-ran/Retrybadges on the Kanban;Auto-runpanel in TaskDetailSheet surfacing confidence + state + Resume.in_progress+paused_for_human, the transcript persists to achatConversationsthread, and the Resume button reopens the thread in AgentChat with full context.autoRunEnableddefaults tofalse.autoRunConfidenceThresholddefaults to0.8.capture:devSeedSession+ DevSeedPanel for testing without the mobile companion. Seeds are hand-crafted to never modify existing repo content (fixture file path under.codefire/, gitignored).AccountMenunow prefers the locally-uploadedprofileAvatarUrlfrom Settings → Me over the remote Supabaseavatar_url, so the avatar a user picks actually shows in the top-right corner (and persists through loading/signed-out states).wal_checkpoint(TRUNCATE)on a dedicated connection with a 500 msbusy_timeout(instead ofPASSIVEon the main connection, which by design can only reuse WAL space internally and never shrinks the file on disk). Interval tightened to 60 s so quiet moments are caught sooner. Bounded main-thread stalls (≤500 ms × 1/min) during heavy writes. Companion fix to commit 6f1e38d: that commit reduced what gets written (binary skip rules); this one reduces how much space the WAL keeps reserved afterwards.UserProfileSheet(avatar, name, email + a multiline message box wired to the existingpremium.sendTeamMessage). Task and note event descriptions resolve their remoteentity_idback to a local row via a newpremium:resolveLocalEntityIPC (backed by thesyncStatetable) and openTaskDetailSheet/ a modal-wrappedNoteEditorin place — no navigation away from the feed. The Activity avatar also prefers the locally-set profile photo for the signed-in user, matching the AccountMenu behavior above.Test plan
Runbook is saved in CodeFire (project note: "Runbook: Mobile Capture → Auto-Run Smoke Tests"). High level:
cd electron && npm run dev, open the CodeFire project window, navigate to Captures, confirm the DEV seed panel renders.autoRunEnabled: truein%APPDATA%/CodeFire/codefire-settings.json, restart desktop.Ship + high-conf→ expect task to land in Todo, flip toRunningwithin ~30s, complete with greenAuto-ranbadge in Done. Verify.codefire/autorun-fixtures/seed-<ts>.txtwas created.Ship + ambiguous (should pause)→ expect task to flip toin_progresswith amberResumebadge. Click Resume → AgentChat opens the paused thread with full transcript + the synthetic "[Auto-run paused for human review]" system note. Continue the conversation; verify the agent picks back up.Create only→ expect two tasks land in Todo and the dispatcher never touches them.ship_and_start+ high confidence) auto-runs.failedrow.%APPDATA%\CodeFire\codefire.db-walsize during an hour of typical agent activity — should stay in the low-MB range (oscillating with the 60 s checkpoint), not grow unbounded.messagenotification. Click atask_*row → TaskDetailSheet opens with the local task. Click anote_*row → note modal opens with editable contents. Non-openable events (session/commit/review/doc/team) stay as plain text.Safety
Auto-run is opt-in (
autoRunEnabled: falsedefault). Even when enabled, the dispatcher only runs tasks withsource='mobile-capture'-style confidence (autoRunConfidence IS NOT NULL), so manually-created tasks never auto-run despite the defaultshipIntent. Claude runs inautoEditspermission mode — file edits proceed without approval but Bash + dangerous tools still pause for human input.🤖 Generated with Claude Code