experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(skills,agents): track .claude/skills/; rewrite peek-tasks for peek:* namespace; add Agent isolation:worktree warning to spawn-isolated-agent.sh

- .gitignore: ignore .claude/* but include .claude/skills/ so per-user settings stay local while skills ship to anyone hacking on Peek
- .claude/skills/peek-tasks.md: scope all queries/mutations to peek:* namespace
- mandate list_items with tags peek:todo; forbid list_tasks and complete_task in this codebase since they are generic bare-tag tools that surface cross-project items
- status transitions are manual untag + tag + record_event triplets
- peek:done added to status vocabulary
- 9 existing skills land as initial committed state
- scripts/spawn-isolated-agent.sh: header comment warns against Agent tool isolation:"worktree" parameter (which orphans commits outside jj). Cross-references CLAUDE.md guidance. Prior agent inverted this rule and stranded a README+DEVELOPMENT.md refresh on a git worktree (recovered in this stack as docs(readme) commit).

+657 -2
+160
.claude/skills/debug-electron.md
··· 1 + # Debug Electron Pages 2 + 3 + Programmatically debug Electron BrowserWindow content (extension pages, app pages, any URL) by capturing console output, errors, DOM state, and evaluating arbitrary JS -- all from stdout. 4 + 5 + ## Script Location 6 + 7 + `scripts/debug-electron-page.mjs` 8 + 9 + ## Quick Start 10 + 11 + ```bash 12 + npx electron scripts/debug-electron-page.mjs \ 13 + --url "https://example.com" \ 14 + --eval "document.title" \ 15 + --timeout 5000 16 + ``` 17 + 18 + ## Options 19 + 20 + | Flag | Description | Default | 21 + |------|-------------|---------| 22 + | `--url <url>` | URL to load | Extension popup if `--extension` given | 23 + | `--extension <path>` | Chrome extension directory to load | none | 24 + | `--eval <js>` | JS to evaluate after page load (repeatable) | none | 25 + | `--timeout <ms>` | Total time before exit | 5000 | 26 + | `--session <partition>` | Electron session partition | default | 27 + | `--wait-sw <ms>` | Wait time for service worker startup | 2000 | 28 + | `--preload <path>` | Preload script path | none | 29 + | `--show` | Make window visible | hidden | 30 + 31 + The `--eval` flag can be used multiple times to evaluate several expressions. 32 + 33 + The magic string `EXTENSION_ID` in `--url` is replaced with the loaded extension's actual ID. 34 + 35 + ## Common Scenarios 36 + 37 + ### Debug a Chrome extension's settings page 38 + 39 + ```bash 40 + npx electron scripts/debug-electron-page.mjs \ 41 + --extension resources/chrome-extensions/proton-pass \ 42 + --url "chrome-extension://EXTENSION_ID/settings.html" \ 43 + --eval "typeof chrome.runtime" \ 44 + --eval "typeof chrome.storage.session" \ 45 + --eval "document.querySelector('#root')?.innerHTML.length" 46 + ``` 47 + 48 + ### Check if extension APIs are available 49 + 50 + ```bash 51 + npx electron scripts/debug-electron-page.mjs \ 52 + --extension resources/chrome-extensions/proton-pass \ 53 + --url "chrome-extension://EXTENSION_ID/popup.html" \ 54 + --eval "Object.keys(chrome).join(', ')" \ 55 + --eval "typeof chrome.storage.local" \ 56 + --eval "typeof chrome.alarms" 57 + ``` 58 + 59 + ### Debug a web page with console capture 60 + 61 + ```bash 62 + npx electron scripts/debug-electron-page.mjs \ 63 + --url "https://example.com" \ 64 + --eval "document.querySelectorAll('a').length" \ 65 + --eval "performance.timing.loadEventEnd - performance.timing.navigationStart" \ 66 + --timeout 8000 67 + ``` 68 + 69 + ### Debug a local app page 70 + 71 + ```bash 72 + npx electron scripts/debug-electron-page.mjs \ 73 + --url "file:///path/to/app/page/index.html" \ 74 + --eval "document.body.childElementCount" 75 + ``` 76 + 77 + ### Inspect service worker status only 78 + 79 + ```bash 80 + npx electron scripts/debug-electron-page.mjs \ 81 + --extension resources/chrome-extensions/proton-pass \ 82 + --url "chrome-extension://EXTENSION_ID/popup.html" \ 83 + --wait-sw 5000 \ 84 + --timeout 8000 85 + ``` 86 + 87 + ## Output Tags Reference 88 + 89 + | Tag | Meaning | 90 + |-----|---------| 91 + | `[CONSOLE:error]` | Console.error from the page | 92 + | `[CONSOLE:warning]` | Console.warn from the page | 93 + | `[CONSOLE:log]` | Console.log from the page | 94 + | `[CONSOLE:debug]` | Console.debug from the page | 95 + | `[PAGE:url]` | The final URL after load/redirects | 96 + | `[PAGE:title]` | The page title | 97 + | `[PAGE:loading]` | URL being loaded | 98 + | `[PAGE:fail]` | Page failed to load (with error code) | 99 + | `[PAGE:crash]` | Renderer process crashed | 100 + | `[SW:running]` | Service worker is active | 101 + | `[SW:stopped]` | No service workers found | 102 + | `[SW:console]` | Console output from a service worker | 103 + | `[SW:waiting]` | Waiting for SW startup | 104 + | `[SW:final]` | Final SW status before exit | 105 + | `[EXT:loaded]` | Extension loaded (with ID) | 106 + | `[EXT:error]` | Extension failed to load | 107 + | `[EVAL]` | Successful eval result | 108 + | `[EVAL:error]` | Eval expression threw an error | 109 + | `[DOM]` | DOM snapshot information | 110 + | `[DOM:error]` | DOM inspection failed | 111 + | `[ERROR]` | Fatal/uncaught error | 112 + | `[EXIT]` | Script exit info | 113 + 114 + ## Iterative Debugging Workflow 115 + 116 + The key pattern for agent-driven debugging: 117 + 118 + 1. **Run the script** to capture all console errors and page state 119 + 2. **Read the output** -- focus on `[CONSOLE:error]` and `[EVAL:error]` lines 120 + 3. **Identify the root cause** from error messages and stack traces 121 + 4. **Apply a fix** to the relevant source file 122 + 5. **Re-run the script** to verify the fix worked 123 + 6. **Repeat** until no errors remain 124 + 125 + ### Example iteration 126 + 127 + ``` 128 + # Step 1: See what's broken 129 + npx electron scripts/debug-electron-page.mjs \ 130 + --extension resources/chrome-extensions/proton-pass \ 131 + --url "chrome-extension://EXTENSION_ID/settings.html" \ 132 + --eval "document.querySelector('#root').innerHTML.length" 133 + 134 + # Output shows: 135 + # [CONSOLE:error] Cannot read properties of undefined (reading 'addListener') (background.js:1234) 136 + # [EVAL] document.querySelector('#root').innerHTML.length = 0 137 + 138 + # Step 2: Fix the missing API (e.g., add a shim) 139 + # ... edit the file ... 140 + 141 + # Step 3: Verify 142 + npx electron scripts/debug-electron-page.mjs \ 143 + --extension resources/chrome-extensions/proton-pass \ 144 + --url "chrome-extension://EXTENSION_ID/settings.html" \ 145 + --eval "document.querySelector('#root').innerHTML.length" 146 + 147 + # Output shows: 148 + # [EVAL] document.querySelector('#root').innerHTML.length = 4523 149 + # No more CONSOLE:error lines -- fixed! 150 + ``` 151 + 152 + ## Tips 153 + 154 + - Use `--timeout 10000` or higher for slow-loading pages 155 + - Use `--wait-sw 5000` if the extension's service worker takes time to initialize 156 + - The `EXTENSION_ID` placeholder in `--url` is auto-replaced with the real extension ID 157 + - Multiple `--eval` flags run in order; use them to build up context 158 + - The script always exits cleanly (no hanging processes) 159 + - All output includes timestamps for correlating events 160 + - DOM snapshot runs automatically and reports body/root element stats
+27
.claude/skills/explore.md
··· 1 + # /explore — Research a codebase question 2 + 3 + When the user invokes /explore with a question: 4 + 5 + 1. Spawn an **Explore agent** (`subagent_type=Explore`) to research the question. 6 + 7 + 2. The agent should: 8 + - Use Grep, Glob, and Read tools to search the codebase — NOT bash commands 9 + - Search broadly first, then narrow down 10 + - Check multiple locations and naming conventions 11 + - Look for related files and cross-references 12 + 13 + 3. Return structured findings: 14 + - **Answer**: Direct answer to the question 15 + - **Relevant files**: Absolute paths to key files 16 + - **Architecture**: How the components fit together (if applicable) 17 + - **Key functions/classes**: Important entry points 18 + 19 + 4. Relay the agent's findings to the user in a clear format. 20 + 21 + ## Usage 22 + 23 + ``` 24 + /explore "how does lazy extension loading work" 25 + /explore "where are sync conflicts resolved" 26 + /explore "what pubsub events does the groups UI listen to" 27 + ```
+37
.claude/skills/fix.md
··· 1 + # /fix — Spawn background coding agent 2 + 3 + When the user invokes /fix with a description: 4 + 5 + 1. Spawn a **background coding agent** (`subagent_type=general-purpose`, `run_in_background=true`) with the task description. 6 + 7 + 2. Include these rules in the agent prompt: 8 + - Use `jj` not `git` for version control 9 + - Use `yarn <script>` for build/test/lint — read `package.json` scripts first 10 + - No compound bash commands (`&&`, `;`, `|`) 11 + - Use Read/Grep/Glob tools instead of bash for file operations 12 + - Read files before editing them 13 + - Do NOT commit unless explicitly asked 14 + - Follow all rules in CLAUDE.md 15 + 16 + 3. The agent should: 17 + - Read relevant files to understand the code 18 + - Make the requested changes 19 + - Verify changes with appropriate build/test commands 20 + - Report what was changed and any issues found 21 + 22 + 4. When the agent completes, relay its findings to the user. 23 + 24 + ## Worktree mode 25 + 26 + If the user passes `--worktree`, create an isolated jj worktree first: 27 + ``` 28 + jj workspace add ../.claude/worktrees/fix-<short-description> 29 + ``` 30 + Then run the agent in that worktree directory. 31 + 32 + ## Usage 33 + 34 + ``` 35 + /fix "description of what to fix or implement" 36 + /fix "description" --worktree 37 + ```
+37
.claude/skills/ios-build.md
··· 1 + # /ios-build — Build for iOS 2 + 3 + When the user invokes /ios-build: 4 + 5 + 1. First, read `backend/tauri-mobile/package.json` to confirm available scripts. 6 + 7 + 2. Determine build target from argument: 8 + 9 + | Argument | Command | Description | 10 + |----------|---------|-------------| 11 + | (none) or `sim` | `yarn mobile:ios:dev` | Simulator + HMR mode for frontend dev | 12 + | `device` | `yarn mobile:ios:xcodebuild:device:full` | Full device build for release testing | 13 + | `full` | `yarn mobile:ios:xcodebuild:full` | Full simulator rebuild (no HMR) | 14 + 15 + 3. Run the build in a **background agent** (`subagent_type=general-purpose`, `run_in_background=true`) — builds are verbose and long-running. 16 + 17 + 4. When complete, report: 18 + - Build success/failure 19 + - Build number from `backend/tauri-mobile/BUILD_NUMBER` 20 + - Any errors or warnings 21 + 22 + ## CRITICAL rules 23 + 24 + - **Read package.json scripts first** — use yarn scripts only, never raw xcodebuild/cargo 25 + - `custom-protocol` feature is REQUIRED for iOS — build scripts handle this automatically 26 + - Simulator builds go to `/tmp/peek-xcodebuild-sim`, device to `/tmp/peek-xcodebuild-device` 27 + - If user reports blank white page, may need `yarn clean:rust:full` (stale Cargo cache) 28 + - NEVER add `custom-protocol` to default Cargo.toml features 29 + 30 + ## Usage 31 + 32 + ``` 33 + /ios-build 34 + /ios-build sim 35 + /ios-build device 36 + /ios-build full 37 + ```
+46
.claude/skills/jj-worktrees.md
··· 1 + --- 2 + name: jj-worktrees 3 + description: Manage jj worktrees and merge agent work 4 + user_invocable: true 5 + --- 6 + 7 + # jj Worktree Management 8 + 9 + Use `scripts/jj-worktrees.sh` for all jj workspace operations instead of compound bash commands. 10 + 11 + ## Commands 12 + 13 + ### Check status of all worktrees 14 + ```bash 15 + scripts/jj-worktrees.sh status 16 + ``` 17 + Shows all workspaces with unmerged commits (commits not yet on main). 18 + 19 + ### Merge a specific workspace to main 20 + ```bash 21 + scripts/jj-worktrees.sh merge <workspace-name> 22 + ``` 23 + Rebases the workspace's commits onto main and moves the main bookmark. 24 + 25 + ### Merge all unmerged workspaces to main 26 + ```bash 27 + scripts/jj-worktrees.sh merge-all 28 + ``` 29 + Iterates all workspaces and merges any with unmerged commits. 30 + 31 + ### List worktree directories 32 + ```bash 33 + scripts/jj-worktrees.sh clean 34 + ``` 35 + Shows worktree directories and their sizes for cleanup. 36 + 37 + ### Show recent main commits 38 + ```bash 39 + scripts/jj-worktrees.sh log 40 + ``` 41 + 42 + ## When to use 43 + 44 + - **Always** use this script for checking worktree status, merging, and cleanup 45 + - **Never** write compound jj commands inline — use this script 46 + - Agents in worktrees should only `jj commit`, never move main or merge
+180
.claude/skills/peek-tasks.md
··· 1 + --- 2 + name: peek-tasks 3 + description: Manage the Peek-codebase todo queue via the Peek MCP server (mcp__peek__*). All tasks live under the peek:* tag namespace — add, list, status changes, complete, and "open in Peek" handoff for collaborative editing. 4 + user_invocable: true 5 + --- 6 + 7 + # Peek Task Queue (peek:* namespace only) 8 + 9 + This skill is **project-scoped**. The Peek MCP server is generic — it 10 + serves every project in the user's datastore (Amsterdam logistics, 11 + taxes, atproto notes, etc.). When you're working in this codebase, 12 + you must keep all task operations inside the `peek:*` tag namespace, 13 + or you'll surface and mutate cross-project items. 14 + 15 + The active queue lives in Peek as items, **not** in `docs/tasks.md`. 16 + That file is a one-line pointer; do not edit it. 17 + 18 + ## CRITICAL: never use bare-tag queries here 19 + 20 + - ❌ `mcp__peek__list_tasks()` — defaults to `tags: ['todo']` (bare), 21 + surfaces every cross-project todo. **Do not use** in this codebase. 22 + - ❌ `mcp__peek__list_tasks({ project: 'peek' })` — queries bare 23 + `#peek` + `#todo`, also wrong namespace. 24 + - ❌ `mcp__peek__complete_task({ id })` — hardcoded to add bare `done` 25 + and remove bare `todo`. Won't touch `peek:todo`. **Do not use.** 26 + - ✅ `mcp__peek__list_items({ tags: ['peek:todo'] })` — correct. 27 + - ✅ Manual untag + tag + event for status changes (see below). 28 + 29 + ## Tag vocabulary (controlled) 30 + 31 + Every task is a Peek item with the `peek:todo` status tag plus at 32 + least one domain or type tag from this controlled list: 33 + 34 + - **Status**: `peek:todo`, `peek:wip`, `peek:blocked`, `peek:deferred`, `peek:done` 35 + - **Domain**: `peek:desktop`, `peek:mobile`, `peek:tauri`, `peek:atproto`, `peek:extensions` 36 + - **Type**: `peek:bug`, `peek:feature`, `peek:test-coverage`, `peek:docs`, `peek:design`, `peek:security`, `peek:tile-arch`, `peek:meta`, `peek:tooling`, `peek:daily-use` 37 + 38 + The bare `#peek` tag is the legacy project membership marker — leave 39 + it alone on existing items, but **don't add `#peek` to new items**. 40 + The `peek:*` namespace is implicit project membership. 41 + 42 + ## Add a task 43 + 44 + ```js 45 + mcp__peek__create_item({ 46 + type: 'text', 47 + title: 'Short imperative title', 48 + content: '# Short imperative title\n\n## Problem\n\n...\n\n## Plan\n\n...', 49 + tags: ['peek:todo', 'peek:desktop', 'peek:bug'], 50 + }) 51 + ``` 52 + 53 + - Title is what shows in lists — keep it scannable. 54 + - Content is markdown; first line `# {title}` matches the title. 55 + - Tags: always include `peek:todo` + at least one domain (`peek:desktop`/`peek:mobile`/etc.) + ideally one type (`peek:bug`/`peek:feature`/etc.). 56 + - Don't write to `docs/tasks.md`. Don't echo the new task back unless asked. 57 + 58 + ## List tasks 59 + 60 + ```js 61 + // All open work in this project 62 + mcp__peek__list_items({ tags: ['peek:todo'] }) 63 + 64 + // Scoped views 65 + mcp__peek__list_items({ tags: ['peek:todo', 'peek:desktop'] }) 66 + mcp__peek__list_items({ tags: ['peek:todo', 'peek:mobile'] }) 67 + mcp__peek__list_items({ tags: ['peek:todo', 'peek:bug'] }) 68 + 69 + // In progress / blocked 70 + mcp__peek__list_items({ tags: ['peek:wip'] }) 71 + mcp__peek__list_items({ tags: ['peek:blocked'] }) 72 + 73 + // Pagination 74 + mcp__peek__list_items({ tags: ['peek:todo'], limit: 50, offset: 0 }) 75 + ``` 76 + 77 + `list_items` returns ALL items matching the tag intersection. The 78 + queue is large (267+ `peek:todo` items as of 2026-04-29) — paginate 79 + or narrow by domain/type tag rather than dumping everything. 80 + 81 + ## Status transitions 82 + 83 + `complete_task` is generic and operates on bare `#todo` — never use 84 + it here. Do transitions manually with `tag_item` + `untag_item` + 85 + `record_event`: 86 + 87 + | State change | Tools | 88 + |----------------------|------------------------------------------------------------------------------------------------| 89 + | **todo → wip** | `untag_item(peek:todo)` + `tag_item(peek:wip)` + `record_event('started')` | 90 + | **wip → blocked** | `untag_item(peek:wip)` + `tag_item(peek:blocked)` + `record_event('blocked', why)` | 91 + | **blocked → wip** | `untag_item(peek:blocked)` + `tag_item(peek:wip)` + `record_event('unblocked')` | 92 + | **wip → done** | `untag_item(peek:wip)` + `tag_item(peek:done)` + `record_event('completed', notes)` | 93 + | **todo → done** | `untag_item(peek:todo)` + `tag_item(peek:done)` + `record_event('completed', notes)` | 94 + | **done → todo (revive)** | `untag_item(peek:done)` + `tag_item(peek:todo)` + `record_event('reopened', why)` | 95 + | **defer** | `untag_item(peek:todo)` + `tag_item(peek:deferred)` + `record_event('deferred', why)` | 96 + 97 + Always do the untag and the tag in a pair — don't leave an item with 98 + `peek:todo` AND `peek:done` set, or `peek:wip` AND `peek:blocked`. 99 + 100 + ## Edit / update a task 101 + 102 + ```js 103 + mcp__peek__update_item({ 104 + id: '<itemId>', 105 + title: 'New title', // optional 106 + content: 'New body…', // optional 107 + }) 108 + ``` 109 + 110 + To change tags (swap domain, add a type tag, etc.): 111 + 112 + ```js 113 + mcp__peek__tag_item({ itemId, tagName: 'peek:test-coverage' }) 114 + mcp__peek__untag_item({ itemId, tagName: 'peek:design' }) 115 + ``` 116 + 117 + ## Open a task in Peek for collaborative editing 118 + 119 + When the user says "open task X" / "let's edit task X together" / 120 + "pull up the X note": 121 + 122 + 1. Resolve the item via `list_items({ tags: ['peek:todo', ...] })` by 123 + matching title — get the item ID. 124 + 2. Tell the user to invoke Peek's cmd panel (default `Option+Space`) 125 + and type **`edit <title-fragment>`** — that routes through the 126 + `edit` command in `app/cmd/commands/edit.js`, which publishes 127 + `editor:open { itemId }` and opens the editor tile loaded with 128 + that item. 129 + 3. After they confirm it's open, collaborate by: 130 + - You read state via `mcp__peek__get_item` / `get_task_context`. 131 + - User types in Peek; you read updated content via `get_item`. 132 + - You write proposed edits via `update_item`. 133 + - User can re-read in Peek (the editor reloads on `editor:changed`). 134 + 135 + **Why not auto-open?** The MCP server is a standalone Node subprocess 136 + talking to `datastore.sqlite` directly — it cannot publish pubsub 137 + events to the running Peek desktop app. Auto-open would require either 138 + (a) registering `peek://` as a macOS protocol handler so 139 + `open "peek://editor/home.html?itemId=…"` from shell routes to the 140 + running Peek, or (b) an MCP-to-Peek IPC bridge. Until then the 141 + cmd-panel handoff is the canonical flow. 142 + 143 + ## Don'ts 144 + 145 + - **Don't read or write `docs/tasks.md`** for task ops. Read the queue 146 + via MCP. (The file is a pointer; treat it as read-only legacy.) 147 + - **Don't use `list_tasks` or `complete_task`** — they're generic 148 + bare-tag tools that ignore the `peek:*` namespace. Use `list_items` 149 + + manual tag/event transitions. 150 + - **Don't add `#todo` or `#peek`** to new items — `peek:todo` already 151 + encodes both project membership and queue status. 152 + - **Don't create duplicate tasks.** Before `create_item`, list with 153 + the relevant domain tag and check by title (substring match). 154 + - **Don't leave inconsistent tag state** (`peek:wip` + `peek:done`, 155 + `peek:todo` + `peek:done`, etc.) — always pair the untag + tag. 156 + - **Don't echo created/updated content** back in chat unless asked. 157 + Acknowledge tersely with the title. 158 + 159 + ## Quick recipes 160 + 161 + **"Add a task: rename X to Y, peek desktop bug"** 162 + → `create_item({ type: 'text', title: 'Rename X to Y', content: '# Rename X to Y\n\n…', tags: ['peek:todo', 'peek:desktop', 'peek:bug'] })` 163 + 164 + **"What's on my plate for desktop?"** 165 + → `list_items({ tags: ['peek:todo', 'peek:desktop'] })` → render as a numbered list of titles only. 166 + 167 + **"What's in flight?"** 168 + → `list_items({ tags: ['peek:wip'] })`. 169 + 170 + **"Mark #3 done"** 171 + → resolve #3 from the prior list output → `untag_item(id, 'peek:todo')` + `tag_item(id, 'peek:done')` + `record_event(id, 'completed', notes)`. 172 + 173 + **"Block the auth refactor — backend isn't ready"** 174 + → resolve item → `untag_item(id, 'peek:todo')` (or `peek:wip`) + `tag_item(id, 'peek:blocked')` + `record_event(id, 'blocked', 'backend not ready')`. 175 + 176 + **"Open the page-host display-switch note"** 177 + → resolve via `list_items({ tags: ['peek:todo'] })` → reply: "It's item `<short-title>`. Pop Peek's cmd (Option+Space) and type `edit page-host display`." 178 + 179 + **"Defer this until after the conversion"** 180 + → `untag_item(id, 'peek:todo')` + `tag_item(id, 'peek:deferred')` + `record_event(id, 'deferred', why)`.
+42
.claude/skills/release.md
··· 1 + # /release — Update changelog and RSS feed 2 + 3 + When the user invokes /release: 4 + 5 + 1. Get recent commits since last changelog entry: 6 + ``` 7 + jj log -r 'main' --no-graph -T 'description.first_line() ++ "\n"' --limit 30 8 + ``` 9 + 10 + 2. Read `CHANGELOG.md` to find the latest date heading (format: `## YYYY-MM-DD`). 11 + 12 + 3. Read recent commit messages between now and that date. 13 + 14 + 4. Add a new date section at the top of the changelog (after any header): 15 + - Use today's date or the date provided as argument 16 + - Group entries by area (features, fixes, docs, etc.) 17 + - Use concise descriptions based on commit messages 18 + - Follow the existing format in CHANGELOG.md 19 + 20 + 5. Regenerate the RSS feed: 21 + ``` 22 + yarn rss 23 + ``` 24 + 25 + 6. Commit both files: 26 + ``` 27 + jj commit -m "docs: update changelog and RSS feed for <date>" 28 + ``` 29 + 30 + ## Important 31 + 32 + - Read the existing CHANGELOG.md format carefully and match it exactly 33 + - The RSS feed is generated from `@marss` metadata in CHANGELOG.md 34 + - Feed URLs must use `tangled.org/burrito.space/peek/raw/main/` — NEVER github.com 35 + - Only include commits that represent user-facing changes (skip merge commits, WIP, etc.) 36 + 37 + ## Usage 38 + 39 + ``` 40 + /release 41 + /release 2026-03-18 42 + ```
+35
.claude/skills/review.md
··· 1 + # /review — Review current changes 2 + 3 + When the user invokes /review: 4 + 5 + 1. Show current change summary: 6 + ``` 7 + jj diff --stat 8 + ``` 9 + 10 + 2. Get the full diff: 11 + ``` 12 + jj diff 13 + ``` 14 + 15 + 3. Spawn a **background agent** (`subagent_type=general-purpose`, `run_in_background=true`) to review all changed files: 16 + 17 + The agent should check for: 18 + - **Correctness**: Logic errors, off-by-one, null/undefined handling 19 + - **Missing tests**: New functionality without test coverage 20 + - **Style**: Adherence to existing codebase conventions 21 + - **CLAUDE.md rules**: jj not git, yarn scripts, no compound bash, etc. 22 + - **Incomplete renames**: Stale references to old names 23 + - **Security**: Exposed secrets, unsafe operations 24 + - **PubSub**: Missing event publications for data mutations (see MEMORY.md) 25 + 26 + 4. Report issues grouped by severity: 27 + - **Blockers**: Must fix before shipping 28 + - **Warnings**: Should fix, but not critical 29 + - **Suggestions**: Nice-to-have improvements 30 + 31 + ## Usage 32 + 33 + ``` 34 + /review 35 + ```
+48
.claude/skills/ship.md
··· 1 + # /ship — Commit, merge to main, push 2 + 3 + When the user invokes /ship: 4 + 5 + 1. Check for uncommitted changes: 6 + ``` 7 + jj diff --stat 8 + ``` 9 + 10 + 2. If changes exist, commit them: 11 + - Use the message provided after `/ship`, e.g. `/ship "feat: add new feature"` 12 + - If no message provided, run `jj diff` to see full changes, summarize them, and generate an appropriate commit message 13 + - Commit: `jj commit -m "<message>"` 14 + 15 + 3. Show commits above main: 16 + ``` 17 + jj log -r '::@ ~ ::main' 18 + ``` 19 + 20 + 4. Rebase onto main: 21 + ``` 22 + jj rebase -s 'roots(::@ ~ ::main)' -d main 23 + ``` 24 + 25 + 5. Move main bookmark: 26 + ``` 27 + jj bookmark set main -r '@-' 28 + ``` 29 + 30 + 6. Push to tangled remote: 31 + ``` 32 + jj git push --remote=tangled 33 + ``` 34 + 35 + 7. Report success with the commit hash from `jj log -r @- --no-graph -T 'commit_id.short(8)'` 36 + 37 + ## Error handling 38 + 39 + - If rebase has conflicts, stop and report them. Do NOT push. 40 + - If push fails, report the error. The commits are still on main locally. 41 + - NEVER use git commands. Only jj. 42 + 43 + ## Usage 44 + 45 + ``` 46 + /ship "commit message here" 47 + /ship # auto-generates message from diff 48 + ```
+36
.claude/skills/test.md
··· 1 + # /test — Run tests 2 + 3 + When the user invokes /test: 4 + 5 + 1. Determine which test suite to run based on argument: 6 + 7 + | Argument | Command | Notes | 8 + |----------|---------|-------| 9 + | (none) or `unit` | `yarn test:unit` | 1196+ unit tests, run in background | 10 + | `electron` or `e2e` | `yarn test:electron:bg` | 212+ Playwright tests, headless background, logs to `/tmp/test-electron.log` | 11 + | `cmd` | `yarn test:cmd` | Cmd state machine + chaining + param mode tests | 12 + | `all` | `yarn test:unit` then `yarn test:electron:bg` | Run sequentially | 13 + 14 + 2. Run the test command via Bash with `run_in_background=true` for long-running suites. 15 + 16 + 3. When complete, report: 17 + - Total tests run 18 + - Pass/fail counts 19 + - Any failures with file path, test name, and error details 20 + 21 + ## CRITICAL rules 22 + 23 + - **NEVER run `npx playwright test` directly** — it steals focus and blocks the user 24 + - Always use `yarn test:electron:bg` for Playwright tests (logs to `/tmp/test-electron.log`) 25 + - For electron test results, read `/tmp/test-electron.log` with the Read tool 26 + - Use `yarn test:electron:x` if user wants stop-on-first-failure mode 27 + 28 + ## Usage 29 + 30 + ``` 31 + /test 32 + /test unit 33 + /test electron 34 + /test cmd 35 + /test all 36 + ```
+3 -2
.gitignore
··· 30 30 test-results/ 31 31 playwright-report/ 32 32 33 - # Claude Code local settings 34 - .claude/ 33 + # Claude Code local settings (per-user); skills/ is shared 34 + .claude/* 35 + !.claude/skills/ 35 36 36 37 # Agent task scratch files 37 38 .agent-task.md
+6
scripts/spawn-isolated-agent.sh
··· 3 3 # 4 4 # Usage: scripts/spawn-isolated-agent.sh <agent-name> 5 5 # 6 + # IF YOU'RE CONSIDERING THE Agent TOOL'S `isolation: "worktree"` PARAMETER: 7 + # STOP. That creates a git worktree outside jj's view; commits made there 8 + # are orphaned from the main jj stack and require manual recovery. Use this 9 + # script instead — it creates a real jj workspace that shares state with 10 + # the default checkout. 11 + # 6 12 # Workspaces are pooled — this script REUSES existing mpeek-agent-<name> 7 13 # if one exists, resetting its working copy to match the default workspace's @. 8 14 # If it doesn't exist, it's created.