feat: self-hosted claude.ai connector (Chrome side panel + bidirectional sync)#73
Merged
Conversation
End-to-end browser-extension-based integration that syncs SkillNote skills
to and from users' claude.ai accounts without routing through any
SkillNote-project infrastructure (data isolation preserved).
Backend (FastAPI)
- 3 alembic migrations: integrations + ops queue + skill links (0019),
audit log + pair-attempt rate limit + per-skill toggle (0020),
cookie_expired audit event (0021).
- Endpoints under /v1/integrations/claude-ai: extension pair/approve/
status/operations/complete/skill-bundle/known-skill-ids/imported-skill/
status/telemetry; UI integrations CRUD; conflicts + preview + resolve;
activity feed (paginated, date-windowed) + CSV export; analytics +
sparkline; health; queue; diagnostic (8-check audit).
- Defenses: token-hash storage, with_for_update redemption lock, YAML
safe_dump for SKILL.md frontmatter, pair-endpoint rate limit per
source IP, telemetry payload validation, integration-scoped tokens,
auth_expired flow flips status + writes cookie_expired audit row.
Browser extension (Manifest V3)
- Service worker (alarms-based), options + popup UIs, vitest tests.
- SkillNote client: timeouts, AbortController, non-JSON guard,
SkillNoteAuthError vs SkillNoteNetworkError categorization, write-
queue mutex on chrome.storage, releaseInFlightOps on claude.ai
outages, fetchSelfStatus for popup counters.
- claude.ai client: REST surface (org skills CRUD), session-cookie
watcher, endpoint-changed detection.
Frontend (Next.js)
- Connect page surfaces claude.ai as a first-class agent card.
- /settings/integrations/claude-ai dedicated page with:
- 4-step interactive setup stepper (browser-aware: Chrome/Edge/
Brave/Arc/Firefox; Safari gets an unsupported panel),
progress counter, troubleshoot section, per-backend localStorage
ack flag, "Mark step done" + "Reset stepper" affordances.
- Connected-browsers list with status pills, conflict-policy
switcher, optimistic disconnect dialog, cookie-expired re-sign-in CTA.
- Live sync-queue panel (5s poll, stale-queue warning).
- 7-day analytics panel (sparkline, top-5 synced, per-browser table).
- Recent-activity preview + dedicated activity page with date
pickers, skill filter, CSV export, search, pagination.
- Conflicts section with bulk Resolve-all menu, per-row diff
preview (last-pushed vs current SkillNote version + claude.ai
metadata).
- One-click diagnostic modal with 8 pass/warn/fail checks.
- Health card (failed_ops counter, stale-data indicator).
- Per-skill SkillSyncBadge on skill detail pages.
- Pair-approval page validates the 6-char code shape client-side,
emits a /v1/setup/installs telemetry ping on success.
CLI
- skillnote connect claude-ai prints unpacked-install instructions
(Web Store / AMO listings are pending review).
Tests
- 223 backend tests (integration + unit) covering every endpoint,
contract, rate limit, audit event, conflict flow, security boundary.
- 51 extension vitest tests (client, storage, telemetry, resilience).
- 100 frontend e2e (Playwright) covering discovery, stepper, pair flow,
cookie-expired, conflict policy + diff, queue, analytics, activity
export, diagnostic modal, accessibility.
Docs
- docs/claude-ai-integration.md (architecture + sequence diagrams)
- docs/claude-ai-admin-runbook.md (operator playbook)
- docs/claude-ai-endpoints.md (REST surface)
- docs/claude-ai-user-guide.md (end-user flow)
- README section under "Wire up your AI agent"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ardening UX: - Per-collection "Sync to claude.ai" via a header Sync dropdown (claude.ai + OpenAI "soon"), with a confirm + transfer animation and real brand marks (claude.ai spark, OpenAI); read-only badge on collection cards. - Notifications bell (top-right) replaces the full-page pairing-approval interstitial: pending requests with Approve/Dismiss (code shown to verify), recent connector activity, and a "View all activity" link to the full feed. - Analytics: split claude.ai (web) vs Claude Code (CLI) in the agent breakdown; new "Recent chats" panel showing session/chat names. Architecture: - Web app proxies /v1/* to the backend (next.config rewrite, SKILLNOTE_API_PROXY_TARGET) so clients pair with the UI URL, not the API port. - Web→extension content-script bridge: a UI toggle wakes the MV3 worker and syncs immediately instead of waiting for the 1-min alarm. Reverse-sync / conflict engine: - staged_version_id marker (migration 0026) replaces the unsound "newest non-latest" heuristic in resolve_conflict; refuse overwrite on unlinked slug-collision; re-stash on re-import; re-anchor baselines. Backend hardening (bug audit): - case-insensitive published-collection matching; idempotent op completion; publish-toggle IntegrityError guard; dynamic alembic head in diagnostic; enqueue_group_publish row lock; analytics scoped to publish_group; refuse CORS '*' in prod; session_name on skill_call_events (migration 0027) + pending-pairings endpoint. Extension hardening: - publish_group per-group try/catch + re-enable + unconditional retire pass; AbortController timeouts on claude.ai calls; tick() re-entrancy guard; bounded conversation-tree recursion; redemption_url scheme allowlist. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ime theme match, Notifications, cross-platform + tests Builds on the connector base (c18c530, c0c2321) with a full polish + hardening pass and comprehensive test coverage. Extension (Chrome side panel) - Migrate the popup to a native Chrome SIDE PANEL (sidePanel API) — full-height, stays open beside claude.ai; read-only status surface (control lives in the app). - Usage hero ("this week on claude.ai"), live synced-collections list, Activity tab, in-panel Settings — no new tabs. - Real-time theme matching: a content-script observer mirrors claude.ai / the app's light/dark instantly (MutationObserver + prefers-color-scheme), with worker pull + on-open fallbacks. Warm palette tuned to Anthropic's surfaces. - Inline pairing form (no options-tab detour); permission priming note. - Native-feel fixes: no flicker/scroll-jump on background polls, focus rings + keyboard tab nav + Escape, timer-leak + re-render-race guards, FOUC fix. - LP (Luna Prompts) brand icon across all sizes. Backend - Notifications: unified activity feed (3-day life + prune), skill lifecycle events (migration 0028 extends the audit CHECK), /extension/reconcile, scalable /v1/collections (?q/?published/?limit + X-Total-Count), "skills synced" counter fix (published-collection skills, not skill_links), tightened op reaper. - Windows-reserved skill-name validation (backend + frontend mirror). Cross-platform - normalizeSkillnoteUrl → origin (fixes pasted URL-with-path breaking all calls) + scheme-less input; defaultBrowserLabel detects ChromeOS/Android/iOS/Windows. Tests: extension 153 (incl. theme, client, render); new backend integration + unit suites (collections filtering, reconcile, lifecycle activity, reserved names). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconciles the connector branch with mainline 0.5.6 (cli-sync, release 0.5.5/0.5.6, import fixes #64/#65, GET /v1/skills content_md drop). Conflicts resolved: - package.json → take master (version 0.5.6; defer the connector bump). - skill-detail.tsx → keep BOTH master's BundlePill and our SkillSyncBadge. - skill_validator.py / skill-validation.ts → master's namespaced name pattern (ns:name, underscores) AND our Windows-reserved-name check coexist. Verified: backend validator 66, extension 153, frontend typecheck clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… for the side-panel UX - README "claude.ai (web app)" section rewritten to the current flow: side panel, in-panel pairing, approve via the notifications bell, per-collection Sync ▾ → claude.ai. Adds a connector screenshot. - User guide: setup steps corrected (no more "new tab" / settings-page approval); Notifications section replaces the old activity-feed wording. - STORE_LISTING: add reviewer justifications for sidePanel + scripting (added this release); refresh the required-screenshots list. - New docs/screenshots/claude-ai-connector.png hero shot. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…aude.ai flow
- Replace the stale Connect hero (connect-browse-r9.png, old "CONNECT"
sidebar, 2 agents) with a current 1440×580 capture: Workspace/
Integrations sidebar + Claude Code, OpenClaw, and the new claude.ai
connector card ("1 browser connected").
- Add a screenshot of a collection's Sync menu open with claude.ai
toggled on ("Live as 'SkillNote: conventions'") — the actual control
users click to sync — to both the README claude.ai section and the
user guide's "What happens next". README/guide copy now points at it
and spells out per-collection on/off control.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c275e30 to
91b8375
Compare
0.5.6 is already published on npm and npm versions are immutable, so the connector release takes the next free minor — 0.6.0. It's a minor (not a patch): a new distribution surface (browser extension), new backend endpoints, and eight migrations, with no breaking changes to existing skill/collection/version APIs. Bumps root + CLI package.json and both lockfiles to 0.6.0 and adds the 0.6.0 CHANGELOG entry. The extension keeps its own 0.1.0 (Chrome Web Store / Firefox AMO scheme). Nothing is published until a cli-v0.6.0 tag is pushed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, CLI, extension All 20 open alerts were vulnerable npm dependencies. Fixed surgically with pinned overrides + minimal dev-tooling bumps — no runtime API changes, all builds and test suites stay green (CLI 143, extension 153). - web app: hono override 4.12.18 → 4.12.25 (Set-Cookie injection, IP-restrict bypass, JWT scheme, mount routing); postcss override → 8.5.15. - CLI: vitest/@vitest/coverage-v8 → ^3.2.6 (UI-server RCE, was <3.2.6); overrides esbuild 0.28.1 (dev-server CORS/file-read), undici ^6.26.0 (CRLF + request smuggling), uuid ^11.1.1 (buffer bounds). tsup/dockerode/ testcontainers were flagged only for bundling vulnerable esbuild/undici and are fixed by the overrides — not major-bumped. - extension: vite → ^6.4.3 (optimized-deps path traversal), vitest/coverage → ^3.2.6, esbuild override 0.28.1. CHANGELOG 0.6.0 gains a Security section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…review Backend - _log_activity: wrap the audit write in a SAVEPOINT (+ pre-flush) so its "never blocks the CRUD" guarantee is real — previously the audit INSERT flushed at the outer commit, so a bad event kind would 500 + roll back the whole create/update/delete/restore. - Op reaper: FOR UPDATE SKIP LOCKED on stale candidates + complete_operation takes the same row lock, fixing a lease-vs-completion race that could resurrect or falsely fail a just-completed op. - /pair/approve: add its own per-IP rate-limit bucket (it consumes a guessed code; start_pairing's limiter didn't cover it). - Collections list `q`: escape LIKE wildcards (%/_) + ESCAPE clause — a literal `_` matched everything and corrupted X-Total-Count. Frontend - Notifications bell: mark-seen only on an explicit user open, not the pairing auto-open (which silently cleared unread activity the user never read). - Activity feed: dedupe "load older" by id (timestamp ties duplicated rows). - Sync-queue: in-flight guard so poll + manual refresh don't stack/flicker. - Collection page: adopt the canonical name returned after publish (the PUT upserts a skill-derived collection server-side). Extension (security-leaning) - sync-now bridge no longer relays on claude.ai (only the SkillNote origin), and the background rejects a claude.ai-origin sync-now sender. - Message handler: start-pair/disconnect restricted to the extension's own UI pages (not content scripts). - cookies.onChanged registered at top level so a dormant MV3 worker still wakes on login/logout. - Pairing: fast ~2s poll so approval isn't gated by the 30s alarm clamp. Validated: backend unit + integration (39 passed), frontend build, extension (153 tests), CLI (153 tests), all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
A self-hosted claude.ai connector: a Chrome side-panel extension + backend that syncs a team's SkillNote skills to their claude.ai account (as named plugin groups), surfaces usage, and keeps the panel matched to claude.ai's look — all without routing data through any SkillNote-project infra.
Three commits: the connector base (
c18c530), UX + web↔extension sync bridge + audit hardening (c0c2321), and this production-hardening + test pass (3a21b69).Highlights
Chrome extension (native side panel)
prefers-color-scheme), with worker-pull + on-open fallbacks. Warm palette tuned to Anthropic's surfaces.Backend
POST /extension/reconcile(Sync-now), scalableGET /v1/collections(?q/?published/?limit+X-Total-Count), and a "skills synced" counter fix (counts published-collection skills, not the unusedskill_links).Cross-platform
normalizeSkillnoteUrlnow returns the origin (fixes a pasted URL-with-path silently breaking every API call) and accepts scheme-less input;defaultBrowserLabeldetects ChromeOS / Android / iOS / Windows correctly.Migrations
Adds
0023→0028(audit ops/events, staged-version link, session name, skill-lifecycle CHECK). Docker auto-runsalembic upgrade head— verified clean from a fresh DB.Testing
imports/openclawfailures are environmental — git/network unavailable in-container — and untouched by this PR.)Not in this PR (follow-ups)
0.6.0) — deferred pending the version/cadence decision.cookies,host_permissions, broad optional hosts) — the longest external-review pole.skillnoteon npm) is unchanged by this PR.🤖 Generated with Claude Code