Fix onboarding: reorder flow, fix restart recovery, fix keychain prompts#5973
Conversation
…move Brave/Edge/Vivaldi Replace security CLI with native Security framework for cookie decryption passwords. This ties "Always Allow" to Omi's code signature so it persists across launches. Also removes Brave, Edge, and Vivaldi from the browser list — only Arc and Chrome are checked now. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…emove Brave/Edge/Vivaldi Mirror the GmailReaderService keychain fix for CalendarReaderService. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…estart recovery Move goal question after all permissions so app restarts never skip it. New flow: scan + email → non-restart permissions → web research → screen recording → email insights + goal → complete. Restart recovery is now trivial: only goal + complete remain after restart. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New tool surfaces Gmail/Calendar synthesis results to the onboarding chat AI so it can inform goal suggestions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Set ChatToolExecutor.emailInsightsText and calendarInsightsText when background reading completes so the onboarding AI can access them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR improves the macOS desktop onboarding experience through three focused changes: replacing the Key changes:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant U as User
participant AI as Onboarding AI
participant App as Desktop App
participant KC as Keychain (SecItemCopyMatching)
participant BG as Background Tasks
U->>AI: Step 1 — Name + Language
AI->>App: set_user_preferences + save_knowledge_graph
AI->>App: Step 2 — scan_files (BLOCKING)
App->>BG: Start Gmail reading (async)
App->>BG: Start Calendar reading (async)
AI->>App: save_knowledge_graph (file findings)
AI->>App: Step 3 — check_permission_status
App-->>AI: permission statuses
AI->>App: request_permission(microphone → notifications → accessibility → automation)
AI->>U: Step 4 — Web research (3 searches)
AI->>App: save_knowledge_graph (company/projects)
AI->>App: Step 5 — request_permission(screen_recording)
Note over App: App may restart here
alt App restarts
App->>BG: Re-start Gmail + Calendar reading
AI->>App: get_email_insights (may return "in progress")
else No restart
BG-->>App: emailInsightsText set
BG-->>App: calendarInsightsText set
AI->>App: Step 6 — get_email_insights
App-->>AI: Email + Calendar summaries
end
AI->>U: Step 6 — ask_followup (monthly goal)
U-->>AI: Goal selected
AI->>App: save_knowledge_graph (goal node)
AI->>App: Step 7 — complete_onboarding
App-->>U: Continue to App
Note over KC: Keychain access now uses<br/>SecItemCopyMatching directly<br/>(persistent "Always Allow" per app)
Reviews (1): Last reviewed commit: "fix(desktop): bridge Gmail/Calendar resu..." | Re-trigger Greptile |
| - Call this in Step 4. The background reading starts automatically after file scan — by the time you reach Step 4, it's usually done. | ||
| - Use the results to inform goal and task suggestions in Step 5. |
There was a problem hiding this comment.
Stale step references in tool docs will mislead the LLM
The get_email_insights tool description says "Call this in Step 4" and "Use the results to inform goal and task suggestions in Step 5", but the actual prompt structure places get_email_insights in Step 6 and the monthly goal is also set in Step 6 (not Step 5, which is now Screen Recording). Step 4 is WEB RESEARCH, and Step 5 is SCREEN RECORDING.
The LLM reads the tool docs as a reference guide. If the docs say to call this tool in Step 4 (WEB RESEARCH), the model may invoke get_email_insights during web research instead of waiting for Step 6. This creates conflicting instructions — the step-by-step body says one thing, the tool docs say another.
| - Call this in Step 4. The background reading starts automatically after file scan — by the time you reach Step 4, it's usually done. | |
| - Use the results to inform goal and task suggestions in Step 5. | |
| - Call this in Step 6. The background reading starts automatically after file scan — by the time you reach Step 6, it's usually done. | |
| - Use the results to inform goal and task suggestions in Step 6. |
| } | ||
| } | ||
|
|
||
| /// Return email/calendar insights from background reading | ||
| private static func executeGetEmailInsights() -> String { | ||
| var sections: [String] = [] | ||
|
|
||
| if let email = emailInsightsText, !email.isEmpty { | ||
| sections.append("## Email Insights\n\(email)") | ||
| } | ||
| if let calendar = calendarInsightsText, !calendar.isEmpty { | ||
| sections.append("## Calendar Insights\n\(calendar)") | ||
| } | ||
|
|
||
| if sections.isEmpty { | ||
| return "No email insights available yet. The background reading may still be in progress, or no browser with a Gmail session was found." | ||
| } | ||
|
|
||
| return sections.joined(separator: "\n\n") | ||
| } | ||
|
|
||
| /// Set user preferences (language, name) | ||
| private static func executeSetUserPreferences(_ args: [String: Any]) async -> String { | ||
| var results: [String] = [] |
There was a problem hiding this comment.
get_email_insights may always return "no data" after restart
After an app restart, emailInsightsText and calendarInsightsText are reset to nil (static vars). In OnboardingChatView, startGmailReading() / startCalendarReading() are only triggered once files are found indexed (line ~1331). The RESTART RECOVERY prompt instructs the AI to call get_email_insights as its very first tool call, but background reading is async and may not have completed by then — causing the tool to consistently return "No email insights available yet" immediately after restart.
Since the restart scenario is one of the key improvements this PR advertises, consider adding a short wait/poll or returning a distinct signal (e.g. "Email reading in progress — try again shortly.") so the LLM can optionally retry after the user finishes typing their goal response, rather than silently skipping insights.
…pts (BasedHardware#5973) ## Summary - **Keychain fix**: Replace `security` CLI with `SecItemCopyMatching` for browser cookie access — "Always Allow" now persists across launches. Remove Brave/Edge/Vivaldi, only check Arc + Chrome. - **Onboarding reorder**: Move goal question AFTER all permissions so app restarts never skip it. New flow: scan + email → non-restart permissions → web research → screen recording → email insights + goal → complete. - **`get_email_insights` tool**: New onboarding tool surfaces Gmail/Calendar background reading results to the AI so goal suggestions are informed by email context. - **Restart recovery**: Now trivial — after any restart, only email insights + goal + complete remain. ## Test plan - [ ] Fresh onboarding: verify goal question appears after all permissions - [ ] Verify no repeated keychain password prompts (only Arc/Chrome attempted) - [ ] Grant Screen Recording → app restarts → verify goal is asked after restart - [ ] Verify email insights are surfaced if Gmail session available 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Summary
securityCLI withSecItemCopyMatchingfor browser cookie access — "Always Allow" now persists across launches. Remove Brave/Edge/Vivaldi, only check Arc + Chrome.get_email_insightstool: New onboarding tool surfaces Gmail/Calendar background reading results to the AI so goal suggestions are informed by email context.Test plan
🤖 Generated with Claude Code