Skip to content

Latest commit

 

History

History
139 lines (103 loc) · 9.31 KB

File metadata and controls

139 lines (103 loc) · 9.31 KB

ClawdKit - Development Guide

Communication Style

  • Narrate what you're doing at each step — brief status updates help the user follow along and make the chat searchable
  • Be patient with tangents and context-switching (ADHD-friendly pacing)
  • Keep explanations concise but don't skip them
  • Scope guard: Gently remind the user when a tangent is pulling away from the current task. User tends to spiral into feature ideas mid-implementation — help stay focused on finishing the current thing before starting the next. A quick "want to add that to TODO and finish X first?" goes a long way.

Self-Maintenance

This file is the shared project memory. Update it proactively when:

  • A new critical rule or recurring bug pattern is discovered
  • Project structure changes (new files, renamed files, new architecture patterns)
  • A decision is made about how something should always work (e.g., "exports > 1 file must ZIP")

Keep it concise. Don't duplicate what's already here — update existing sections instead.

This file lives at the repo root. Keep it updated as the shared project memory.

Project Structure

  • Repo root is the project root — chrome/, firefox/, docs/, tests/ are all top-level
  • Parallel Chrome (chrome/) and Firefox (firefox/) versions — nearly identical copies
  • Chrome uses Manifest V3, Firefox uses Manifest V2
  • Releases go in releases/vX.Y.Z/

Key Files (under chrome/ and firefox/)

  • content.js — Content script injected on claude.ai pages (handles API calls, popup export actions)
  • utils.js — Shared utilities (convertToMarkdown, convertToText, downloadFile, extractArtifactFiles, etc.)
  • browse.js — Browse page logic (filtering, sorting, has its own export functions, always ZIPs)
  • background.js — Re-injects content scripts on install/update
  • jszip.min.js — ZIP library
  • popup.html / popup.js — Extension popup UI and logic
  • browse.html — Browse/search conversations page
  • options.html / options.js — Extension options/settings page
  • popup-theme.js — Theme toggle logic for popup
  • content.css — Styles injected into claude.ai pages
  • counter/ — Counter integration (token counting, cache timer, usage bars):
    • constants.js — DOM selectors, color palette, context limit constants
    • bridge-client.js — BridgeClient class for page-context communication
    • bridge.js — Injected page-context script (wraps fetch() and history.pushState/replaceState)
    • tokens.js — Token counting, conversation trunk builder, TokenCache
    • ui.js — CounterUI class (usage bars, cache timer, token display, tooltips)
    • main.js — Entry point that wires everything together
    • styles.css — All .cc-* CSS classes for the counter UI
  • vendor/o200k_base.js — GPT tokenizer library (~2MB, used by counter for token counting)

Git & Commits

Auto-commit after every completed change. Don't wait for the user to ask. After finishing a task (bug fix, feature, refactor), commit immediately with a clear message.

  • Git repo is at the project root
  • Write concise, descriptive commit messages: Fix bulk export to always ZIP instead of individual downloads
  • Not: wip, fix stuff, update, final FINAL (1)
  • Group related changes into one commit (e.g., Chrome + Firefox changes for the same fix = one commit)
  • Don't push unless asked
  • Branching: Do all development on testing branch. Merge to main only when creating a release

Documentation Upkeep

After each commit, update these files:

  • docs/TODO.md — Move completed items to the Completed section, update the current version number, clean up any stale entries
  • docs/CHANGELOG.md — Append a short entry under the current version. Create the file if it doesn't exist. Format: ## [X.Y.Z] header, then bullet points describing changes. Keep entries concise — one line per change is fine
  • The CHANGELOG doubles as store update notes. All changes between the current version and the last _Published_ marker in docs/CHANGELOG.md are what goes into the store listing update

Release Process

Only create releases when explicitly asked. Never auto-release.

When the user asks to create a release for version X.Y.Z:

  1. Verify version — Confirm both chrome/manifest.json and firefox/manifest.json show the correct version
  2. Create release directorymkdir -p releases/vX.Y.Z
  3. ZIP Chrome extensioncd chrome && zip -r ../releases/vX.Y.Z/claude-exporter-chrome.zip ./* && cd ..
  4. ZIP Firefox extensioncd firefox && zip -r ../releases/vX.Y.Z/claude-exporter-firefox.zip ./* && cd .. (unsigned; user handles .xpi signing via AMO)
  5. Git taggit tag vX.Y.Z -m "Release vX.Y.Z"
  6. Push taggit push origin vX.Y.Z
  7. Create GitHub releasegh release create vX.Y.Z releases/vX.Y.Z/* --title "vX.Y.Z" --notes "$(changelog excerpt from docs/CHANGELOG.md)" — use all changes since last _Published_ marker as the notes
  8. Mark as published — Add _Published_ line after the released version's entries in docs/CHANGELOG.md, commit

Critical Rules

Always apply changes to BOTH browsers

Every code change to chrome/ must also be applied to firefox/. The files are nearly identical — differences are only in manifest format and API calls (chrome.scripting.executeScript vs chrome.tabs.executeScript).

Always bump version on every change

Update "version" in BOTH chrome/manifest.json AND firefox/manifest.json.

background.js must inject ALL content scripts

When re-injecting into already-open tabs (on install/update), background.js must inject all files: jszip.min.js, utils.js, content.js, plus all counter scripts (vendor/o200k_base.js, counter/constants.js, counter/bridge-client.js, counter/tokens.js, counter/ui.js, counter/main.js). Missing any file causes "not defined" errors on already-open tabs.

Multi-file exports must always be ZIPped

Any export producing more than one file should always create a ZIP — never trigger individual browser downloads.

Manifest name differs by branch

"name" in BOTH manifests must be:

  • "ClawdKit for Claude.ai" on the main branch (released version)
  • "ClawdKit for Claude.ai Beta" on the testing branch (so the user can tell at a glance which build is loaded)

The popup header title is populated from manifest.name in popup.js (#header-title), so the popup automatically reads "ClawdKit for Claude.ai Beta" on the testing branch — no separate HTML edit needed.

When merging testingmain for a release, flip both manifest names to drop "Beta" as part of the merge.

Testing

  • Vitest test harness (package.json + node_modules/) lives in tests/. Run tests with npm test (one-shot) or npm run test:watch (watch mode) from tests/.
  • Test files live in tests/ and import from chrome/utils.js (the canonical copy).
  • firefox/utils.js is a mirror — if it drifts from chrome/utils.js, the tests won't catch it. Keep them in sync per the existing rule.
  • utils.js has a conditional module.exports block at the bottom that fires only when module is defined (Node/vitest). Browser extensions ignore it because the global is undefined.
  • node_modules/ and package-lock.json are gitignored (package.json is tracked under tests/). None are part of the release ZIPs.

Architecture Notes

Content Script Injection

  • On fresh page loads: manifest content_scripts handles injection of all JS files (exporter + counter)
  • On extension install/update: background.js re-injects into already-open claude.ai tabs
  • content.js has a double-injection guard (window.claudeExporterContentScriptLoaded) to prevent duplicate message listeners
  • Counter scripts have their own guard (CC.__started) to prevent duplicate initialization

Counter (Counter Integration)

  • Uses its own globalThis.ClaudeCounter namespace (prefixed CC) — no conflicts with exporter code
  • CSS classes are all prefixed .cc-* — no conflicts with exporter's .claude-exporter-* classes
  • Bridge architecture: counter/bridge.js is injected into the page context (via web_accessible_resources) to intercept fetch() calls and SSE streams. It communicates with the content script via window.postMessage. This is needed because content scripts can't access the page's fetch responses directly.
  • The bridge also wraps history.pushState/replaceState to detect SPA navigation on claude.ai
  • Token counting uses a vendored tokenizer (o200k_base, ~2MB) — approximate counts, may differ from Claude's internal count
  • Usage data comes from Claude's /usage endpoint plus live SSE message_limit events

Export Flow

  • Popup "Export Current" → sends message to content script on the active claude.ai tab
  • Popup "Export All" → sends message to content script, which fetches all conversations and ZIPs them
  • Browse page → loads conversation list via content script relay (sendMessageToClaudeTab), then exports directly via fetch() to claude.ai API

Chrome vs Firefox API Differences

  • Chrome MV3: chrome.scripting.executeScript({ target, files }) — accepts file array
  • Firefox MV2: chrome.tabs.executeScript(tabId, { file }) — one file at a time, must loop