Sentinel v0.8.0
Features
- desktop: route the Claude Desktop app through Sentinel alongside the CLI
- detect the Claude Code CLI and Claude Desktop app independently and broadcast surface state only on change, so a surface installed later is picked up automatically
- add one-click Enable/Disable for the Claude Desktop app by writing its Claude-3p configLibrary gateway config with atomic temp+rename, preserving any non-Sentinel entries and never leaving appliedId dangling
- inject the rotating pool token for desktop /v1/messages requests so the desktop app inherits multi-account routing (its dummy gateway key never reaches upstream)
- watch the desktop configLibrary for drift and offer one-click re-apply, matching the CLI OTEL re-patch behavior
- track desktop routing health from the claude-desktop-3p proxy user-agent marker (positive-only; desktop emits no OTEL)
- add a Claude Desktop status card and drift banner to the app UI, rendered only when the desktop app is detected
- persist the Sentinel-owned desktop config id in settings so update and remove target exactly our entry
- document both surfaces in the README and site, including a new Connect Claude Desktop guide and troubleshooting entry
Bug fixes
- daemon: stop subagent prompts for Sentinel's retrieve tool when settings-sync is off
- write Sentinel's own read-only/loopback allow-rules (mcp__sentinel__retrieve and the code-mode curl endpoint) straight into ~/.claude/settings.json when Claude Code settings-sync is off, so they reach subagents (which do not inherit a project-local grant) instead of only living in the DB and prompting on every call
- add ensureClaudeSettingsAllow / removeClaudeSettingsAllow: additive, idempotent settings.json writers that preserve every other key
- re-assert the infra allow-rules on daemon startup so an install from a prior session self-heals into settings.json with no user action
- add mcp__sentinel__retrieve to every curated subagent's tools allowlist so reversible elision is actually reversible inside restricted-tools agents
- extend the retrieval-MCP integration test to assert settings.json (not just the DB) carries the allow-rule
- app: hide the Claude Desktop banner once active and move Disable into Settings
- hide DesktopSurfaceCard when the desktop app is already routed through Sentinel (active), matching the CLI ActivationBanner's active-state gate, so the banner no longer persists with a Disable button after enabling
- keep the banner only for the two actionable states: Enable (not routed) and Re-apply (foreign-gateway drift recovery)
- add a "Route Claude Desktop through Sentinel" toggle to Settings, General tab, wired to the drift hook's activate/deactivate, shown only when the desktop app is installed and disabled while an action is in flight
- add optional disabled support to the ToggleRow settings primitive
- daemon: roll over usage windows on an internal timer when their reset elapses
- add RateLimitStore.expireStaleWindows to zero utilization, clear status, and null the reset on any window whose reset timestamp has already passed
- add a rate-limit sweeper that runs at daemon startup and every 60s, broadcasting rate_limits_updated for each account it rolls over
- reset stale pool and per-account usage (and stop the "resets soon" countdown) even when no requests flow through the proxy
- release a lingering weekly-rate-limit pause off the now-allowed status via a recompute hook, since a nulled reset is skipped by the reset-delta release paths
Maintenance
- apply Prettier formatting to daemon desktop, sweeper, and claude-sync files
- reformat files flagged by the CI format:check (whitespace and line-wrapping only, no logic change)
- site: update Claude Desktop enable/disable flow and note retrieve auto-allow
- move the Claude Desktop disable instructions from the now auto-hiding banner card to Settings, General tab
- note that the desktop card disappears once routing is active, in both the connect guide and troubleshooting
- document that Sentinel auto-allows mcp__sentinel__retrieve in ~/.claude/settings.json so Claude Code never prompts for it, including inside subagents
Full changelog: v0.7.0...v0.8.0