Co-do
CLAUDE.md78 starsChanged 9 months agoApache-2.0View on GitHub
Guidance for Claude Code working in this repository. Co-do is a Cowork-like browser experience using the File System Access API for collaborative coding with native filesystem integration. IMPORTANT: Always run npm test after code changes. Tests must pass before committing. Exception: Not required for documentation-only changes (.md files, comments). IMPORTANT: Never modify version in package.json. Version bumping is automatic via GitHub Action on PR merge. Target: Latest Chrome (Chrome 140+) — File System Access API is the core dependency.
- Installs packages
- Commits and pushes
In this repository9 other files it gives its agents.
- agent-reviewsSkill
- code-reviewerSkill
- code-simplifierSkill
- comment-analyzerSkill
- fix-pr-commentsSkill
- moder-web-devSkill
- pr-test-analyzerSkill
- silent-failure-hunterSkill
- type-design-analyzerSkill
The file
Show its rules and text
We split this CLAUDE.md into the rules it gives an agent
38 rules. About 0 are common, 19 are distinctive, and 19 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈19
Distinctive · estimate
This author's own choices. Worth a look.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 18
Use modern web platform APIs freely.
- Very specific: line 109
Modern APIs First: Prefer modern web platform APIs.
- Very specific: line 116
Add tool name to ToolName type in src/preferences.ts
- Very specific: line 117
Add default permission in DEFAULT_PERMISSIONS in src/preferences.ts
- Very specific: line 118
Add permission UI element in index.html inside #tool-permissions
- Very specific: line 119
Use checkPermission() in the tool's execute function
- Very specific: line 121
Adding Pipeable Commands: Import registerPipeable from src/pipeable.ts, call at module evaluation time.
- Very specific: line 124
Add C/WASI source in wasm-tools/src/, config in BUILTIN_TOOLS in src/wasm-tools/registry.ts
- Very specific: line 127
Binary data: Use parameter type 'binary' (AI sends base64 → decoded to bytes via stdin).
- Very specific: line 129
Tool Grouping: Always group by function, never by implementation.
- Very specific: line 131
IndexedDB Storage: All persistent data via src/storage.ts storageManager singleton — never access IndexedDB directly.
- Distinctive: line 137
Collaboration Features: Consider real-time sync, conflict resolution, presence indicators, efficient file content transfer.
- Distinctive: line 141
Keep docs up-to-date with every feature: Update:
- Distinctive: line 147
Before marking a feature complete: Verify README reflects it, features are listed, example prompts updated, security documented, new tools …
- Distinctive: line 154
Ask before proceeding when: multiple valid approaches exist, design trade-offs are involved, scope is ambiguous, new features requested, …
- Distinctive: line 181
Run silent-failure-hunter (if error handling touched)
- Distinctive: line 182
Run pr-test-analyzer (if tests changed)
- Distinctive: line 183
Run type-design-analyzer (if types changed)
- Distinctive: line 185
Run code-simplifier (final pass)
- Distinctive: line 214
Test all states: normal, hover, focus, active, disabled
- Distinctive: line 215
Use IDs/data-testid over CSS classes
- Very specific: line 217
Test mobile viewports with page.setViewportSize()
- Distinctive: line 218
All text must meet WCAG AA contrast (4.5:1)
- Very specific: line 222
When intentionally changing UI: make changes → npm run test:visual:update → review snapshots → commit code + screenshots together.
- Distinctive: line 230
Always rebase onto latest main before pushing: Commit first — never rebase with uncommitted changes.
- Very specific: line 236
If lockfile regenerated: git add package-lock.json && git commit --amend --no-edit
- Very specific: line 237
Run npm test (for code changes)
- Very specific: line 243
Run npm test after fixes
- Distinctive: line 244
If feedback reveals a recurring pattern, add it to Lessons Learned below and update relevant CLAUDE.md sections
- Very specific: line 252
When a value can be a valid empty string, use value !== undefined or value != null — not if (value) which silently drops "".
- Very specific: line 261
Only set initialization flags on successful completion.
- Distinctive: line 265
Use a shared Promise so the first caller creates it and subsequent callers await the same one, preventing redundant fetches and race …
- Distinctive: line 277
Treat manifest + binary (or config + data) as atomic units.
- Distinctive: line 281
Update registries when source data changes (install, enable, disable, uninstall).
- Very specific: line 295
Don't use JSON.stringify for comparison — property ordering varies.
- Distinctive: line 309
Create tags after rebase/push.
- Distinctive: line 313
Verify every factual claim in comments/docstrings against actual code: numeric thresholds, function signatures, parameter names, git …
- Very specific: line 321
Read and parse shared config files (e.g., package.json) once.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
Guidance for Claude Code working in this repository.
Project Overview
Co-do is a Cowork-like browser experience using the File System Access API for collaborative coding with native filesystem integration.
IMPORTANT: Always run
npm testafter code changes. Tests must pass before committing. Exception: Not required for documentation-only changes (.mdfiles, comments).
IMPORTANT: Never modify
versioninpackage.json. Version bumping is automatic via GitHub Action on PR merge.
Browser Support
Target: Latest Chrome (Chrome 140+) — File System Access API is the core dependency.
- Use modern web platform APIs freely; no polyfills or legacy support needed
- Chrome-specific APIs acceptable; focus on Baseline Newly/Widely Available features
- See
.claude/skills/modern-web-dev/SKILL.mdfor detailed guidance
Development Commands
| Command | Description |
npm install | Install dependencies |
npm run dev | Vite dev server on http://localhost:3000 |
npm run build | Full production build (WASM + TS + Vite → dist/) |
npm run build:web-only | Build without WASM compilation |
npm run type-check | TypeScript type checking only |
npm run preview | Preview production build |
npm test | All Playwright tests (visual + accessibility) |
npm run test:visual | Visual regression tests only |
npm run test:accessibility | Accessibility tests only (WCAG 2.1 AA) |
npm run test:visual:update | Update baseline screenshots |
npm run test:unit | Vitest unit tests |
npm run test:unit:watch | Unit tests in watch mode |
npm run test:ui | Playwright interactive UI mode |
npm run test:debug | Debug mode with Playwright Inspector |
npm run test:report | Open HTML test report |
npm run wasm:build | Build all WASM tools (requires wasi-sdk) |
npm run wasm:build:native | Build native-only WASM tools |
Project Structure
Co-do/
├── src/
│ ├── main.ts # Entry point, PWA init, version checking
│ ├── ui.ts # UI manager, event handlers, conversations, permissions UI
│ ├── ai.ts # AI SDK integration (streaming, multi-provider, dynamic import)
│ ├── tools.ts # 20 file operation tools + pipe command
│ ├── pipeable.ts # Self-registering pipeable command registry
│ ├── fileSystem.ts # File System Access API wrapper with caching
│ ├── preferences.ts # Tool permissions (ToolName type, permission levels)
│ ├── storage.ts # IndexedDB manager (configs, conversations, workspaces, WASM tools)
│ ├── router.ts # Hash-based workspace URL routing
│ ├── diff.ts # Unified diff generation (LCS algorithm)
│ ├── markdown.ts # Markdown rendering in sandboxed iframes (XSS protection)
│ ├── toasts.ts # Toast notification system
│ ├── notifications.ts # Native browser notifications
│ ├── viewTransitions.ts # View Transitions API integration
│ ├── provider-registry.ts # Provider cookie management + CSP coordination
│ ├── network-monitor.ts # CSP violation monitoring, network request logger, visual firewall
│ ├── tool-response-format.ts # Pure functions for tool response formatting
│ ├── toolResultCache.ts # Caching large tool outputs (>2KB → summary to AI, full to UI)
│ ├── styles.css # CSS with custom properties for dark mode
│ └── wasm-tools/ # WebAssembly custom tools system
│ ├── manager.ts # Central tool orchestrator
│ ├── runtime.ts # WASI runtime (main-thread fallback)
│ ├── wasm-worker.ts # Worker-based WASM runtime (default, sandboxed)
│ ├── worker-manager.ts # Worker lifecycle and pooling
│ ├── vfs.ts # Virtual file system (WASI syscall interception)
│ ├── loader.ts # ZIP package loader and manifest validator
│ ├── registry.ts # Built-in tool config (41 tools by category)
│ ├── types.ts # TypeScript interfaces and Zod schemas
│ ├── worker-types.ts # Worker message protocol types
│ ├── index.ts # Public API exports
│ └── adapters/ # Non-WASI tool adapters (FFmpeg)
├── server/
│ ├── main.ts # Vite server plugins entry
│ ├── providers.ts # Provider registry and cookie parsing
│ └── csp.ts # Dynamic CSP header generation per provider
├── tests/
│ ├── visual/ # Visual regression tests (screenshots)
│ ├── accessibility/ # WCAG 2.1 Level AA compliance tests
│ ├── unit/ # Unit tests (Vitest)
│ └── helpers/ # Test utilities (test-utils.ts, dom-inspector.ts)
├── docs/ # Architecture docs (WASM, CSP, security)
├── public/ # PWA manifest, service worker, icons
├── wasm-tools/ # C/WASI source, manifests, build scripts
├── index.html # HTML entry point (UI structure, modals, permissions)
├── vite.config.ts # Vite config with dynamic CSP + version plugin
├── playwright.config.ts # Playwright test configuration
├── tsconfig.json # TypeScript strict mode config
└── package.json # Dependencies and scriptsKey Dependencies
Runtime: Vercel AI SDK (ai ^6.0.39) with @ai-sdk/anthropic, @ai-sdk/openai, @ai-sdk/google, @openrouter/ai-sdk-provider; zod for schema validation; marked for markdown; jszip for WASM package uploads.
Dev: Vite ^6.0.7, TypeScript ^5.7.2 (strict, ES2022), Playwright ^1.57.0, Vitest ^4.0.18, @axe-core/playwright ^4.11.0.
Key tech: File System Access API, WebAssembly + WASI (41 built-in tools in Workers), IndexedDB (primary storage), localStorage (preferences), dynamic ES Module imports, View Transitions API, Web Speech API. AI uses stepCountIs(10) step limits.
Architecture Guidelines
- Modern APIs First: Prefer modern web platform APIs. See
.claude/skills/modern-web-dev/SKILL.md. - File System Access API: Core feature. Uses
window.showDirectoryPicker(), FileSystemFileHandle/DirectoryHandle. Directory handles persisted in IndexedDB for session restoration. - Security: Handle permission requests/denials gracefully. All file ops sandboxed to user-selected directory.
- Adding New File Operation Tools (in
src/tools.ts):- Add tool name to
ToolNametype insrc/preferences.ts - Add default permission in
DEFAULT_PERMISSIONSinsrc/preferences.ts - Add permission UI element in
index.htmlinside#tool-permissions - Use
checkPermission()in the tool's execute function
- Add tool name to
- Adding Pipeable Commands: Import
registerPipeablefromsrc/pipeable.ts, call at module evaluation time. The pipe tool discovers registered commands automatically. - Adding Built-in WASM Tools:
- Add C/WASI source in
wasm-tools/src/, config inBUILTIN_TOOLSinsrc/wasm-tools/registry.ts - Assign a functional
category(existing:text,data,crypto,file,code,search,compression,database). New categories need entries inCATEGORY_DISPLAY_NAMESandCATEGORY_DISPLAY_ORDER - Build with
npm run wasm:build; setpipeable: truefor pipe chain support - Binary data: Use parameter type
'binary'(AI sends base64 → decoded to bytes via stdin). Binary stdout auto-detected and preserved asstdoutBinary. VFS usesreadFileBinary()/Uint8Arraywrites. Worker usesTransferableArrayBuffers.
- Add C/WASI source in
- Tool Grouping: Always group by function, never by implementation. Built-in tools grouped statically in
index.html; WASM tools grouped dynamically bycategoryviaCATEGORY_DISPLAY_NAMES/CATEGORY_DISPLAY_ORDERinsrc/wasm-tools/registry.ts. - IndexedDB Storage: All persistent data via
src/storage.tsstorageManagersingleton — never access IndexedDB directly. Separate stores for provider configs, workspaces, conversations, WASM tools. API keys in IndexedDB (not localStorage). - Dynamic CSP: Provider cookie (
co-do-provider) →server/csp.tsbuilds per-providerconnect-src. Vite code-splits provider SDKs. Workers inherit page CSP. - Tool Result Caching: Outputs >2KB cached in
toolResultCache— AI gets summary + first 5 lines; UI gets full content viaresultId. - Collaboration Features: Consider real-time sync, conflict resolution, presence indicators, efficient file content transfer.
Documentation Guidelines
Keep docs up-to-date with every feature. Update:
- README.md — new features, tools, security, browser support, config, architecture
- CHANGELOG.md — new versions, significant features, breaking changes, bug fixes
- PWA-SETUP.md — PWA config, service worker, manifest changes
- CLAUDE.md — new commands, structure changes, new guidelines, PR review lessons
Before marking a feature complete: Verify README reflects it, features are listed, example prompts updated, security documented, new tools listed, architecture changes reflected.
Document: What it does, how to use it, configuration, security considerations. Skip: Internal refactoring, non-behavior-changing bug fixes, comment improvements, test-only changes.
Asking Clarifying Questions
Ask before proceeding when: multiple valid approaches exist, design trade-offs are involved, scope is ambiguous, new features requested, breaking changes possible, or UI/UX decisions needed.
How to ask: Be specific, offer 2-3 options with trade-offs, suggest a default with reasoning.
Skip questions when: task is straightforward, following established patterns, user specified exactly what they want, clear bug fix, or docs-only changes.
Proactively suggest related improvements while keeping user in control of scope.
Code Review Skills (PR Review Toolkit)
Review agents in .claude/skills/ must be used for all code changes.
| Skill | Purpose |
| code-reviewer | Reviews against CLAUDE.md guidelines (confidence >= 80) |
| silent-failure-hunter | Finds silent failures, empty catch blocks |
| pr-test-analyzer | Evaluates test coverage, identifies gaps |
| type-design-analyzer | Rates type design quality |
| comment-analyzer | Verifies comment accuracy, finds comment rot |
| code-simplifier | Simplifies for clarity and maintainability |
/review-pr — runs all applicable agents. Target specific: code, tests, errors, types, comments, simplify.
Required Pre-Commit Workflow
- Write code
- Run code-reviewer
- Run silent-failure-hunter (if error handling touched)
- Run pr-test-analyzer (if tests changed)
- Run type-design-analyzer (if types changed)
- Fix all critical (90-100) and important (80-89) issues
- Run code-simplifier (final pass)
- Run
npm test - Commit
Skip reviews for: docs-only changes, non-runtime config changes, test baseline updates.
Testing Guidelines
All UI changes must include tests.
Uses Playwright (visual regression + accessibility) and Vitest (unit tests).
When Tests Are Required
Adding/modifying UI components, adding features, changing styles, adding modals/overlays, implementing responsive design → write visual regression + accessibility tests.
When Tests Are NOT Required
.md files, comment-only changes, README updates, license changes, config file comments.
Test Types
- Visual regression (
tests/visual/): Screenshot comparison. Useanimations: 'disabled'. Catches layout breaks, misalignment, style regressions. - Accessibility (
tests/accessibility/): WCAG 2.1 AA via axe-core. Contrast (4.5:1 normal, 3:1 large), ARIA, keyboard nav, focus, semantic HTML. - Unit (
tests/unit/): Vitest for pure functions (tool response formatting, pipe logic).
Best Practices
- Disable animations in screenshots; wait for
networkidle - Test all states: normal, hover, focus, active, disabled
- Use IDs/data-testid over CSS classes
- One test = one thing; reuse helpers from
tests/helpers/test-utils.ts - Test mobile viewports with
page.setViewportSize() - All text must meet WCAG AA contrast (4.5:1)
Updating Baselines
When intentionally changing UI: make changes → npm run test:visual:update → review snapshots → commit code + screenshots together.
CI/CD
Tests run on every PR, push to main, and feature branch commit. Failing tests = failing build.
Pre-Push Rebase Workflow
Always rebase onto latest main before pushing. Commit first — never rebase with uncommitted changes.
git add <files> && git commit -m "message"git fetch origin maingit rebase origin/main- Resolve conflicts (for
package-lock.json:git checkout --ours package-lock.json && npm install && git add package-lock.json && git rebase --continue) - If lockfile regenerated:
git add package-lock.json && git commit --amend --no-edit - Run
npm test(for code changes) git push -u origin <branch> --force-with-lease
GitHub PR Review Feedback
- Fix all reviewer comments
- Run
npm testafter fixes - If feedback reveals a recurring pattern, add it to Lessons Learned below and update relevant CLAUDE.md sections
Lessons Learned from PR Reviews
<!-- Add lessons learned from PR reviews below this line -->1. Empty String vs Falsy — Use Explicit Undefined Checks
When a value can be a valid empty string, use value !== undefined or value != null — not if (value) which silently drops "". Applies to stdin, search queries, file contents, user text.
// BAD: if (stdin) { ... }
// GOOD: if (stdin !== undefined) { ... }2. One-Time Init Must Handle Failure Gracefully
Only set initialization flags on successful completion. Use three-state (unloaded | loading | loaded) for lazy-loading. Never mark loaded before knowing the operation succeeded.
3. Concurrent Access — Deduplicate Lazy Initialization
Use a shared Promise so the first caller creates it and subsequent callers await the same one, preventing redundant fetches and race conditions.
let loadPromise: Promise<void> | null = null;
function ensureLoaded() {
if (!loadPromise) loadPromise = fetch(url).then(r => { data = r; });
return loadPromise;
}4. Update All Related State When Syncing Cached Entities
Treat manifest + binary (or config + data) as atomic units. Partial syncs create mismatches.
5. Dynamic Registries Must Stay in Sync
Update registries when source data changes (install, enable, disable, uninstall). Rebuild derived descriptions after modifications. Prefer getters/callbacks over cached-once values.
6. URL and Path Handling — Strip Query Strings, Handle Dev vs Prod
Strip query strings/hash fragments before path matching. Handle both .ts (dev) and .js (prod) extensions.
const pathname = url.split(/[?#]/, 1)[0];
const segment = pathname.split('/').pop() ?? '';
return segment.startsWith('wasm-worker') && (segment.endsWith('.js') || segment.endsWith('.ts'));7. JSON.stringify Is Unreliable for Deep Equality
Don't use JSON.stringify for comparison — property ordering varies. Use deep-equal utilities or normalize objects first.
8. MessagePort and Worker Cleanup
MessagePort doesn't fire close on tab unload. Wrap postMessage broadcasts in try-catch, remove failed ports. Use explicit disconnect protocols (beforeunload → disconnect message).
9. Permission Checks Must Be Granular
Pipeable commands must respect their own tool-specific permission, not just the global pipe permission. Pre-validate every command in a chain against its specific permission.
10. GitHub Actions — Validate Workflow Syntax and Safety
- Valid top-level keys only:
name,on,permissions,env,defaults,concurrency,jobs - Least privilege permissions; add
concurrencygroups; make operations idempotent - Create tags after rebase/push; pin action versions to SHAs/exact tags
11. Comments Must Match Actual Behavior
Verify every factual claim in comments/docstrings against actual code: numeric thresholds, function signatures, parameter names, git semantics, referenced files. PR reviews repeatedly caught wrong terminology, incorrect thresholds, and references to nonexistent code.
12. Wrap Throwing Calls in Try-Catch at System Boundaries
atob, JSON.parse, new URL, decodeURIComponent can throw on invalid input. Wrap at first use point, converting exceptions to meaningful error responses.
13. Avoid Redundant File I/O — Cache Parsed Configuration
Read and parse shared config files (e.g., package.json) once; share the result across functions.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

