@staff0rd/assist 0.965.0 → 0.966.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,658 +1,23 @@
1
1
  # assist
2
2
 
3
- A CLI tool for enforcing determinism in LLM development workflow automation.
3
+ A dashboard and CLI for running coding agents (Claude Code, Codex or pi) across your repos, from a shared backlog through to verified commits and pull requests.
4
4
 
5
- See [devlog](https://staffordwilliams.com/devlog/assist/) for latest features.
5
+ <picture>
6
+ <source media="(prefers-color-scheme: dark)" srcset="https://staffordwilliams.com/assist/screenshots/sessions-dashboard-dark.png">
7
+ <img alt="The sessions dashboard, with sessions grouped by repo in the sidebar and one agent's terminal open" src="https://staffordwilliams.com/assist/screenshots/sessions-dashboard.png">
8
+ </picture>
6
9
 
7
- ## Installation
10
+ Read the [documentation](https://staffordwilliams.com/assist/) to get started.
8
11
 
9
- You can install `assist` globally using npm:
12
+ ## Install
10
13
 
11
14
  ```bash
12
15
  npm install -g @staff0rd/assist
13
16
  assist sync
14
17
  ```
15
18
 
16
- ## Updating
19
+ Then follow [Getting started](https://staffordwilliams.com/assist/getting-started/). Update with `assist update`.
17
20
 
18
- ```bash
19
- assist update
20
- ```
21
-
22
- ## Local Development
23
-
24
- ```bash
25
- # Clone the repository
26
- git clone git@github.com:staff0rd/assist.git
27
- cd assist
28
-
29
- # Install dependencies
30
- npm install
31
-
32
- # Build the project
33
- npm run build
34
-
35
- # Install globally
36
- npm install -g .
37
- ```
38
-
39
- After installation, the `assist` command will be available globally. You can also use the shorter `ast` alias.
40
-
41
- ## User guide
42
-
43
- The user guide is an [Astro Starlight](https://starlight.astro.build/) site in its own `docs/` package, built from markdown pages in `docs/src/content/docs/` and PNGs in `docs/public/screenshots/`. Astro is a dependency of `docs/` only; run `npm run docs:install` once to install it.
44
-
45
- - **Add a page** — add `docs/src/content/docs/<id>.md`. Its YAML frontmatter, validated by `docsPageSchema` in `src/docs/docsPageSchema.ts`, has `id` (the file name), `title`, `group` (a sidebar group from `docsNavGroups`), `order` within the group, `covers` and optional `screenshots`. Each `##` heading starts a section. `covers` lists the inventory ids the page documents (`cli:<command path>`, `claude:<name>`, `config:<key>`, `route:<path>`, `skill:<name>`). Unknown keys, unknown ids, unknown scenes and missing screenshots fail the build.
46
- - **Keyboard shortcuts** — write a shortcut as `:kbd[Mod+N]`, with keys joined by `+`. It renders as key caps; `Mod`, `Ctrl`, `Alt` and `Shift` show as ⌘, ⌃, ⌥ and ⇧ on macOS and by name elsewhere, picked from the reader's platform.
47
- - **Session status glyphs** — write `:status[running]` (or `verifying`, `waiting`, `done`, `error`, `stopped`) to show a session card's status glyph in the dashboard's colours, and `:badge[clone]` (or `harness`, `serving`, `node`) for a card badge.
48
- - **Icons** — write `:icon[OpenInFull]` to show the icon a dashboard button uses. Add a new icon to the registry in `src/docs/starlight/renderIcon.ts`.
49
- - **Coverage report** — `npx tsx src/docs/docsCoverage.ts --report` lists the commands, skills, config keys and routes no page covers, by kind. `verify:docs-coverage` fails when any item is covered by no page, so a new command, skill, config key or route needs docs before verify passes.
50
- - **Screenshots** — each entry in the frontmatter's `screenshots` declares a `file`, `alt` and either a `route` on the capture web server or a `url` on `https://github.com/` (a live page, logged out, with the browser extension's `content.js` injected and its `browser.*` APIs stubbed; a `script: <name>` action runs `docs/capture/github/<name>.js` in the page to stand in for what a logged-out page lacks), and optionally `viewport` (default 1280×800), `theme`, `waitFor` and `crop` selectors, a `scene` (a named list of setup steps in `docs/capture/scenes.json`), `setup` steps run after the scene, and `actions` (`click: <selector>`, `press: <key>`, `type: <text>`, `drag: { from: <selector>, to: <selector> }`) performed on the page before capture, and `highlight` (a list of selectors; every match is outlined in the capture to point the reader at it). Setup steps: `assist: [args]` runs an assist command in the sandbox, `run: <name>` starts a run session from `docs/capture/assist.yml`, and `session: { repo, prompt, title?, reply?, status? }` starts an agent session in the `sandbox`, `api` or `website` repo and sets its status (`running`, `waiting` or `done`). `openPr: { repo, number, title, author? }` gives the repo an open pull request: the capture also puts a fake `gh` (`docs/capture/bin/gh`) on the `PATH`, which answers `gh pr list` and `gh pr view` with it and fails every other call. `gh: { match, json }` makes that fake `gh` print `json` for any call whose arguments contain every string in `match`, with each `"{{ago:<n><m|h|d>}}"` in it replaced by the ISO time that long ago. `sql: <statements>` runs SQL against the capture database, and `newsFeed: { name, title, items }` serves an RSS feed of `{ title, hoursAgo, excerpt? }` items locally and adds it with `assist news add`. Between states the capture also restores `~/.assist.yml` and empties the backlog, backups and usage tables. Preview steps open a preview pane on the session started with the step's `session` prompt and hold it open until the state changes: `preview: { session, kind: ask|show, title, body }`, `pr: { session, title, what, why, how?, resolves?, prNumber?, draft? }`, `proposal: { session, item }` (an `assist backlog propose` payload) and `highLevelReview: { session, prNumber, title, headRef, body, linkedIssues?, criticalPaths?, uiPaths?, files }`, where each file is `{ path, status, content?, patch? }` and an added file's patch is built from its `content`. The capture puts a fake `claude` (`docs/capture/bin/claude`) on the `PATH`, which prints the step's `reply` lines as its transcript and answers title generation with its `title`, so no real harness runs. Screenshots sharing a scene and setup are captured together, and the sessions are drained before the next state is set up. Without a `theme`, it is captured as `<file>` (light) and `<file>-dark.png`, and the site shows the one matching the theme the reader picked. A `::screenshot{file="<file>"}` line in the page places it; a declared screenshot with no such line, or a line naming an undeclared one, fails the build.
51
- - **Recapture** — `npm run docs:capture [-- <file.png>...] [--skip-build] [--keep-home]` builds assist, starts a throwaway Postgres container (Docker required), clones `staff0rd/sandbox` (plus local `api` and `website` repos) into a temporary `HOME`, runs the real daemon and web server there on a free port, captures the screenshots with Playwright (`npx playwright install chromium` once) and tears everything down. Commit the changed PNGs.
52
- - **Preview** — `npm run docs:build` builds the site into `docs/dist/`, and `npm run docs:preview` runs the Astro dev server on port 4173, replacing any dev server already running for the checkout, which reloads open tabs as pages change; a tab with a feedback popover open reloads once the popover closes. Set `DOCS_BASE_PATH=<path>` to build for a site hosted under a sub-path. The server restarts itself when a page is added or removed, a page's `group` or `order` changes, a screenshot PNG is added or removed, or code under `src/docs/` or `docs/capture/scenes.json` changes. A page whose frontmatter fails validation shows the error in the browser instead of its last valid copy.
53
- - **Feedback** — start the `docs` run entry (a `server: docs` run of `docs:preview` on port 4173) from the dashboard and open the preview in Firefox with the [assist browser extension](#docs-feedback) installed. Select text on a page with the mouse, and a prompt popover opens at the end of the selection with its textbox focused; type a prompt and press **Enter**: it arrives as a user prompt naming the page id, section heading and source `.md` file, with the selected text quoted, in the live Claude session that shares the docs server's directory — the one the run is grouped under on the dashboard. With several such sessions, the one that most recently wrote that page (else the newest) gets it; with none, the live session that most recently wrote the page or anything under `docs/src/`.
54
-
55
- ## Claude Commands
56
-
57
- - `/add-command` - Add a new run command via `assist run add`
58
- - `/add-rule` - Capture a new `CLAUDE.md` rule from a review comment
59
- - `/branch <description> [--jira KEY]` - Create a branch off the fresh remote default
60
- - `/bug` - File a bug with reproduction steps, expected and actual behavior
61
- - `/close` - End this session if its work is finished
62
- - `/comment` - Add pending review comments to the current PR
63
- - `/commit` - Commit only relevant files from the session
64
- - `/devlog` - Generate devlog entry for the next unversioned day
65
- - `/extension` - Get the install link for the assist browser extension
66
- - `/draft` - Draft a new backlog item with LLM-assisted questioning
67
- - `/fix-conflict [--rebase]` - Resolve the current PR branch's conflicts against the remote default; `--rebase` rebases instead of merging
68
- - `/fix-rules [dir]` - Put existing rules into the `## Rules` format `assist rules` reads
69
- - `/forward-comments` - Split a coarse PR comment into per-line review comments, attributed to the original reviewer
70
- - `/pr` - Raise a PR with a concise description
71
- - `/prs-slack <number> [--no-confirm]` - Post a PR's title and URL to the `prs.slack` channel (else `slack.channel`); `--no-confirm` skips the confirmation
72
- - `/prs-status [channel] <owner/repo>...` - Post an overview of the open PRs across the named repos to Slack (default channel `slack.channel`)
73
- - `/refactor` - Run refactoring checks for code quality
74
- - `/prompts` - Analyze denied tool calls and suggest settings changes to auto-allow recurring prompts
75
- - `/run-logs [session-id|group]` - Summarise a run session's output, by session id or this repo's server group (default `default`)
76
- - `/releases-configure` - Derive this repo's release promotion topology from its workflows and write it to `releases.streams`
77
- - `/refine` - Refine an existing backlog item through conversation
78
- - `/rename [title]` - Retitle this session's dashboard card, inferring a title when given none
79
- - `/restructure` - Analyze and restructure tightly-coupled files
80
- - `/review-config` - Configure this repo's high-level review checklist keys
81
- - `/review-ci` - Install a GitHub workflow that reviews new PRs with Claude and Codex through LiteLLM or Azure AI Foundry, without depending on assist
82
- - `/review-high-level [number]` - Open the high-level review checklist for the current branch's PR, or PR `<number>`, as a background task, answering diff questions while it is open; outside a web session, show the printed checklist
83
- - `/review-pr-comments` - Process PR review comments one by one
84
- - `/jira [action] [KEY] [args]` - Jira actions: `view`, `associate`, `update`, `started`, `done`, `help`. `[KEY]` defaults to the session's backlog item's
85
- - `/github [action] [ref] [args]` - GitHub issue actions: `view`, `edit`, `create`, `associate`, `update`, `started`, `done`, `help`. `[ref]` defaults to the session's backlog item's; a bare `/github <ref>` runs `edit`
86
- - `/next [id]` - Signal completion and chain into the next backlog item
87
- - `/slack-post [channel] [--thread <ts-or-permalink>] <what to say>` - Preview a markdown message, or a thread of them, then post it to a Slack channel (default `slack.channel`); `--thread` replies in that thread
88
- - `/strip-code-comments` - Strip redundant comments from tracked source files
89
- - `/sync` - Sync commands and settings to ~/.claude
90
- - `/design <prompt>` - Apply the vendored design system prompt to a design task
91
- - `/test-cover` - Incrementally increase test coverage by identifying and testing uncovered files
92
- - `/test-review` - Review existing tests for quality, coverage gaps, and conventions
93
- - `/inspect` - Run .NET code inspections on changed files
94
- - `/screenshot` - Capture a screenshot of a running application window
95
- - `/ask [what to ask about]` - Put a plan, summary or proposed decision in the web preview pane and wait for the user's sign-off
96
- - `/show [what to show]` - Open long links, paths and snippets in the web preview pane, defaulting to those in the previous reply
97
- - `/raven` - Query and manage RavenDB connections and collections
98
- - `/miro [board url | extract name]` - Extract a Miro frame's boxes as an ordered YAML list
99
- - `/seq` - Query Seq logs from a URL or filter expression
100
- - `/sql` - Query a MSSQL database via assist sql
101
- - `/verify` - Run all verification commands in parallel
102
- - `/verify-new` - Add a new verify:\* run command to assist.yml
103
- - `/transcripts` - Format and summarise meeting transcripts end to end
104
-
105
- ## CLI Commands
106
-
107
- Every command supports `--help` for full detail on its flags and behaviour.
108
-
109
- ### Database
110
-
111
- - `assist backup [-o, --out <dir>]` - Dump the backlog database to `<dir>` (default `~/.assist/backups`, or `backup.dir`)
112
- - `assist backup schedule --every <duration>` - Schedule `assist backup` on a cadence (e.g. `5m`, `6h`)
113
- - `assist backup schedule status` - Show the active backup cadence
114
- - `assist backup schedule remove` - Remove the backup schedule
115
- - `assist db migrate` - Apply pending backlog database migrations in order
116
- - `assist db status` - Report whether the database is in sync with the build's bundled migrations
117
- - `assist db drop-retired` - Drop tables left by removed features
118
-
119
- ### Git and GitHub
120
-
121
- - `assist sync [--prune] [--force]` - Copy commands (as `~/.claude/skills/<name>/SKILL.md`, so they override a project skill of the same name), settings and design assets to `~/.claude` (plus `~/.codex` and `~/.pi` when those CLIs are installed); `--prune` lists commands sync did not write and `--prune --force` removes them
122
- - `assist activity [--since <date>]` - Chart GitHub commit activity per day (defaults to last 30 days)
123
- - `assist commit status` - Show git status and diff
124
- - `assist commit <message> [files...] [--ref <ref>]` - Stage files and create a validated single-line commit; each `--ref` (free text containing a URL) adds a `Ref:` trailer
125
- - `assist branch <slug> [--jira <key>] [--from <ref>]` - Create and switch to a new branch off the fresh remote default (or `--from <ref>`)
126
- - `assist watch wait [--interval <d>] [--timeout <d>|none] [--pull] [--build [entry]]` - Wait until the current branch's upstream gains commits; `--pull` fast-forwards to them and `--build` then runs the `auto-build` run entry (or `[entry]`), showing its output only if it fails
127
- - `assist watch loop` - Keep the current branch pulled and built as its upstream moves
128
- - `assist watch simulate-divergence` - Make the next `assist watch wait` poll in this repo exit 3 as a simulated divergence, to test the auto-update loop's escalation
129
- - `assist watch report [--from <sha>]` - Summarise recent commits and the restarts and sync they call for, since `<sha>` when given
130
- - `assist read-time <target> [--budget <duration>]` - Estimate how long a PR (number or URL), file or stdin (`-`) takes to read, against `--budget` (default 1m)
131
- - `assist prs` - List pull requests for the current repository
132
- - `assist prs status <owner/repo>... [--json]` - Report the open pull requests across the named repos and what each is waiting on
133
- - `assist prs slack-channel` - Print the Slack channel PRs are announced to: `prs.slack`, else `slack.channel`; exits non-zero when neither is set
134
- - `assist prs raise --title <t> --what <w> --why <y> [--how <h>] [--resolves <ref>] [--screenshot '[Group/]Caption=path']... [--force] [--draft|--no-draft]` - Raise a PR with a What/Why/How body, previewed for approval in a web session; `--draft`/`--no-draft` override `prs.draft`; each `--screenshot` is uploaded via `gh --attach` and rendered under `## Screenshots` as a `### Group` heading with a 2-column captioned table, ungrouped images last as plain images
135
- - `assist prs edit [--title <t>] [--what <w>] [--why <y>] [--how <h>] [--resolves <ref>] [--screenshot '[Group/]Caption=path']...` - Update the supplied sections of the current PR's body, previewed for approval in a web session; `--screenshot` replaces the existing `## Screenshots` section
136
- - `assist prs read-time <target> [--budget <duration>]` - Alias of `assist read-time`
137
- - `assist prs list-comments` - List all comments on the current branch's pull request (GitHub via `gh`, or Azure DevOps via `az` when the remote is on Azure DevOps — see [Azure DevOps PRs](#azure-devops-prs))
138
- - `assist prs fixed <comment-id> <sha>` - Reply with commit link and resolve thread
139
- - `assist prs wontfix <comment-id> <reason>` - Reply with reason and resolve thread, previewed for approval in a web session; `-` reads the reason from stdin
140
- - `assist prs reply <comment-id> <body>` - Reply to a comment thread without resolving it, previewed for approval in a web session; `-` reads the body from stdin
141
- - `assist prs comment <path> <line> <body>` - Add a line comment to the pending review, previewed for approval in a web session; `-` reads the body from stdin
142
- - `assist review [number]` - Review the current branch's PR (or PR `[number]`) with Claude and Codex in parallel and post line-bound comments
143
- - `[number]` - Check out that PR first (see [docs/parallel-work.md](docs/parallel-work.md))
144
- - `--no-prompt` - Skip all confirmations
145
- - `--submit` - Default the submit prompt to yes
146
- - `--force` - Re-run every phase instead of reusing cached results; with `--high-level`, start a fresh review
147
- - `--refine` - Skip posting; walk through the findings interactively and edit them
148
- - `--apply` - Skip posting; walk through each finding asking apply/skip
149
- - `--backlog` - Skip posting; file all findings as a single bug backlog item with one phase per finding
150
- - `--checkout-only` - Skip the review; check the PR out and leave an idle Claude session in it. In a clone whose remote is on Azure DevOps it checks out with `az repos pr checkout` instead of `gh` (see [Azure DevOps PRs](#azure-devops-prs))
151
- - `--high-level` - Open the high-level review checklist in the web preview pane and post it to the PR as an Approve, Comment or Request changes review. Comments on lines selected in a diff or a test's source are either sent to the agent or added to the review, where those on lines in the PR diff post as line-level comments. See [docs/high-level-review.md](docs/high-level-review.md)
152
- - `--configure` - With `--high-level`: configure the checklist's `review.highLevel.*` keys instead of reviewing
153
- - `--scope <db|git>` - With `--configure`: write to repo (db), this repo's override in the shared assist database, or repo (git), the repo's `assist.yml`, instead of asking
154
- - `--answer <key=value>` - With `--configure`: answer one key without prompting, repeatable; an empty value leaves the key unset
155
- - `--address-comments` - Start an Address Comments session for the PR once comments are posted and the review submitted
156
- - `--announce` - Announce the PR in Slack at the end of the chain
157
- - `--verbose` - Per-line log output instead of the stacked-spinner UI
158
- - `review.codexModel` - LiteLLM model the Codex reviewer uses; unset, it uses your own codex auth
159
- - `review.highLevel.criticalPaths` - Globs of files whose diffs back the critical-diff checklist item; defaults to `**/.github/workflows/**`, `**/.github/actions/**`, `**/package.json`, `**/Dockerfile`, `**/Dockerfile.*`, `**/*.Dockerfile` and `**/CLAUDE.md`, and a configured value replaces the defaults
160
- - `review.highLevel.uiPaths` - Globs that make a change a UI change, requiring a screenshot or video; unset, the check passes
161
- - `review.highLevel.descriptionWordCap` - Word cap for the PR description; defaults to 300
162
- - `review.highLevel.testPaths` - Globs of test files whose changed tests back the tests checklist item as a file > describe > it hierarchy, each test's source a click away and open to line comments; defaults to `**/*.{test,spec}.{ts,tsx,js,jsx}`
163
- - `review.highLevel.collapsedPaths` - Globs of files that start collapsed in the changed-files tree, each tagged with the glob it matched; a directory whose files all match starts collapsed; defaults to `**/*.test.*` and `**/generated/**`
164
- - `assist github commits <org> [--since <date>] [--top <n>] [--json]` - Report commit activity across a GitHub organisation
165
- - `assist github issue create --title <title> --body <body> [-R <owner>/<repo>] [--type <name>] [--parent <issue>] [--project <number>] [--status <name>] [--label <name>] [--milestone <name>]` - Create a GitHub issue on the current repo (or `-R`'s), previewed for approval in a web session; the options set its issue type, parent issue, project, project status, labels and milestone
166
- - `assist github issue edit <number> [-R <owner>/<repo>] [--body <body>] [--fresh] [--fetch] [--parent <issue>]` - Rework an issue's body in the web preview pane; `--body` previews a proposed body (`-` reads stdin) instead of the current one, `--fetch` writes the current body to the working file without previewing so it can be edited before the first preview, `--fresh` discards an unpushed revision, and `--parent` instead makes the issue a sub-issue of `<issue>`
167
- - `assist github issue comment <number> --body <body> [-R <owner>/<repo>]` - Comment on a GitHub issue, previewed for approval in a web session; `--body -` reads stdin
168
- - `assist github issue edit-comment <comment-id> --body <body> [-R <owner>/<repo>]` - Replace the body of a posted issue comment, previewed for approval in a web session; `--body -` reads stdin
169
- - `assist github issue started <number> [-R <owner>/<repo>]` - Assign a GitHub issue to yourself and move it to In Progress on its project boards
170
- - `assist github issue unassign <number> [-R <owner>/<repo>] [--assignee <login>...]` - Remove yourself, or each `--assignee` login, from a GitHub issue's assignees
171
- - `assist github issue fix-structure <target> [-R <owner>/<repo>] [--level <level>] [--type-chain <names>] [--strip-label <label>...] [--apply]` - Normalise the issue types across an issue's sub-issue subtree to a type chain (default `Epic,Story,Subtask`); `--level` sets the target's position in the chain, `--strip-label` removes a label, and nothing is written without `--apply`
172
- - `assist inbox scan` - Run a read-only headless `claude -p` (allowed only Gmail `search_threads`/`get_thread` and Slack `slack_search_public_and_private`/`slack_read_thread`) over unread Gmail inbox threads and Slack DMs and @mentions since the last scan, and store each message a person wrote that looks like it needs a reply; bots, notification systems, mailing lists, your own Slack messages and Slack threads you already replied in are skipped, and a message already flagged (from any node) is not added again
173
- - `assist inbox list` - List the flagged inbox messages, newest first, with sender, source, summary and link
174
- - `assist news add [url]` - Add an RSS feed URL to `news.feeds` (rendered in the sessions web News tab)
175
- - `assist news list` - List the feed URLs in `news.feeds`
176
- - `assist news remove <url>` - Remove a feed URL from `news.feeds`
177
- - `news.feeds` - The feed URLs, stored in the assist database so every machine shares them; `assist config set news.feeds <url1>,<url2>` replaces the whole list
178
- - `assist releases [list]` - Print the release promotion streams declared in `releases.streams`
179
- - `assist releases configure --streams <file> [--scope <git|db>]` - Write release streams from a JSON or YAML file (`-` for stdin) to `releases.streams`, in repo (git), the repo's `assist.yml` (default), or repo (db), this repo's shared override in the assist database
180
-
181
- ### Backlog
182
-
183
- Backlog data is stored in a global Postgres database (shared across all repos, scoped per repository by git origin), so a connection string is required. Set it via the `ASSIST_DATABASE_URL` environment variable or the `database.url` key in `assist.yml`; the environment variable takes precedence. Commands default to the current repository's items; pass `--all-repos` to span every repository.
184
-
185
- Backlog item ids are written in an `a`-prefixed form (e.g. item 555 is `a555`) to disambiguate them from GitHub PR/issue numbers (`#42`) and Jira keys. Commands that take an `<id>` accept either form.
186
-
187
- - `assist backlog [--dir <path>]` - Open the backlog tab in the web dashboard (same as `backlog web`)
188
- - `assist backlog list [--status <type>] [-a, --all] [--all-repos] [-v]` - List backlog items (alias: `ls`; also `assist list` / `assist ls`)
189
- - `assist backlog add` - Add a new backlog item interactively (human CLI use only; agents must use `propose`)
190
- - `assist backlog add --name <n> --type <t> --desc <d> --ac <criterion...>` - Add a backlog item from CLI options
191
- - `assist backlog propose --json <file|-> [--confirmed]` - Create an agent-authored item from a JSON payload, previewed for approval in a web session, where **Approve & start** also launches `assist backlog run a<id>` in a new session; outside one, `--confirmed` writes it. See [docs/backlog-item-preview.md](docs/backlog-item-preview.md)
192
- - `assist backlog show <id> [--all-commits]` - Display full detail for a backlog item (alias: `view`); `--all-commits` lists every commit
193
- - `assist backlog plan <id>` - Display the phased plan for a backlog item
194
- - `assist backlog update-field <id> [--name <n>] [--desc <d>] [--type <t>] [--ac <criterion...>]` - Update fields on a backlog item
195
- - `assist backlog update-field <id> [--add-ac <text>] [--edit-ac <n> <text>] [--remove-ac <n>]` - Granular 1-based acceptance-criteria edits
196
- - `assist backlog update-field <id> --origin [url-or-key]` - Retag a single item to a different repo
197
- - `assist backlog add-phase <id> <name> --task <t...> [--manual-check <c...>] [--position <pos>]` - Add a phase to an existing item
198
- - `assist backlog update-phase <id> <phase> [--name <n>] [--task <t...>] [--manual-check <c...>]` - Modify a plan phase (alias: `edit-phase`)
199
- - `assist backlog update-phase <id> <phase> [--add-task <t>] [--edit-task <n> <t>] [--remove-task <n>] [--add-check <c>] [--edit-check <n> <c>] [--remove-check <n>]` - Granular 1-based task and manual-check edits
200
- - `assist backlog remove-phase <id> <phase>` - Remove a plan phase from a backlog item
201
- - `assist backlog move-phase <id> <from> <to>` - Reorder a plan phase between 1-based positions
202
- - `assist backlog update-plan <id> --json <file|->` - Replace an item's whole plan from a JSON payload, previewed as a diff for approval
203
- - `assist backlog start <id>` - Set a backlog item to in-progress
204
- - `assist backlog stop` - Revert all in-progress items to todo and reset their phase to 1
205
- - `assist backlog done <id>` - Set a backlog item to done
206
- - `assist backlog wontdo <id> [reason]` - Set a backlog item to won't do
207
- - `assist backlog set-status <id> <status>` - Set status (`todo`, `in-progress`, `done`, `wontdo`)
208
- - `assist backlog star <id>` / `assist backlog unstar <id>` - Pin an item ahead of unstarred items in the web view
209
- - `assist backlog delete <id>` - Delete a backlog item
210
- - `assist backlog comment <id> <text>` - Add a comment to a backlog item
211
- - `assist backlog comments <id>` - List comments and summaries for a backlog item
212
- - `assist backlog delete-comment <id> <comment-id>` - Delete a comment (summaries cannot be deleted)
213
- - `assist backlog phase-done <id> <phase> <summary>` - Signal that a plan phase is complete
214
- - `assist backlog rewind <id> <phase> --reason <reason>` - Rewind an item to an earlier phase
215
- - `assist backlog next [id] [--once]` - Pick and run the next backlog item, or open `/draft` if none remain
216
- - `assist backlog refine [id] [--once] [--harness <claude|codex|pi>]` - Alias for `refine`
217
- - `assist backlog run <id> [--harness <claude|codex|pi>] [--write|--no-write]` - Run a backlog item's plan phase-by-phase with the selected harness (default `harness.engine`)
218
- - `assist backlog export [file]` - Export the backlog database to a file, or stdout
219
- - `assist backlog import [file]` - Restore a dump into the backlog database (`-y, --yes` skips the prompt)
220
- - `assist backlog associate-jira <id> [key]` - Associate a Jira ticket (bare key or browse URL), replacing any GitHub issue; `--clear` removes it
221
- - `assist backlog associate-github <id> [issue]` - Associate a GitHub issue (URL or `owner/repo#number`), replacing any Jira key; `--clear` removes it
222
- - `assist backlog add-activity <id> <kind> <ref>` - Attach an activity ref (`branch`, `commit`, `commit-parent`, `pr`, `slack`, `session`); `--title`, `--url`, `--state` override metadata
223
- - `assist backlog record-slack <url>` - Attach a Slack thread permalink to the current session's item
224
- - `assist backlog move-repo <old-origin> [new-origin]` - Retag all items from one origin to another after a repo rename (`-y, --yes` skips the prompt)
225
- - `assist backlog clone <origin>` - Clone a repo into `clone.baseDir` (default `~/git`)
226
- - `assist backlog web [-p, --port <number>] [--no-open]` - Open the backlog tab in the web dashboard (default port 3100)
227
-
228
- ### Config and run commands
229
-
230
- - `assist run <name> [params...]` - Run a configured command from assist.yml, or a backlog item (`a555` / `555`) when no command matches
231
- - `assist run add <name> <command> [args...] [--cwd <dir>] [--server [group]] [--port <port>] [--env KEY=VALUE]... [--pre <command>]... [--filter <glob>] [--quiet] [--param <name>[!|=default]]... [--repo [name]]` - Add a new run configuration to assist.yml and create a Claude command file; `--server`/`--port` mark it as a dev server, `--env` sets an environment variable, `--pre` adds a shell command run first, `--filter` limits a `verify:` entry to changed files matching a glob, `--quiet` hides output unless it fails, `--param` adds a positional param (`!` marks it required; `--env`, `--pre` and `--param` repeat), `--help` lists every run entry property, and `--repo` writes it to the repo's shared db override instead (no command file)
232
- - `assist run link <path> --prefix <prefix>` - Link run configurations from another project's assist.yml
233
- - `assist run remove <name> [--repo [name]]` - Remove a run configuration and delete its Claude command file; `--repo` removes it from the repo's shared db override instead
234
-
235
- A run entry's relative `cwd` (and a `link` path) resolves against the **repo root** - the directory holding `assist.yml` or `.claude/`, or the enclosing git repository when the repo has no project config, whichever config file the entry came from.
236
-
237
- - `assist config keys [filter]` - List every config key with its type, default, effect and setter, optionally filtered by name
238
- - `assist config get <key>` - Get a config value; secret values are hidden unless `--reveal` is passed
239
- - `assist config list` - List the config values that are set, with secret values hidden
240
- - `assist config set <key> <value>` - Set a config value. With no scope flag it writes repo (git), the repo's `assist.yml`; `--repo [name]` writes repo (db), a per-repo override in the shared assist database that every node on that database sees; `--node` writes user (node), this node's `~/.assist.yml`; `--user` writes user (db), a layer in the shared database that applies to every repo on every node. Precedence is repo (git) > repo (db) > user (node) > user (db); array keys such as `advice.rules` and `deny` concatenate across scopes, user (db) entries first. `database.*` and `sync.autoConfirm` stay in user (node)
241
- - `assist config unset <key>` - Remove a config value so the key falls back to a lower scope or the schema default, taking the same `--repo [name]`, `--node` and `--user` flags
242
- - `assist config import-repos` - Move this machine's `~/.assist.yml` `repos:` overrides into the shared database: prints a per-key diff against each repo's shared override, then on confirmation writes the keys and removes `repos:` from `~/.assist.yml`
243
- - `assist config import-user [keys...]` - Move keys (default `advice.rules`) from this node's `~/.assist.yml` into user (db): prints a diff against user (db) (array keys gain only the entries it lacks), then on confirmation writes them and removes the keys from `~/.assist.yml`. `loadConfig` warns while `~/.assist.yml` holds `advice.rules` entries user (db) lacks
244
-
245
- The web config page's "repo (db)" scope reads and writes the same shared override. Each node mirrors the shared per-repo overrides into `~/.assist/repo-config-cache.json` when its daemon starts, every minute while it runs, and after its own repo-scope writes, and resolves config from that snapshot, so an unreachable database leaves the last snapshot in effect. A `repos:` entry in `~/.assist.yml` still applies, with a warning naming `assist config import-repos`, until the shared database holds an override for that repo, after which it is ignored.
246
-
247
- The Config tab of the sessions web dashboard never shows secret values; their fields are write-only.
248
-
249
- ### Verify and lint
250
-
251
- - `assist verify` - Run all verify:\* commands in parallel (from assist.yml run configs and package.json scripts); with `verify.roots`, each listed package dir's `verify:*` scripts run as `<root>:verify:*` when files under it change, and the repo-root package.json scripts run only for changes outside every root; each `verify:<name>` / `verify:<name>:fix` pair (MakerXStudio/verify convention) runs once — the `:fix` variant in fix mode, the base in check mode (`VERIFY_MODE=check|fix`, else check when `CI` is set)
252
- - `assist verify all` - Run all checks, ignoring diff-based filters
253
- - `assist verify --measure` - Run all verify:\* commands and time each one
254
- - `assist verify init [--package-json]` - Add verify scripts to a project
255
- - `assist verify hardcoded-colors` - Check for hardcoded hex colors in src/ (`hardcodedColors.ignore`)
256
- - `assist verify block-code-comments` - Fail on any comment on a changed line (`blockCodeComments.ignore`); machine directives exempt
257
- - `assist verify forbidden-strings` - Check configured JSON files for disallowed values (`forbiddenStrings` rules)
258
- - `assist verify config-keys` - Check every config key is surfaced in some command's `--help`
259
- - `assist verify advice-fragments` - Check the advice fragment names match the fragments shipped in `claude/advice`
260
- - `assist verify migrations` - Check bundled DB migrations are sequentially numbered, append-only, and free of unacknowledged destructive DDL
261
- - `assist lint [-f, --fix]` - Run lint checks for conventions not enforced by oxlint
262
- - `assist lint init` - Initialize oxlint with baseline linter config
263
-
264
- ### Refactoring
265
-
266
- - `assist refactor check [pattern]` - Check for files that exceed the maximum line count
267
- - `assist refactor ignore <file>` - Add a file to the refactor ignore list
268
- - `assist refactor rename file <source> <destination>` - Rename/move a TypeScript file and update all imports (`--apply` to execute)
269
- - `assist refactor rename symbol <file> <oldName> <newName>` - Rename a symbol across the project (`--apply` to execute)
270
- - `assist refactor extract <file> <functionName> <destination>` - Extract a function and its private dependencies to a new file (`--apply` to execute)
271
- - `assist refactor restructure [root]` - Move files under `root` (default `src`) into folders derived from the import graph (`--apply` to execute, `--check` to fail on drift or when the plan exceeds `restructure.maxDepth` or `restructure.maxPathLength`)
272
-
273
- ### Rules
274
-
275
- Rules are `- **<code>** — **<title>** — <text>` bullets, the title optional, in the `## Rules` section of a `CLAUDE.md`.
276
-
277
- - `assist rules list [path] [--full]` - List the rules in scope for a path (default: cwd); `--full` adds each rule's description
278
- - `assist rules add <text> [--title <title>] [--scope <path>]` - Add a rule to the `## Rules` section of the `CLAUDE.md` nearest `--scope` (default cwd)
279
- - `assist rules add <text> --title <title> --user` - Append a `{ title, text }` entry to `advice.rules` in user (db) instead, for rules about agent conduct that hold in every repo on every node; it takes no R-code and can't be combined with `--scope`
280
- - `assist rules add <text> --title <title> --node` - As `--user`, but append to `advice.rules` in user (node), this node's `~/.assist.yml`
281
- - `assist rules index` - Record the directories that carry their own `## Rules` in the repo root's `CLAUDE.md`; run it after hand-editing a `## Rules` section
282
-
283
- ### Devlog
284
-
285
- - `assist devlog list` - Group git commits by date
286
- - `assist devlog next` - Show commits for the day after the last versioned entry
287
- - `assist devlog repos` - Show which github.com/staff0rd repos are missing devlog entries
288
- - `assist devlog skip <date>` - Add a date to the skip list
289
- - `assist devlog version` - Show current repo name and version info
290
-
291
- ### Hooks
292
-
293
- - `assist cli-hook` - PreToolUse hook auto-approving CLI commands from `allowed.cli-reads` / `allowed.cli-writes`, denying reads of `~/.assist/restricted`, and (with `sessions.askQuestion` on) denying `AskUserQuestion` in assist sessions in favour of `assist ask-question`
294
- - `assist cli-hook add <cli>` - Discover a CLI's commands and auto-permit read-only ones
295
- - `assist cli-hook check <command> [--tool <tool>]` - Check whether a command would be auto-approved
296
- - `assist cli-hook deny` - List all deny rules
297
- - `assist cli-hook deny add <pattern> <message> [--node]` - Add a deny rule for a command pattern to the repo's `assist.yml`, or with `--node` to user (node), this node's `~/.assist.yml`
298
- - `assist cli-hook deny remove <pattern> [--node]` - Remove a deny rule by pattern
299
- - `assist codex-hook` - Codex hook that auto-approves read-only commands and reports session status to the sessions dashboard
300
- - `assist pi-hook` - pi permission gate that auto-approves read-only commands
301
- - `assist edit-hook` - PreToolUse hook that blocks `Edit`/`Write`/`MultiEdit` calls from adding, changing, or removing a `// assist-maintainability-override` marker, or from introducing a code comment (use `code-comment set`/`confirm` for the rare comment that belongs)
302
- - `assist code-comment set <file> <line> <text>` - Request a pin authorising a single-line comment (max 50 chars)
303
- - `assist code-comment confirm <pin>` - Insert the pinned comment at its file/line
304
- - `assist db-migration unlock` - Ask a human to approve creating the next migration module
305
- - `assist db-migration confirm <pin>` - Confirm a pin from `db-migration unlock`, letting that migration's file be written once
306
- - `assist advise [--hook] [--explain]` - Print the advice fragments that apply to the current repo; `--hook` runs it as a SessionStart hook and `--explain` shows why each fragment was or wasn't included. `advice.sections` forces a fragment in or out by name, `advice.verify` replaces the verify fragment's text, `advice.extra` appends repo notes and `advice.rules` (`{ title, text }` entries, concatenated across every scope, user (db) first) adds a "Your rules" section
307
- - `assist notify` - Show desktop notification from JSON stdin (macOS, Windows, WSL)
308
- - `assist status-line` - Format Claude Code status line from JSON stdin
309
-
310
- ### .NET
311
-
312
- - `assist dotnet inspect [sln]` - Run JetBrains inspections on changed .cs files to find dead code
313
- - `--scope all|base:<ref>|commit:<ref>` - Inspect the whole solution, everything changed since a base ref, or one commit
314
- - `--only <ids...>` / `--suppress <ids...>` - Show only, or suppress, specific issue type IDs
315
- - `--roslyn` - Use Roslyn analyzers via msbuild instead of JetBrains
316
- - `--swea` - Enable solution-wide error analysis (slower but more thorough)
317
- - `assist dotnet check-locks` - Check if build output files are locked by a debugger
318
- - `assist dotnet deps <csproj>` - Show .csproj project dependency tree and solution membership
319
- - `assist dotnet in-sln <csproj>` - Check whether a .csproj is referenced by any .sln file
320
-
321
- ### Data sources
322
-
323
- - `assist jira auth` - Authenticate with Jira via API token
324
- - `assist jira ac <issue-key>` - Print acceptance criteria for a Jira issue
325
- - `assist jira view <issue-key>` - Print the title and description of a Jira issue
326
- - `assist miro extract [name] [--items <file>] [--top-left <id|link> --bottom-right <id|link>] [--ignore <file>] [--out <file>] [--board <id>] [--frame <id>] [--save <name>] [--node] [-r [repo]]` - Extract the text of every box inside a rectangle on a Miro board as an ordered YAML list. Omit the anchors to pick them in the web preview pane; `--save <name>` saves the selection under `miro.extracts` so `assist miro extract <name>` replays it, in the repo's `assist.yml`, or with `--node` in user (node) or `-r [repo]` in repo (db)
327
- - `assist litellm list-models [--json]` - List the model ids the configured LiteLLM proxy serves
328
- - `assist ravendb auth add` - Add a new RavenDB connection
329
- - `assist ravendb auth list` - List configured RavenDB connections
330
- - `assist ravendb auth remove <name>` - Remove a configured connection
331
- - `assist ravendb set-connection <name>` - Set the default connection
332
- - `assist ravendb query [connection] [collection]` - Query a RavenDB collection (`--page-size`, `--sort`, `--query`, `--limit`)
333
- - `assist ravendb collections [connection]` - List collections and document counts
334
- - `assist seq auth add` - Add a new Seq connection
335
- - `assist seq auth list` - List configured Seq connections
336
- - `assist seq auth remove <name>` - Remove a configured connection
337
- - `assist seq set-connection <name>` - Set the default Seq connection
338
- - `assist seq query <filter>` - Query Seq events (`-c <connection>`, `--json`, `-n <count>`, `--from <date>`, `--to <date>`)
339
- - `assist slack post [channel] --body <body|-> | --parts <file>... [--thread <ts-or-permalink>]` - Preview a markdown message bound for a Slack channel (default `slack.channel`) for approval, for `/slack-post` to send; `--body -` reads stdin, `--thread` takes a message ts or permalink to reply under, and `--parts` previews a thread of messages, one file each, in order
340
- - `assist sql auth add` - Add a new MSSQL connection
341
- - `assist sql auth list` - List configured SQL connections
342
- - `assist sql auth remove <name>` - Remove a configured connection
343
- - `assist sql set-connection <name>` - Set the default SQL connection
344
- - `assist sql query "<sql>" [connection]` - Execute a read-only SQL statement
345
- - `assist sql mutate "<sql>" [connection]` - Execute a mutating SQL statement
346
- - `assist sql tables [connection]` - List tables in the connected database
347
- - `assist sql columns <table> [connection]` - List columns for a table (`schema.table` for a non-default schema)
348
-
349
- ### Other
350
-
351
- - `assist netcap [-p, --port <port>] [-o, --out <dir>] [-f, --filter <pattern>]` - Capture browser network traffic under `--out` (default `~/.assist/netcap`), paired with the [netcap browser extension](#netcap-browser-extension)
352
- - `assist netcap extract-linkedin-posts [file]` - Parse a netcap capture into structured LinkedIn posts
353
- - `assist extension [--sign] [--url]` - Locate the [assist browser extension](#assist-browser-extension) to load unpacked; `--sign` signs it for a permanent Firefox install; `--url` prints the latest signed build's download URL
354
- - `assist browser status [--url <substring>] [--server <url>]` - Through the [browser link](#browser-link), print the connected extension's version, the target tab's URL and whether the assist content script runs there; `--url` targets the most recently active tab whose URL contains the substring instead of the focused window's active tab; `--server` is the web server the extension connects to (default `http://localhost:3100`)
355
- - `assist browser snapshot [--url <substring>] [--server <url>]` - Write the target tab's DOM (`outerHTML`) to `~/.assist/browser/<host>-<timestamp>.html` and print the tab's URL and the file's path
356
- - `assist browser inspect [selector] [--text <text>] [--url <substring>] [--server <url>]` - For each element matching the CSS selector, or whose own text contains `--text` (skipping `script`/`style`), print its rendered size, text (first 80 characters) and ancestor chain from `html` down, one `tag#id.class.class` per line; prints the first 20 matches with the total, or that nothing matched
357
- - `assist screenshot <process>` - Capture a screenshot of a running application window (`screenshot.outputDir`, default `./screenshots`)
358
- - `assist mermaid export [file.md]` - Render each fenced mermaid block to SVG via [Kroki](https://kroki.io) (`--out`, `--index`, `mermaid.krokiUrl`)
359
- - `assist prompts` - Show the most frequently denied tool calls
360
- - `assist chart [--title <title>]` - Draw a terminal line chart of a `label value` series piped in on stdin, one pair per line
361
- - `assist ask --title <title> --body <markdown|->` - Put a plan, summary or proposed decision in the session's web preview pane and wait for the user to approve or reject it; `--body -` reads stdin
362
- - `assist ask-question --json <file|->` - Ask `AskUserQuestion` questions (1-4, each with 2-4 options, plus an Other free-text answer) as a form in the session's web preview pane and wait for the answers; prints the same result text as the built-in tool, exits non-zero when dismissed, and outside an assist session or with `sessions.askQuestion` off (the default) exits non-zero so Claude uses the built-in tool
363
- - `assist show --body <markdown|-> [--title <title>]` - Render markdown in the session's web preview pane so long links, paths and code can be clicked and copied unbroken; `--body -` reads stdin
364
-
365
- ### Project setup
366
-
367
- - `assist init` - Initialize project with VS Code and verify configurations
368
- - `assist new vite` - Initialize a new Vite React TypeScript project
369
- - `assist new cli` - Initialize a new tsup CLI project
370
- - `assist update` - Update assist to the latest version and sync commands
371
- - `assist vscode init` - Add VS Code configuration files
372
- - `assist deploy init` - Initialize Netlify project and configure deployment
373
- - `assist deploy redirect` - Add trailing slash redirect script to index.html
374
- - `assist roam show-claude-code-icon` - Forward Claude Code hook activity to Roam local API
375
-
376
- ### Complexity
377
-
378
- - `assist coverage` - Print global statement coverage percentage
379
- - `assist complexity <pattern>` - Analyze a file (all metrics if single match, maintainability if multiple)
380
- - `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
381
- - `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
382
- - `assist complexity maintainability [pattern]` - Calculate maintainability index per file (`--ignore <glob>`, plus `complexity.ignore`). A file can declare its own threshold with a `// assist-maintainability-override: N` comment in its first ~10 lines, replacing `--threshold` for that file only
383
- - `assist complexity sloc [pattern]` - Count source lines of code per file
384
-
385
- ### Transcripts
386
-
387
- - `assist transcript configure` - Configure transcript directories
388
- - `assist transcript clean <path>` - Clean a .vtt file to markdown or, with `--format vtt`, WebVTT; `--timestamps` prefixes each markdown speaker turn with its time
389
- - `assist transcript list` - List raw .vtt filenames waiting in the pick-up directory
390
- - `assist transcript merge <path...>` - Collapse several .vtt files into one transcript on a continuous timeline (`--out <path>`); `--select <file|->` keeps only the chosen ranges, `--no-provenance` omits source notes and `--widen-audience` drops asides aimed at those in the call
391
- - `assist transcript move <file>` - Convert a raw .vtt to a dated markdown transcript and archive the original
392
-
393
- ### Sessions
394
-
395
- - `assist sessions` - Start the web dashboard (same as `sessions web`)
396
- - `assist sessions web [-p, --port <number>] [--no-open]` - Start the web dashboard with Sessions, Backlog, News and Inbox tabs (default port 3100); the Inbox tab lists the messages `assist inbox scan` flagged, newest first, each linking to the original with a dismiss button, and its badge shows how many are waiting
397
- - `assist sessions close` - End the current daemon-managed session
398
- - `assist sessions rename <title>` - Retitle the current daemon-managed session's dashboard card
399
- - `assist sessions output [session-id] [--server [group]] [-n, --lines <count>]` - Print the recent output of a session on this node, or with `--server [group]` the current repo's live server run
400
- - `assist sessions nodes [--json]` - List this node and every linked node with its link state (see [Linked nodes](#linked-nodes))
401
- - `assist sessions nodes link <name> [url] [--tailscale <host> --port <port>]` - Link a peer node by its web server URL or its Tailscale name
402
- - `assist sessions nodes unlink <name>` - Remove a linked node
403
- - `assist sessions nodes doctor [name] [--json]` - Find where a link is broken and how to fix it
404
- - `assist sessions nodes logs <name> [-n, --lines <count>] [--json]` - Tail a linked node's `daemon.log`
405
- - `assist sessions nodes restart <name> [--target daemon|webserver|both]` - Restart a linked node and wait for its link to reconnect
406
- - `assist sessions nodes update <name>` - Update assist on a linked node and wait for its link to reconnect
407
- - `assist sessions set-status <status>` - Report the current session's status (`running`/`waiting`) to the daemon
408
- - `assist daemon run` - Run the sessions daemon in the foreground
409
- - `assist daemon status` - Show daemon status, live sessions and each link's state
410
- - `assist daemon stop` - Stop the sessions daemon; running claude sessions resume on next start
411
- - `assist daemon restart` - Restart the sessions daemon, resuming previously running claude sessions
412
- - `assist daemon drain [--yes]` - Remove all sessions from the local daemon; a session holding unpushed work is stopped, not removed
413
-
414
- ### Session launchers
415
-
416
- - `assist next [id] [--once]` - Alias for `backlog next [id]`; `--once` exits after the first completed item run
417
- - `assist draft [description] [--once]` (alias: `feat`) - Launch Claude in `/draft` mode, chain into next on `/next` signal
418
- - `assist bug [description] [--once]` - Launch Claude in `/bug` mode, chain into next on `/next` signal
419
- - `assist refine [id] [--once] [--harness <claude|codex|pi>]` - Launch a coding harness in `/refine` mode (default `harness.engine`)
420
- - `assist review-pr-comments [number] [--batch | --auto] [--announce] [--resume-session <id>]` - Launch Claude in `/review-pr-comments` mode, on PR `[number]` when given; `--batch` asks about every thread before changing anything, then commits each addressed fix separately, pushes once and replies to/resolves every decided thread; `--auto` accepts Claude's own recommendation for each thread (asking only about threads it cannot confidently decide), commits each fix separately, pushes once and resolves every thread; `--announce` announces the PR in Slack once every thread is processed
421
- - `assist fix-conflict [number] [--rebase] [--resume-session <id>]` - Launch Claude in `/fix-conflict` mode, on PR `[number]` when given; `--rebase` rebases instead of merging
422
- - `assist signal next [id]` - Signal the session to chain into `assist next`
423
- - `assist signal done [id]` - Signal the session's initial task complete, surfacing backlog item `[id]` on its card
424
-
425
- `draft`, `bug`, `refine`, `review-pr-comments`, `fix-conflict` and `backlog run` accept `--resume-session <id>` to resume an interrupted Claude session.
426
-
427
- ## Sessions dashboard
428
-
429
- Web sessions are owned by a long-lived daemon process, not the web server: the server is a thin client relaying WebSocket traffic to the daemon over a local IPC socket (`~/.assist/daemon/daemon.sock`; per-user named pipe `\\.\pipe\assist-sessions-daemon-<user>` on Windows). Restarting the web server leaves sessions running with scrollback intact. The daemon logs to `~/.assist/daemon/daemon.log` and auto-exits once no sessions remain and no client has connected for 60 seconds. See [docs/session-lifecycle.md](docs/session-lifecycle.md).
430
-
431
- When assist is installed as a git clone, each daemon keeps that install current in the background: it runs `assist watch wait --pull --build` in the clone lap after lap, with no session card, logging each lap to `daemon.log` (prefixed `auto-update:`) and to the clone's history in `~/.assist/watchers/`. If the clone cannot fast-forward, the daemon starts one claude session in it that rebases (or merges) onto the upstream without force-pushing or resetting, pushes, rebuilds and closes; the loop pauses until that session ends. A rebuilt version takes effect once the daemon and web server are restarted. The version badge in the web UI opens the Updates page, which lists every node with its running and built version, restart advice and history, and offers Restart per node or for every ready node, Pause/Resume (a pause persists across daemon restarts) and Check now (an immediate fetch). Turn it off with `assist config set autoUpdate.enabled false --node`.
432
-
433
- The topnav's **+** button (or Ctrl+N / Alt+N; Cmd+N on macOS) opens the new-session dialog, which replaces the old draft / bug / prompt / design topnav buttons. Its mode selector picks `draft`, `bug`, `prompt` or `design`; in `prompt` mode a harness selector under it picks Claude, Codex or pi when those are exposed, and Up/Down moves between the two rows. `design` launches an interactive `claude` session with the vendored design system prompt appended via `--append-system-prompt`. Left/Right change the mode or harness, and Tab steps through a selector's options before moving on to the next control.
434
-
435
- Every hotkey is Alt plus a left-hand key, one keyboard row per screen region, and works while the terminal has focus; on macOS use Option.
436
-
437
- - **Numbers**: Alt+1 to Alt+6 select the Nth visible top-level tab (with Releases hidden, News is Alt+4; Inbox is always last).
438
- - **Q W E** (top right): Alt+Q opens the Updates page (the version badge), Alt+W opens the config page and Alt+E opens the menu with focus on its first item.
439
- - **R** (toolbar): Alt+R focuses the toolbar's repo picker; Tab / Shift+Tab then move along the toolbar.
440
- - **A S D** (main area, left to right): Alt+A focuses the active session's sidebar card (expanding the sidebar and switching to Active), Alt+S focuses its terminal, and Alt+D opens and focuses its diff panel, or closes it back to the terminal when the diff already has focus. While the session's preview pane is open, Alt+D focuses the pane instead (landing on its primary decision button, **Approve & start** or else **Approve**, when it has one), and pressing it again returns focus to the terminal, leaving the pane open.
441
- - **Z X C** (session top bar): Alt+Z, Alt+X and Alt+C focus the active session's top-bar **Add agent**, **VS Code** and **Done** buttons; Tab / Shift+Tab then move to neighbouring top-bar buttons. A key whose button isn't shown does nothing.
442
-
443
- Keys whose target is on Sessions return there first. Ctrl+/ (Cmd+/ on macOS) or the menu's **Keyboard shortcuts** item opens a sheet listing every sessions-view shortcut. The top-level tabs, the new-session button, the repo picker, the top-bar add agent / VS Code / done buttons, the active session's diff counts, the version badge, the config cog and the menu button show their chord in their tooltip on hover and keyboard focus.
444
-
445
- Each shortcut's chord can be overridden under `sessions.hotkeys.<action>`, e.g. `assist config set sessions.hotkeys.focusTerminal Ctrl+Alt+J --node`; restart the web server and reload the page to apply it. `assist sessions web --help` lists every action with its default. A chord is modifiers plus one key joined by `+`, such as `Alt+S`, `Ctrl+Shift+K` or `Mod+/`: the modifiers are `Ctrl`, `Alt` (`Option`), `Shift`, `Meta` (`Cmd`) and `Mod` (Cmd on macOS, Ctrl elsewhere), at least one of them other than Shift, and the key is a letter, digit, punctuation, `F1`–`F12` or a named key such as `Enter` or `ArrowUp`. Keys match the physical key, so macOS Option chords work. `navTab` takes modifiers only (e.g. `Ctrl+Alt`); its digits stay 1–6. An override replaces all of an action's default chords, and `assist config set` rejects an invalid chord. Tab card-cycling is fixed.
446
-
447
- Every live session card carries an **add-agent** button (👥) that starts a second agent inside that session's existing workspace rather than allocating a new one. While several agents share a workspace, only the last one to leave triggers teardown.
448
-
449
- A `run:` entry in `assist.yml` flagged `server:` (with an optional display-only `port:`) is a singleton **dev server**. `server:` takes a group name — `server: api` and `server: web` are separate slots, so a repo that serves an API and a front end can keep both live at once; `server: true` normalises to the group `default`. At most one server may be live per group per normalised git remote, i.e. across a clone and all its sibling clones. Session cards for such a repo show a **▶ start** button; the daemon rejects a second server run for that remote and group, and the web UI turns the conflict into a "replace running server?" prompt. The serving card shows a `serving :<port>` chip and a **⏹ stop** button, and the slot frees whenever that session stops. Non-`server` runs are unconstrained.
450
-
451
- ### Linked nodes
452
-
453
- Each assist install is a **node** with its own daemon and web server. A node can link to other nodes, and its web UI then shows its own sessions merged with each linked node's, as `<node>:<id>` cards carrying a node badge. Links are flat: a node only exports its own sessions and log lines, so two nodes linked to each other show no duplicates. See [docs/multi-node-sessions.md](docs/multi-node-sessions.md).
454
-
455
- - `assist sessions nodes [--json]` — this node and each link's state and peer version.
456
- - `assist sessions nodes link <name> --tailscale <host> --port <port>` (or `<url>`) — link a peer by its Tailscale host name, or by any web server URL. `<name>` must match the peer's `sessions.nodeName`. See [Linking machines over Tailscale](#linking-machines-over-tailscale).
457
- - `assist sessions nodes unlink <name>` — remove a link.
458
- - `assist sessions nodes doctor [name] [--json]` — find where a link is broken and how to fix it.
459
- - `assist sessions nodes logs <name> [-n, --lines <count>] [--json]` — tail a linked node's `daemon.log`; naming this node reads the local log.
460
- - `assist sessions nodes restart <name> [--target daemon|webserver|both]` — the CLI form of **Restart <node>**: posts the node's `/api/restart`, waits up to 90s for its link to reconnect and prints its version.
461
- - `assist sessions nodes update <name>` — the CLI form of **Update assist on <node>**: over a connected link it opens an `assist update` card on the node, waits for its daemon to come back, then restarts its web server; otherwise it posts the node's `/api/self-update`. It then prints the node's new version.
462
- - `sessions.linkVersionCheck` — reaction when a linked node's protocol range doesn't overlap this node's (links use the highest shared protocol, whatever the app versions, and never restart a peer): `block` (default) holds the link `version-blocked` until the older node is updated; `warn` proceeds anyway; `off` skips the check.
463
-
464
- `nodes restart` and `nodes update` log `nodes <action> <name> trace=<id>` here and send that trace id to the node, and when the node can't be reached or doesn't come back they name the first broken `nodes doctor` hop.
465
-
466
- With more than one node, a machine picker appears in the top nav and a machine selector in the new-session dialog; the dialog's selector defaults to the top nav's choice, which is remembered per browser. With a linked node selected in the picker, the hamburger's restart item becomes **Restart <node>**: it restarts that node's daemon and web server via `POST /api/restart?target=both&node=<node>` without reloading the page, toasts once the node's link reconnects, and on failure names the first broken `nodes doctor` hop (served locally by `GET /api/node-doctor?link=<node>`). The peer logs each restart as `restart <target> from=<viewer> trace=<id>`. The update item likewise becomes **Update assist on <node>**: over a connected link it opens an `assist update` card on that node, restarts the node's web server once the card completes, and toasts the node's new version; when the link is disconnected or `version-blocked` it falls back to `POST /api/self-update?node=<node>` (logged by the peer as `self-update: requested from=<viewer> trace=<id>`). The picker's menu shows each linked node's version, and the picker marks a node **behind** or **ahead** of this node's version. Linked nodes' daemon lines appear in this node's `daemon.log` tagged `[<node>]`. Every launch forwarded over a link and every `?node=` panel request carries a `traceId`, logged as `trace=<id>` by both nodes. `GET /api/health` reports the node's name, version, protocol, daemon reachability and its links' states. The retired `sessions.windows*` keys are ignored.
467
-
468
- #### Linking machines over Tailscale
469
-
470
- Every web server listens on `127.0.0.1` only and, when it starts, exposes itself on the tailnet with `tailscale serve` (`tailscale.exe` under WSL) at `https://<host>.<tailnet>.ts.net:<port>`. Windows' `tailscale serve` fronts the WSL web server on `<port>` + 1000, because mirrored WSL networking holds `<port>` itself.
471
-
472
- 1. Install Tailscale on every machine, sign in to the same tailnet, and turn on MagicDNS and HTTPS certificates in the admin console.
473
- 2. Link each peer by its Tailscale host name. From the Mac to both PC nodes:
474
-
475
- ```
476
- assist sessions nodes link pc-wsl --tailscale pc --port 4100
477
- assist sessions nodes link pc-windows --tailscale pc --port 3101
478
- ```
479
-
480
- and optionally from the PC's WSL node back to the Mac: `assist sessions nodes link mac --tailscale mac --port 3100`.
481
-
482
- 3. Check each link with `assist sessions nodes doctor`.
483
-
484
- A config still holding a retired ssh link (`ssh:` / `port:` / `localPort:`) fails to load; `assist sessions nodes link` and `unlink` remove such links and name them so they can be relinked with `--tailscale`.
485
-
486
- #### iOS app
487
-
488
- `ios-app/` is a Capacitor iOS app that bundles the sessions web UI and views one **home node** over Tailscale. It has no sessions of its own; the home node already merges its linked nodes' sessions. The web server accepts REST and `/ws` requests from the app's `capacitor://localhost` origin and refuses `/ws` from any other cross-origin browser.
489
-
490
- Needs macOS with Xcode, an iOS simulator or a device, and the Tailscale app on the phone signed in to the same tailnet.
491
-
492
- 1. `npm run ios:install` — install the Capacitor CLI and iOS platform into `ios-app/`.
493
- 2. `npm run ios:build` — build assist, copy the UI bundle into `ios-app/www`, and `cap sync` it into the Xcode project. Re-run after any UI change.
494
- 3. `npm run ios:run` to pick a simulator or connected device, or `npm run ios:open` to build and run from Xcode (a device needs your Apple ID team set under **Signing & Capabilities**).
495
- 4. On first launch, enter the home node's URL, e.g. `https://mac.<tailnet>.ts.net:3100`. It is stored on the device.
496
-
497
- The app uses a phone layout rather than the desktop one. The session list groups sessions by status with **Needs you** (waiting and errored) first; pull down to refresh, tap **Done** to expand finished sessions, and use the clock icon for history. Tap a session to open it full screen: the terminal is read-only and never resizes the shared pty, so pinch to zoom and drag to pan. Type in the reply field (Return adds a line, the send button submits) or use the key strip for `1`/`2`/`3`, arrows, Esc, Tab and ⌃C.
498
-
499
- ### Session config keys
500
-
501
- - `sessions.nodeName` — this install's node label. Defaults to the OS hostname, suffixed `-wsl` under WSL.
502
- - `sessions.tailscaleServe` — expose the web server on the tailnet. Defaults to **true**.
503
- - `sessions.includeCommittedChanges` — include the commits recorded against the session's backlog item, not just uncommitted work, in its change counts and diff. Defaults to **true**.
504
- - `sessions.newSessionMode` — the mode pre-selected in the new session dialog: `draft`, `bug`, `prompt` or `design`. Defaults to **draft**.
505
- - `sessions.maxLive` — the most live sessions one daemon holds at once. Defaults to **24**.
506
-
507
- ### Releases
508
-
509
- The **Releases** tab draws one row per declared release stream: a left rail naming the stream, its repo, its release workflow, the tip of the default branch, a link to the latest run and a summary pill per group of environments, and beside it the promotion graph the stream declares. Nodes sit in columns by edge depth, so a fan-in gate or a missing step is something you see rather than something you decode, and an SVG edge joins each pair — solid where the promotion has happened, dashed where the target does not carry the source's commit. Hovering or focusing a summary pill dims the graph and rings exactly the nodes that pill counts.
510
-
511
- Two layers sit over the one graph, toggled rather than shown side by side:
512
-
513
- - **What's live** — per environment, the commit of its newest deployment whose status is `success`, how long ago that went live, and how many commits behind the repo's default branch it is. A deployment still `waiting` on an approval is gated, not live, so it is passed over and shown on its own `queued` line instead.
514
- - **Latest run** — per node, the state of its job in the latest run of the stream's workflow: how long it took, how long it has been sitting on an environment approval, or that the run never got there. Jobs are matched to nodes by name, most specific node first, so `Deploy to EU Staging` goes to the `eu-staging` node rather than the `staging` one.
515
-
516
- Every timestamp renders in the viewer's own timezone, and every glyph and short token carries a tooltip on hover and on keyboard focus. Commit SHAs link to the commit, and their tooltip carries the commit subject and author. A stream whose repo or workflow cannot be read shows its error in place of its graph, leaving the other streams intact. Live state is read from the repo's GitHub deployments, so two streams deploying into the same environment read the same commit.
517
-
518
- Topology is declared, not derived: assist does not parse workflow YAML at runtime.
519
-
520
- ```yaml
521
- releases:
522
- streams:
523
- - name: Web App
524
- repo: owner/name
525
- workflow: release.yml
526
- nodes:
527
- - { id: build, kind: build }
528
- - { id: dev, environment: dev }
529
- - { id: eu-prod, environment: EU Production, label: eu-prod }
530
- edges:
531
- - [build, dev]
532
- - [dev, eu-prod]
533
- ```
534
-
535
- - `id` names the node within the stream and is what `edges` refer to. A node with an `environment` is a GitHub deployment environment and reads live state; `kind` (`build` or `gate`) marks a node that deploys nothing. `label` overrides the text on the node, which is otherwise the `id`.
536
- - `/releases-configure` derives the block from the repo's own workflows instead of hand-writing it, and `assist releases list` prints whatever is declared back as assist reads it.
537
-
538
- ## Next
539
-
540
- The **Next** tab (`/next`) recommends what to do next, in this order:
541
-
542
- 1. **Peer PRs** — open PRs across `next.repos` by `next.peers` or requesting your review
543
- 2. **Assigned issues** — open issues assigned to you across `next.repos`
544
- 3. **Pickups** — unassigned items on `next.projects` boards in a `next.pickStatuses` status, in board order
545
-
546
- **Start session** runs in the item's local clone: PRs open the review dialog, issues open the new-session dialog, and pickups are assigned to you and moved to In Progress first. Project pickups need the gh `project` scope. See `assist sessions web --help` for each key.
547
-
548
- ```bash
549
- assist config set next.peers alice,bob --repo
550
- assist config set next.repos my-org,other/web --repo
551
- assist config set next.projects my-org/3,my-org/5 --repo
552
- assist config set next.pickStatuses Ready,Todo --repo
553
- assist config set next.excludeLabels blocked,spike --repo
554
- assist config set next.excludeTypes Epic --repo
555
- ```
556
-
557
- ## Parallel work
558
-
559
- Concurrent sessions in one repo can be isolated with native git worktrees instead of keeping multiple physical clones: see [docs/parallel-work.md](docs/parallel-work.md). All of these keys **default off** except `worktree.install`:
560
-
561
- - `worktree.enabled` (parallel work) — every session (prompt, assist command, backlog run, resume of a reaped worktree, `assist review` from a terminal) gets a fresh adjacent `<clone>-N` worktree; the clone itself is never allocated. Only `inPlace` launches (e.g. the PR Review button) and agents added to an existing stream stay in their tree.
562
- - `worktree.trunk` (trunk-based) — a worktree's branch tracks `origin/<trunk>` so commits land on the mainline. Off, worktrees start off the remote default branch with no mainline tracking.
563
- - `worktree.install` — how a new worktree installs its deps: `true` (default) auto-detects pnpm/yarn/bun/npm (`npm ci` when a `package-lock.json` exists), a string is the install command, `false` skips it, and a list of paths installs in each in order.
564
-
565
- None of them leaves permanent state on the clone, so turning parallel work back off leaves the repo as it was.
566
-
567
- ## Iterating on assist itself
568
-
569
- Web server changes only need the `assist sessions` process restarted — sessions survive. Daemon/session-core changes need `assist daemon restart`: claude sessions are auto-respawned via `claude --resume` with scrollback starting fresh, while run sessions reappear as not-restored tiles that can be retried.
570
-
571
- A restart kills every managed session's pty, which also kills any background task running inside it. `daemon.log` names each session it kills, and the shutdown records the reason against them in `sessions.json` before the ptys die. On restore, a session the restart caught mid-turn is resumed with a prompt naming the restart instead of the generic one, and a session that was idle only because it was waiting on a background task is woken with the same prompt, naming the task ids that died. An idle session with no background work in flight is left idle, as before.
572
-
573
- ## Other config keys
574
-
575
- - `harness.codexModel` — LiteLLM model every non-review Codex launch uses. Unset, Codex uses its own configured provider.
576
- - `slack.channel` — the Slack channel `assist slack post` and `/slack-post` target when given none.
577
- - `prs.slack` — the Slack channel `/prs-slack` posts pull requests to. Falls back to `slack.channel` when unset.
578
- - `prs.required` — cut a fresh branch when `assist backlog run` starts a story with no recorded branch. Defaults to `true`.
579
- - `prs.promptJira` — have `assist prs raise --help` ask the user for a Jira key to resolve. Defaults to `false`.
580
- - `prs.promptGithub` — have `assist prs raise --help` ask the user for a GitHub issue to resolve. Defaults to `false`.
581
- - `prs.draft` — raise PRs as drafts. Defaults to `false`.
582
- - `readTime.wordsPerMinute` — the prose reading speed `assist read-time` assumes. Defaults to `200`.
583
- - `prs.readingWordsPerMinute` — the former name of `readTime.wordsPerMinute`, read only when that is unset.
584
- - `commit.pull` — fast-forward before `assist draft`, `bug`, `refine`, `next` and `backlog run` start, aborting if that fails. A branch with no upstream (such as a fresh worktree branch) fast-forwards onto `origin/<default>` when it has no commits of its own. Defaults to off.
585
- - `commit.expectedBranch` — warn on `assist commit` when HEAD is on any other branch. Unset by default.
586
- - `branch.prefix` — prefix for branch names from `assist branch`. Unset by default.
587
- - `branch.defaultBranch` — the base branch for new branches. Defaults to the remote's default branch.
588
- - `releases.streams` — the release promotion streams the [Releases page](#releases) draws.
589
- - `cliHook.blockNpmRun` — deny `npm run` in favour of `assist run`. Defaults to `true`.
590
-
591
- ## assist browser extension
592
-
593
- `assist extension` prints the directory to load unpacked. The extension is a Manifest V3 content script scoped to `https://github.com/*`, a [docs feedback](#docs-feedback) content script on `localhost`, plus a background script and an options page, built by `npm run build` from `src/commands/extension/` into `extension/content.js`, `docs.js`, `background.js` and `options.js` (gitignored). It adds an **Outline criteria** toggle to the markdown toolbar of an issue's body editor and the new-issue form, re-attaching after client-side navigation; pressing it hides the textarea and mounts the same `AcceptanceCriteriaOutline` control the web preview panel uses, in a shadow root with its own emotion cache and the web UI's Slate theme (`createDesignTheme`). Every popover and the injected **assist** button use Slate's colours, radius and font stack (falling back along the stack, as no fonts are bundled), in light or dark following GitHub's `data-color-mode` and theme names, else the OS `prefers-color-scheme`, and switch when either changes. A body whose acceptance criteria are bullets, checkboxes or prose gets a **Convert to outline** button instead, and a body with no acceptance criteria heading gets **Add acceptance criteria**. Each edit is written back through `writeAcceptanceCriteria` into the textarea and dispatched as an `input` event, so GitHub's own Save pushes it.
594
-
595
- 1. Run `assist extension` — it prints the extension directory. Under WSL it copies the extension to `C:\tools\extension` and prints that Windows path instead; re-run and reload the extension after a rebuild.
596
- 2. Load the unpacked extension:
597
- - **Chrome**: open `chrome://extensions`, enable **Developer mode**, click **Load unpacked**, and select the extension directory.
598
- - **Firefox**: open `about:debugging#/runtime/this-firefox` → **Load Temporary Add-on…** → pick `manifest.json` inside the printed extension directory. Firefox drops a temporary add-on on every restart; see [permanent Firefox install](#permanent-firefox-install) to avoid that.
599
- 3. Open an issue, press **Edit** on the body, and press **Outline criteria**. The new-issue form works the same way.
600
-
601
- ### Send to assist
602
-
603
- The extension also adds an **assist** button beside each PR review comment, review and issue comment timestamp, and to the PR/issue header. Pressing it opens a popover with an optional instructions field and **Prompt**, **Draft** and **Bug** buttons; **Enter** sends as Prompt (even when empty), **Shift+Enter** adds a newline and **Escape** closes. The background script POSTs the link and instructions to the assist web server's `POST /api/sessions/from-github` (`{ url, instructions?, mode? }`), which parses `owner/repo` from the GitHub URL, finds its clone under `clone.baseDir` (`<baseDir>/<repo>`, else any folder directly under `baseDir` whose origin matches) and starts a Claude session there whose prompt is the link followed by the instructions, answering `{ sessionId, cwd }`. `mode: "draft"` or `"bug"` instead runs `assist draft --once` / `assist bug --once` with that text; any other mode gets a 400. `extension.redirects` maps an `owner/repo` to another `owner/repo` whose clone hosts these sessions instead (e.g. issues tracked in one repo but worked on in another); the prompt keeps the original link, and PR review sends always open the PR's own repo. A toast reports the result: a URL that isn't a GitHub repo link gets a 400, a repo that isn't cloned gets a 404 saying so (nothing is cloned), and an unreachable server names the URL the extension tried. The endpoint has no auth and answers CORS only for `moz-extension://` and `chrome-extension://` origins.
604
-
605
- On `mail.google.com` the content script adds the **assist** button beside the date of each expanded message in a thread. It fetches that message's **Show original** view to read its RFC 822 `Message-ID` and sends the permalink `https://mail.google.com/mail/u/0/#search/rfc822msgid%3A<url-encoded Message-ID>`; the agent reads the email through the Gmail connector. An email has no repo, so the popover adds a picker listing the folders under `clone.baseDir` (from `GET /api/clones`), defaulting to the last repo picked (kept in extension storage, ignored once that folder is gone). The send POSTs `{ url, repo, instructions?, mode? }` to `POST /api/sessions/from-link`, which starts the same Prompt/Draft/Bug session in `<baseDir>/<repo>`. Sending with no repo picked, or from a message whose `Message-ID` can't be resolved, toasts the problem and starts nothing; a repo no longer under `baseDir` gets a 404.
606
-
607
- On a PR page the header button opens a menu mirroring the web app's PR dialog instead: the review modes (Review, Review & refine, Review & apply, Review & post, High-level review), the Force re-run / Address comments after / Announce to Slack after toggles that add their flags to the picked mode, and the PR actions (Checkout, Address Comments, Fix conflicts merge/rebase). Arrow keys move, Enter picks or toggles, Escape or a click outside closes. Picking an entry POSTs `{ url, args }` to `POST /api/sessions/review-from-github`, which resolves the clone the same way and starts an assist session running those args plus the PR number. Args that aren't a shared review mode (optionally followed by toggle flags) or PR action get a 400.
608
-
609
- ### Azure DevOps PRs
610
-
611
- The content script also runs on `dev.azure.com` and `*.visualstudio.com`. On a PR page (`…/<project>/_git/<repo>/pullrequest/<id>`) it adds the **assist** button to the PR header with only **Checkout**, **Address Comments**, **Address Comments (batch)** and **Address Comments (auto)**; the review modes and Fix conflicts are GitHub-only and get a 400 for an Azure DevOps URL. The endpoint finds the clone under `clone.baseDir` whose remote is the same org/project/repo in any form (`https://org@dev.azure.com/…/_git/repo`, `https://org.visualstudio.com/…/_git/repo`, `git@ssh.dev.azure.com:v3/org/project/repo`), preferring `<baseDir>/<repo>`.
612
-
613
- Assist stores no Azure DevOps credentials: it drives the [Azure CLI](https://aka.ms/azure-cli) with your own login, so install `az`, add its extension with `az extension add --name azure-devops`, and run `az login`. When a checkout or an `assist prs` thread command fails, assist says which of these is missing.
614
-
615
- In a clone whose remote is on Azure DevOps, `assist prs list-comments`, `fixed`, `wontfix` and `reply` work on the current branch's active PR through `az repos pr list` and `az devops invoke`. Each thread prints with its ADO web URL and the thread id as its `id` (every comment in a thread shares it); `fixed` replies with a `dev.azure.com/…/commit/<sha>` link and sets the thread to **Fixed**, `wontfix` sets it to **Won't fix**. A thread counts as resolved unless its status is Active or Pending.
616
-
617
- Sending is Firefox-only (it relies on the `browser.*` promise APIs). The web server URL is set on the extension's options page (**about:addons** → the extension → **Options**) and defaults to `http://localhost:3100`. `host_permissions` covers any port on `localhost` and `127.0.0.1`; another host relies on the endpoint's CORS.
618
-
619
- ### Browser link
620
-
621
- The background script keeps a websocket open to the options page's web server at `/ws/browser`, which accepts only `moz-extension://` and `chrome-extension://` origins, and says hello with the extension's version. It reconnects 5s after the socket drops, and a 30s `alarms` alarm wakes a suspended event page to reconnect, so a web server restart or suspension needs no browser restart. `assist browser` commands POST to `/api/browser`, which refuses any request carrying an `Origin` header, relays the request to the extension and waits 10s for its reply. While no extension is connected but one was seen in the last 90s (or the web server started that recently), the relay waits up to 35s for it to reconnect before answering that none is connected. The background script resolves the target tab and only acts on tabs on the assist content scripts' hosts (`github.com`, `dev.azure.com`, `*.visualstudio.com`, `localhost`, `127.0.0.1`); any other tab gets an error naming its URL.
622
-
623
- ### Docs feedback
624
-
625
- `npm run docs:preview` stamps each page with `<meta name="assist-docs-page">` (the page id), `assist-docs-title` and `assist-docs-source` (its title and `.md` file, used as the section for a selection in the page title or the text before the first heading) and marks each section with `data-docs-heading` and `data-docs-source` (its `.md` file); `docs:build` output carries none of these. The `docs.js` content script runs on any `localhost` / `127.0.0.1` page but only activates on one with the page meta. Selecting text inside a section with the mouse opens the same prompt popover straight away, anchored at the end of the selection with its textbox focused (keyboard selections open nothing), and **Enter** sends a non-empty prompt. Ctrl/Cmd+C in the empty textbox copies the selected page text. Clicking away closes an empty popover, but one with a typed draft stays open — ignoring new selections — until **Esc** or a successful send. The background script POSTs `{ pageId, heading, source, selection, prompt }` to `POST /api/sessions/docs-feedback`, which asks the daemon (`type-prompt-to-writer`) to paste the prompt into the live agent session whose working directory matches a live server run's directory that contains `source`, and submit it. Ties go to the session whose Claude transcript has the newest Write/Edit of `source`, else the newest session; with no such session it falls back to the newest writer of `source`, else of any file under `docs/src/`. A toast names the session, or reports a 404 when no session qualifies.
626
-
627
- ### Permanent Firefox install
628
-
629
- Firefox release and beta only install signed add-ons, so a permanent install means having Mozilla sign the package. Signing uses AMO's **unlisted** (self-distribution) channel: Mozilla signs the `.xpi` and hands it back, with no public store listing and no human review queue.
630
-
631
- Signing runs in CI, so the AMO key lives only as repo secrets and never on a developer machine. One-time setup: create an AMO API key at [addons.mozilla.org/developers/addon/api/key](https://addons.mozilla.org/en-US/developers/addon/api/key/) and add its two halves as the repo secrets `AMO_JWT_ISSUER` (the `user:12345678:123` issuer) and `AMO_JWT_SECRET`. The **Extension** workflow maps them onto the `WEB_EXT_API_KEY` / `WEB_EXT_API_SECRET` that `web-ext` reads.
632
-
633
- 1. Each release signs a new add-on version on its own when it changed the extension (see below). To sign by hand, run the **Extension** workflow from the Actions tab (`gh workflow run extension.yml`). It checks out `main`, builds, signs the extension at assist's current version, and uploads the signed add-on to that version's GitHub release as `assist-extension.xpi`. A failed AMO submission fails the job and attaches nothing.
634
- 2. Download `assist-extension.xpi` from the release — the URL follows from the version, `https://github.com/staff0rd/assist/releases/download/v<version>/assist-extension.xpi`. `assist extension --url` (or `/extension`) prints the latest signed build's URL, read from the update manifest on `main`.
635
- 3. Open the `.xpi` in Firefox (drag it onto a window, or `about:addons` → gear → **Install Add-on From File…**). It survives restarts.
636
-
637
- AMO refuses a version it has already signed, which is why the staged manifest carries assist's version instead of the manifest's `1.0.0` placeholder — sign once per release, not twice at the same version.
638
-
639
- After each release, the **Release** workflow dispatches **Extension** for the new tag with `only-if-changed`, which runs `extensionChanged.ts`. A release signs a new add-on version only when, since the last signed version (read from `updates.json` on `main`), it changed `extension/`, `src/commands/extension/`, or any file under `src/commands/sessions/web/ui` that `content.js` bundles, so a change to a criterion row ships. Every other release skips signing and publishes nothing. Dependency bumps alone do not sign; dispatch by hand to ship one. The release workflow dispatches rather than the signing workflow listening for `release: published`, because a release published with `GITHUB_TOKEN` starts no other workflows.
640
-
641
- Unlisted add-ons get no updates from AMO, so the manifest's `gecko.update_url` points at `extension/updates.json` on `main` instead. `--sign` writes that update manifest next to the `.xpi`, pointing at the signed version's release asset, and the workflow commits it back to `main` with `[skip ci]`, then dispatches **Release** so commits that a release run in flight skipped (seeing `main` move under it) still get released; an installed add-on then upgrades itself on Firefox's next update check (or **Check for Updates** in `about:addons`).
642
-
643
- `assist extension --sign` still signs locally for someone who holds an AMO key: export `WEB_EXT_API_KEY` and `WEB_EXT_API_SECRET`, run `npm run build` (to refresh `content.js`), then the command. It stages a copy of the extension with assist's version stamped into `manifest.json`, shells out to `npx web-ext sign`, and writes the signed add-on to `~/.assist/extension/assist-extension.xpi`. Under WSL it copies that to `C:\tools\assist-extension.xpi` and prints the Windows path.
644
-
645
- The add-on was previously called `assist criteria outliner` with the id `criteria-outliner@staff0rd.github.io`. It is now `assist` with the id `assist@staff0rd.github.io`, which Firefox treats as a different add-on, so an existing `assist criteria outliner` install no longer updates: remove it in `about:addons` and reinstall via `/extension`.
646
-
647
- Two alternatives need no signing: **Firefox Developer Edition** or **Nightly** honour `xpinstall.signatures.required = false` in `about:config` and will then install an unsigned local `.xpi` permanently, and Chrome's **Load unpacked** already survives restarts, so the unpacked directory is one-time setup there.
648
-
649
- ## netcap browser extension
650
-
651
- `assist netcap` only runs the receiver; the browser side is a raw Manifest V3 extension (no build step) under `netcap-extension/`. A MAIN-world content script patches `fetch`/`XMLHttpRequest` to capture `{url, method, status, requestBody, responseBody, timestamp}` and relays each entry to the background service worker, which POSTs it to the receiver. Forwarding happens in the background context, so the page's CSP (`connect-src`) never blocks it.
21
+ ## Contributing
652
22
 
653
- 1. Run `assist netcap` — it prints the receiver URL, the capture file path, and the extension directory to load. The receiver host/port and the optional `--filter` substring are baked into the extension's `background.js` at this point. Under WSL it copies the extension to `C:\tools\netcap-extension` and targets the WSL VM's IP, printing that Windows path instead; re-run after a reboot (the WSL IP can change) and reload the extension.
654
- 2. Load the unpacked extension:
655
- - **Firefox**: open `about:debugging#/runtime/this-firefox` → **Load Temporary Add-on…** → pick `manifest.json` inside the printed extension directory. (Requires Firefox 128+ for MAIN-world content scripts.)
656
- - **Chrome**: open `chrome://extensions`, enable **Developer mode**, click **Load unpacked**, and select the extension directory.
657
- 3. On load the background worker pings the receiver; `ping from extension` appears in the `assist netcap` log, confirming browser→server connectivity.
658
- 4. Browse a site; matching requests append to the capture file live and survive page refreshes. Press Ctrl-C to stop the receiver.
23
+ See [Working on assist](https://staffordwilliams.com/assist/working-on-assist/).