refactor: replace as unknown as with type guards#8234
Merged
Conversation
Co-Authored-By: Claude <noreply@anthropic.com>
e6980da to
3773541
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 37735412bf
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Contributor
Author
|
Addressed in #8360 |
noanflaherty
added a commit
that referenced
this pull request
Feb 24, 2026
…cts (#8398) * fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180) Co-authored-by: Claude <noreply@anthropic.com> * fix: use effective base URL for polling and cancel task on dismiss (#8185) Co-authored-by: Claude <noreply@anthropic.com> * fix: derive segment count from manifest in media diagnostics (#8187) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce payload size limit on pairing proxy endpoints (#8188) Co-authored-by: Claude <noreply@anthropic.com> * fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: approved devices race condition and optimistic clear (#8190) Co-authored-by: Claude <noreply@anthropic.com> * fix: move zero-frame check before atomic rename in preprocess (#8191) Co-authored-by: Claude <noreply@anthropic.com> * fix: include context field in map cache config hash (#8192) Co-authored-by: Claude <noreply@anthropic.com> * fix: align lastPairedAt type to Int matching generated IPC types (#8193) Co-authored-by: Claude <noreply@anthropic.com> * improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194) Rewrite the Google OAuth setup skill prompts to feel like 3 user actions instead of a confusing 10-step process. Auto-detect sign-in completion by polling browser snapshots instead of asking users to confirm manually. Add progress callouts and clearer credential entry instructions. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195) Co-authored-by: Claude <noreply@anthropic.com> * fix: send deny on PairingApprovalWindow close and supersede (#8196) When the pairing approval window is closed via the X button or superseded by a new request, sends a deny response to the daemon. Prevents iOS devices from hanging in pending state indefinitely. - Track currentPairingRequestId and responseSent flag - Add WindowCloseDelegate (NSWindowDelegate) for X-button close - denyIfNeeded() sends deny for unanswered requests in close() - Set responseSent = true in onDecision before calling close() Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: clear stale pairing overrides during v4 migration (#8197) Co-authored-by: Claude <noreply@anthropic.com> * fix: re-register QR pairing before TTL and handle missing daemon (#8199) Adds a timer to re-register the pairing request before the 5-minute TTL expires, keeping the QR code valid while the sheet is open. Also shows an error when daemon client is unavailable instead of rendering an empty sheet. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: honor task cancellation in QRPairingSheet pairing flow (#8210) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce Content-Length pre-check in pairing proxy (#8212) Co-authored-by: Claude <noreply@anthropic.com> * fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: reduce maxTokens default from 64000 to 16000 (#8217) Co-authored-by: Claude <noreply@anthropic.com> * feat: add streamThinking config flag and filter thinking deltas (#8219) Co-authored-by: Claude <noreply@anthropic.com> * fix: skip deny on same-ID retry in PairingApprovalWindow (#8223) Co-authored-by: Claude <noreply@anthropic.com> * fix: update maxTokens schema default and tests to 16000 (#8224) Co-authored-by: Claude <noreply@anthropic.com> * fix: separate iOS override migration and guard macOS cleanup (#8225) iOS: moves override cleanup into its own migratePairingOverridesIfNeeded() with a separate migration key, so existing v4-migrated users still get cleanup. macOS: only runs cleanup when legacy iosPairingUseOverride key is actually present, preserving intentional post-M9 overrides. Addresses feedback from PR #8197. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: avoid QR flicker during refresh and register on daemon connect (#8227) Keeps old QR visible during re-registration by only swapping credentials atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger registration when daemon becomes available after sheet opens. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle floating promise and add timeout in title generation (#8228) Co-authored-by: Claude <noreply@anthropic.com> * refactor: deduplicate isPlainObject into shared utility (#8229) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on memorySegments table (#8230) Co-authored-by: Claude <noreply@anthropic.com> * feat: add backpressure and metrics to session message queue (#8231) Co-authored-by: Claude <noreply@anthropic.com> * perf: cache shell-parsing and risk classification results (#8232) Co-authored-by: Claude <noreply@anthropic.com> * security: add pino log serializer to scrub sensitive data (#8233) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace unsafe type assertions with proper type guards (#8234) Co-authored-by: Claude <noreply@anthropic.com> * feat: add circuit breaker to gateway runtime client (#8236) Co-authored-by: Claude <noreply@anthropic.com> * refactor: create centralized environment variable registry (#8235) Co-authored-by: Claude <noreply@anthropic.com> * feat: add status indication to macOS menu bar icon (#8237) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace any types with proper interfaces in test files (#8241) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove iosPairingUseOverride deletion from v4 migration (#8239) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240) Porcupine's SPM package is iOS-only and pulls in ios-voice-processor which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now strict about this. The wake word engine is currently a stub so removing the dep is safe. Also fixes missing VellumAssistantShared imports and a stale protocol conformance in the wake word files. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add database indexes on memoryItems table (#8244) Co-authored-by: Claude <noreply@anthropic.com> * fix: add per-surface serialization to prevent race conditions (#8245) Co-authored-by: Claude <noreply@anthropic.com> * feat: source filter for Available Skills + platform catalog API (#8097) * feat: add source filter to Available Skills and fetch catalog from platform API - Add All/Vellum/Community source filter pills to Available Skills tab - Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter - Show Vellum catalog skills even if installed (with "Installed" label) - Add refresh button to Installed tab empty state - Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/) - Pass platform session token (X-Session-Token) through IPC for authenticated fetch - Regenerate IPC contract with optional sessionToken on SkillsSearchRequest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve platform token locally and fetch skill content via tar API - Remove sessionToken from IPC contract and Swift chain; the daemon now reads the platform API token from ~/.vellum/platform-token instead of receiving it via IPC messages - SessionTokenManager writes platform token to disk when set/deleted so the daemon can read it for authenticated platform API calls - Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/) which returns a tar.gz archive; extracts SKILL.md from the tarball with bundled fallback on failure - Add readPlatformToken()/getPlatformTokenPath() to platform.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add AbortSignal support to tool implementations (#8246) Co-authored-by: Claude <noreply@anthropic.com> * refactor: split http-server.ts into focused middleware and route modules (#8243) Co-authored-by: Claude <noreply@anthropic.com> * fix: handle QR refresh failure and remove dead onChange (#8248) Shows error state after 2 consecutive refresh registration failures instead of silently leaving a stale QR. Removes dead .onChange(of: daemonClient != nil) since daemonClient is always non-nil in production. Addresses feedback from PR #8227. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249) * security: enforce 0o600 permissions on log files (#8252) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate AbortSignal through permission checking (#8253) Co-authored-by: Claude <noreply@anthropic.com> * feat: complete ingress config schema with validation (#8254) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on remaining tables (#8255) Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add secret dev mode toggle (#8226) * feat(macos): add secret dev mode toggle via Assistant ID tap gesture Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode, similar to Android's developer options. Dev mode gates the Feature Flags editor, Developer (env vars) section, and Platform URL in Connect tab. State persists in UserDefaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: default dev mode to enabled in DEBUG builds Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds start with dev mode on, while still respecting an explicit toggle-off. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset refresh timer and failure counter on QR retry (#8257) Resets consecutiveRefreshFailures to 0 and restarts the refresh timer when the user clicks Retry after a QR refresh failure. Without this, the QR would silently expire after 5 minutes and the next single failure would immediately re-trigger the error state. Addresses feedback from PR #8248. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * refactor: split lifecycle.ts into focused modules (#8259) Co-authored-by: Claude <noreply@anthropic.com> * feat: make global hotkey configurable in macOS client (#8258) Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic re-registration. Defaults to Cmd+Shift+G. * feat: add structured error serialization to pino logger (#8260) Co-authored-by: Claude <noreply@anthropic.com> * fix: add numeric bounds validation for memory item confidence/importance (#8261) Co-authored-by: Claude <noreply@anthropic.com> * feat: make hardcoded daemon timeout values configurable (#8265) Co-authored-by: Claude <noreply@anthropic.com> * feat: add Zod schema for message metadata validation (#8268) Co-authored-by: Claude <noreply@anthropic.com> * refactor: separate migration code from platform utilities (#8272) Co-authored-by: Claude <noreply@anthropic.com> * refactor: use consistent pino logging throughout migration and startup code (#8273) Co-authored-by: Claude <noreply@anthropic.com> * fix: resolve all CI type-check and lint errors (#8276) - Add missing streamThinking to ThinkingConfigSchema default and test assertions - Fix boolean | undefined return type in contradiction-checker transaction - Wrap media-processing stage handlers to return Promise<void> - Cast Cron through unknown for Record<string, unknown> conversion - Update AgentLoopRun type to accept CheckpointInfo parameter - Add withSurface to ToolSetupContext test stubs - Add sessionId to ToolContext test stubs - Cast input_schema to typed interface for property access in tests - Fix fetch mock casts through unknown for Bun's preconnect property - Remove unused imports/vars and fix lint violations across 14 files Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add health check indicator to Platform URL row (#8271) * feat(macos): add health check indicator to Platform URL row Show a dynamic status icon on the Platform URL row in Settings > Connect that indicates whether the Vellum platform is reachable. Hits /healthz on appear and displays green checkmark (reachable), red xmark (unreachable), or spinner (checking). Error details shown on hover via tooltip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate platform health check on dev mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277) * Guardian Cross-Channel Approval UX Polish (#8208) * M1: Backend generative guardian copy + emoji title (#8117) * feat: replace static guardian thread copy with model-generated copy Co-Authored-By: Claude <noreply@anthropic.com> * fix: avoid blocking external channel dispatch on LLM copy generation (#8122) Co-authored-by: Claude <noreply@anthropic.com> * fix: create macOS delivery row before awaiting LLM copy generation (#8127) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: macOS native notification + deep link to thread (#8147) * feat: add macOS native notification + deep link for guardian requests Co-Authored-By: Claude <noreply@anthropic.com> * fix: add questionText to guardian IPC message for notification body (#8162) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: QA hardening + documentation (#8179) * test: add guardian copy generation tests and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * test: add dedicated test for real buildFallbackCopy implementation (#8198) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Fix: reject non-emoji guardian titles from model output (#8247) * fix: validate emoji prefix in generated guardian title Co-Authored-By: Claude <noreply@anthropic.com> * fix: only reject old Guardian question prefix, don't enforce emoji (#8251) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistant inbox feature flag gating from desktop UI (#8281) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox config schema and defaults (#8282) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add rule for agents to keep AGENTS.md up to date (#8284) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: update inbox docs to reflect always-on behavior (#8293) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: change private to internal for properties accessed from AppDelegate extension (#8294) connectionStatusCancellable, pulseTimer, and pulsePhase are accessed from AppDelegate+MenuBar.swift, which is a separate file. Private restricts access to the declaring file, so these need internal access. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: increase maxInputTokens from 180k to 200k (#8295) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve CI type-check and lint errors in ingress config and imports (#8296) Co-authored-by: Claude <noreply@anthropic.com> * fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove QuickChat feature (#8300) The QuickChat floating panel had an unfixable input focus bug — the NSPanel couldn't reliably receive keyboard input. Remove the entire feature: panel, view, hotkey monitors, notification category, settings shortcut, and background session helpers. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove stale relayPort from storage when port field is cleared (#8301) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): use consistent paragraph style for placeholder height measurement (#8303) Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): resolve CI build errors in settings views (#8306) - Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles in release builds (already gated by dev mode at runtime) - Use explicit .some(true)/.some(false)/.none patterns in SettingsConnectTab switch statements to satisfy exhaustiveness checker Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: make error message bubbles span full chat width (#8312) Error bubbles were constrained to the same 520pt maxWidth as regular messages. Use .infinity for error messages so they fill the available chat area. Co-authored-by: Claude <noreply@anthropic.com> * feat: add Quick Input bar (Cmd+/) (#8309) * feat: add Quick Input bar (Cmd+/) for fast new thread creation Adds a floating Spotlight-style input bar that appears system-wide via Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it opens the main window with a new thread containing that message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit - Track and remove Carbon event handler on teardown to prevent accumulation - Place Quick Input panel on the screen with the mouse cursor - Skip restoring previous app on submit so main window doesn't flash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: don't restore previous app on resign-key dismissal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(lint): resolve lint errors in influencer client (#8316) - Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast - Change InfluencerProfile nullable fields from `| null` to `| undefined` - Update parseFollowerCount return type from `number | null` to `number | undefined` - Replace all `!== null` checks with `!== undefined` per project convention Co-authored-by: Claude <noreply@anthropic.com> * feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318) Co-authored-by: Claude <noreply@anthropic.com> * feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320) Co-authored-by: Claude <noreply@anthropic.com> * feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321) Co-authored-by: Claude <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing (#8322) The daemon's HTTP server (port 7821) is required for iOS pairing — the gateway proxies all iOS traffic through it. Previously this was gated behind the `localHttpEnabled` feature flag, so the daemon never started its HTTP server unless the flag was manually enabled via env var, causing HTTP 502 errors on iOS after QR pairing. Three fixes: - AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate) - AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate) - CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list (the CLI was building a second minimal env and stripping it out) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323) Co-authored-by: Claude <noreply@anthropic.com> * feat: add wake word keyword selection and fix APIKeyManager usage (#8324) Co-authored-by: Claude <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325) * fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need internal access — private restricts to the declaring file. Also wrap registration error strings in a proper Error-conforming type since Result requires its Failure type to conform to Error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway - Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT env var, then default 7821, when daemonClient.httpPort is nil (happens when daemon HTTP server starts after socket connection during Qdrant timeout) - Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway is configured, enabling LAN-only pairing - Update canGenerateQR, registration body, and QR payload to use effectiveGatewayUrl instead of gatewayUrl - Update hasGateway check to include LAN availability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var, which relied on a fragile setenv → getenv → subprocess forwarding chain from the macOS app. ProcessInfo.processInfo.environment is a frozen snapshot from launch, so the env var often wasn't forwarded, causing the HTTP server to never start and iOS pairing requests to fail silently. Three fixes: - getRuntimeHttpPort() now defaults to 7821, so the HTTP server always starts regardless of env var forwarding - Wire setPairingBroadcast so pairing_approval_request IPC messages actually reach the macOS app - Remove conditional guard around HTTP server startup in lifecycle.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): add loading state during token regeneration Show a spinner and disable the QR button while the daemon restarts after bearer token regeneration. Polls the healthz endpoint for up to 30s to avoid showing a dead-end "daemon unreachable" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel Two issues caused the macOS app to disconnect from the daemon after ~1 second and never reconnect: 1. DaemonConnection configured NWProtocolTCP.Options() on a Unix domain socket endpoint. Unix sockets don't use TCP — the invalid protocol stack caused the NWConnection to become unstable and disconnect shortly after connecting, before authentication could complete. 2. The .cancelled state handler didn't call scheduleReconnect() when the connection had already been established (resumed==true). This meant spontaneous disconnects were permanent — unlike .failed which properly triggers auto-reconnect. Without a stable IPC connection, all daemon broadcasts (pairing approval requests, reminders, schedule events, watcher alerts) were silently dropped because there were 0 authenticated sockets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326) Co-authored-by: Claude <noreply@anthropic.com> * fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328) Co-authored-by: Claude <noreply@anthropic.com> * fix: add input validation and handle cleanup in PorcupineBinding (#8327) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent double dismiss of Quick Input panel on submit (#8315) Add isDismissing guard to prevent re-entrant dismiss calls when showMainWindow causes the panel to resign key while the onSubmit closure also calls dismiss explicitly. Co-authored-by: Claude <noreply@anthropic.com> * Release v0.3.6 (#8329) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: move wake word callback outside lock and use dynamic frame length (#8331) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332) Co-authored-by: Claude <noreply@anthropic.com> * perf: disable LLM reranking for memory recall (#8067) LLM reranking was calling Claude Haiku API on every message to re-score memory candidates, adding ~2.2s latency. The RRF merge already produces a well-ordered list from lexical, semantic, recency, and entity scores. Disabling reranking reduces memory recall from ~2.6s to ~700ms. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340) The previous commit removed NWProtocolTCP.Options() from Unix socket connections, but this protocol has been in use since the original IPC implementation (PR #499) and has been working in production for years. Removing it risks breaking IPC in the v0.3.7 release. Restores the TCP protocol stack while keeping the .cancelled state reconnect improvement (scheduleReconnect on post-connection cancel). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self. for property captures in PorcupineWakeWordEngine (#8337) Swift strict concurrency requires explicit `self.` when referencing properties inside closures. os.Logger string interpolation creates implicit closures, so `keyword` and `sensitivity` need `self.` prefix. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self for keyword reference in os.Logger closure (#8342) The release build (universal binary) requires explicit `self.` for property references inside os.Logger string interpolation closures. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve CI failures blocking v0.3.7 release (#8344) - TypeScript: fix setPairingBroadcast type to use ServerMessage instead of loose { type: string; [key: string]: unknown } - Gateway lint: prefix unused vars with _ in whatsapp-deliver test - Swift: add explicit self. for keyword property in closure Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: broadcast pairing approval to HTTP/SSE clients (#8348) When the macOS app uses HTTP transport (localHttpEnabled flag), it connects via SSE instead of the Unix domain socket. Pairing approval requests were only broadcast to IPC socket clients, so HTTP-connected clients never received them. Two changes: 1. RuntimeHttpServer now also publishes pairing events to the AssistantEventHub with assistantId 'self' so SSE subscribers receive them. 2. AssistantEventHub allows events without sessionId (system events) to pass through to all subscribers regardless of their sessionId filter. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * M1: Add Voice -> Run/Session Bridge (#8222) * feat: add voice -> run/session bridge with streaming event sink and cancellation Co-Authored-By: Claude <noreply@anthropic.com> * fix: scope run abort handles to originating run to prevent stale cancellation (#8238) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: Replace CallOrchestrator with Session-Backed Voice Controller (#8275) * feat: replace CallOrchestrator with session-backed CallController for voice turns Co-Authored-By: Claude <noreply@anthropic.com> * Fix: Resolve voice turn promise on abort/exception (#8280) * fix: resolve voice turn promise on abort and agent-loop exceptions Co-Authored-By: Claude <noreply@anthropic.com> * fix: increment llmRunVersion in destroy() to prevent post-turn side effects on destroyed controller (#8290) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: Guardian Context and Side-Effect Policy Parity (#8299) * feat: enforce guardian context and strict side-effect policy parity for voice turns Co-Authored-By: Claude <noreply@anthropic.com> * fix: auto-deny tool confirmations for non-guardian voice turns to prevent 300s timeout (#8302) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M4: Clean Up Legacy Orchestrator Artifacts + Docs (#8304) * chore: clean up legacy call orchestrator artifacts and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * fix: fix stale Orch participant and duplicate Session declaration in ARCHITECTURE.md Mermaid diagrams (#8307) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * fix: address final PR review feedback — move bridge injection, fix opener marker persistence, remove duplicate user message persist Co-Authored-By: Claude <noreply@anthropic.com> * feat(macos): add Restart menu item to status bar menu (#8347) * feat(macos): add Restart menu item to status bar menu Add a Restart option to the menu bar dropdown that stops the daemon, launches a fresh app instance, and terminates the current one. Useful for recovering from stuck states without manually quitting and relaunching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate app termination on successful relaunch in performRestart Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add memory degradation banner to component gallery with #F5F3EB background (#8356) Co-authored-by: Claude <noreply@anthropic.com> * Add rename option to thread right-click context menu (#8351) * M1: Add session_rename IPC message to daemon (#8338) * feat: add session_rename IPC message for client-initiated title changes Co-Authored-By: Claude <noreply@anthropic.com> * fix: validate conversation exists before renaming in handleSessionRename (#8341) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * M2: Add rename option to macOS thread context menu UI (#8346) * feat: add rename option to macOS thread context menu Co-Authored-By: Claude <noreply@anthropic.com> * fix: only show rename option for threads with a daemon session (#8350) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant conversation_id index on memory_segments (#8357) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove unscoped queue-full error and guard expireStale against exceptions (#8358) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve statusCode fallback when status is undefined in getErrorStatusCode (#8360) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve Error name/message/stack in log redaction serializer (#8359) Co-authored-by: Claude <noreply@anthropic.com> * fix: include workingDir and manifestOverride in risk cache key (#8361) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant fingerprint index from memoryItems migration (#8362) Co-authored-by: Claude <noreply@anthropic.com> * fix: add missing legitimate env vars to KNOWN_VELLUM_VARS (#8363) Co-authored-by: Claude <noreply@anthropic.com> * fix: clean up settled surface mutex entries to prevent memory leak (#8364) Co-authored-by: Claude <noreply@anthropic.com> * fix: return immediately on aborted CAPTCHA wait instead of breaking (#8365) Co-authored-by: Claude <noreply@anthropic.com> * fix: rebind menu bar connection observer after client replacement and fix pulse animation (#8366) Co-authored-by: Claude <noreply@anthropic.com> * fix: limit half-open probes to single attempt and propagate CircuitBreakerOpenError (#8367) Co-authored-by: Claude <noreply@anthropic.com> * fix: read daemon timeouts without triggering loadConfig/migration side effects (#8368) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce log file permissions on existing files at startup (#8371) Co-authored-by: Claude <noreply@anthropic.com> * fix: auto-start SSE on HTTP transport connect for system events (#8370) When using HTTP transport (VELLUM_FLAG_LOCAL_HTTP_ENABLED=1), SSE was only started when MainWindowView.onAppear fired. This meant system events like pairing approval requests were lost if they arrived before the main window appeared. Auto-start the SSE stream immediately after the first health check passes in connect(). MainWindowView.onAppear still calls startSSE() but it's a no-op when the stream is already running. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: throw typed cancellation error from permission checks (#8372) Co-authored-by: Claude <noreply@anthropic.com> * feat: add pre-commit warning when modifying system-prompt.ts (#8354) * feat: add pre-commit warning when modifying system-prompt.ts Adds a non-blocking warning to the pre-commit hook that fires when system-prompt.ts is staged. Reminds contributors to consider whether their change belongs in a skill, IDENTITY.md, SOUL.md, USER.md, LOOKS.md, or skills/ instead of directly in the system prompt. Includes a 3-second pause to ensure the warning is actually read. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add BOOTSTRAP.md to system-prompt warning file list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Release v0.3.7 (#8373) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: initialize pairing handlers so approval responses are processed (#8374) initPairingHandlers() was defined but never called, leaving pairingStoreRef as null. When macOS sent a pairing_approval_response over IPC, the handler silently returned on the null check (line 29), so approvals never reached the PairingStore — iOS stayed stuck on "Waiting for approval" and the device was never added to the allowlist. Wire up initPairingHandlers() in lifecycle.ts after the HTTP server starts, passing the PairingStore instance and bearer token. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: inject call-control prompt + await barge-in teardown Co-Authored-By: Claude <noreply@anthropic.com> * feat: improve media analysis skill defaults and add best practices (#8385) Update defaults based on real-world usage feedback: keyframe interval 3s→1s, segment duration 20s→15s, skip_dead_time on→off. Add best practices section with broad-vs-targeted map prompt guidance, sample prompt/schema, clip delivery notes, and vision analysis limitations. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: unconditional teardown await + bump run version before barge-in Co-Authored-By: Claude <noreply@anthropic.com> * feat: add holistic Codex review phase to safe-blitz command (#8387) Co-authored-by: Claude <noreply@anthropic.com> * fix: watch http-token file so gateway picks up daemon token changes (#8389) When the daemon restarts and writes a new bearer token to ~/.vellum/http-token, a gateway process that started earlier still holds the stale token. This causes 401 errors for iOS clients that received the new token during pairing. Add a file watcher for http-token (following the existing CredentialWatcher pattern) that refreshes runtimeBearerToken, runtimeProxyBearerToken, and runtimeGatewayOriginSecret in the live config when the file changes. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: drop legacy conversation_id index and remove from Drizzle schema (#8393) Co-authored-by: Claude <noreply@anthropic.com> * fix: unreserve dedup cache entries on CircuitBreakerOpenError before returning 503 (#8394) Co-authored-by: Claude <noreply@anthropic.com> * fix: validate daemon timeout bounds in readDaemonTimeouts (#8395) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate queue-full status through subagent message path (#8397) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Alex Nork <48630278+alex-nork@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ashlee Radka <ashleeradka@gmail.com> Co-authored-by: asharma53 <64060709+asharma53@users.noreply.github.com> Co-authored-by: siddseethepalli <siddseethepalli@gmail.com> Co-authored-by: David Vargas Fuertes <vargas@vellum.ai> Co-authored-by: NgoHarrison <harrison.ngo719@gmail.com> Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Aaron Levin <awlevin@users.noreply.github.com> Co-authored-by: V <vincent@vellum.ai> Co-authored-by: Marina Trajkovska <trajk.marina@gmail.com> Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: vellum-automation[bot] <192048195+vellum-automation[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jason Zhou <jason@vellum.ai> Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Tirman Sidhu <tirmansidhu@gmail.com> Co-authored-by: Nick <127171085+ZeebBoyBlue@users.noreply.github.com> Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
noanflaherty
added a commit
that referenced
this pull request
Feb 24, 2026
* fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180) Co-authored-by: Claude <noreply@anthropic.com> * fix: use effective base URL for polling and cancel task on dismiss (#8185) Co-authored-by: Claude <noreply@anthropic.com> * fix: derive segment count from manifest in media diagnostics (#8187) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce payload size limit on pairing proxy endpoints (#8188) Co-authored-by: Claude <noreply@anthropic.com> * fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: approved devices race condition and optimistic clear (#8190) Co-authored-by: Claude <noreply@anthropic.com> * fix: move zero-frame check before atomic rename in preprocess (#8191) Co-authored-by: Claude <noreply@anthropic.com> * fix: include context field in map cache config hash (#8192) Co-authored-by: Claude <noreply@anthropic.com> * fix: align lastPairedAt type to Int matching generated IPC types (#8193) Co-authored-by: Claude <noreply@anthropic.com> * improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194) Rewrite the Google OAuth setup skill prompts to feel like 3 user actions instead of a confusing 10-step process. Auto-detect sign-in completion by polling browser snapshots instead of asking users to confirm manually. Add progress callouts and clearer credential entry instructions. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195) Co-authored-by: Claude <noreply@anthropic.com> * fix: send deny on PairingApprovalWindow close and supersede (#8196) When the pairing approval window is closed via the X button or superseded by a new request, sends a deny response to the daemon. Prevents iOS devices from hanging in pending state indefinitely. - Track currentPairingRequestId and responseSent flag - Add WindowCloseDelegate (NSWindowDelegate) for X-button close - denyIfNeeded() sends deny for unanswered requests in close() - Set responseSent = true in onDecision before calling close() Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: clear stale pairing overrides during v4 migration (#8197) Co-authored-by: Claude <noreply@anthropic.com> * fix: re-register QR pairing before TTL and handle missing daemon (#8199) Adds a timer to re-register the pairing request before the 5-minute TTL expires, keeping the QR code valid while the sheet is open. Also shows an error when daemon client is unavailable instead of rendering an empty sheet. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: honor task cancellation in QRPairingSheet pairing flow (#8210) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce Content-Length pre-check in pairing proxy (#8212) Co-authored-by: Claude <noreply@anthropic.com> * fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: reduce maxTokens default from 64000 to 16000 (#8217) Co-authored-by: Claude <noreply@anthropic.com> * feat: add streamThinking config flag and filter thinking deltas (#8219) Co-authored-by: Claude <noreply@anthropic.com> * fix: skip deny on same-ID retry in PairingApprovalWindow (#8223) Co-authored-by: Claude <noreply@anthropic.com> * fix: update maxTokens schema default and tests to 16000 (#8224) Co-authored-by: Claude <noreply@anthropic.com> * fix: separate iOS override migration and guard macOS cleanup (#8225) iOS: moves override cleanup into its own migratePairingOverridesIfNeeded() with a separate migration key, so existing v4-migrated users still get cleanup. macOS: only runs cleanup when legacy iosPairingUseOverride key is actually present, preserving intentional post-M9 overrides. Addresses feedback from PR #8197. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: avoid QR flicker during refresh and register on daemon connect (#8227) Keeps old QR visible during re-registration by only swapping credentials atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger registration when daemon becomes available after sheet opens. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle floating promise and add timeout in title generation (#8228) Co-authored-by: Claude <noreply@anthropic.com> * refactor: deduplicate isPlainObject into shared utility (#8229) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on memorySegments table (#8230) Co-authored-by: Claude <noreply@anthropic.com> * feat: add backpressure and metrics to session message queue (#8231) Co-authored-by: Claude <noreply@anthropic.com> * perf: cache shell-parsing and risk classification results (#8232) Co-authored-by: Claude <noreply@anthropic.com> * security: add pino log serializer to scrub sensitive data (#8233) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace unsafe type assertions with proper type guards (#8234) Co-authored-by: Claude <noreply@anthropic.com> * feat: add circuit breaker to gateway runtime client (#8236) Co-authored-by: Claude <noreply@anthropic.com> * refactor: create centralized environment variable registry (#8235) Co-authored-by: Claude <noreply@anthropic.com> * feat: add status indication to macOS menu bar icon (#8237) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace any types with proper interfaces in test files (#8241) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove iosPairingUseOverride deletion from v4 migration (#8239) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240) Porcupine's SPM package is iOS-only and pulls in ios-voice-processor which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now strict about this. The wake word engine is currently a stub so removing the dep is safe. Also fixes missing VellumAssistantShared imports and a stale protocol conformance in the wake word files. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add database indexes on memoryItems table (#8244) Co-authored-by: Claude <noreply@anthropic.com> * fix: add per-surface serialization to prevent race conditions (#8245) Co-authored-by: Claude <noreply@anthropic.com> * feat: source filter for Available Skills + platform catalog API (#8097) * feat: add source filter to Available Skills and fetch catalog from platform API - Add All/Vellum/Community source filter pills to Available Skills tab - Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter - Show Vellum catalog skills even if installed (with "Installed" label) - Add refresh button to Installed tab empty state - Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/) - Pass platform session token (X-Session-Token) through IPC for authenticated fetch - Regenerate IPC contract with optional sessionToken on SkillsSearchRequest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve platform token locally and fetch skill content via tar API - Remove sessionToken from IPC contract and Swift chain; the daemon now reads the platform API token from ~/.vellum/platform-token instead of receiving it via IPC messages - SessionTokenManager writes platform token to disk when set/deleted so the daemon can read it for authenticated platform API calls - Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/) which returns a tar.gz archive; extracts SKILL.md from the tarball with bundled fallback on failure - Add readPlatformToken()/getPlatformTokenPath() to platform.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add AbortSignal support to tool implementations (#8246) Co-authored-by: Claude <noreply@anthropic.com> * refactor: split http-server.ts into focused middleware and route modules (#8243) Co-authored-by: Claude <noreply@anthropic.com> * fix: handle QR refresh failure and remove dead onChange (#8248) Shows error state after 2 consecutive refresh registration failures instead of silently leaving a stale QR. Removes dead .onChange(of: daemonClient != nil) since daemonClient is always non-nil in production. Addresses feedback from PR #8227. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249) * security: enforce 0o600 permissions on log files (#8252) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate AbortSignal through permission checking (#8253) Co-authored-by: Claude <noreply@anthropic.com> * feat: complete ingress config schema with validation (#8254) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on remaining tables (#8255) Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add secret dev mode toggle (#8226) * feat(macos): add secret dev mode toggle via Assistant ID tap gesture Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode, similar to Android's developer options. Dev mode gates the Feature Flags editor, Developer (env vars) section, and Platform URL in Connect tab. State persists in UserDefaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: default dev mode to enabled in DEBUG builds Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds start with dev mode on, while still respecting an explicit toggle-off. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset refresh timer and failure counter on QR retry (#8257) Resets consecutiveRefreshFailures to 0 and restarts the refresh timer when the user clicks Retry after a QR refresh failure. Without this, the QR would silently expire after 5 minutes and the next single failure would immediately re-trigger the error state. Addresses feedback from PR #8248. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * refactor: split lifecycle.ts into focused modules (#8259) Co-authored-by: Claude <noreply@anthropic.com> * feat: make global hotkey configurable in macOS client (#8258) Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic re-registration. Defaults to Cmd+Shift+G. * feat: add structured error serialization to pino logger (#8260) Co-authored-by: Claude <noreply@anthropic.com> * fix: add numeric bounds validation for memory item confidence/importance (#8261) Co-authored-by: Claude <noreply@anthropic.com> * feat: make hardcoded daemon timeout values configurable (#8265) Co-authored-by: Claude <noreply@anthropic.com> * feat: add Zod schema for message metadata validation (#8268) Co-authored-by: Claude <noreply@anthropic.com> * refactor: separate migration code from platform utilities (#8272) Co-authored-by: Claude <noreply@anthropic.com> * refactor: use consistent pino logging throughout migration and startup code (#8273) Co-authored-by: Claude <noreply@anthropic.com> * fix: resolve all CI type-check and lint errors (#8276) - Add missing streamThinking to ThinkingConfigSchema default and test assertions - Fix boolean | undefined return type in contradiction-checker transaction - Wrap media-processing stage handlers to return Promise<void> - Cast Cron through unknown for Record<string, unknown> conversion - Update AgentLoopRun type to accept CheckpointInfo parameter - Add withSurface to ToolSetupContext test stubs - Add sessionId to ToolContext test stubs - Cast input_schema to typed interface for property access in tests - Fix fetch mock casts through unknown for Bun's preconnect property - Remove unused imports/vars and fix lint violations across 14 files Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add health check indicator to Platform URL row (#8271) * feat(macos): add health check indicator to Platform URL row Show a dynamic status icon on the Platform URL row in Settings > Connect that indicates whether the Vellum platform is reachable. Hits /healthz on appear and displays green checkmark (reachable), red xmark (unreachable), or spinner (checking). Error details shown on hover via tooltip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate platform health check on dev mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277) * Guardian Cross-Channel Approval UX Polish (#8208) * M1: Backend generative guardian copy + emoji title (#8117) * feat: replace static guardian thread copy with model-generated copy Co-Authored-By: Claude <noreply@anthropic.com> * fix: avoid blocking external channel dispatch on LLM copy generation (#8122) Co-authored-by: Claude <noreply@anthropic.com> * fix: create macOS delivery row before awaiting LLM copy generation (#8127) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: macOS native notification + deep link to thread (#8147) * feat: add macOS native notification + deep link for guardian requests Co-Authored-By: Claude <noreply@anthropic.com> * fix: add questionText to guardian IPC message for notification body (#8162) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: QA hardening + documentation (#8179) * test: add guardian copy generation tests and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * test: add dedicated test for real buildFallbackCopy implementation (#8198) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Fix: reject non-emoji guardian titles from model output (#8247) * fix: validate emoji prefix in generated guardian title Co-Authored-By: Claude <noreply@anthropic.com> * fix: only reject old Guardian question prefix, don't enforce emoji (#8251) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistant inbox feature flag gating from desktop UI (#8281) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox config schema and defaults (#8282) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add rule for agents to keep AGENTS.md up to date (#8284) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: update inbox docs to reflect always-on behavior (#8293) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: change private to internal for properties accessed from AppDelegate extension (#8294) connectionStatusCancellable, pulseTimer, and pulsePhase are accessed from AppDelegate+MenuBar.swift, which is a separate file. Private restricts access to the declaring file, so these need internal access. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: increase maxInputTokens from 180k to 200k (#8295) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve CI type-check and lint errors in ingress config and imports (#8296) Co-authored-by: Claude <noreply@anthropic.com> * fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove QuickChat feature (#8300) The QuickChat floating panel had an unfixable input focus bug — the NSPanel couldn't reliably receive keyboard input. Remove the entire feature: panel, view, hotkey monitors, notification category, settings shortcut, and background session helpers. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove stale relayPort from storage when port field is cleared (#8301) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): use consistent paragraph style for placeholder height measurement (#8303) Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): resolve CI build errors in settings views (#8306) - Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles in release builds (already gated by dev mode at runtime) - Use explicit .some(true)/.some(false)/.none patterns in SettingsConnectTab switch statements to satisfy exhaustiveness checker Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: make error message bubbles span full chat width (#8312) Error bubbles were constrained to the same 520pt maxWidth as regular messages. Use .infinity for error messages so they fill the available chat area. Co-authored-by: Claude <noreply@anthropic.com> * feat: add Quick Input bar (Cmd+/) (#8309) * feat: add Quick Input bar (Cmd+/) for fast new thread creation Adds a floating Spotlight-style input bar that appears system-wide via Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it opens the main window with a new thread containing that message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit - Track and remove Carbon event handler on teardown to prevent accumulation - Place Quick Input panel on the screen with the mouse cursor - Skip restoring previous app on submit so main window doesn't flash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: don't restore previous app on resign-key dismissal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(lint): resolve lint errors in influencer client (#8316) - Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast - Change InfluencerProfile nullable fields from `| null` to `| undefined` - Update parseFollowerCount return type from `number | null` to `number | undefined` - Replace all `!== null` checks with `!== undefined` per project convention Co-authored-by: Claude <noreply@anthropic.com> * feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318) Co-authored-by: Claude <noreply@anthropic.com> * feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320) Co-authored-by: Claude <noreply@anthropic.com> * feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321) Co-authored-by: Claude <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing (#8322) The daemon's HTTP server (port 7821) is required for iOS pairing — the gateway proxies all iOS traffic through it. Previously this was gated behind the `localHttpEnabled` feature flag, so the daemon never started its HTTP server unless the flag was manually enabled via env var, causing HTTP 502 errors on iOS after QR pairing. Three fixes: - AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate) - AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate) - CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list (the CLI was building a second minimal env and stripping it out) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323) Co-authored-by: Claude <noreply@anthropic.com> * feat: add wake word keyword selection and fix APIKeyManager usage (#8324) Co-authored-by: Claude <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325) * fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need internal access — private restricts to the declaring file. Also wrap registration error strings in a proper Error-conforming type since Result requires its Failure type to conform to Error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway - Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT env var, then default 7821, when daemonClient.httpPort is nil (happens when daemon HTTP server starts after socket connection during Qdrant timeout) - Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway is configured, enabling LAN-only pairing - Update canGenerateQR, registration body, and QR payload to use effectiveGatewayUrl instead of gatewayUrl - Update hasGateway check to include LAN availability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var, which relied on a fragile setenv → getenv → subprocess forwarding chain from the macOS app. ProcessInfo.processInfo.environment is a frozen snapshot from launch, so the env var often wasn't forwarded, causing the HTTP server to never start and iOS pairing requests to fail silently. Three fixes: - getRuntimeHttpPort() now defaults to 7821, so the HTTP server always starts regardless of env var forwarding - Wire setPairingBroadcast so pairing_approval_request IPC messages actually reach the macOS app - Remove conditional guard around HTTP server startup in lifecycle.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): add loading state during token regeneration Show a spinner and disable the QR button while the daemon restarts after bearer token regeneration. Polls the healthz endpoint for up to 30s to avoid showing a dead-end "daemon unreachable" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel Two issues caused the macOS app to disconnect from the daemon after ~1 second and never reconnect: 1. DaemonConnection configured NWProtocolTCP.Options() on a Unix domain socket endpoint. Unix sockets don't use TCP — the invalid protocol stack caused the NWConnection to become unstable and disconnect shortly after connecting, before authentication could complete. 2. The .cancelled state handler didn't call scheduleReconnect() when the connection had already been established (resumed==true). This meant spontaneous disconnects were permanent — unlike .failed which properly triggers auto-reconnect. Without a stable IPC connection, all daemon broadcasts (pairing approval requests, reminders, schedule events, watcher alerts) were silently dropped because there were 0 authenticated sockets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326) Co-authored-by: Claude <noreply@anthropic.com> * fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328) Co-authored-by: Claude <noreply@anthropic.com> * fix: add input validation and handle cleanup in PorcupineBinding (#8327) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent double dismiss of Quick Input panel on submit (#8315) Add isDismissing guard to prevent re-entrant dismiss calls when showMainWindow causes the panel to resign key while the onSubmit closure also calls dismiss explicitly. Co-authored-by: Claude <noreply@anthropic.com> * Release v0.3.6 (#8329) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: move wake word callback outside lock and use dynamic frame length (#8331) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332) Co-authored-by: Claude <noreply@anthropic.com> * perf: disable LLM reranking for memory recall (#8067) LLM reranking was calling Claude Haiku API on every message to re-score memory candidates, adding ~2.2s latency. The RRF merge already produces a well-ordered list from lexical, semantic, recency, and entity scores. Disabling reranking reduces memory recall from ~2.6s to ~700ms. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340) The previous commit removed NWProtocolTCP.Options() from Unix socket connections, but this protocol has been in use since the original IPC implementation (PR #499) and has been working in production for years. Removing it risks breaking IPC in the v0.3.7 release. Restores the TCP protocol stack while keeping the .cancelled state reconnect improvement (scheduleReconnect on post-connection cancel). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self. for property captures in PorcupineWakeWordEngine (#8337) Swift strict concurrency requires explicit `self.` when referencing properties inside closures. os.Logger string interpolation creates implicit closures, so `keyword` and `sensitivity` need `self.` prefix. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self for keyword reference in os.Logger closure (#8342) The release build (universal binary) requires explicit `self.` for property references inside os.Logger string interpolation closures. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve CI failures blocking v0.3.7 release (#8344) - TypeScript: fix setPairingBroadcast type to use ServerMessage instead of loose { type: string; [key: string]: unknown } - Gateway lint: prefix unused vars with _ in whatsapp-deliver test - Swift: add explicit self. for keyword property in closure Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: broadcast pairing approval to HTTP/SSE clients (#8348) When the macOS app uses HTTP transport (localHttpEnabled flag), it connects via SSE instead of the Unix domain socket. Pairing approval requests were only broadcast to IPC socket clients, so HTTP-connected clients never received them. Two changes: 1. RuntimeHttpServer now also publishes pairing events to the AssistantEventHub with assistantId 'self' so SSE subscribers receive them. 2. AssistantEventHub allows events without sessionId (system events) to pass through to all subscribers regardless of their sessionId filter. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat(macos): add Restart menu item to status bar menu (#8347) * feat(macos): add Restart menu item to status bar menu Add a Restart option to the menu bar dropdown that stops the daemon, launches a fresh app instance, and terminates the current one. Useful for recovering from stuck states without manually quitting and relaunching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate app termination on successful relaunch in performRestart Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add memory degradation banner to component gallery with #F5F3EB background (#8356) Co-authored-by: Claude <noreply@anthropic.com> * Add rename option to thread right-click context menu (#8351) * M1: Add session_rename IPC message to daemon (#8338) * feat: add session_rename IPC message for client-initiated title changes Co-Authored-By: Claude <noreply@anthropic.com> * fix: validate conversation exists before renaming in handleSessionRename (#8341) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * M2: Add rename option to macOS thread context menu UI (#8346) * feat: add rename option to macOS thread context menu Co-Authored-By: Claude <noreply@anthropic.com> * fix: only show rename option for threads with a daemon session (#8350) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant conversation_id index on memory_segments (#8357) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove unscoped queue-full error and guard expireStale against exceptions (#8358) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve statusCode fallback when status is undefined in getErrorStatusCode (#8360) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve Error name/message/stack in log redaction serializer (#8359) Co-authored-by: Claude <noreply@anthropic.com> * fix: include workingDir and manifestOverride in risk cache key (#8361) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant fingerprint index from memoryItems migration (#8362) Co-authored-by: Claude <noreply@anthropic.com> * fix: add missing legitimate env vars to KNOWN_VELLUM_VARS (#8363) Co-authored-by: Claude <noreply@anthropic.com> * fix: clean up settled surface mutex entries to prevent memory leak (#8364) Co-authored-by: Claude <noreply@anthropic.com> * fix: return immediately on aborted CAPTCHA wait instead of breaking (#8365) Co-authored-by: Claude <noreply@anthropic.com> * fix: rebind menu bar connection observer after client replacement and fix pulse animation (#8366) Co-authored-by: Claude <noreply@anthropic.com> * fix: limit half-open probes to single attempt and propagate CircuitBreakerOpenError (#8367) Co-authored-by: Claude <noreply@anthropic.com> * fix: read daemon timeouts without triggering loadConfig/migration side effects (#8368) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce log file permissions on existing files at startup (#8371) Co-authored-by: Claude <noreply@anthropic.com> * fix: auto-start SSE on HTTP transport connect for system events (#8370) When using HTTP transport (VELLUM_FLAG_LOCAL_HTTP_ENABLED=1), SSE was only started when MainWindowView.onAppear fired. This meant system events like pairing approval requests were lost if they arrived before the main window appeared. Auto-start the SSE stream immediately after the first health check passes in connect(). MainWindowView.onAppear still calls startSSE() but it's a no-op when the stream is already running. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: throw typed cancellation error from permission checks (#8372) Co-authored-by: Claude <noreply@anthropic.com> * feat: add pre-commit warning when modifying system-prompt.ts (#8354) * feat: add pre-commit warning when modifying system-prompt.ts Adds a non-blocking warning to the pre-commit hook that fires when system-prompt.ts is staged. Reminds contributors to consider whether their change belongs in a skill, IDENTITY.md, SOUL.md, USER.md, LOOKS.md, or skills/ instead of directly in the system prompt. Includes a 3-second pause to ensure the warning is actually read. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add BOOTSTRAP.md to system-prompt warning file list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Release v0.3.7 (#8373) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: initialize pairing handlers so approval responses are processed (#8374) initPairingHandlers() was defined but never called, leaving pairingStoreRef as null. When macOS sent a pairing_approval_response over IPC, the handler silently returned on the null check (line 29), so approvals never reached the PairingStore — iOS stayed stuck on "Waiting for approval" and the device was never added to the allowlist. Wire up initPairingHandlers() in lifecycle.ts after the HTTP server starts, passing the PairingStore instance and bearer token. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: improve media analysis skill defaults and add best practices (#8385) Update defaults based on real-world usage feedback: keyframe interval 3s→1s, segment duration 20s→15s, skip_dead_time on→off. Add best practices section with broad-vs-targeted map prompt guidance, sample prompt/schema, clip delivery notes, and vision analysis limitations. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add holistic Codex review phase to safe-blitz command (#8387) Co-authored-by: Claude <noreply@anthropic.com> * fix: watch http-token file so gateway picks up daemon token changes (#8389) When the daemon restarts and writes a new bearer token to ~/.vellum/http-token, a gateway process that started earlier still holds the stale token. This causes 401 errors for iOS clients that received the new token during pairing. Add a file watcher for http-token (following the existing CredentialWatcher pattern) that refreshes runtimeBearerToken, runtimeProxyBearerToken, and runtimeGatewayOriginSecret in the live config when the file changes. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: drop legacy conversation_id index and remove from Drizzle schema (#8393) Co-authored-by: Claude <noreply@anthropic.com> * fix: unreserve dedup cache entries on CircuitBreakerOpenError before returning 503 (#8394) Co-authored-by: Claude <noreply@anthropic.com> * fix: validate daemon timeout bounds in readDaemonTimeouts (#8395) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate queue-full status through subagent message path (#8397) Co-authored-by: Claude <noreply@anthropic.com> * fix: respect env var precedence in http-token watcher (#8399) Address review feedback on #8389: 1. Skip file-based token refresh when RUNTIME_BEARER_TOKEN env var is set, preserving the same precedence as loadConfig() where env vars override the file. Prevents cloud deployments with pinned tokens from being silently overwritten by daemon file writes. 2. Wrap mkdirSync in try-catch so a non-writable parent directory doesn't crash the gateway at startup — the watcher is gracefully skipped instead. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add queue-if-busy behavior and hub publishing to POST /v1/messages (#8391) (#8400) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Alex Nork <48630278+alex-nork@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ashlee Radka <ashleeradka@gmail.com> Co-authored-by: asharma53 <64060709+asharma53@users.noreply.github.com> Co-authored-by: siddseethepalli <siddseethepalli@gmail.com> Co-authored-by: David Vargas Fuertes <vargas@vellum.ai> Co-authored-by: NgoHarrison <harrison.ngo719@gmail.com> Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Aaron Levin <awlevin@users.noreply.github.com> Co-authored-by: V <vincent@vellum.ai> Co-authored-by: Marina Trajkovska <trajk.marina@gmail.com> Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: vellum-automation[bot] <192048195+vellum-automation[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jason Zhou <jason@vellum.ai> Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Tirman Sidhu <tirmansidhu@gmail.com> Co-authored-by: Nick <127171085+ZeebBoyBlue@users.noreply.github.com> Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
noanflaherty
added a commit
that referenced
this pull request
Feb 24, 2026
…cts (#8398) * fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180) Co-authored-by: Claude <noreply@anthropic.com> * fix: use effective base URL for polling and cancel task on dismiss (#8185) Co-authored-by: Claude <noreply@anthropic.com> * fix: derive segment count from manifest in media diagnostics (#8187) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce payload size limit on pairing proxy endpoints (#8188) Co-authored-by: Claude <noreply@anthropic.com> * fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: approved devices race condition and optimistic clear (#8190) Co-authored-by: Claude <noreply@anthropic.com> * fix: move zero-frame check before atomic rename in preprocess (#8191) Co-authored-by: Claude <noreply@anthropic.com> * fix: include context field in map cache config hash (#8192) Co-authored-by: Claude <noreply@anthropic.com> * fix: align lastPairedAt type to Int matching generated IPC types (#8193) Co-authored-by: Claude <noreply@anthropic.com> * improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194) Rewrite the Google OAuth setup skill prompts to feel like 3 user actions instead of a confusing 10-step process. Auto-detect sign-in completion by polling browser snapshots instead of asking users to confirm manually. Add progress callouts and clearer credential entry instructions. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195) Co-authored-by: Claude <noreply@anthropic.com> * fix: send deny on PairingApprovalWindow close and supersede (#8196) When the pairing approval window is closed via the X button or superseded by a new request, sends a deny response to the daemon. Prevents iOS devices from hanging in pending state indefinitely. - Track currentPairingRequestId and responseSent flag - Add WindowCloseDelegate (NSWindowDelegate) for X-button close - denyIfNeeded() sends deny for unanswered requests in close() - Set responseSent = true in onDecision before calling close() Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: clear stale pairing overrides during v4 migration (#8197) Co-authored-by: Claude <noreply@anthropic.com> * fix: re-register QR pairing before TTL and handle missing daemon (#8199) Adds a timer to re-register the pairing request before the 5-minute TTL expires, keeping the QR code valid while the sheet is open. Also shows an error when daemon client is unavailable instead of rendering an empty sheet. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: honor task cancellation in QRPairingSheet pairing flow (#8210) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce Content-Length pre-check in pairing proxy (#8212) Co-authored-by: Claude <noreply@anthropic.com> * fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: reduce maxTokens default from 64000 to 16000 (#8217) Co-authored-by: Claude <noreply@anthropic.com> * feat: add streamThinking config flag and filter thinking deltas (#8219) Co-authored-by: Claude <noreply@anthropic.com> * fix: skip deny on same-ID retry in PairingApprovalWindow (#8223) Co-authored-by: Claude <noreply@anthropic.com> * fix: update maxTokens schema default and tests to 16000 (#8224) Co-authored-by: Claude <noreply@anthropic.com> * fix: separate iOS override migration and guard macOS cleanup (#8225) iOS: moves override cleanup into its own migratePairingOverridesIfNeeded() with a separate migration key, so existing v4-migrated users still get cleanup. macOS: only runs cleanup when legacy iosPairingUseOverride key is actually present, preserving intentional post-M9 overrides. Addresses feedback from PR #8197. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: avoid QR flicker during refresh and register on daemon connect (#8227) Keeps old QR visible during re-registration by only swapping credentials atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger registration when daemon becomes available after sheet opens. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle floating promise and add timeout in title generation (#8228) Co-authored-by: Claude <noreply@anthropic.com> * refactor: deduplicate isPlainObject into shared utility (#8229) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on memorySegments table (#8230) Co-authored-by: Claude <noreply@anthropic.com> * feat: add backpressure and metrics to session message queue (#8231) Co-authored-by: Claude <noreply@anthropic.com> * perf: cache shell-parsing and risk classification results (#8232) Co-authored-by: Claude <noreply@anthropic.com> * security: add pino log serializer to scrub sensitive data (#8233) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace unsafe type assertions with proper type guards (#8234) Co-authored-by: Claude <noreply@anthropic.com> * feat: add circuit breaker to gateway runtime client (#8236) Co-authored-by: Claude <noreply@anthropic.com> * refactor: create centralized environment variable registry (#8235) Co-authored-by: Claude <noreply@anthropic.com> * feat: add status indication to macOS menu bar icon (#8237) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace any types with proper interfaces in test files (#8241) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove iosPairingUseOverride deletion from v4 migration (#8239) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240) Porcupine's SPM package is iOS-only and pulls in ios-voice-processor which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now strict about this. The wake word engine is currently a stub so removing the dep is safe. Also fixes missing VellumAssistantShared imports and a stale protocol conformance in the wake word files. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add database indexes on memoryItems table (#8244) Co-authored-by: Claude <noreply@anthropic.com> * fix: add per-surface serialization to prevent race conditions (#8245) Co-authored-by: Claude <noreply@anthropic.com> * feat: source filter for Available Skills + platform catalog API (#8097) * feat: add source filter to Available Skills and fetch catalog from platform API - Add All/Vellum/Community source filter pills to Available Skills tab - Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter - Show Vellum catalog skills even if installed (with "Installed" label) - Add refresh button to Installed tab empty state - Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/) - Pass platform session token (X-Session-Token) through IPC for authenticated fetch - Regenerate IPC contract with optional sessionToken on SkillsSearchRequest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve platform token locally and fetch skill content via tar API - Remove sessionToken from IPC contract and Swift chain; the daemon now reads the platform API token from ~/.vellum/platform-token instead of receiving it via IPC messages - SessionTokenManager writes platform token to disk when set/deleted so the daemon can read it for authenticated platform API calls - Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/) which returns a tar.gz archive; extracts SKILL.md from the tarball with bundled fallback on failure - Add readPlatformToken()/getPlatformTokenPath() to platform.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add AbortSignal support to tool implementations (#8246) Co-authored-by: Claude <noreply@anthropic.com> * refactor: split http-server.ts into focused middleware and route modules (#8243) Co-authored-by: Claude <noreply@anthropic.com> * fix: handle QR refresh failure and remove dead onChange (#8248) Shows error state after 2 consecutive refresh registration failures instead of silently leaving a stale QR. Removes dead .onChange(of: daemonClient != nil) since daemonClient is always non-nil in production. Addresses feedback from PR #8227. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249) * security: enforce 0o600 permissions on log files (#8252) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate AbortSignal through permission checking (#8253) Co-authored-by: Claude <noreply@anthropic.com> * feat: complete ingress config schema with validation (#8254) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on remaining tables (#8255) Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add secret dev mode toggle (#8226) * feat(macos): add secret dev mode toggle via Assistant ID tap gesture Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode, similar to Android's developer options. Dev mode gates the Feature Flags editor, Developer (env vars) section, and Platform URL in Connect tab. State persists in UserDefaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: default dev mode to enabled in DEBUG builds Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds start with dev mode on, while still respecting an explicit toggle-off. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset refresh timer and failure counter on QR retry (#8257) Resets consecutiveRefreshFailures to 0 and restarts the refresh timer when the user clicks Retry after a QR refresh failure. Without this, the QR would silently expire after 5 minutes and the next single failure would immediately re-trigger the error state. Addresses feedback from PR #8248. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * refactor: split lifecycle.ts into focused modules (#8259) Co-authored-by: Claude <noreply@anthropic.com> * feat: make global hotkey configurable in macOS client (#8258) Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic re-registration. Defaults to Cmd+Shift+G. * feat: add structured error serialization to pino logger (#8260) Co-authored-by: Claude <noreply@anthropic.com> * fix: add numeric bounds validation for memory item confidence/importance (#8261) Co-authored-by: Claude <noreply@anthropic.com> * feat: make hardcoded daemon timeout values configurable (#8265) Co-authored-by: Claude <noreply@anthropic.com> * feat: add Zod schema for message metadata validation (#8268) Co-authored-by: Claude <noreply@anthropic.com> * refactor: separate migration code from platform utilities (#8272) Co-authored-by: Claude <noreply@anthropic.com> * refactor: use consistent pino logging throughout migration and startup code (#8273) Co-authored-by: Claude <noreply@anthropic.com> * fix: resolve all CI type-check and lint errors (#8276) - Add missing streamThinking to ThinkingConfigSchema default and test assertions - Fix boolean | undefined return type in contradiction-checker transaction - Wrap media-processing stage handlers to return Promise<void> - Cast Cron through unknown for Record<string, unknown> conversion - Update AgentLoopRun type to accept CheckpointInfo parameter - Add withSurface to ToolSetupContext test stubs - Add sessionId to ToolContext test stubs - Cast input_schema to typed interface for property access in tests - Fix fetch mock casts through unknown for Bun's preconnect property - Remove unused imports/vars and fix lint violations across 14 files Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add health check indicator to Platform URL row (#8271) * feat(macos): add health check indicator to Platform URL row Show a dynamic status icon on the Platform URL row in Settings > Connect that indicates whether the Vellum platform is reachable. Hits /healthz on appear and displays green checkmark (reachable), red xmark (unreachable), or spinner (checking). Error details shown on hover via tooltip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate platform health check on dev mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277) * Guardian Cross-Channel Approval UX Polish (#8208) * M1: Backend generative guardian copy + emoji title (#8117) * feat: replace static guardian thread copy with model-generated copy Co-Authored-By: Claude <noreply@anthropic.com> * fix: avoid blocking external channel dispatch on LLM copy generation (#8122) Co-authored-by: Claude <noreply@anthropic.com> * fix: create macOS delivery row before awaiting LLM copy generation (#8127) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: macOS native notification + deep link to thread (#8147) * feat: add macOS native notification + deep link for guardian requests Co-Authored-By: Claude <noreply@anthropic.com> * fix: add questionText to guardian IPC message for notification body (#8162) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: QA hardening + documentation (#8179) * test: add guardian copy generation tests and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * test: add dedicated test for real buildFallbackCopy implementation (#8198) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Fix: reject non-emoji guardian titles from model output (#8247) * fix: validate emoji prefix in generated guardian title Co-Authored-By: Claude <noreply@anthropic.com> * fix: only reject old Guardian question prefix, don't enforce emoji (#8251) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistant inbox feature flag gating from desktop UI (#8281) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox config schema and defaults (#8282) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add rule for agents to keep AGENTS.md up to date (#8284) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: update inbox docs to reflect always-on behavior (#8293) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: change private to internal for properties accessed from AppDelegate extension (#8294) connectionStatusCancellable, pulseTimer, and pulsePhase are accessed from AppDelegate+MenuBar.swift, which is a separate file. Private restricts access to the declaring file, so these need internal access. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: increase maxInputTokens from 180k to 200k (#8295) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve CI type-check and lint errors in ingress config and imports (#8296) Co-authored-by: Claude <noreply@anthropic.com> * fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove QuickChat feature (#8300) The QuickChat floating panel had an unfixable input focus bug — the NSPanel couldn't reliably receive keyboard input. Remove the entire feature: panel, view, hotkey monitors, notification category, settings shortcut, and background session helpers. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove stale relayPort from storage when port field is cleared (#8301) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): use consistent paragraph style for placeholder height measurement (#8303) Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): resolve CI build errors in settings views (#8306) - Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles in release builds (already gated by dev mode at runtime) - Use explicit .some(true)/.some(false)/.none patterns in SettingsConnectTab switch statements to satisfy exhaustiveness checker Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: make error message bubbles span full chat width (#8312) Error bubbles were constrained to the same 520pt maxWidth as regular messages. Use .infinity for error messages so they fill the available chat area. Co-authored-by: Claude <noreply@anthropic.com> * feat: add Quick Input bar (Cmd+/) (#8309) * feat: add Quick Input bar (Cmd+/) for fast new thread creation Adds a floating Spotlight-style input bar that appears system-wide via Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it opens the main window with a new thread containing that message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit - Track and remove Carbon event handler on teardown to prevent accumulation - Place Quick Input panel on the screen with the mouse cursor - Skip restoring previous app on submit so main window doesn't flash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: don't restore previous app on resign-key dismissal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(lint): resolve lint errors in influencer client (#8316) - Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast - Change InfluencerProfile nullable fields from `| null` to `| undefined` - Update parseFollowerCount return type from `number | null` to `number | undefined` - Replace all `!== null` checks with `!== undefined` per project convention Co-authored-by: Claude <noreply@anthropic.com> * feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318) Co-authored-by: Claude <noreply@anthropic.com> * feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320) Co-authored-by: Claude <noreply@anthropic.com> * feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321) Co-authored-by: Claude <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing (#8322) The daemon's HTTP server (port 7821) is required for iOS pairing — the gateway proxies all iOS traffic through it. Previously this was gated behind the `localHttpEnabled` feature flag, so the daemon never started its HTTP server unless the flag was manually enabled via env var, causing HTTP 502 errors on iOS after QR pairing. Three fixes: - AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate) - AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate) - CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list (the CLI was building a second minimal env and stripping it out) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323) Co-authored-by: Claude <noreply@anthropic.com> * feat: add wake word keyword selection and fix APIKeyManager usage (#8324) Co-authored-by: Claude <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325) * fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need internal access — private restricts to the declaring file. Also wrap registration error strings in a proper Error-conforming type since Result requires its Failure type to conform to Error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway - Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT env var, then default 7821, when daemonClient.httpPort is nil (happens when daemon HTTP server starts after socket connection during Qdrant timeout) - Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway is configured, enabling LAN-only pairing - Update canGenerateQR, registration body, and QR payload to use effectiveGatewayUrl instead of gatewayUrl - Update hasGateway check to include LAN availability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var, which relied on a fragile setenv → getenv → subprocess forwarding chain from the macOS app. ProcessInfo.processInfo.environment is a frozen snapshot from launch, so the env var often wasn't forwarded, causing the HTTP server to never start and iOS pairing requests to fail silently. Three fixes: - getRuntimeHttpPort() now defaults to 7821, so the HTTP server always starts regardless of env var forwarding - Wire setPairingBroadcast so pairing_approval_request IPC messages actually reach the macOS app - Remove conditional guard around HTTP server startup in lifecycle.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): add loading state during token regeneration Show a spinner and disable the QR button while the daemon restarts after bearer token regeneration. Polls the healthz endpoint for up to 30s to avoid showing a dead-end "daemon unreachable" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel Two issues caused the macOS app to disconnect from the daemon after ~1 second and never reconnect: 1. DaemonConnection configured NWProtocolTCP.Options() on a Unix domain socket endpoint. Unix sockets don't use TCP — the invalid protocol stack caused the NWConnection to become unstable and disconnect shortly after connecting, before authentication could complete. 2. The .cancelled state handler didn't call scheduleReconnect() when the connection had already been established (resumed==true). This meant spontaneous disconnects were permanent — unlike .failed which properly triggers auto-reconnect. Without a stable IPC connection, all daemon broadcasts (pairing approval requests, reminders, schedule events, watcher alerts) were silently dropped because there were 0 authenticated sockets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326) Co-authored-by: Claude <noreply@anthropic.com> * fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328) Co-authored-by: Claude <noreply@anthropic.com> * fix: add input validation and handle cleanup in PorcupineBinding (#8327) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent double dismiss of Quick Input panel on submit (#8315) Add isDismissing guard to prevent re-entrant dismiss calls when showMainWindow causes the panel to resign key while the onSubmit closure also calls dismiss explicitly. Co-authored-by: Claude <noreply@anthropic.com> * Release v0.3.6 (#8329) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: move wake word callback outside lock and use dynamic frame length (#8331) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332) Co-authored-by: Claude <noreply@anthropic.com> * perf: disable LLM reranking for memory recall (#8067) LLM reranking was calling Claude Haiku API on every message to re-score memory candidates, adding ~2.2s latency. The RRF merge already produces a well-ordered list from lexical, semantic, recency, and entity scores. Disabling reranking reduces memory recall from ~2.6s to ~700ms. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340) The previous commit removed NWProtocolTCP.Options() from Unix socket connections, but this protocol has been in use since the original IPC implementation (PR #499) and has been working in production for years. Removing it risks breaking IPC in the v0.3.7 release. Restores the TCP protocol stack while keeping the .cancelled state reconnect improvement (scheduleReconnect on post-connection cancel). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self. for property captures in PorcupineWakeWordEngine (#8337) Swift strict concurrency requires explicit `self.` when referencing properties inside closures. os.Logger string interpolation creates implicit closures, so `keyword` and `sensitivity` need `self.` prefix. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self for keyword reference in os.Logger closure (#8342) The release build (universal binary) requires explicit `self.` for property references inside os.Logger string interpolation closures. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve CI failures blocking v0.3.7 release (#8344) - TypeScript: fix setPairingBroadcast type to use ServerMessage instead of loose { type: string; [key: string]: unknown } - Gateway lint: prefix unused vars with _ in whatsapp-deliver test - Swift: add explicit self. for keyword property in closure Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: broadcast pairing approval to HTTP/SSE clients (#8348) When the macOS app uses HTTP transport (localHttpEnabled flag), it connects via SSE instead of the Unix domain socket. Pairing approval requests were only broadcast to IPC socket clients, so HTTP-connected clients never received them. Two changes: 1. RuntimeHttpServer now also publishes pairing events to the AssistantEventHub with assistantId 'self' so SSE subscribers receive them. 2. AssistantEventHub allows events without sessionId (system events) to pass through to all subscribers regardless of their sessionId filter. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * M1: Add Voice -> Run/Session Bridge (#8222) * feat: add voice -> run/session bridge with streaming event sink and cancellation Co-Authored-By: Claude <noreply@anthropic.com> * fix: scope run abort handles to originating run to prevent stale cancellation (#8238) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: Replace CallOrchestrator with Session-Backed Voice Controller (#8275) * feat: replace CallOrchestrator with session-backed CallController for voice turns Co-Authored-By: Claude <noreply@anthropic.com> * Fix: Resolve voice turn promise on abort/exception (#8280) * fix: resolve voice turn promise on abort and agent-loop exceptions Co-Authored-By: Claude <noreply@anthropic.com> * fix: increment llmRunVersion in destroy() to prevent post-turn side effects on destroyed controller (#8290) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: Guardian Context and Side-Effect Policy Parity (#8299) * feat: enforce guardian context and strict side-effect policy parity for voice turns Co-Authored-By: Claude <noreply@anthropic.com> * fix: auto-deny tool confirmations for non-guardian voice turns to prevent 300s timeout (#8302) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M4: Clean Up Legacy Orchestrator Artifacts + Docs (#8304) * chore: clean up legacy call orchestrator artifacts and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * fix: fix stale Orch participant and duplicate Session declaration in ARCHITECTURE.md Mermaid diagrams (#8307) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * fix: address final PR review feedback — move bridge injection, fix opener marker persistence, remove duplicate user message persist Co-Authored-By: Claude <noreply@anthropic.com> * feat(macos): add Restart menu item to status bar menu (#8347) * feat(macos): add Restart menu item to status bar menu Add a Restart option to the menu bar dropdown that stops the daemon, launches a fresh app instance, and terminates the current one. Useful for recovering from stuck states without manually quitting and relaunching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate app termination on successful relaunch in performRestart Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add memory degradation banner to component gallery with #F5F3EB background (#8356) Co-authored-by: Claude <noreply@anthropic.com> * Add rename option to thread right-click context menu (#8351) * M1: Add session_rename IPC message to daemon (#8338) * feat: add session_rename IPC message for client-initiated title changes Co-Authored-By: Claude <noreply@anthropic.com> * fix: validate conversation exists before renaming in handleSessionRename (#8341) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * M2: Add rename option to macOS thread context menu UI (#8346) * feat: add rename option to macOS thread context menu Co-Authored-By: Claude <noreply@anthropic.com> * fix: only show rename option for threads with a daemon session (#8350) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant conversation_id index on memory_segments (#8357) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove unscoped queue-full error and guard expireStale against exceptions (#8358) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve statusCode fallback when status is undefined in getErrorStatusCode (#8360) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve Error name/message/stack in log redaction serializer (#8359) Co-authored-by: Claude <noreply@anthropic.com> * fix: include workingDir and manifestOverride in risk cache key (#8361) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant fingerprint index from memoryItems migration (#8362) Co-authored-by: Claude <noreply@anthropic.com> * fix: add missing legitimate env vars to KNOWN_VELLUM_VARS (#8363) Co-authored-by: Claude <noreply@anthropic.com> * fix: clean up settled surface mutex entries to prevent memory leak (#8364) Co-authored-by: Claude <noreply@anthropic.com> * fix: return immediately on aborted CAPTCHA wait instead of breaking (#8365) Co-authored-by: Claude <noreply@anthropic.com> * fix: rebind menu bar connection observer after client replacement and fix pulse animation (#8366) Co-authored-by: Claude <noreply@anthropic.com> * fix: limit half-open probes to single attempt and propagate CircuitBreakerOpenError (#8367) Co-authored-by: Claude <noreply@anthropic.com> * fix: read daemon timeouts without triggering loadConfig/migration side effects (#8368) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce log file permissions on existing files at startup (#8371) Co-authored-by: Claude <noreply@anthropic.com> * fix: auto-start SSE on HTTP transport connect for system events (#8370) When using HTTP transport (VELLUM_FLAG_LOCAL_HTTP_ENABLED=1), SSE was only started when MainWindowView.onAppear fired. This meant system events like pairing approval requests were lost if they arrived before the main window appeared. Auto-start the SSE stream immediately after the first health check passes in connect(). MainWindowView.onAppear still calls startSSE() but it's a no-op when the stream is already running. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: throw typed cancellation error from permission checks (#8372) Co-authored-by: Claude <noreply@anthropic.com> * feat: add pre-commit warning when modifying system-prompt.ts (#8354) * feat: add pre-commit warning when modifying system-prompt.ts Adds a non-blocking warning to the pre-commit hook that fires when system-prompt.ts is staged. Reminds contributors to consider whether their change belongs in a skill, IDENTITY.md, SOUL.md, USER.md, LOOKS.md, or skills/ instead of directly in the system prompt. Includes a 3-second pause to ensure the warning is actually read. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add BOOTSTRAP.md to system-prompt warning file list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Release v0.3.7 (#8373) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: initialize pairing handlers so approval responses are processed (#8374) initPairingHandlers() was defined but never called, leaving pairingStoreRef as null. When macOS sent a pairing_approval_response over IPC, the handler silently returned on the null check (line 29), so approvals never reached the PairingStore — iOS stayed stuck on "Waiting for approval" and the device was never added to the allowlist. Wire up initPairingHandlers() in lifecycle.ts after the HTTP server starts, passing the PairingStore instance and bearer token. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: inject call-control prompt + await barge-in teardown Co-Authored-By: Claude <noreply@anthropic.com> * feat: improve media analysis skill defaults and add best practices (#8385) Update defaults based on real-world usage feedback: keyframe interval 3s→1s, segment duration 20s→15s, skip_dead_time on→off. Add best practices section with broad-vs-targeted map prompt guidance, sample prompt/schema, clip delivery notes, and vision analysis limitations. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: unconditional teardown await + bump run version before barge-in Co-Authored-By: Claude <noreply@anthropic.com> * feat: add holistic Codex review phase to safe-blitz command (#8387) Co-authored-by: Claude <noreply@anthropic.com> * fix: watch http-token file so gateway picks up daemon token changes (#8389) When the daemon restarts and writes a new bearer token to ~/.vellum/http-token, a gateway process that started earlier still holds the stale token. This causes 401 errors for iOS clients that received the new token during pairing. Add a file watcher for http-token (following the existing CredentialWatcher pattern) that refreshes runtimeBearerToken, runtimeProxyBearerToken, and runtimeGatewayOriginSecret in the live config when the file changes. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: drop legacy conversation_id index and remove from Drizzle schema (#8393) Co-authored-by: Claude <noreply@anthropic.com> * fix: unreserve dedup cache entries on CircuitBreakerOpenError before returning 503 (#8394) Co-authored-by: Claude <noreply@anthropic.com> * fix: validate daemon timeout bounds in readDaemonTimeouts (#8395) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate queue-full status through subagent message path (#8397) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Alex Nork <48630278+alex-nork@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ashlee Radka <ashleeradka@gmail.com> Co-authored-by: asharma53 <64060709+asharma53@users.noreply.github.com> Co-authored-by: siddseethepalli <siddseethepalli@gmail.com> Co-authored-by: David Vargas Fuertes <vargas@vellum.ai> Co-authored-by: NgoHarrison <harrison.ngo719@gmail.com> Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Aaron Levin <awlevin@users.noreply.github.com> Co-authored-by: V <vincent@vellum.ai> Co-authored-by: Marina Trajkovska <trajk.marina@gmail.com> Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: vellum-automation[bot] <192048195+vellum-automation[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jason Zhou <jason@vellum.ai> Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Tirman Sidhu <tirmansidhu@gmail.com> Co-authored-by: Nick <127171085+ZeebBoyBlue@users.noreply.github.com> Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
noanflaherty
added a commit
that referenced
this pull request
Feb 24, 2026
* fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180) Co-authored-by: Claude <noreply@anthropic.com> * fix: use effective base URL for polling and cancel task on dismiss (#8185) Co-authored-by: Claude <noreply@anthropic.com> * fix: derive segment count from manifest in media diagnostics (#8187) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce payload size limit on pairing proxy endpoints (#8188) Co-authored-by: Claude <noreply@anthropic.com> * fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: approved devices race condition and optimistic clear (#8190) Co-authored-by: Claude <noreply@anthropic.com> * fix: move zero-frame check before atomic rename in preprocess (#8191) Co-authored-by: Claude <noreply@anthropic.com> * fix: include context field in map cache config hash (#8192) Co-authored-by: Claude <noreply@anthropic.com> * fix: align lastPairedAt type to Int matching generated IPC types (#8193) Co-authored-by: Claude <noreply@anthropic.com> * improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194) Rewrite the Google OAuth setup skill prompts to feel like 3 user actions instead of a confusing 10-step process. Auto-detect sign-in completion by polling browser snapshots instead of asking users to confirm manually. Add progress callouts and clearer credential entry instructions. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195) Co-authored-by: Claude <noreply@anthropic.com> * fix: send deny on PairingApprovalWindow close and supersede (#8196) When the pairing approval window is closed via the X button or superseded by a new request, sends a deny response to the daemon. Prevents iOS devices from hanging in pending state indefinitely. - Track currentPairingRequestId and responseSent flag - Add WindowCloseDelegate (NSWindowDelegate) for X-button close - denyIfNeeded() sends deny for unanswered requests in close() - Set responseSent = true in onDecision before calling close() Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: clear stale pairing overrides during v4 migration (#8197) Co-authored-by: Claude <noreply@anthropic.com> * fix: re-register QR pairing before TTL and handle missing daemon (#8199) Adds a timer to re-register the pairing request before the 5-minute TTL expires, keeping the QR code valid while the sheet is open. Also shows an error when daemon client is unavailable instead of rendering an empty sheet. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: honor task cancellation in QRPairingSheet pairing flow (#8210) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce Content-Length pre-check in pairing proxy (#8212) Co-authored-by: Claude <noreply@anthropic.com> * fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: reduce maxTokens default from 64000 to 16000 (#8217) Co-authored-by: Claude <noreply@anthropic.com> * feat: add streamThinking config flag and filter thinking deltas (#8219) Co-authored-by: Claude <noreply@anthropic.com> * fix: skip deny on same-ID retry in PairingApprovalWindow (#8223) Co-authored-by: Claude <noreply@anthropic.com> * fix: update maxTokens schema default and tests to 16000 (#8224) Co-authored-by: Claude <noreply@anthropic.com> * fix: separate iOS override migration and guard macOS cleanup (#8225) iOS: moves override cleanup into its own migratePairingOverridesIfNeeded() with a separate migration key, so existing v4-migrated users still get cleanup. macOS: only runs cleanup when legacy iosPairingUseOverride key is actually present, preserving intentional post-M9 overrides. Addresses feedback from PR #8197. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: avoid QR flicker during refresh and register on daemon connect (#8227) Keeps old QR visible during re-registration by only swapping credentials atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger registration when daemon becomes available after sheet opens. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle floating promise and add timeout in title generation (#8228) Co-authored-by: Claude <noreply@anthropic.com> * refactor: deduplicate isPlainObject into shared utility (#8229) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on memorySegments table (#8230) Co-authored-by: Claude <noreply@anthropic.com> * feat: add backpressure and metrics to session message queue (#8231) Co-authored-by: Claude <noreply@anthropic.com> * perf: cache shell-parsing and risk classification results (#8232) Co-authored-by: Claude <noreply@anthropic.com> * security: add pino log serializer to scrub sensitive data (#8233) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace unsafe type assertions with proper type guards (#8234) Co-authored-by: Claude <noreply@anthropic.com> * feat: add circuit breaker to gateway runtime client (#8236) Co-authored-by: Claude <noreply@anthropic.com> * refactor: create centralized environment variable registry (#8235) Co-authored-by: Claude <noreply@anthropic.com> * feat: add status indication to macOS menu bar icon (#8237) Co-authored-by: Claude <noreply@anthropic.com> * refactor: replace any types with proper interfaces in test files (#8241) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove iosPairingUseOverride deletion from v4 migration (#8239) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240) Porcupine's SPM package is iOS-only and pulls in ios-voice-processor which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now strict about this. The wake word engine is currently a stub so removing the dep is safe. Also fixes missing VellumAssistantShared imports and a stale protocol conformance in the wake word files. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * perf: add database indexes on memoryItems table (#8244) Co-authored-by: Claude <noreply@anthropic.com> * fix: add per-surface serialization to prevent race conditions (#8245) Co-authored-by: Claude <noreply@anthropic.com> * feat: source filter for Available Skills + platform catalog API (#8097) * feat: add source filter to Available Skills and fetch catalog from platform API - Add All/Vellum/Community source filter pills to Available Skills tab - Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter - Show Vellum catalog skills even if installed (with "Installed" label) - Add refresh button to Installed tab empty state - Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/) - Pass platform session token (X-Session-Token) through IPC for authenticated fetch - Regenerate IPC contract with optional sessionToken on SkillsSearchRequest Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve platform token locally and fetch skill content via tar API - Remove sessionToken from IPC contract and Swift chain; the daemon now reads the platform API token from ~/.vellum/platform-token instead of receiving it via IPC messages - SessionTokenManager writes platform token to disk when set/deleted so the daemon can read it for authenticated platform API calls - Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/) which returns a tar.gz archive; extracts SKILL.md from the tarball with bundled fallback on failure - Add readPlatformToken()/getPlatformTokenPath() to platform.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add AbortSignal support to tool implementations (#8246) Co-authored-by: Claude <noreply@anthropic.com> * refactor: split http-server.ts into focused middleware and route modules (#8243) Co-authored-by: Claude <noreply@anthropic.com> * fix: handle QR refresh failure and remove dead onChange (#8248) Shows error state after 2 consecutive refresh registration failures instead of silently leaving a stale QR. Removes dead .onChange(of: daemonClient != nil) since daemonClient is always non-nil in production. Addresses feedback from PR #8227. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249) * security: enforce 0o600 permissions on log files (#8252) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate AbortSignal through permission checking (#8253) Co-authored-by: Claude <noreply@anthropic.com> * feat: complete ingress config schema with validation (#8254) Co-authored-by: Claude <noreply@anthropic.com> * perf: add database indexes on remaining tables (#8255) Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add secret dev mode toggle (#8226) * feat(macos): add secret dev mode toggle via Assistant ID tap gesture Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode, similar to Android's developer options. Dev mode gates the Feature Flags editor, Developer (env vars) section, and Platform URL in Connect tab. State persists in UserDefaults. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: default dev mode to enabled in DEBUG builds Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds start with dev mode on, while still respecting an explicit toggle-off. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: reset refresh timer and failure counter on QR retry (#8257) Resets consecutiveRefreshFailures to 0 and restarts the refresh timer when the user clicks Retry after a QR refresh failure. Without this, the QR would silently expire after 5 minutes and the next single failure would immediately re-trigger the error state. Addresses feedback from PR #8248. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * refactor: split lifecycle.ts into focused modules (#8259) Co-authored-by: Claude <noreply@anthropic.com> * feat: make global hotkey configurable in macOS client (#8258) Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic re-registration. Defaults to Cmd+Shift+G. * feat: add structured error serialization to pino logger (#8260) Co-authored-by: Claude <noreply@anthropic.com> * fix: add numeric bounds validation for memory item confidence/importance (#8261) Co-authored-by: Claude <noreply@anthropic.com> * feat: make hardcoded daemon timeout values configurable (#8265) Co-authored-by: Claude <noreply@anthropic.com> * feat: add Zod schema for message metadata validation (#8268) Co-authored-by: Claude <noreply@anthropic.com> * refactor: separate migration code from platform utilities (#8272) Co-authored-by: Claude <noreply@anthropic.com> * refactor: use consistent pino logging throughout migration and startup code (#8273) Co-authored-by: Claude <noreply@anthropic.com> * fix: resolve all CI type-check and lint errors (#8276) - Add missing streamThinking to ThinkingConfigSchema default and test assertions - Fix boolean | undefined return type in contradiction-checker transaction - Wrap media-processing stage handlers to return Promise<void> - Cast Cron through unknown for Record<string, unknown> conversion - Update AgentLoopRun type to accept CheckpointInfo parameter - Add withSurface to ToolSetupContext test stubs - Add sessionId to ToolContext test stubs - Cast input_schema to typed interface for property access in tests - Fix fetch mock casts through unknown for Bun's preconnect property - Remove unused imports/vars and fix lint violations across 14 files Co-authored-by: Claude <noreply@anthropic.com> * feat(macos): add health check indicator to Platform URL row (#8271) * feat(macos): add health check indicator to Platform URL row Show a dynamic status icon on the Platform URL row in Settings > Connect that indicates whether the Vellum platform is reachable. Hits /healthz on appear and displays green checkmark (reachable), red xmark (unreachable), or spinner (checking). Error details shown on hover via tooltip. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate platform health check on dev mode Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277) * Guardian Cross-Channel Approval UX Polish (#8208) * M1: Backend generative guardian copy + emoji title (#8117) * feat: replace static guardian thread copy with model-generated copy Co-Authored-By: Claude <noreply@anthropic.com> * fix: avoid blocking external channel dispatch on LLM copy generation (#8122) Co-authored-by: Claude <noreply@anthropic.com> * fix: create macOS delivery row before awaiting LLM copy generation (#8127) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M2: macOS native notification + deep link to thread (#8147) * feat: add macOS native notification + deep link for guardian requests Co-Authored-By: Claude <noreply@anthropic.com> * fix: add questionText to guardian IPC message for notification body (#8162) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * M3: QA hardening + documentation (#8179) * test: add guardian copy generation tests and update architecture docs Co-Authored-By: Claude <noreply@anthropic.com> * test: add dedicated test for real buildFallbackCopy implementation (#8198) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * Fix: reject non-emoji guardian titles from model output (#8247) * fix: validate emoji prefix in generated guardian title Co-Authored-By: Claude <noreply@anthropic.com> * fix: only reject old Guardian question prefix, don't enforce emoji (#8251) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistant inbox feature flag gating from desktop UI (#8281) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox config schema and defaults (#8282) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: add rule for agents to keep AGENTS.md up to date (#8284) Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude <noreply@anthropic.com> * docs: update inbox docs to reflect always-on behavior (#8293) Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: change private to internal for properties accessed from AppDelegate extension (#8294) connectionStatusCancellable, pulseTimer, and pulsePhase are accessed from AppDelegate+MenuBar.swift, which is a separate file. Private restricts access to the declaring file, so these need internal access. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: increase maxInputTokens from 180k to 200k (#8295) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: resolve CI type-check and lint errors in ingress config and imports (#8296) Co-authored-by: Claude <noreply@anthropic.com> * fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * refactor: remove QuickChat feature (#8300) The QuickChat floating panel had an unfixable input focus bug — the NSPanel couldn't reliably receive keyboard input. Remove the entire feature: panel, view, hotkey monitors, notification category, settings shortcut, and background session helpers. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: remove stale relayPort from storage when port field is cleared (#8301) Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): use consistent paragraph style for placeholder height measurement (#8303) Co-authored-by: Claude <noreply@anthropic.com> * fix(macos): resolve CI build errors in settings views (#8306) - Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles in release builds (already gated by dev mode at runtime) - Use explicit .some(true)/.some(false)/.none patterns in SettingsConnectTab switch statements to satisfy exhaustiveness checker Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: make error message bubbles span full chat width (#8312) Error bubbles were constrained to the same 520pt maxWidth as regular messages. Use .infinity for error messages so they fill the available chat area. Co-authored-by: Claude <noreply@anthropic.com> * feat: add Quick Input bar (Cmd+/) (#8309) * feat: add Quick Input bar (Cmd+/) for fast new thread creation Adds a floating Spotlight-style input bar that appears system-wide via Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it opens the main window with a new thread containing that message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit - Track and remove Carbon event handler on teardown to prevent accumulation - Place Quick Input panel on the screen with the mouse cursor - Skip restoring previous app on submit so main window doesn't flash Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: don't restore previous app on resign-key dismissal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(lint): resolve lint errors in influencer client (#8316) - Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast - Change InfluencerProfile nullable fields from `| null` to `| undefined` - Update parseFollowerCount return type from `number | null` to `number | undefined` - Replace all `!== null` checks with `!== undefined` per project convention Co-authored-by: Claude <noreply@anthropic.com> * feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318) Co-authored-by: Claude <noreply@anthropic.com> * feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320) Co-authored-by: Claude <noreply@anthropic.com> * feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321) Co-authored-by: Claude <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing (#8322) The daemon's HTTP server (port 7821) is required for iOS pairing — the gateway proxies all iOS traffic through it. Previously this was gated behind the `localHttpEnabled` feature flag, so the daemon never started its HTTP server unless the flag was manually enabled via env var, causing HTTP 502 errors on iOS after QR pairing. Three fixes: - AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate) - AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate) - CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list (the CLI was building a second minimal env and stripping it out) Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323) Co-authored-by: Claude <noreply@anthropic.com> * feat: add wake word keyword selection and fix APIKeyManager usage (#8324) Co-authored-by: Claude <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325) * fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need internal access — private restricts to the declaring file. Also wrap registration error strings in a proper Error-conforming type since Result requires its Failure type to conform to Error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway - Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT env var, then default 7821, when daemonClient.httpPort is nil (happens when daemon HTTP server starts after socket connection during Qdrant timeout) - Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway is configured, enabling LAN-only pairing - Update canGenerateQR, registration body, and QR payload to use effectiveGatewayUrl instead of gatewayUrl - Update hasGateway check to include LAN availability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: always start daemon HTTP server for iOS pairing The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var, which relied on a fragile setenv → getenv → subprocess forwarding chain from the macOS app. ProcessInfo.processInfo.environment is a frozen snapshot from launch, so the env var often wasn't forwarded, causing the HTTP server to never start and iOS pairing requests to fail silently. Three fixes: - getRuntimeHttpPort() now defaults to 7821, so the HTTP server always starts regardless of env var forwarding - Wire setPairingBroadcast so pairing_approval_request IPC messages actually reach the macOS app - Remove conditional guard around HTTP server startup in lifecycle.ts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(macos): add loading state during token regeneration Show a spinner and disable the QR button while the daemon restarts after bearer token regeneration. Polls the healthz endpoint for up to 30s to avoid showing a dead-end "daemon unreachable" error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): fix IPC Unix socket protocol and reconnect on cancel Two issues caused the macOS app to disconnect from the daemon after ~1 second and never reconnect: 1. DaemonConnection configured NWProtocolTCP.Options() on a Unix domain socket endpoint. Unix sockets don't use TCP — the invalid protocol stack caused the NWConnection to become unstable and disconnect shortly after connecting, before authentication could complete. 2. The .cancelled state handler didn't call scheduleReconnect() when the connection had already been established (resumed==true). This meant spontaneous disconnects were permanent — unlike .failed which properly triggers auto-reconnect. Without a stable IPC connection, all daemon broadcasts (pairing approval requests, reminders, schedule events, watcher alerts) were silently dropped because there were 0 authenticated sockets. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326) Co-authored-by: Claude <noreply@anthropic.com> * fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328) Co-authored-by: Claude <noreply@anthropic.com> * fix: add input validation and handle cleanup in PorcupineBinding (#8327) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent double dismiss of Quick Input panel on submit (#8315) Add isDismissing guard to prevent re-entrant dismiss calls when showMainWindow causes the panel to resign key while the onSubmit closure also calls dismiss explicitly. Co-authored-by: Claude <noreply@anthropic.com> * Release v0.3.6 (#8329) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: move wake word callback outside lock and use dynamic frame length (#8331) Co-authored-by: Claude <noreply@anthropic.com> * fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332) Co-authored-by: Claude <noreply@anthropic.com> * perf: disable LLM reranking for memory recall (#8067) LLM reranking was calling Claude Haiku API on every message to re-score memory candidates, adding ~2.2s latency. The RRF merge already produces a well-ordered list from lexical, semantic, recency, and entity scores. Disabling reranking reduces memory recall from ~2.6s to ~700ms. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340) The previous commit removed NWProtocolTCP.Options() from Unix socket connections, but this protocol has been in use since the original IPC implementation (PR #499) and has been working in production for years. Removing it risks breaking IPC in the v0.3.7 release. Restores the TCP protocol stack while keeping the .cancelled state reconnect improvement (scheduleReconnect on post-connection cancel). Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self. for property captures in PorcupineWakeWordEngine (#8337) Swift strict concurrency requires explicit `self.` when referencing properties inside closures. os.Logger string interpolation creates implicit closures, so `keyword` and `sensitivity` need `self.` prefix. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: add explicit self for keyword reference in os.Logger closure (#8342) The release build (universal binary) requires explicit `self.` for property references inside os.Logger string interpolation closures. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: resolve CI failures blocking v0.3.7 release (#8344) - TypeScript: fix setPairingBroadcast type to use ServerMessage instead of loose { type: string; [key: string]: unknown } - Gateway lint: prefix unused vars with _ in whatsapp-deliver test - Swift: add explicit self. for keyword property in closure Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: broadcast pairing approval to HTTP/SSE clients (#8348) When the macOS app uses HTTP transport (localHttpEnabled flag), it connects via SSE instead of the Unix domain socket. Pairing approval requests were only broadcast to IPC socket clients, so HTTP-connected clients never received them. Two changes: 1. RuntimeHttpServer now also publishes pairing events to the AssistantEventHub with assistantId 'self' so SSE subscribers receive them. 2. AssistantEventHub allows events without sessionId (system events) to pass through to all subscribers regardless of their sessionId filter. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat(macos): add Restart menu item to status bar menu (#8347) * feat(macos): add Restart menu item to status bar menu Add a Restart option to the menu bar dropdown that stops the daemon, launches a fresh app instance, and terminates the current one. Useful for recovering from stuck states without manually quitting and relaunching. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: gate app termination on successful relaunch in performRestart Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add memory degradation banner to component gallery with #F5F3EB background (#8356) Co-authored-by: Claude <noreply@anthropic.com> * Add rename option to thread right-click context menu (#8351) * M1: Add session_rename IPC message to daemon (#8338) * feat: add session_rename IPC message for client-initiated title changes Co-Authored-By: Claude <noreply@anthropic.com> * fix: validate conversation exists before renaming in handleSessionRename (#8341) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * M2: Add rename option to macOS thread context menu UI (#8346) * feat: add rename option to macOS thread context menu Co-Authored-By: Claude <noreply@anthropic.com> * fix: only show rename option for threads with a daemon session (#8350) Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local> Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant conversation_id index on memory_segments (#8357) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove unscoped queue-full error and guard expireStale against exceptions (#8358) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve statusCode fallback when status is undefined in getErrorStatusCode (#8360) Co-authored-by: Claude <noreply@anthropic.com> * fix: preserve Error name/message/stack in log redaction serializer (#8359) Co-authored-by: Claude <noreply@anthropic.com> * fix: include workingDir and manifestOverride in risk cache key (#8361) Co-authored-by: Claude <noreply@anthropic.com> * fix: remove redundant fingerprint index from memoryItems migration (#8362) Co-authored-by: Claude <noreply@anthropic.com> * fix: add missing legitimate env vars to KNOWN_VELLUM_VARS (#8363) Co-authored-by: Claude <noreply@anthropic.com> * fix: clean up settled surface mutex entries to prevent memory leak (#8364) Co-authored-by: Claude <noreply@anthropic.com> * fix: return immediately on aborted CAPTCHA wait instead of breaking (#8365) Co-authored-by: Claude <noreply@anthropic.com> * fix: rebind menu bar connection observer after client replacement and fix pulse animation (#8366) Co-authored-by: Claude <noreply@anthropic.com> * fix: limit half-open probes to single attempt and propagate CircuitBreakerOpenError (#8367) Co-authored-by: Claude <noreply@anthropic.com> * fix: read daemon timeouts without triggering loadConfig/migration side effects (#8368) Co-authored-by: Claude <noreply@anthropic.com> * fix: enforce log file permissions on existing files at startup (#8371) Co-authored-by: Claude <noreply@anthropic.com> * fix: auto-start SSE on HTTP transport connect for system events (#8370) When using HTTP transport (VELLUM_FLAG_LOCAL_HTTP_ENABLED=1), SSE was only started when MainWindowView.onAppear fired. This meant system events like pairing approval requests were lost if they arrived before the main window appeared. Auto-start the SSE stream immediately after the first health check passes in connect(). MainWindowView.onAppear still calls startSSE() but it's a no-op when the stream is already running. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: throw typed cancellation error from permission checks (#8372) Co-authored-by: Claude <noreply@anthropic.com> * feat: add pre-commit warning when modifying system-prompt.ts (#8354) * feat: add pre-commit warning when modifying system-prompt.ts Adds a non-blocking warning to the pre-commit hook that fires when system-prompt.ts is staged. Reminds contributors to consider whether their change belongs in a skill, IDENTITY.md, SOUL.md, USER.md, LOOKS.md, or skills/ instead of directly in the system prompt. Includes a 3-second pause to ensure the warning is actually read. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add BOOTSTRAP.md to system-prompt warning file list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * Release v0.3.7 (#8373) Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * fix: initialize pairing handlers so approval responses are processed (#8374) initPairingHandlers() was defined but never called, leaving pairingStoreRef as null. When macOS sent a pairing_approval_response over IPC, the handler silently returned on the null check (line 29), so approvals never reached the PairingStore — iOS stayed stuck on "Waiting for approval" and the device was never added to the allowlist. Wire up initPairingHandlers() in lifecycle.ts after the HTTP server starts, passing the PairingStore instance and bearer token. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: improve media analysis skill defaults and add best practices (#8385) Update defaults based on real-world usage feedback: keyframe interval 3s→1s, segment duration 20s→15s, skip_dead_time on→off. Add best practices section with broad-vs-targeted map prompt guidance, sample prompt/schema, clip delivery notes, and vision analysis limitations. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: add holistic Codex review phase to safe-blitz command (#8387) Co-authored-by: Claude <noreply@anthropic.com> * fix: watch http-token file so gateway picks up daemon token changes (#8389) When the daemon restarts and writes a new bearer token to ~/.vellum/http-token, a gateway process that started earlier still holds the stale token. This causes 401 errors for iOS clients that received the new token during pairing. Add a file watcher for http-token (following the existing CredentialWatcher pattern) that refreshes runtimeBearerToken, runtimeProxyBearerToken, and runtimeGatewayOriginSecret in the live config when the file changes. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * fix: drop legacy conversation_id index and remove from Drizzle schema (#8393) Co-authored-by: Claude <noreply@anthropic.com> * fix: unreserve dedup cache entries on CircuitBreakerOpenError before returning 503 (#8394) Co-authored-by: Claude <noreply@anthropic.com> * fix: validate daemon timeout bounds in readDaemonTimeouts (#8395) Co-authored-by: Claude <noreply@anthropic.com> * fix: propagate queue-full status through subagent message path (#8397) Co-authored-by: Claude <noreply@anthropic.com> * fix: respect env var precedence in http-token watcher (#8399) Address review feedback on #8389: 1. Skip file-based token refresh when RUNTIME_BEARER_TOKEN env var is set, preserving the same precedence as loadConfig() where env vars override the file. Prevents cloud deployments with pinned tokens from being silently overwritten by daemon file writes. 2. Wrap mkdirSync in try-catch so a non-writable parent directory doesn't crash the gateway at startup — the watcher is gracefully skipped instead. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> * feat: add queue-if-busy behavior and hub publishing to POST /v1/messages (#8391) (#8400) Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Alex Nork <48630278+alex-nork@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Ashlee Radka <ashleeradka@gmail.com> Co-authored-by: asharma53 <64060709+asharma53@users.noreply.github.com> Co-authored-by: siddseethepalli <siddseethepalli@gmail.com> Co-authored-by: David Vargas Fuertes <vargas@vellum.ai> Co-authored-by: NgoHarrison <harrison.ngo719@gmail.com> Co-authored-by: Harrison Ngo <harrison@vellum.ai> Co-authored-by: Aaron Levin <awlevin@users.noreply.github.com> Co-authored-by: V <vincent@vellum.ai> Co-authored-by: Marina Trajkovska <trajk.marina@gmail.com> Co-authored-by: marinatrajk <marina@odyseek.com> Co-authored-by: vellum-automation[bot] <192048195+vellum-automation[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Jason Zhou <jason@vellum.ai> Co-authored-by: Vellum Assistant <assistant@vellum.ai> Co-authored-by: Tirman Sidhu <tirmansidhu@gmail.com> Co-authored-by: Nick <127171085+ZeebBoyBlue@users.noreply.github.com> Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
noanflaherty
added a commit
that referenced
this pull request
Feb 24, 2026
* M1: Add Voice -> Run/Session Bridge (#8222)
* feat: add voice -> run/session bridge with streaming event sink and cancellation
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: scope run abort handles to originating run to prevent stale cancellation (#8238)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M2: Replace CallOrchestrator with Session-Backed Voice Controller (#8275)
* feat: replace CallOrchestrator with session-backed CallController for voice turns
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix: Resolve voice turn promise on abort/exception (#8280)
* fix: resolve voice turn promise on abort and agent-loop exceptions
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: increment llmRunVersion in destroy() to prevent post-turn side effects on destroyed controller (#8290)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M3: Guardian Context and Side-Effect Policy Parity (#8299)
* feat: enforce guardian context and strict side-effect policy parity for voice turns
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: auto-deny tool confirmations for non-guardian voice turns to prevent 300s timeout (#8302)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M4: Clean Up Legacy Orchestrator Artifacts + Docs (#8304)
* chore: clean up legacy call orchestrator artifacts and update architecture docs
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: fix stale Orch participant and duplicate Session declaration in ARCHITECTURE.md Mermaid diagrams (#8307)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: merge feedback PRs (#8352, #8375, #8386) + resolve main conflicts (#8398)
* fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: use effective base URL for polling and cancel task on dismiss (#8185)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: derive segment count from manifest in media diagnostics (#8187)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: enforce payload size limit on pairing proxy endpoints (#8188)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: approved devices race condition and optimistic clear (#8190)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: move zero-frame check before atomic rename in preprocess (#8191)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: include context field in map cache config hash (#8192)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: align lastPairedAt type to Int matching generated IPC types (#8193)
Co-authored-by: Claude <noreply@anthropic.com>
* improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194)
Rewrite the Google OAuth setup skill prompts to feel like 3 user actions
instead of a confusing 10-step process. Auto-detect sign-in completion
by polling browser snapshots instead of asking users to confirm manually.
Add progress callouts and clearer credential entry instructions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: send deny on PairingApprovalWindow close and supersede (#8196)
When the pairing approval window is closed via the X button or superseded
by a new request, sends a deny response to the daemon. Prevents iOS
devices from hanging in pending state indefinitely.
- Track currentPairingRequestId and responseSent flag
- Add WindowCloseDelegate (NSWindowDelegate) for X-button close
- denyIfNeeded() sends deny for unanswered requests in close()
- Set responseSent = true in onDecision before calling close()
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clear stale pairing overrides during v4 migration (#8197)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: re-register QR pairing before TTL and handle missing daemon (#8199)
Adds a timer to re-register the pairing request before the 5-minute TTL
expires, keeping the QR code valid while the sheet is open. Also shows
an error when daemon client is unavailable instead of rendering an empty
sheet.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: honor task cancellation in QRPairingSheet pairing flow (#8210)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: enforce Content-Length pre-check in pairing proxy (#8212)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: reduce maxTokens default from 64000 to 16000 (#8217)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add streamThinking config flag and filter thinking deltas (#8219)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: skip deny on same-ID retry in PairingApprovalWindow (#8223)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: update maxTokens schema default and tests to 16000 (#8224)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: separate iOS override migration and guard macOS cleanup (#8225)
iOS: moves override cleanup into its own migratePairingOverridesIfNeeded()
with a separate migration key, so existing v4-migrated users still get
cleanup.
macOS: only runs cleanup when legacy iosPairingUseOverride key is actually
present, preserving intentional post-M9 overrides.
Addresses feedback from PR #8197.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: avoid QR flicker during refresh and register on daemon connect (#8227)
Keeps old QR visible during re-registration by only swapping credentials
atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger
registration when daemon becomes available after sheet opens.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: handle floating promise and add timeout in title generation (#8228)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: deduplicate isPlainObject into shared utility (#8229)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: add database indexes on memorySegments table (#8230)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add backpressure and metrics to session message queue (#8231)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: cache shell-parsing and risk classification results (#8232)
Co-authored-by: Claude <noreply@anthropic.com>
* security: add pino log serializer to scrub sensitive data (#8233)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: replace unsafe type assertions with proper type guards (#8234)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add circuit breaker to gateway runtime client (#8236)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: create centralized environment variable registry (#8235)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add status indication to macOS menu bar icon (#8237)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: replace any types with proper interfaces in test files (#8241)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove iosPairingUseOverride deletion from v4 migration (#8239)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240)
Porcupine's SPM package is iOS-only and pulls in ios-voice-processor
which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now
strict about this. The wake word engine is currently a stub so removing
the dep is safe. Also fixes missing VellumAssistantShared imports and
a stale protocol conformance in the wake word files.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: add database indexes on memoryItems table (#8244)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add per-surface serialization to prevent race conditions (#8245)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: source filter for Available Skills + platform catalog API (#8097)
* feat: add source filter to Available Skills and fetch catalog from platform API
- Add All/Vellum/Community source filter pills to Available Skills tab
- Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter
- Show Vellum catalog skills even if installed (with "Installed" label)
- Add refresh button to Installed tab empty state
- Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/)
- Pass platform session token (X-Session-Token) through IPC for authenticated fetch
- Regenerate IPC contract with optional sessionToken on SkillsSearchRequest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve platform token locally and fetch skill content via tar API
- Remove sessionToken from IPC contract and Swift chain; the daemon now
reads the platform API token from ~/.vellum/platform-token instead of
receiving it via IPC messages
- SessionTokenManager writes platform token to disk when set/deleted so
the daemon can read it for authenticated platform API calls
- Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/)
which returns a tar.gz archive; extracts SKILL.md from the tarball
with bundled fallback on failure
- Add readPlatformToken()/getPlatformTokenPath() to platform.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add AbortSignal support to tool implementations (#8246)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: split http-server.ts into focused middleware and route modules (#8243)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: handle QR refresh failure and remove dead onChange (#8248)
Shows error state after 2 consecutive refresh registration failures
instead of silently leaving a stale QR. Removes dead
.onChange(of: daemonClient != nil) since daemonClient is always
non-nil in production. Addresses feedback from PR #8227.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249)
* security: enforce 0o600 permissions on log files (#8252)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: propagate AbortSignal through permission checking (#8253)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: complete ingress config schema with validation (#8254)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: add database indexes on remaining tables (#8255)
Co-authored-by: Claude <noreply@anthropic.com>
* feat(macos): add secret dev mode toggle (#8226)
* feat(macos): add secret dev mode toggle via Assistant ID tap gesture
Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode,
similar to Android's developer options. Dev mode gates the Feature Flags
editor, Developer (env vars) section, and Platform URL in Connect tab.
State persists in UserDefaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: default dev mode to enabled in DEBUG builds
Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds
start with dev mode on, while still respecting an explicit toggle-off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reset refresh timer and failure counter on QR retry (#8257)
Resets consecutiveRefreshFailures to 0 and restarts the refresh timer
when the user clicks Retry after a QR refresh failure. Without this,
the QR would silently expire after 5 minutes and the next single
failure would immediately re-trigger the error state.
Addresses feedback from PR #8248.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: split lifecycle.ts into focused modules (#8259)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make global hotkey configurable in macOS client (#8258)
Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic
re-registration. Defaults to Cmd+Shift+G.
* feat: add structured error serialization to pino logger (#8260)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add numeric bounds validation for memory item confidence/importance (#8261)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make hardcoded daemon timeout values configurable (#8265)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add Zod schema for message metadata validation (#8268)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: separate migration code from platform utilities (#8272)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: use consistent pino logging throughout migration and startup code (#8273)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: resolve all CI type-check and lint errors (#8276)
- Add missing streamThinking to ThinkingConfigSchema default and test assertions
- Fix boolean | undefined return type in contradiction-checker transaction
- Wrap media-processing stage handlers to return Promise<void>
- Cast Cron through unknown for Record<string, unknown> conversion
- Update AgentLoopRun type to accept CheckpointInfo parameter
- Add withSurface to ToolSetupContext test stubs
- Add sessionId to ToolContext test stubs
- Cast input_schema to typed interface for property access in tests
- Fix fetch mock casts through unknown for Bun's preconnect property
- Remove unused imports/vars and fix lint violations across 14 files
Co-authored-by: Claude <noreply@anthropic.com>
* feat(macos): add health check indicator to Platform URL row (#8271)
* feat(macos): add health check indicator to Platform URL row
Show a dynamic status icon on the Platform URL row in Settings > Connect
that indicates whether the Vellum platform is reachable. Hits /healthz on
appear and displays green checkmark (reachable), red xmark (unreachable),
or spinner (checking). Error details shown on hover via tooltip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: gate platform health check on dev mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277)
* Guardian Cross-Channel Approval UX Polish (#8208)
* M1: Backend generative guardian copy + emoji title (#8117)
* feat: replace static guardian thread copy with model-generated copy
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: avoid blocking external channel dispatch on LLM copy generation (#8122)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: create macOS delivery row before awaiting LLM copy generation (#8127)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M2: macOS native notification + deep link to thread (#8147)
* feat: add macOS native notification + deep link for guardian requests
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add questionText to guardian IPC message for notification body (#8162)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M3: QA hardening + documentation (#8179)
* test: add guardian copy generation tests and update architecture docs
Co-Authored-By: Claude <noreply@anthropic.com>
* test: add dedicated test for real buildFallbackCopy implementation (#8198)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix: reject non-emoji guardian titles from model output (#8247)
* fix: validate emoji prefix in generated guardian title
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: only reject old Guardian question prefix, don't enforce emoji (#8251)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistant inbox feature flag gating from desktop UI (#8281)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistantInbox config schema and defaults (#8282)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: add rule for agents to keep AGENTS.md up to date (#8284)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: update inbox docs to reflect always-on behavior (#8293)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: change private to internal for properties accessed from AppDelegate extension (#8294)
connectionStatusCancellable, pulseTimer, and pulsePhase are accessed
from AppDelegate+MenuBar.swift, which is a separate file. Private
restricts access to the declaring file, so these need internal access.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: increase maxInputTokens from 180k to 200k (#8295)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve CI type-check and lint errors in ingress config and imports (#8296)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297)
Co-authored-by: marinatrajk <marina@odyseek.com>
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove QuickChat feature (#8300)
The QuickChat floating panel had an unfixable input focus bug — the
NSPanel couldn't reliably receive keyboard input. Remove the entire
feature: panel, view, hotkey monitors, notification category, settings
shortcut, and background session helpers.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove stale relayPort from storage when port field is cleared (#8301)
Co-authored-by: marinatrajk <marina@odyseek.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(macos): use consistent paragraph style for placeholder height measurement (#8303)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(macos): resolve CI build errors in settings views (#8306)
- Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles
in release builds (already gated by dev mode at runtime)
- Use explicit .some(true)/.some(false)/.none patterns in
SettingsConnectTab switch statements to satisfy exhaustiveness checker
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: make error message bubbles span full chat width (#8312)
Error bubbles were constrained to the same 520pt maxWidth as regular
messages. Use .infinity for error messages so they fill the available
chat area.
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add Quick Input bar (Cmd+/) (#8309)
* feat: add Quick Input bar (Cmd+/) for fast new thread creation
Adds a floating Spotlight-style input bar that appears system-wide via
Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it
opens the main window with a new thread containing that message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit
- Track and remove Carbon event handler on teardown to prevent accumulation
- Place Quick Input panel on the screen with the mouse cursor
- Skip restoring previous app on submit so main window doesn't flash
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: don't restore previous app on resign-key dismissal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(lint): resolve lint errors in influencer client (#8316)
- Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast
- Change InfluencerProfile nullable fields from `| null` to `| undefined`
- Update parseFollowerCount return type from `number | null` to `number | undefined`
- Replace all `!== null` checks with `!== undefined` per project convention
Co-authored-by: Claude <noreply@anthropic.com>
* feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: always start daemon HTTP server for iOS pairing (#8322)
The daemon's HTTP server (port 7821) is required for iOS pairing —
the gateway proxies all iOS traffic through it. Previously this was
gated behind the `localHttpEnabled` feature flag, so the daemon never
started its HTTP server unless the flag was manually enabled via env
var, causing HTTP 502 errors on iOS after QR pairing.
Three fixes:
- AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate)
- AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate)
- CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list
(the CLI was building a second minimal env and stripping it out)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add wake word keyword selection and fix APIKeyManager usage (#8324)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325)
* fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error
Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need
internal access — private restricts to the declaring file. Also wrap
registration error strings in a proper Error-conforming type since
Result requires its Failure type to conform to Error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway
- Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT
env var, then default 7821, when daemonClient.httpPort is nil (happens when
daemon HTTP server starts after socket connection during Qdrant timeout)
- Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway
is configured, enabling LAN-only pairing
- Update canGenerateQR, registration body, and QR payload to use
effectiveGatewayUrl instead of gatewayUrl
- Update hasGateway check to include LAN availability
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: always start daemon HTTP server for iOS pairing
The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var,
which relied on a fragile setenv → getenv → subprocess forwarding
chain from the macOS app. ProcessInfo.processInfo.environment is a
frozen snapshot from launch, so the env var often wasn't forwarded,
causing the HTTP server to never start and iOS pairing requests to
fail silently.
Three fixes:
- getRuntimeHttpPort() now defaults to 7821, so the HTTP server
always starts regardless of env var forwarding
- Wire setPairingBroadcast so pairing_approval_request IPC messages
actually reach the macOS app
- Remove conditional guard around HTTP server startup in lifecycle.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(macos): add loading state during token regeneration
Show a spinner and disable the QR button while the daemon restarts
after bearer token regeneration. Polls the healthz endpoint for up
to 30s to avoid showing a dead-end "daemon unreachable" error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(swift): fix IPC Unix socket protocol and reconnect on cancel
Two issues caused the macOS app to disconnect from the daemon after
~1 second and never reconnect:
1. DaemonConnection configured NWProtocolTCP.Options() on a Unix
domain socket endpoint. Unix sockets don't use TCP — the invalid
protocol stack caused the NWConnection to become unstable and
disconnect shortly after connecting, before authentication could
complete.
2. The .cancelled state handler didn't call scheduleReconnect() when
the connection had already been established (resumed==true). This
meant spontaneous disconnects were permanent — unlike .failed
which properly triggers auto-reconnect.
Without a stable IPC connection, all daemon broadcasts (pairing
approval requests, reminders, schedule events, watcher alerts) were
silently dropped because there were 0 authenticated sockets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add input validation and handle cleanup in PorcupineBinding (#8327)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: prevent double dismiss of Quick Input panel on submit (#8315)
Add isDismissing guard to prevent re-entrant dismiss calls when
showMainWindow causes the panel to resign key while the onSubmit
closure also calls dismiss explicitly.
Co-authored-by: Claude <noreply@anthropic.com>
* Release v0.3.6 (#8329)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix: move wake word callback outside lock and use dynamic frame length (#8331)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: disable LLM reranking for memory recall (#8067)
LLM reranking was calling Claude Haiku API on every message to re-score
memory candidates, adding ~2.2s latency. The RRF merge already produces
a well-ordered list from lexical, semantic, recency, and entity scores.
Disabling reranking reduces memory recall from ~2.6s to ~700ms.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340)
The previous commit removed NWProtocolTCP.Options() from Unix socket
connections, but this protocol has been in use since the original IPC
implementation (PR #499) and has been working in production for years.
Removing it risks breaking IPC in the v0.3.7 release.
Restores the TCP protocol stack while keeping the .cancelled state
reconnect improvement (scheduleReconnect on post-connection cancel).
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add explicit self. for property captures in PorcupineWakeWordEngine (#8337)
Swift strict concurrency requires explicit `self.` when referencing
properties inside closures. os.Logger string interpolation creates
implicit closures, so `keyword` and `sensitivity` need `self.` prefix.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add explicit self for keyword reference in os.Logger closure (#8342)
The release build (universal binary) requires explicit `self.` for
property references inside os.Logger string interpolation closures.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve CI failures blocking v0.3.7 release (#8344)
- TypeScript: fix setPairingBroadcast type to use ServerMessage instead
of loose { type: string; [key: string]: unknown }
- Gateway lint: prefix unused vars with _ in whatsapp-deliver test
- Swift: add explicit self. for keyword property in closure
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: broadcast pairing approval to HTTP/SSE clients (#8348)
When the macOS app uses HTTP transport (localHttpEnabled flag), it
connects via SSE instead of the Unix domain socket. Pairing approval
requests were only broadcast to IPC socket clients, so HTTP-connected
clients never received them.
Two changes:
1. RuntimeHttpServer now also publishes pairing events to the
AssistantEventHub with assistantId 'self' so SSE subscribers
receive them.
2. AssistantEventHub allows events without sessionId (system events)
to pass through to all subscribers regardless of their sessionId
filter.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* M1: Add Voice -> Run/Session Bridge (#8222)
* feat: add voice -> run/session bridge with streaming event sink and cancellation
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: scope run abort handles to originating run to prevent stale cancellation (#8238)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M2: Replace CallOrchestrator with Session-Backed Voice Controller (#8275)
* feat: replace CallOrchestrator with session-backed CallController for voice turns
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix: Resolve voice turn promise on abort/exception (#8280)
* fix: resolve voice turn promise on abort and agent-loop exceptions
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: increment llmRunVersion in destroy() to prevent post-turn side effects on destroyed controller (#8290)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M3: Guardian Context and Side-Effect Policy Parity (#8299)
* feat: enforce guardian context and strict side-effect policy parity for voice turns
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: auto-deny tool confirmations for non-guardian voice turns to prevent 300s timeout (#8302)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M4: Clean Up Legacy Orchestrator Artifacts + Docs (#8304)
* chore: clean up legacy call orchestrator artifacts and update architecture docs
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: fix stale Orch participant and duplicate Session declaration in ARCHITECTURE.md Mermaid diagrams (#8307)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* fix: address final PR review feedback — move bridge injection, fix opener marker persistence, remove duplicate user message persist
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(macos): add Restart menu item to status bar menu (#8347)
* feat(macos): add Restart menu item to status bar menu
Add a Restart option to the menu bar dropdown that stops the daemon,
launches a fresh app instance, and terminates the current one. Useful
for recovering from stuck states without manually quitting and relaunching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: gate app termination on successful relaunch in performRestart
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Vellum Assistant <assistant@vellum.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add memory degradation banner to component gallery with #F5F3EB background (#8356)
Co-authored-by: Claude <noreply@anthropic.com>
* Add rename option to thread right-click context menu (#8351)
* M1: Add session_rename IPC message to daemon (#8338)
* feat: add session_rename IPC message for client-initiated title changes
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: validate conversation exists before renaming in handleSessionRename (#8341)
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
* M2: Add rename option to macOS thread context menu UI (#8346)
* feat: add rename option to macOS thread context menu
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: only show rename option for threads with a daemon session (#8350)
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove redundant conversation_id index on memory_segments (#8357)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove unscoped queue-full error and guard expireStale against exceptions (#8358)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: preserve statusCode fallback when status is undefined in getErrorStatusCode (#8360)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: preserve Error name/message/stack in log redaction serializer (#8359)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: include workingDir and manifestOverride in risk cache key (#8361)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove redundant fingerprint index from memoryItems migration (#8362)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add missing legitimate env vars to KNOWN_VELLUM_VARS (#8363)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: clean up settled surface mutex entries to prevent memory leak (#8364)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: return immediately on aborted CAPTCHA wait instead of breaking (#8365)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: rebind menu bar connection observer after client replacement and fix pulse animation (#8366)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: limit half-open probes to single attempt and propagate CircuitBreakerOpenError (#8367)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: read daemon timeouts without triggering loadConfig/migration side effects (#8368)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: enforce log file permissions on existing files at startup (#8371)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: auto-start SSE on HTTP transport connect for system events (#8370)
When using HTTP transport (VELLUM_FLAG_LOCAL_HTTP_ENABLED=1), SSE was
only started when MainWindowView.onAppear fired. This meant system
events like pairing approval requests were lost if they arrived before
the main window appeared.
Auto-start the SSE stream immediately after the first health check
passes in connect(). MainWindowView.onAppear still calls startSSE()
but it's a no-op when the stream is already running.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: throw typed cancellation error from permission checks (#8372)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add pre-commit warning when modifying system-prompt.ts (#8354)
* feat: add pre-commit warning when modifying system-prompt.ts
Adds a non-blocking warning to the pre-commit hook that fires when
system-prompt.ts is staged. Reminds contributors to consider whether
their change belongs in a skill, IDENTITY.md, SOUL.md, USER.md,
LOOKS.md, or skills/ instead of directly in the system prompt.
Includes a 3-second pause to ensure the warning is actually read.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add BOOTSTRAP.md to system-prompt warning file list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Release v0.3.7 (#8373)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix: initialize pairing handlers so approval responses are processed (#8374)
initPairingHandlers() was defined but never called, leaving
pairingStoreRef as null. When macOS sent a pairing_approval_response
over IPC, the handler silently returned on the null check (line 29),
so approvals never reached the PairingStore — iOS stayed stuck on
"Waiting for approval" and the device was never added to the allowlist.
Wire up initPairingHandlers() in lifecycle.ts after the HTTP server
starts, passing the PairingStore instance and bearer token.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: inject call-control prompt + await barge-in teardown
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: improve media analysis skill defaults and add best practices (#8385)
Update defaults based on real-world usage feedback: keyframe interval
3s→1s, segment duration 20s→15s, skip_dead_time on→off. Add best
practices section with broad-vs-targeted map prompt guidance, sample
prompt/schema, clip delivery notes, and vision analysis limitations.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: unconditional teardown await + bump run version before barge-in
Co-Authored-By: Claude <noreply@anthropic.com>
* feat: add holistic Codex review phase to safe-blitz command (#8387)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: watch http-token file so gateway picks up daemon token changes (#8389)
When the daemon restarts and writes a new bearer token to
~/.vellum/http-token, a gateway process that started earlier still
holds the stale token. This causes 401 errors for iOS clients that
received the new token during pairing.
Add a file watcher for http-token (following the existing
CredentialWatcher pattern) that refreshes runtimeBearerToken,
runtimeProxyBearerToken, and runtimeGatewayOriginSecret in the
live config when the file changes.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: drop legacy conversation_id index and remove from Drizzle schema (#8393)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: unreserve dedup cache entries on CircuitBreakerOpenError before returning 503 (#8394)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: validate daemon timeout bounds in readDaemonTimeouts (#8395)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: propagate queue-full status through subagent message path (#8397)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Alex Nork <48630278+alex-nork@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Ashlee Radka <ashleeradka@gmail.com>
Co-authored-by: asharma53 <64060709+asharma53@users.noreply.github.com>
Co-authored-by: siddseethepalli <siddseethepalli@gmail.com>
Co-authored-by: David Vargas Fuertes <vargas@vellum.ai>
Co-authored-by: NgoHarrison <harrison.ngo719@gmail.com>
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Aaron Levin <awlevin@users.noreply.github.com>
Co-authored-by: V <vincent@vellum.ai>
Co-authored-by: Marina Trajkovska <trajk.marina@gmail.com>
Co-authored-by: marinatrajk <marina@odyseek.com>
Co-authored-by: vellum-automation[bot] <192048195+vellum-automation[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jason Zhou <jason@vellum.ai>
Co-authored-by: Vellum Assistant <assistant@vellum.ai>
Co-authored-by: Tirman Sidhu <tirmansidhu@gmail.com>
Co-authored-by: Nick <127171085+ZeebBoyBlue@users.noreply.github.com>
Co-authored-by: Nicolas Zeeb <all@Nicolass-MacBook-Pro.local>
* chore: merge main into feature branch (#8402)
* fix: reset activatedViaWakeWord flag on voice mode activation failure (#8180)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: use effective base URL for polling and cancel task on dismiss (#8185)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: derive segment count from manifest in media diagnostics (#8187)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: enforce payload size limit on pairing proxy endpoints (#8188)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: restore approvalConversationGenerator in RuntimeHttpServer (#8189)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: approved devices race condition and optimistic clear (#8190)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: move zero-frame check before atomic rename in preprocess (#8191)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: include context field in map cache config hash (#8192)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: align lastPairedAt type to Int matching generated IPC types (#8193)
Co-authored-by: Claude <noreply@anthropic.com>
* improve Gmail OAuth setup UX with auto-detection and clearer messaging (#8194)
Rewrite the Google OAuth setup skill prompts to feel like 3 user actions
instead of a confusing 10-step process. Auto-detect sign-in completion
by polling browser snapshots instead of asking users to confirm manually.
Add progress callouts and clearer credential entry instructions.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reset activatedViaWakeWord flag outside wakeWordEnabled guard (#8195)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: send deny on PairingApprovalWindow close and supersede (#8196)
When the pairing approval window is closed via the X button or superseded
by a new request, sends a deny response to the daemon. Prevents iOS
devices from hanging in pending state indefinitely.
- Track currentPairingRequestId and responseSent flag
- Add WindowCloseDelegate (NSWindowDelegate) for X-button close
- denyIfNeeded() sends deny for unanswered requests in close()
- Set responseSent = true in onDecision before calling close()
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clear stale pairing overrides during v4 migration (#8197)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: re-register QR pairing before TTL and handle missing daemon (#8199)
Adds a timer to re-register the pairing request before the 5-minute TTL
expires, keeping the QR code valid while the sheet is open. Also shows
an error when daemon client is unavailable instead of rendering an empty
sheet.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: honor task cancellation in QRPairingSheet pairing flow (#8210)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: enforce Content-Length pre-check in pairing proxy (#8212)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: roll back optimistic removal in removeApprovedDevice on IPC failure (#8215)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: reduce maxTokens default from 64000 to 16000 (#8217)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add streamThinking config flag and filter thinking deltas (#8219)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: skip deny on same-ID retry in PairingApprovalWindow (#8223)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: update maxTokens schema default and tests to 16000 (#8224)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: separate iOS override migration and guard macOS cleanup (#8225)
iOS: moves override cleanup into its own migratePairingOverridesIfNeeded()
with a separate migration key, so existing v4-migrated users still get
cleanup.
macOS: only runs cleanup when legacy iosPairingUseOverride key is actually
present, preserving intentional post-M9 overrides.
Addresses feedback from PR #8197.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: avoid QR flicker during refresh and register on daemon connect (#8227)
Keeps old QR visible during re-registration by only swapping credentials
atomically on HTTP 200 success. Adds .onChange(of: daemonClient) to trigger
registration when daemon becomes available after sheet opens.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: handle floating promise and add timeout in title generation (#8228)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: deduplicate isPlainObject into shared utility (#8229)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: add database indexes on memorySegments table (#8230)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add backpressure and metrics to session message queue (#8231)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: cache shell-parsing and risk classification results (#8232)
Co-authored-by: Claude <noreply@anthropic.com>
* security: add pino log serializer to scrub sensitive data (#8233)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: replace unsafe type assertions with proper type guards (#8234)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add circuit breaker to gateway runtime client (#8236)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: create centralized environment variable registry (#8235)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add status indication to macOS menu bar icon (#8237)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: replace any types with proper interfaces in test files (#8241)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove iosPairingUseOverride deletion from v4 migration (#8239)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: remove Porcupine iOS-only SPM dep that breaks Xcode 26.2 build (#8240)
Porcupine's SPM package is iOS-only and pulls in ios-voice-processor
which uses AVAudioSession (unavailable on macOS). Xcode 26.2 is now
strict about this. The wake word engine is currently a stub so removing
the dep is safe. Also fixes missing VellumAssistantShared imports and
a stale protocol conformance in the wake word files.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* perf: add database indexes on memoryItems table (#8244)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add per-surface serialization to prevent race conditions (#8245)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: source filter for Available Skills + platform catalog API (#8097)
* feat: add source filter to Available Skills and fetch catalog from platform API
- Add All/Vellum/Community source filter pills to Available Skills tab
- Capitalize "Vellum" in empty state, hide community disclaimer for Vellum filter
- Show Vellum catalog skills even if installed (with "Installed" label)
- Add refresh button to Installed tab empty state
- Switch catalog fetch from GitHub raw URL to platform API (/v1/skills/)
- Pass platform session token (X-Session-Token) through IPC for authenticated fetch
- Regenerate IPC contract with optional sessionToken on SkillsSearchRequest
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve platform token locally and fetch skill content via tar API
- Remove sessionToken from IPC contract and Swift chain; the daemon now
reads the platform API token from ~/.vellum/platform-token instead of
receiving it via IPC messages
- SessionTokenManager writes platform token to disk when set/deleted so
the daemon can read it for authenticated platform API calls
- Implement fetchSkillContent via platform tar API (GET /v1/skills/{id}/)
which returns a tar.gz archive; extracts SKILL.md from the tarball
with bundled fallback on failure
- Add readPlatformToken()/getPlatformTokenPath() to platform.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add AbortSignal support to tool implementations (#8246)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: split http-server.ts into focused middleware and route modules (#8243)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: handle QR refresh failure and remove dead onChange (#8248)
Shows error state after 2 consecutive refresh registration failures
instead of silently leaving a stale QR. Removes dead
.onChange(of: daemonClient != nil) since daemonClient is always
non-nil in production. Addresses feedback from PR #8227.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add response style section, trim verbose system prompt sections, strengthen SOUL.md conciseness (#8249)
* security: enforce 0o600 permissions on log files (#8252)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: propagate AbortSignal through permission checking (#8253)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: complete ingress config schema with validation (#8254)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: add database indexes on remaining tables (#8255)
Co-authored-by: Claude <noreply@anthropic.com>
* feat(macos): add secret dev mode toggle (#8226)
* feat(macos): add secret dev mode toggle via Assistant ID tap gesture
Tap the Assistant ID 7 times in Settings > Advanced to toggle dev mode,
similar to Android's developer options. Dev mode gates the Feature Flags
editor, Developer (env vars) section, and Platform URL in Connect tab.
State persists in UserDefaults.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: default dev mode to enabled in DEBUG builds
Uses `UserDefaults.object(forKey:) as? Bool ?? true` so debug builds
start with dev mode on, while still respecting an explicit toggle-off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reset refresh timer and failure counter on QR retry (#8257)
Resets consecutiveRefreshFailures to 0 and restarts the refresh timer
when the user clicks Retry after a QR refresh failure. Without this,
the QR would silently expire after 5 minutes and the next single
failure would immediately re-trigger the error state.
Addresses feedback from PR #8248.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: split lifecycle.ts into focused modules (#8259)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make global hotkey configurable in macOS client (#8258)
Add keyboard shortcut settings UI, UserDefaults persistence, and dynamic
re-registration. Defaults to Cmd+Shift+G.
* feat: add structured error serialization to pino logger (#8260)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add numeric bounds validation for memory item confidence/importance (#8261)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: make hardcoded daemon timeout values configurable (#8265)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add Zod schema for message metadata validation (#8268)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: separate migration code from platform utilities (#8272)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: use consistent pino logging throughout migration and startup code (#8273)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: resolve all CI type-check and lint errors (#8276)
- Add missing streamThinking to ThinkingConfigSchema default and test assertions
- Fix boolean | undefined return type in contradiction-checker transaction
- Wrap media-processing stage handlers to return Promise<void>
- Cast Cron through unknown for Record<string, unknown> conversion
- Update AgentLoopRun type to accept CheckpointInfo parameter
- Add withSurface to ToolSetupContext test stubs
- Add sessionId to ToolContext test stubs
- Cast input_schema to typed interface for property access in tests
- Fix fetch mock casts through unknown for Bun's preconnect property
- Remove unused imports/vars and fix lint violations across 14 files
Co-authored-by: Claude <noreply@anthropic.com>
* feat(macos): add health check indicator to Platform URL row (#8271)
* feat(macos): add health check indicator to Platform URL row
Show a dynamic status icon on the Platform URL row in Settings > Connect
that indicates whether the Vellum platform is reachable. Hits /healthz on
appear and displays green checkmark (reachable), red xmark (unreachable),
or spinner (checking). Error details shown on hover via tooltip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: gate platform health check on dev mode
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: move response style directives to SOUL.md, remove buildResponseStyleSection (#8277)
* Guardian Cross-Channel Approval UX Polish (#8208)
* M1: Backend generative guardian copy + emoji title (#8117)
* feat: replace static guardian thread copy with model-generated copy
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: avoid blocking external channel dispatch on LLM copy generation (#8122)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: create macOS delivery row before awaiting LLM copy generation (#8127)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M2: macOS native notification + deep link to thread (#8147)
* feat: add macOS native notification + deep link for guardian requests
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: add questionText to guardian IPC message for notification body (#8162)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* M3: QA hardening + documentation (#8179)
* test: add guardian copy generation tests and update architecture docs
Co-Authored-By: Claude <noreply@anthropic.com>
* test: add dedicated test for real buildFallbackCopy implementation (#8198)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* Fix: reject non-emoji guardian titles from model output (#8247)
* fix: validate emoji prefix in generated guardian title
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: only reject old Guardian question prefix, don't enforce emoji (#8251)
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistant inbox feature flag gating from desktop UI (#8281)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: add provider abstraction and approval resilience rules to AGENTS.md (#8279)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistantInbox config schema and defaults (#8282)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: make ingress ACL enforcement always-on (remove feature flag gating) (#8283)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: add rule for agents to keep AGENTS.md up to date (#8284)
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove assistantInbox feature-flag check from ingress ACL enforcement (#8287)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude <noreply@anthropic.com>
* docs: update inbox docs to reflect always-on behavior (#8293)
Co-authored-by: Harrison Ngo <harrison@vellum.ai>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: change private to internal for properties accessed from AppDelegate extension (#8294)
connectionStatusCancellable, pulseTimer, and pulsePhase are accessed
from AppDelegate+MenuBar.swift, which is a separate file. Private
restricts access to the declaring file, so these need internal access.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: increase maxInputTokens from 180k to 200k (#8295)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve CI type-check and lint errors in ingress config and imports (#8296)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: use Chrome debugger API for CSP-bypass eval, fix Swift Result<Void,String> build error, add influencer CLI command (#8297)
Co-authored-by: marinatrajk <marina@odyseek.com>
Co-authored-by: Claude <noreply@anthropic.com>
* refactor: remove QuickChat feature (#8300)
The QuickChat floating panel had an unfixable input focus bug — the
NSPanel couldn't reliably receive keyboard input. Remove the entire
feature: panel, view, hotkey monitors, notification category, settings
shortcut, and background session helpers.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove stale relayPort from storage when port field is cleared (#8301)
Co-authored-by: marinatrajk <marina@odyseek.com>
Co-authored-by: Claude <noreply@anthropic.com>
* fix(macos): use consistent paragraph style for placeholder height measurement (#8303)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(macos): resolve CI build errors in settings views (#8306)
- Remove #if DEBUG guard from SettingsPanelEnvVarsSheet so it compiles
in release builds (already gated by dev mode at runtime)
- Use explicit .some(true)/.some(false)/.none patterns in
SettingsConnectTab switch statements to satisfy exhaustiveness checker
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: make error message bubbles span full chat width (#8312)
Error bubbles were constrained to the same 520pt maxWidth as regular
messages. Use .infinity for error messages so they fill the available
chat area.
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add Quick Input bar (Cmd+/) (#8309)
* feat: add Quick Input bar (Cmd+/) for fast new thread creation
Adds a floating Spotlight-style input bar that appears system-wide via
Cmd+/ (Carbon RegisterEventHotKey). Type a message, hit Return, and it
opens the main window with a new thread containing that message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review — prevent handler leak, fix multi-monitor, no-flash on submit
- Track and remove Carbon event handler on teardown to prevent accumulation
- Place Quick Input panel on the screen with the mouse cursor
- Skip restoring previous app on submit so main window doesn't flash
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: don't restore previous app on resign-key dismissal
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(lint): resolve lint errors in influencer client (#8316)
- Replace `as any` with proper `Omit<ExtensionCommand, 'id'>` type cast
- Change InfluencerProfile nullable fields from `| null` to `| undefined`
- Update parseFollowerCount return type from `number | null` to `number | undefined`
- Replace all `!== null` checks with `!== undefined` per project convention
Co-authored-by: Claude <noreply@anthropic.com>
* feat: request 16kHz mono format in AlwaysOnAudioMonitor audio tap (#8318)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add PorcupineBinding.swift — dlopen wrapper for Porcupine C API (#8320)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: bundle Porcupine dylib, model, and keywords in build.sh (#8321)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: always start daemon HTTP server for iOS pairing (#8322)
The daemon's HTTP server (port 7821) is required for iOS pairing —
the gateway proxies all iOS traffic through it. Previously this was
gated behind the `localHttpEnabled` feature flag, so the daemon never
started its HTTP server unless the flag was manually enabled via env
var, causing HTTP 502 errors on iOS after QR pairing.
Three fixes:
- AppDelegate: always set RUNTIME_HTTP_PORT=7821 (remove flag gate)
- AssistantCli: always forward RUNTIME_HTTP_PORT to CLI (remove flag gate)
- CLI local.ts: add RUNTIME_HTTP_PORT to the daemon env forwarding list
(the CLI was building a second minimal env and stripping it out)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: replace PorcupineWakeWordEngine stub with real Porcupine C SDK implementation (#8323)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add wake word keyword selection and fix APIKeyManager usage (#8324)
Co-authored-by: Claude <noreply@anthropic.com>
* fix(swift): fix IPC Unix socket protocol and reconnect on cancel (#8325)
* fix(swift): widen access control for AppDelegate+MenuBar extension and fix Result<Void, String> error
Properties accessed by AppDelegate+MenuBar.swift (in a separate file) need
internal access — private restricts to the declaring file. Also wrap
registration error strings in a proper Error-conforming type since
Result requires its Failure type to conform to Error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(macos): resolve QR pairing issues with httpPort fallback and LAN gateway
- Add resolvedHttpPort computed property that falls back to RUNTIME_HTTP_PORT
env var, then default 7821, when daemonClient.httpPort is nil (happens when
daemon HTTP server starts after socket connection during Qdrant timeout)
- Add effectiveGatewayUrl that falls back to localLanUrl when no cloud gateway
is configured, enabling LAN-only pairing
- Update canGenerateQR, registration body, and QR payload to use
effectiveGatewayUrl instead of gatewayUrl
- Update hasGateway check to include LAN availability
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: always start daemon HTTP server for iOS pairing
The daemon HTTP server was gated behind RUNTIME_HTTP_PORT env var,
which relied on a fragile setenv → getenv → subprocess forwarding
chain from the macOS app. ProcessInfo.processInfo.environment is a
frozen snapshot from launch, so the env var often wasn't forwarded,
causing the HTTP server to never start and iOS pairing requests to
fail silently.
Three fixes:
- getRuntimeHttpPort() now defaults to 7821, so the HTTP server
always starts regardless of env var forwarding
- Wire setPairingBroadcast so pairing_approval_request IPC messages
actually reach the macOS app
- Remove conditional guard around HTTP server startup in lifecycle.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(macos): add loading state during token regeneration
Show a spinner and disable the QR button while the daemon restarts
after bearer token regeneration. Polls the healthz endpoint for up
to 30s to avoid showing a dead-end "daemon unreachable" error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(swift): fix IPC Unix socket protocol and reconnect on cancel
Two issues caused the macOS app to disconnect from the daemon after
~1 second and never reconnect:
1. DaemonConnection configured NWProtocolTCP.Options() on a Unix
domain socket endpoint. Unix sockets don't use TCP — the invalid
protocol stack caused the NWConnection to become unstable and
disconnect shortly after connecting, before authentication could
complete.
2. The .cancelled state handler didn't call scheduleReconnect() when
the connection had already been established (resumed==true). This
meant spontaneous disconnects were permanent — unlike .failed
which properly triggers auto-reconnect.
Without a stable IPC connection, all daemon broadcasts (pairing
approval requests, reminders, schedule events, watcher alerts) were
silently dropped because there were 0 authenticated sockets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use AVAudioConverter for 16kHz resampling instead of custom tap format (#8326)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: move FRAMEWORKS_DIR definition before Porcupine staleness check in build.sh (#8328)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: add input validation and handle cleanup in PorcupineBinding (#8327)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: prevent double dismiss of Quick Input panel on submit (#8315)
Add isDismissing guard to prevent re-entrant dismiss calls when
showMainWindow causes the panel to resign key while the onSubmit
closure also calls dismiss explicitly.
Co-authored-by: Claude <noreply@anthropic.com>
* Release v0.3.6 (#8329)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix: move wake word callback outside lock and use dynamic frame length (#8331)
Co-authored-by: Claude <noreply@anthropic.com>
* fix: prevent duplicate audio in AVAudioConverter and use ceil for buffer capacity (#8332)
Co-authored-by: Claude <noreply@anthropic.com>
* perf: disable LLM reranking for memory recall (#8067)
LLM reranking was calling Claude Haiku API on every message to re-score
memory candidates, adding ~2.2s latency. The RRF merge already produces
a well-ordered list from lexical, semantic, recency, and entity scores.
Disabling reranking reduces memory recall from ~2.6s to ~700ms.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix(swift): restore NWProtocolTCP on Unix socket, keep cancelled reconnect (#8340)
The previous commit removed NWProtocolTCP.Options() from …
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.
Replace unsafe type assertions with proper type guard functions and existing utilities:
msg as unknown as Record<string, unknown>with object spread ({ ...msg }) to safely widen the type for extractPromptSpeakerMetadata, and narrow the default branch cast fromRecord<string, unknown>to{ type: unknown }.as unknown as { changes?: number }casts on Drizzle.run()return values with the existingrawChanges()utility from raw-query.ts (designed exactly for this purpose). Replace the singleas unknown asfor Croner internals with runtime property checks that gracefully fall back to the raw expression.err as Record<string, unknown>with agetErrorStatusCode()helper that usesinnarrowing to safely access.status/.statusCodeon error objects.Tconstruction casts are a fundamental TypeScript limitation (no type guard applies when constructing values for generic types).