Skip to content

Releases: OceansCreative/claude-code-context-capturer

v0.5.0 — claude.ai artifacts + MCP server

02 Jun 21:33
adc6aa9

Choose a tag to compare

Highlights

Two big additions on top of the v0.4.x clipper foundation:

1. claude.ai artifact extraction + range selection

For long planning conversations, you can now capture just the artifacts Claude authored — code, documents, diagrams — dropping the surrounding chat entirely. Or limit a capture to the last N messages so a 50-turn brainstorm doesn't dump its full history.

Toggles surface as quick checkboxes on the popup whenever you're on a `claude.ai/chat/*` URL, so each capture can be different without going to settings.

2. MCP server: on-demand context for Claude Code

The extension now exposes captured contexts through a Model Context Protocol server. Claude Code (or any MCP-aware agent) can fetch them on demand:

  • `get_context` — pull a specific capture by id, with options like `format: "code"` to extract artifacts as standalone files
  • `list_contexts` — browse what's captured, filter by tag or date
  • `search_contexts` — full-text search across stored captures, with tag/date filters
  • `stats_contexts` — counts and storage summary

This closes the loop differently from CLAUDE.md append: instead of pre-loading everything as fixed context, the agent pulls what it needs when it needs it. Heavy users with hundreds of captures don't blow their context window.

3. In-place re-capture (no silos)

Re-capturing the same `claude.ai/chat/` now updates the existing file rather than creating a new dated snapshot. A `dedupeKey` derived from the conversation UUID makes this idempotent. Artifacts-only and full-conversation modes get distinct dedupe keys so they don't clobber each other.

4. Artifacts-as-files (`get_context format: "code"`)

When the MCP server emits a capture in code format, each artifact becomes its own file with the right extension inferred from the language. Lets the agent treat them as drop-in references rather than chunks of Markdown.

Other changes

  • MCP filtering: `list_contexts` and `search_contexts` now accept tag and date filters
  • MCP misconfiguration: an unconfigured captures directory now surfaces a clear error instead of failing silently
  • Security fixes: path traversal, hash collision, CRLF handling, `extractCode` semantics, artifact ordering all hardened (self-review pass)

Compatibility

  • Permissions unchanged from v0.4.3 (no new justifications needed for Chrome Web Store review)
  • v0.4.x users upgrade in place — existing routes and linked CLAUDE.md files keep working
  • The MCP server is opt-in: configure the captures directory in Options to enable it

Verification

  • 91/91 unit tests pass (up from 58 in v0.4.3)
  • Build: 92 KB zip (up from 88 KB, MCP module additions)

Diff

v0.4.3...v0.5.0

v0.4.3 — Retry offscreen sendMessage

02 May 09:03

Choose a tag to compare

What

v0.4.2 added a PING handshake to `ensureOffscreen`, but the user still hit `Could not establish connection. Receiving end does not exist.` in production Chrome — meaning even after a successful PING, the very next `WRITE_TO_CLIPBOARD` or `APPEND_TO_CLAUDE_MD` message could fail because the listener-flap window in `chrome.runtime` is wider than the PING confirms.

Fix

  1. Retry wrapper. All offscreen sendMessages now go through `sendToOffscreenWithRetry` which retries up to 8 times (50ms apart, ~400ms worst case) on the specific race-condition error. Other errors propagate immediately so real failures aren't masked.

  2. PING handler return value. Offscreen's PING handler now returns `true` after `sendResponse` instead of `false`. Some Chrome versions discard the synchronous response when the listener returns `false`; returning `true` is the conservative choice for "we're handling this, keep the channel open until response is delivered."

Verification

End-to-end harness covers three scenarios:

  • Cold-start capture (offscreen not yet created)
  • Warm-path capture (offscreen alive from previous capture)
  • After forcibly closing offscreen (`chrome.offscreen.closeDocument()`, then capture — retry must rebuild and succeed)

6/6 assertions pass. Clipboard receives the rendered Markdown in all three scenarios. 58/58 unit tests still pass.

Diff

v0.4.2...v0.4.3

v0.4.2 — Offscreen ping/pong fix

02 May 07:05

Choose a tag to compare

What

Fixes a cold-start race that surfaced in v0.4.1 as `[CCC] Could not establish connection. Receiving end does not exist.` in the popup.

Root cause

`chrome.offscreen.createDocument`'s promise resolves on the document's `load` event, but the offscreen module's ESM imports (`handle-store`, `file-appender`) are split into separate chunks and load asynchronously. The `onMessage` listener registers AFTER the SW has already moved on and called `runtime.sendMessage`, which races and fails because no listener is wired up yet.

The race didn't reproduce in puppeteer (Chrome for Testing 147 loads chunks fast enough that timing happened to work). It surfaces on production Chrome when the user's first capture after extension reload hits the SW cold and the offscreen has zero warm-up.

Fix: PING/PONG handshake

  • Offscreen now responds synchronously to `{ target: 'offscreen', type: 'PING' }` with `{ ok: true }` as soon as its `onMessage` listener is registered.
  • `ensureOffscreen()` polls PING (25ms backoff, 2s deadline) after `createDocument` resolves AND after a `hasDocument()=true` short-circuit (the SW can restart and find a document whose script context hasn't fully bootstrapped yet).
  • `waitForOffscreenReady()` throws `offscreen-not-ready` if the deadline expires, so users get a descriptive error instead of the cryptic "Receiving end does not exist".

Verification

End-to-end cold-start harness:

  • Capture #1 (offscreen not yet created): 4/4 pass — frontmatter, page title, length all land in clipboard
  • Capture #2 (offscreen warm): still works, 338 bytes in clipboard

The same fix applies to `APPEND_TO_CLAUDE_MD` writes too, which were prone to the same race on a less-trodden code path.

Diff

v0.4.1...v0.4.2

v0.4.1 — Clipboard fix

02 May 06:38

Choose a tag to compare

What

Fixes a bug where the popup showed Captured ✓ but the clipboard stayed empty.

Root cause (two bugs compounding)

  1. `chrome.scripting.executeScript` silently swallows inner-Promise rejection — its outer Promise resolves successfully even when the injected `navigator.clipboard.writeText()` rejects. The previous implementation never inspected `result.error`, so a failed clipboard write looked identical to a successful one.

  2. `navigator.clipboard.writeText()` requires document focus. When the user clicks Capture page in the popup, the popup steals focus from the captured tab, so the injected `writeText()` fails with `Document is not focused` — every popup-driven capture in clipboard mode silently failed.

This affected v0.1.0 through v0.4.0. The keyboard shortcut path (`Cmd+Shift+L`) was unaffected because no popup means no focus theft.

Fix

Route clipboard writes through the offscreen document (the official MV3 pattern for SW-initiated clipboard work):

  • `chrome.offscreen.createDocument` now lists `CLIPBOARD` alongside `BLOBS` in reasons.
  • Offscreen handler uses the legacy textarea + `document.execCommand("copy")` dance instead of `navigator.clipboard.writeText`. The latter still requires focus even from offscreen contexts; the legacy path doesn't and is what Chrome's offscreen-clipboard examples use.
  • New `writeToClipboardViaOffscreen` sends `WRITE_TO_CLIPBOARD` to the offscreen doc and propagates errors properly — silent-success bug is gone.
  • `OffscreenMessage` is now a discriminated union of `APPEND_TO_CLAUDE_MD` and `WRITE_TO_CLIPBOARD`; `OffscreenResult` split into `OffscreenAppendResult` and `OffscreenClipboardResult` so callers narrow correctly.

Verification

End-to-end real-Chrome puppeteer harness sets `defaultMode: 'clipboard'`, triggers capture from the popup-message path, then reads the system clipboard back. 5/5 assertions pass — clipboard receives the rendered Markdown including frontmatter, body, and source footer. 58/58 unit tests still pass.

Diff

v0.4.0...v0.4.1

v0.4.0 — claude.ai conversation capture

02 May 05:43

Choose a tag to compare

Highlights

You can now capture claude.ai conversations with one click. Brainstorm in claude.ai, switch to Claude Code, and your project's CLAUDE.md already has the conversation — ## Human / ## Assistant headings, thinking blocks, tool_use entries, and the current branch all preserved.

This closes the most painful loop in the AI-coding workflow: share links 403, manual copy-paste decays after 30 minutes, and Mozilla Readability can't parse a React SPA conversation.

How it works

The content script runs in your claude.ai tab, so its fetch() inherits your authenticated session cookie. The parser:

  1. Detects URLs of the form claude.ai/chat/<uuid>
  2. Walks /api/organizations to find the org owning the conversation (most users have one; we probe each)
  3. Fetches the full tree via /api/organizations/{org}/chat_conversations/{uuid}?tree=True&rendering_mode=raw
  4. Walks from current_leaf_message_uuid back to root, then reverses for chronological order — handles regenerate/edit branches correctly
  5. Renders each message as ## Human / ## Assistant; thinking blocks become collapsible <details>; tool_use becomes a fenced JSON block; unknown content types are preserved as JSON for fidelity

Combine with v0.3.0's URL-pattern routing for the killer setup:

Route: claude.ai/chat/*  →  ~/myproject/CLAUDE.md

Now every claude.ai conversation auto-feeds your Claude Code session.

Caveats

  • These are internal endpoints — Anthropic may change them without notice. The parser is defensive: if the shape doesn't match, the user gets a descriptive error (`"unsupported content block: ..."`) rather than a corrupted capture.
  • Requires you to be signed in to claude.ai in the same browser profile. Returns a friendly error otherwise.

Architectural change

dispatchPageParser() is now async because claude.ai requires fetching its API. Existing DOM-only parsers wrap trivially in Promise.resolve(). The content script uses an async IIFE to await the parser then sendResponse, keeping the message channel open via synchronous return true. Verified zero regression on github / stackoverflow / generic via the existing real-Chrome harness (3/3 pass).

Tests

  • 13 new unit tests covering URL detection, tree walker (current_leaf ordering, created_at fallback, cycle defense), org probing across multiple orgs, 401 handling, unknown content blocks, and missing UUID
  • Total 58/58 unit tests pass
  • Production zip: `claude-code-context-capturer-v0.4.0.zip` (88 KB)

Diff

v0.3.0...v0.4.0

v0.3.0 — Multi-route CLAUDE.md

01 May 11:57

Choose a tag to compare

Highlights

You can now link multiple CLAUDE.md files and route captures to them by URL pattern. Captures from github.com/anthropic/* go to one file, zenn.dev/* to another, and unmatched URLs fall through to a default route. The single-file v0.2.0 setup migrates automatically — no action needed.

How to use

In the options page, click + Add route and set:

  • Label — anything readable, e.g. "anthropic project"
  • URL pattern — glob with * wildcard, matched as substring against the full URL. Examples:
    • github.com/anthropic/*
    • zenn.dev/*
    • *.notion.site/*
  • Default — leave the pattern empty to mark this route as the catch-all for unmatched URLs (only one default allowed).

Routes are evaluated in order: first non-default match wins, then the default. If no route matches and there is no default, the capture surfaces an error with a settings link.

Implementation notes

  • IndexedDB schema bumped to v2 (new routes store keyed by route id, each row carries label, pattern, isDefault, and the FileSystemFileHandle)
  • Lazy migration on first read converts the v0.2.0 claudeMdHandle key into a single default route
  • OffscreenMessage now carries a routeId; the offscreen doc looks up the specific handle for that capture
  • 10 new unit tests cover the glob matcher (regex meta escaping, multi-* patterns) and route resolver (first-match, fallback, no-match)

What's new

  • New src/shared/route-matcher.ts with matchesPattern() and resolveRoute()
  • Options page rewritten as a routes table with add / edit / remove
  • Service worker resolves the route by ctx.url before dispatching to offscreen
  • 45 unit tests passing (was 35), end-to-end real-Chrome multi-route verification: 3/3 pass

Diff

v0.2.0...v0.3.0

v0.2.0 — Direct CLAUDE.md write

30 Apr 15:14

Choose a tag to compare

Highlights

You can now link a CLAUDE.md file once in the options page, and every subsequent capture is appended directly to that file on disk — no copy/paste loop. Built on the File System Access API.

How it works

  1. Open the extension's options page → click Link CLAUDE.md… → pick the file in the OS dialog
  2. Set the default action to Append to linked CLAUDE.md file
  3. Capture as usual (toolbar / Cmd+Shift+L / context menu) — each entry is appended with a ## YYYY-MM-DD HH:MM — <title> heading and a blank-line separator

Implementation notes

MV3 service workers can't use the File System Access API (no DOM context), so the SW spawns a hidden offscreen document on demand and forwards an APPEND_TO_CLAUDE_MD message. The offscreen doc loads the persisted FileSystemFileHandle from IndexedDB and performs the write. If write permission has lapsed (Chrome may downgrade to prompt across restarts), the popup surfaces an inline link to re-grant from settings.

What's new

  • New claude-md output mode in the default-action dropdown
  • New IndexedDB-backed handle store (chrome.storage would lose the handle to JSON serialization)
  • 6 new unit tests covering the entry-block formatter
  • Bilingual UI updated (English / Japanese)

Compatibility

  • Chrome / Chromium / Edge: full support
  • Firefox: not supported until Mozilla ships the File System Access API (other features still work)

Privacy

  • File handle stored locally in extension's IndexedDB
  • No telemetry, no external servers — same as v0.1.0

Diff

v0.1.0...v0.2.0

v0.1.0 - Initial Release

30 Apr 13:20

Choose a tag to compare

What's in this release

The first public release of Claude Code Context Capturer — a Chrome extension that converts any web page into Claude Code-friendly Markdown.

Features

  • One-click capture from toolbar or keyboard shortcut
  • Site-specific parsers:
    • GitHub (Issues, Pull Requests, Discussions, README)
    • Stack Overflow / Stack Exchange
    • Zenn
    • Qiita
    • MDN Web Docs
  • Generic parser powered by Mozilla Readability for any other site
  • Selection mode: capture only the highlighted text
  • Capture buffer: stack multiple captures and export them all at once
  • YAML frontmatter with URL, title, captured_at, author, tags
  • Bilingual UI (English / Japanese)

Keyboard shortcuts

  • Ctrl+Shift+L (Cmd+Shift+L on macOS) — capture page
  • Ctrl+Shift+K (Cmd+Shift+K on macOS) — capture selection

Privacy

  • 100% local processing
  • No telemetry, no analytics, no external server communication
  • Open source under the MIT license

Installation

The extension is currently being submitted to the Chrome Web Store. Until approved, install manually:

  1. Clone this repository
  2. npm install && npm run build
  3. Load dist/ as an unpacked extension at chrome://extensions/

License

MIT - free to fork, modify, and use commercially.