Skip to content

feat: self-hosted claude.ai connector (Chrome side panel + bidirectional sync)#73

Merged
latentloop07 merged 9 commits into
masterfrom
feat/claude-ai-connector
Jun 15, 2026
Merged

feat: self-hosted claude.ai connector (Chrome side panel + bidirectional sync)#73
latentloop07 merged 9 commits into
masterfrom
feat/claude-ai-connector

Conversation

@latentloop07

Copy link
Copy Markdown
Contributor

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)

  • Toolbar icon opens a full-height side panel (same surface as Claude-in-Chrome), not a cramped popup. Read-only status surface — sync control stays in the SkillNote 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's light/dark instantly (MutationObserver + prefers-color-scheme), with worker-pull + on-open fallbacks. Warm palette tuned to Anthropic's surfaces.
  • Inline pairing (URL + label + Connect, with a permission-priming note) — approve from the in-app notifications bell.
  • Native-feel hardening: no flicker/scroll-jump on background polls, focus rings + arrow-key tabs + Escape, timer-leak / re-render-race / FOUC fixes.
  • Luna Prompts (LP) brand icon at all sizes.

Backend

  • Unified Notifications feed (3-day life + prune); skill-lifecycle events — migration 0028 extends the audit-log CHECK constraint.
  • POST /extension/reconcile (Sync-now), scalable GET /v1/collections (?q / ?published / ?limit + X-Total-Count), and a "skills synced" counter fix (counts published-collection skills, not the unused skill_links).
  • Tightened stalled-op reaper (3-min lease) with clear "tried N times" messaging.
  • Windows-reserved skill-name validation (backend + frontend mirror).

Cross-platform

  • normalizeSkillnoteUrl now returns the origin (fixes a pasted URL-with-path silently breaking every API call) and accepts scheme-less input; defaultBrowserLabel detects ChromeOS / Android / iOS / Windows correctly.

Migrations

Adds 00230028 (audit ops/events, staged-version link, session name, skill-lifecycle CHECK). Docker auto-runs alembic upgrade head — verified clean from a fresh DB.

Testing

  • Extension: 153 unit/render tests (theme luminance, clients, all panel states, keyboard).
  • Backend: new integration + unit suites (collections filtering, reconcile, lifecycle activity, reserved names); blast-radius green. (Pre-existing imports/openclaw failures are environmental — git/network unavailable in-container — and untouched by this PR.)
  • Frontend typecheck clean; full stack verified end-to-end on a fresh containerized DB.

Not in this PR (follow-ups)

  • Version bump + CHANGELOG for the release (suggest 0.6.0) — deferred pending the version/cadence decision.
  • Chrome Web Store submission assets: privacy policy + permission justifications (cookies, host_permissions, broad optional hosts) — the longest external-review pole.
  • The CLI (skillnote on npm) is unchanged by this PR.

🤖 Generated with Claude Code

latentloop07 and others added 6 commits May 24, 2026 20:55
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>
@latentloop07 latentloop07 force-pushed the feat/claude-ai-connector branch from c275e30 to 91b8375 Compare June 15, 2026 13:43
latentloop07 and others added 3 commits June 15, 2026 19:41
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>
@latentloop07 latentloop07 merged commit 5e69b18 into master Jun 15, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant