@staff0rd/assist
v0.877.2
Published
A CLI tool for enforcing determinism in LLM development workflow automation.
Readme
assist
A CLI tool for enforcing determinism in LLM development workflow automation.
See devlog for latest features.
Installation
You can install assist globally using npm:
npm install -g @staff0rd/assist
assist syncUpdating
assist updateLocal Development
# Clone the repository
git clone [email protected]:staff0rd/assist.git
cd assist
# Install dependencies
npm install
# Build the project
npm run build
# Install globally
npm install -g .After installation, the assist command will be available globally. You can also use the shorter ast alias.
Claude Commands
/add-command- Add a new run command viaassist run add/add-rule- Capture a newCLAUDE.mdrule from a review comment/branch <description> [--jira KEY]- Create a branch off the fresh remote default/bug- File a bug with reproduction steps, expected and actual behavior/close- End this session if its work is finished/comment- Add pending review comments to the current PR/commit- Commit only relevant files from the session/devlog- Generate devlog entry for the next unversioned day/extension- Get the install link for the assist browser extension/draft- Draft a new backlog item with LLM-assisted questioning/fix-conflict [--rebase]- Resolve the current PR branch's conflicts against the remote default;--rebaserebases instead of merging/fix-rules [dir]- Put existing rules into the## Rulesformatassist rulesreads/forward-comments- Split a coarse PR comment into per-line review comments, attributed to the original reviewer/pr- Raise a PR with a concise description/prs-slack <number> [--no-confirm]- Post a PR's title and URL to theprs.slackchannel (elseslack.channel);--no-confirmskips the confirmation/prs-status [channel] <owner/repo>...- Post an overview of the open PRs across the named repos to Slack (default channelslack.channel)/refactor- Run refactoring checks for code quality/prompts- Analyze denied tool calls and suggest settings changes to auto-allow recurring prompts/run-logs [session-id|group]- Summarise a run session's output, by session id or this repo's server group (defaultdefault)/releases-configure- Derive this repo's release promotion topology from its workflows and write it toreleases.streams/refine- Refine an existing backlog item through conversation/rename [title]- Retitle this session's dashboard card, inferring a title when given none/restructure- Analyze and restructure tightly-coupled files/review-config- Configure this repo's high-level review checklist keys/review-ci- Install a GitHub workflow that reviews new PRs with Claude and Codex through LiteLLM or Azure AI Foundry, without depending on assist/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/review-pr-comments- Process PR review comments one by one/jira [action] [KEY] [args]- Jira actions:view,associate,update,started,done,help.[KEY]defaults to the session's backlog item's/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>runsedit/next [id]- Signal completion and chain into the next backlog item/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 (defaultslack.channel);--threadreplies in that thread/subtask <text>- Add a sub-task to the session's current backlog item/strip-code-comments- Strip redundant comments from tracked source files/sync- Sync commands and settings to ~/.claude/design <prompt>- Apply the vendored design system prompt to a design task/test-cover- Incrementally increase test coverage by identifying and testing uncovered files/test-review- Review existing tests for quality, coverage gaps, and conventions/inspect- Run .NET code inspections on changed files/screenshot- Capture a screenshot of a running application window/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/show [what to show]- Open long links, paths and snippets in the web preview pane, defaulting to those in the previous reply/raven- Query and manage RavenDB connections and collections/miro [board url | extract name]- Extract a Miro frame's boxes as an ordered YAML list/seq- Query Seq logs from a URL or filter expression/sql- Query a MSSQL database via assist sql/verify- Run all verification commands in parallel/verify-new- Add a new verify:* run command to assist.yml/transcripts- Format and summarise meeting transcripts end to end
CLI Commands
Every command supports --help for full detail on its flags and behaviour.
Database
assist backup [-o, --out <dir>]- Dump the backlog database to<dir>(default~/.assist/backups, orbackup.dir)assist backup schedule --every <duration>- Scheduleassist backupon a cadence (e.g.5m,6h)assist backup schedule status- Show the active backup cadenceassist backup schedule remove- Remove the backup scheduleassist db migrate- Apply pending backlog database migrations in orderassist db status- Report whether the database is in sync with the build's bundled migrationsassist db drop-retired- Drop tables left by removed features
Git and GitHub
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~/.codexand~/.piwhen those CLIs are installed);--prunelists commands sync did not write and--prune --forceremoves themassist activity [--since <date>]- Chart GitHub commit activity per day (defaults to last 30 days)assist commit status- Show git status and diffassist commit <message> [files...] [--ref <ref>]- Stage files and create a validated single-line commit; each--ref(free text containing a URL) adds aRef:trailerassist branch <slug> [--jira <key>] [--from <ref>]- Create and switch to a new branch off the fresh remote default (or--from <ref>)assist watch wait [--interval <d>] [--timeout <d>|none] [--pull] [--build [entry]]- Wait until the current branch's upstream gains commits;--pullfast-forwards to them and--buildthen runs theauto-buildrun entry (or[entry]), showing its output only if it failsassist watch loop- Keep the current branch pulled and built as its upstream movesassist watch simulate-divergence- Make the nextassist watch waitpoll in this repo exit 3 as a simulated divergence, to test the auto-update loop's escalationassist watch report [--from <sha>]- Summarise recent commits and the restarts and sync they call for, since<sha>when givenassist read-time <target> [--budget <duration>]- Estimate how long a PR (number or URL), file or stdin (-) takes to read, against--budget(default 1m)assist prs- List pull requests for the current repositoryassist prs status <owner/repo>... [--json]- Report the open pull requests across the named repos and what each is waiting onassist prs slack-channel- Print the Slack channel PRs are announced to:prs.slack, elseslack.channel; exits non-zero when neither is setassist 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-draftoverrideprs.draft; each--screenshotis uploaded viagh --attachand rendered under## Screenshotsas a### Groupheading with a 2-column captioned table, ungrouped images last as plain imagesassist 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;--screenshotreplaces the existing## Screenshotssectionassist prs read-time <target> [--budget <duration>]- Alias ofassist read-timeassist prs list-comments- List all comments on the current branch's pull requestassist prs fixed <comment-id> <sha>- Reply with commit link and resolve threadassist prs wontfix <comment-id> <reason>- Reply with reason and resolve thread, previewed for approval in a web session;-reads the reason from stdinassist prs reply <comment-id> <body>- Reply to a comment thread without resolving it, previewed for approval in a web session;-reads the body from stdinassist prs comment <path> <line> <body>- Add a line comment to the pending review, previewed for approval in a web session;-reads the body from stdinassist review [number]- Review the current branch's PR (or PR[number]) with Claude and Codex in parallel and post line-bound comments[number]- Check out that PR first (see docs/parallel-work.md)--no-prompt- Skip all confirmations--submit- Default the submit prompt to yes--force- Re-run every phase instead of reusing cached results; with--high-level, start a fresh review--refine- Skip posting; walk through the findings interactively and edit them--apply- Skip posting; walk through each finding asking apply/skip--backlog- Skip posting; file all findings as a single bug backlog item with one phase per finding--checkout-only- Skip the review; check the PR out and leave an idle Claude session in it--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--configure- With--high-level: configure the checklist'sreview.highLevel.*keys instead of reviewing--scope <repo|project>- With--configure: write to this repo's override in the shared assist database or the projectassist.ymlinstead of asking--answer <key=value>- With--configure: answer one key without prompting, repeatable; an empty value leaves the key unset--address-comments- Start an Address Comments session for the PR once comments are posted and the review submitted--announce- Announce the PR in Slack at the end of the chain--verbose- Per-line log output instead of the stacked-spinner UIreview.codexModel- LiteLLM model the Codex reviewer uses; unset, it uses your own codex authreview.highLevel.criticalPaths- Globs of files whose diffs back the critical-diff checklist item; unset, no file is criticalreview.highLevel.uiPaths- Globs that make a change a UI change, requiring a screenshot or video; unset, the check passesreview.highLevel.descriptionWordCap- Word cap for the PR description; defaults to 300review.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}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/**
assist github commits <org> [--since <date>] [--top <n>] [--json]- Report commit activity across a GitHub organisationassist 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 milestoneassist github issue edit <number> [-R <owner>/<repo>] [--body <body>] [--fresh] [--fetch] [--parent <issue>]- Rework an issue's body in the web preview pane;--bodypreviews a proposed body (-reads stdin) instead of the current one,--fetchwrites the current body to the working file without previewing so it can be edited before the first preview,--freshdiscards an unpushed revision, and--parentinstead makes the issue a sub-issue of<issue>assist github issue comment <number> --body <body> [-R <owner>/<repo>]- Comment on a GitHub issue, previewed for approval in a web session;--body -reads stdinassist 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 stdinassist github issue started <number> [-R <owner>/<repo>]- Assign a GitHub issue to yourself and move it to In Progress on its project boardsassist 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 (defaultEpic,Story,Subtask);--levelsets the target's position in the chain,--strip-labelremoves a label, and nothing is written without--applyassist news add [url]- Add an RSS feed URL (rendered in the sessions web News tab)assist releases [list]- Print the release promotion streams declared inreleases.streamsassist releases configure --streams <file> [--scope <project|repo>]- Write release streams from a JSON or YAML file (-for stdin) toreleases.streams, in the projectassist.yml(default) or this repo's shared override in the assist database
Backlog
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.
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.
assist backlog [--dir <path>]- Open the backlog tab in the web dashboard (same asbacklog web)assist backlog list [--status <type>] [-a, --all] [--all-repos] [-v]- List backlog items (alias:ls; alsoassist list/assist ls)assist backlog add- Add a new backlog item interactively (human CLI use only; agents must usepropose)assist backlog add --name <n> --type <t> --desc <d> --ac <criterion...>- Add a backlog item from CLI optionsassist 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 launchesassist backlog run a<id>in a new session; outside one,--confirmedwrites it. See docs/backlog-item-preview.mdassist backlog show <id> [--all-commits]- Display full detail for a backlog item (alias:view);--all-commitslists every commitassist backlog plan <id>- Display the phased plan for a backlog itemassist backlog update-field <id> [--name <n>] [--desc <d>] [--type <t>] [--ac <criterion...>]- Update fields on a backlog itemassist backlog update-field <id> [--add-ac <text>] [--edit-ac <n> <text>] [--remove-ac <n>]- Granular 1-based acceptance-criteria editsassist backlog update-field <id> --origin [url-or-key]- Retag a single item to a different repoassist backlog add-phase <id> <name> --task <t...> [--manual-check <c...>] [--position <pos>]- Add a phase to an existing itemassist backlog update-phase <id> <phase> [--name <n>] [--task <t...>] [--manual-check <c...>]- Modify a plan phase (alias:edit-phase)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 editsassist backlog remove-phase <id> <phase>- Remove a plan phase from a backlog itemassist backlog move-phase <id> <from> <to>- Reorder a plan phase between 1-based positionsassist backlog update-plan <id> --json <file|->- Replace an item's whole plan from a JSON payload, previewed as a diff for approvalassist backlog add-subtask <id> --title <t> [--desc <d>]- Add a sub-task. Sub-tasks under thesubtaskskey inassist.yml/~/.assist.ymlare added to every new itemassist backlog edit-subtask <id> <idx> [--title <t>] [--desc <d>] [--status <s>]- Edit a sub-task by its 1-based indexassist backlog remove-subtask <id> <idx>- Remove a sub-task by its 1-based indexassist backlog subtask-status <id> <idx> <status>- Set a sub-task's status (todo,in-progress,done)assist backlog start <id>- Set a backlog item to in-progressassist backlog stop- Revert all in-progress items to todo and reset their phase to 1assist backlog done <id>- Set a backlog item to done (blocked while any sub-task is not done)assist backlog wontdo <id> [reason]- Set a backlog item to won't doassist backlog set-status <id> <status>- Set status (todo,in-progress,done,wontdo)assist backlog star <id>/assist backlog unstar <id>- Pin an item ahead of unstarred items in the web viewassist backlog delete <id>- Delete a backlog itemassist backlog comment <id> <text>- Add a comment to a backlog item, previewed for approval first whenbacklog.previewCommentsistrueassist backlog comments <id>- List comments and summaries for a backlog itemassist backlog delete-comment <id> <comment-id>- Delete a comment (summaries cannot be deleted)assist backlog phase-done <id> <phase> <summary>- Signal that a plan phase is completeassist backlog rewind <id> <phase> --reason <reason>- Rewind an item to an earlier phaseassist backlog next [id] [--once]- Pick and run the next backlog item, or open/draftif none remainassist backlog refine [id] [--once] [--harness <claude|codex|pi>]- Alias forrefineassist backlog run <id> [--harness <claude|codex|pi>] [--write|--no-write]- Run a backlog item's plan phase-by-phase with the selected harness (defaultharness.engine)assist backlog export [file]- Export the backlog database to a file, or stdoutassist backlog import [file]- Restore a dump into the backlog database (-y, --yesskips the prompt)assist backlog associate-jira <id> [key]- Associate a Jira ticket (bare key or browse URL), replacing any GitHub issue;--clearremoves itassist backlog associate-github <id> [issue]- Associate a GitHub issue (URL orowner/repo#number), replacing any Jira key;--clearremoves itassist backlog add-activity <id> <kind> <ref>- Attach an activity ref (branch,commit,commit-parent,pr,slack,session);--title,--url,--stateoverride metadataassist backlog record-slack <url>- Attach a Slack thread permalink to the current session's itemassist backlog record-session <id>- Attach the current Claude session to an item;--session <sessionId>overrides detectionassist backlog move-repo <old-origin> [new-origin]- Retag all items from one origin to another after a repo rename (-y, --yesskips the prompt)assist backlog clone <origin>- Clone a repo intoclone.baseDir(default~/git)assist backlog web [-p, --port <number>] [--no-open]- Open the backlog tab in the web dashboard (default port 3100)
Config and run commands
assist run <name> [params...]- Run a configured command from assist.yml, or a backlog item (a555/555) when no command matchesassist 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/--portmark it as a dev server,--envsets an environment variable,--preadds a shell command run first,--filterlimits averify:entry to changed files matching a glob,--quiethides output unless it fails,--paramadds a positional param (!marks it required;--env,--preand--paramrepeat),--helplists every run entry property, and--repowrites it to the repo's shared db override instead (no command file)assist run link <path> --prefix <prefix>- Link run configurations from another project's assist.ymlassist run remove <name> [--repo [name]]- Remove a run configuration and delete its Claude command file;--reporemoves it from the repo's shared db override instead
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.
assist config keys [filter]- List every config key with its type, default, effect and setter, optionally filtered by nameassist config get <key>- Get a config value; secret values are hidden unless--revealis passedassist config list- List the config values that are set, with secret values hiddenassist config set <key> <value>- Set a config value.--globalwrites to~/.assist.yml;-g --repo [name]writes a per-repo override to the shared assist database, so every node on that database sees itassist config unset <key>- Remove a config value so the key falls back to the global value or schema default (-gtargets~/.assist.yml;-g --repo [name]removes it from the shared per-repo override)assist config import-repos- Move this machine's~/.assist.ymlrepos:overrides into the shared database: prints a per-key diff against each repo's shared override, then on confirmation writes the keys and removesrepos:from~/.assist.yml
The web config page's "This repo" 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.
The Config tab of the sessions web dashboard never shows secret values; their fields are write-only.
Verify and lint
assist verify- Run all verify:* commands in parallel (from assist.yml run configs and package.json scripts); withverify.roots, each listed package dir'sverify:*scripts run as<root>:verify:*when files under it change, and the repo-root package.json scripts run only for changes outside every root; eachverify:<name>/verify:<name>:fixpair (MakerXStudio/verify convention) runs once — the:fixvariant in fix mode, the base in check mode (VERIFY_MODE=check|fix, else check whenCIis set)assist verify all- Run all checks, ignoring diff-based filtersassist verify --measure- Run all verify:* commands and time each oneassist verify init [--package-json]- Add verify scripts to a projectassist verify hardcoded-colors- Check for hardcoded hex colors in src/ (hardcodedColors.ignore)assist verify block-code-comments- Fail on any comment on a changed line (blockCodeComments.ignore); machine directives exemptassist verify forbidden-strings- Check configured JSON files for disallowed values (forbiddenStringsrules)assist verify config-keys- Check every config key is surfaced in some command's--helpassist verify advice-fragments- Check the advice fragment names match the fragments shipped inclaude/adviceassist verify migrations- Check bundled DB migrations are sequentially numbered, append-only, and free of unacknowledged destructive DDLassist lint [-f, --fix]- Run lint checks for conventions not enforced by oxlintassist lint init- Initialize oxlint with baseline linter config
Refactoring
assist refactor check [pattern]- Check for files that exceed the maximum line countassist refactor ignore <file>- Add a file to the refactor ignore listassist refactor rename file <source> <destination>- Rename/move a TypeScript file and update all imports (--applyto execute)assist refactor rename symbol <file> <oldName> <newName>- Rename a symbol across the project (--applyto execute)assist refactor extract <file> <functionName> <destination>- Extract a function and its private dependencies to a new file (--applyto execute)assist refactor restructure [root]- Move files underroot(defaultsrc) into folders derived from the import graph (--applyto execute,--checkto fail on drift or when the plan exceedsrestructure.maxDepthorrestructure.maxPathLength)
Rules
Rules are - **<code>** — **<title>** — <text> bullets, the title optional, in the ## Rules section of a CLAUDE.md.
assist rules list [path] [--full]- List the rules in scope for a path (default: cwd);--fulladds each rule's descriptionassist rules add <text> [--title <title>] [--scope <path>]- Add a rule to the## Rulessection of theCLAUDE.mdnearest--scope(default cwd)assist rules index- Record the directories that carry their own## Rulesin the repo root'sCLAUDE.md; run it after hand-editing a## Rulessection
Devlog
assist devlog list- Group git commits by dateassist devlog next- Show commits for the day after the last versioned entryassist devlog repos- Show which github.com/staff0rd repos are missing devlog entriesassist devlog skip <date>- Add a date to the skip listassist devlog version- Show current repo name and version info
Hooks
assist cli-hook- PreToolUse hook auto-approving CLI commands fromallowed.cli-reads/allowed.cli-writes, and denying reads of~/.assist/restrictedassist cli-hook add <cli>- Discover a CLI's commands and auto-permit read-only onesassist cli-hook check <command> [--tool <tool>]- Check whether a command would be auto-approvedassist cli-hook deny- List all deny rulesassist cli-hook deny add <pattern> <message>- Add a deny rule for a command patternassist cli-hook deny remove <pattern>- Remove a deny rule by patternassist codex-hook- Codex hook that auto-approves read-only commands and reports session status to the sessions dashboardassist pi-hook- pi permission gate that auto-approves read-only commandsassist edit-hook- PreToolUse hook that blocksEdit/Write/MultiEditcalls from adding, changing, or removing a// assist-maintainability-overridemarker, or from introducing a code comment (usecode-comment set/confirmfor the rare comment that belongs)assist code-comment set <file> <line> <text>- Request a pin authorising a single-line comment (max 50 chars)assist code-comment confirm <pin>- Insert the pinned comment at its file/lineassist db-migration unlock- Ask a human to approve creating the next migration moduleassist db-migration confirm <pin>- Confirm a pin fromdb-migration unlock, letting that migration's file be written onceassist advise [--hook] [--explain]- Print the advice fragments that apply to the current repo;--hookruns it as a SessionStart hook and--explainshows why each fragment was or wasn't included.advice.sectionsforces a fragment in or out by name,advice.verifyreplaces the verify fragment's text andadvice.extraappends repo notesassist notify- Show desktop notification from JSON stdin (macOS, Windows, WSL)assist status-line- Format Claude Code status line from JSON stdin
.NET
assist dotnet inspect [sln]- Run JetBrains inspections on changed .cs files to find dead code--scope all|base:<ref>|commit:<ref>- Inspect the whole solution, everything changed since a base ref, or one commit--only <ids...>/--suppress <ids...>- Show only, or suppress, specific issue type IDs--roslyn- Use Roslyn analyzers via msbuild instead of JetBrains--swea- Enable solution-wide error analysis (slower but more thorough)
assist dotnet check-locks- Check if build output files are locked by a debuggerassist dotnet deps <csproj>- Show .csproj project dependency tree and solution membershipassist dotnet in-sln <csproj>- Check whether a .csproj is referenced by any .sln file
Data sources
assist jira auth- Authenticate with Jira via API tokenassist jira ac <issue-key>- Print acceptance criteria for a Jira issueassist jira view <issue-key>- Print the title and description of a Jira issueassist miro extract [name] [--items <file>] [--top-left <id|link> --bottom-right <id|link>] [--ignore <file>] [--out <file>] [--board <id>] [--frame <id>] [--save <name>] [-g] [-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 undermiro.extractssoassist miro extract <name>replays itassist litellm list-models [--json]- List the model ids the configured LiteLLM proxy servesassist ravendb auth add- Add a new RavenDB connectionassist ravendb auth list- List configured RavenDB connectionsassist ravendb auth remove <name>- Remove a configured connectionassist ravendb set-connection <name>- Set the default connectionassist ravendb query [connection] [collection]- Query a RavenDB collection (--page-size,--sort,--query,--limit)assist ravendb collections [connection]- List collections and document countsassist seq auth add- Add a new Seq connectionassist seq auth list- List configured Seq connectionsassist seq auth remove <name>- Remove a configured connectionassist seq set-connection <name>- Set the default Seq connectionassist seq query <filter>- Query Seq events (-c <connection>,--json,-n <count>,--from <date>,--to <date>)assist slack post [channel] --body <body|-> | --parts <file>... [--thread <ts-or-permalink>]- Preview a markdown message bound for a Slack channel (defaultslack.channel) for approval, for/slack-postto send;--body -reads stdin,--threadtakes a message ts or permalink to reply under, and--partspreviews a thread of messages, one file each, in orderassist sql auth add- Add a new MSSQL connectionassist sql auth list- List configured SQL connectionsassist sql auth remove <name>- Remove a configured connectionassist sql set-connection <name>- Set the default SQL connectionassist sql query "<sql>" [connection]- Execute a read-only SQL statementassist sql mutate "<sql>" [connection]- Execute a mutating SQL statementassist sql tables [connection]- List tables in the connected databaseassist sql columns <table> [connection]- List columns for a table (schema.tablefor a non-default schema)
Other
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 extensionassist netcap extract-linkedin-posts [file]- Parse a netcap capture into structured LinkedIn postsassist extension [--sign] [--url]- Locate the assist browser extension to load unpacked;--signsigns it for a permanent Firefox install;--urlprints the latest signed build's download URLassist screenshot <process>- Capture a screenshot of a running application window (screenshot.outputDir, default./screenshots)assist mermaid export [file.md]- Render each fenced mermaid block to SVG via Kroki (--out,--index,mermaid.krokiUrl)assist prompts- Show the most frequently denied tool callsassist chart [--title <title>]- Draw a terminal line chart of alabel valueseries piped in on stdin, one pair per lineassist 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 stdinassist 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
Project setup
assist init- Initialize project with VS Code and verify configurationsassist new vite- Initialize a new Vite React TypeScript projectassist new cli- Initialize a new tsup CLI projectassist update- Update assist to the latest version and sync commandsassist vscode init- Add VS Code configuration filesassist deploy init- Initialize Netlify project and configure deploymentassist deploy redirect- Add trailing slash redirect script to index.htmlassist roam auth- Authenticate with Roam via OAuthassist roam show-claude-code-icon- Forward Claude Code hook activity to Roam local API
Complexity
assist coverage- Print global statement coverage percentageassist complexity <pattern>- Analyze a file (all metrics if single match, maintainability if multiple)assist complexity cyclomatic [pattern]- Calculate cyclomatic complexity per functionassist complexity halstead [pattern]- Calculate Halstead metrics per functionassist complexity maintainability [pattern]- Calculate maintainability index per file (--ignore <glob>, pluscomplexity.ignore). A file can declare its own threshold with a// assist-maintainability-override: Ncomment in its first ~10 lines, replacing--thresholdfor that file onlyassist complexity sloc [pattern]- Count source lines of code per file
Transcripts
assist transcript configure- Configure transcript directoriesassist transcript clean <path>- Clean a .vtt file to markdown or, with--format vtt, WebVTT;--timestampsprefixes each markdown speaker turn with its timeassist transcript list- List raw .vtt filenames waiting in the pick-up directoryassist transcript merge <path...>- Collapse several .vtt files into one transcript on a continuous timeline (--out <path>);--select <file|->keeps only the chosen ranges,--no-provenanceomits source notes and--widen-audiencedrops asides aimed at those in the callassist transcript move <file>- Convert a raw .vtt to a dated markdown transcript and archive the original
Sessions
assist sessions- Start the web dashboard (same assessions web)assist sessions web [-p, --port <number>] [--no-open]- Start the web dashboard with Sessions, Backlog and News tabs (default port 3100)assist sessions summarise [-f, --force] [-n, --limit <count>]- Generate one-line summaries for unsummarised Claude sessionsassist sessions close- End the current daemon-managed sessionassist sessions rename <title>- Retitle the current daemon-managed session's dashboard cardassist 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 runassist sessions nodes [--json]- List this node and every linked node with its link state (see Linked nodes)assist sessions nodes link <name> [url] [--tailscale <host> --port <port>]- Link a peer node by its web server URL or its Tailscale nameassist sessions nodes unlink <name>- Remove a linked nodeassist sessions nodes doctor [name] [--json]- Find where a link is broken and how to fix itassist sessions nodes logs <name> [-n, --lines <count>] [--json]- Tail a linked node'sdaemon.logassist sessions nodes restart <name> [--target daemon|webserver|both]- Restart a linked node and wait for its link to reconnectassist sessions nodes update <name>- Update assist on a linked node and wait for its link to reconnectassist sessions set-status <status>- Report the current session's status (running/waiting) to the daemonassist daemon run- Run the sessions daemon in the foregroundassist daemon status- Show daemon status, live sessions and each link's stateassist daemon stop- Stop the sessions daemon; running claude sessions resume on next startassist daemon restart- Restart the sessions daemon, resuming previously running claude sessionsassist daemon drain [--yes]- Remove all sessions from the local daemon; a session holding unpushed work is stopped, not removed
Session launchers
assist next [id] [--once]- Alias forbacklog next [id];--onceexits after the first completed item runassist draft [description] [--once](alias:feat) - Launch Claude in/draftmode, chain into next on/nextsignalassist bug [description] [--once]- Launch Claude in/bugmode, chain into next on/nextsignalassist refine [id] [--once] [--harness <claude|codex|pi>]- Launch a coding harness in/refinemode (defaultharness.engine)assist review-pr-comments [number] [--announce] [--resume-session <id>]- Launch Claude in/review-pr-commentsmode, on PR[number]when given;--announceannounces the PR in Slack once every thread is processedassist fix-conflict [number] [--rebase] [--resume-session <id>]- Launch Claude in/fix-conflictmode, on PR[number]when given;--rebaserebases instead of mergingassist signal next [id]- Signal the session to chain intoassist nextassist signal done [id]- Signal the session's initial task complete, surfacing backlog item[id]on its card
draft, bug, refine, review-pr-comments, fix-conflict and backlog run accept --resume-session <id> to resume an interrupted Claude session.
Sessions dashboard
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.
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 -g.
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.
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.
- Numbers: Alt+1 to Alt+5 select the Nth visible top-level tab (with Releases hidden, News is Alt+4).
- 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.
- R (toolbar): Alt+R focuses the toolbar's repo picker; Tab / Shift+Tab then move along the toolbar.
- 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.
- 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.
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.
Each shortcut's chord can be overridden under sessions.hotkeys.<action>, e.g. assist config set sessions.hotkeys.focusTerminal Ctrl+Alt+J -g; 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–5. An override replaces all of an action's default chords, and assist config set rejects an invalid chord. Tab card-cycling is fixed.
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.
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.
Linked nodes
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.
assist sessions nodes [--json]— this node and each link's state and peer version.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'ssessions.nodeName. See Linking machines over Tailscale.assist sessions nodes unlink <name>— remove a link.assist sessions nodes doctor [name] [--json]— find where a link is broken and how to fix it.assist sessions nodes logs <name> [-n, --lines <count>] [--json]— tail a linked node'sdaemon.log; naming this node reads the local log.assist sessions nodes restart <name> [--target daemon|webserver|both]— the CLI form of Restart : posts the node's/api/restart, waits up to 90s for its link to reconnect and prints its version.assist sessions nodes update <name>— the CLI form of Update assist on : over a connected link it opens anassist updatecard 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.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 linkversion-blockeduntil the older node is updated;warnproceeds anyway;offskips the check.
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.
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 : 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 : 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.
Linking machines over Tailscale
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.
Install Tailscale on every machine, sign in to the same tailnet, and turn on MagicDNS and HTTPS certificates in the admin console.
Link each peer by its Tailscale host name. From the Mac to both PC nodes:
assist sessions nodes link pc-wsl --tailscale pc --port 4100 assist sessions nodes link pc-windows --tailscale pc --port 3101and optionally from the PC's WSL node back to the Mac:
assist sessions nodes link mac --tailscale mac --port 3100.Check each link with
assist sessions nodes doctor.
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.
Session config keys
sessions.nodeName— this install's node label. Defaults to the OS hostname, suffixed-wslunder WSL.sessions.tailscaleServe— expose the web server on the tailnet. Defaults to true.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.sessions.topBar— show the session's details and actions in a top bar inside the terminal panel instead of on the card. Defaults to true.sessions.floatWaiting— float sessions waiting on input above the other cards. Defaults to true.sessions.floatWaitingAfterMs— how long a session must wait on input before it floats. Defaults to 5000.sessions.newSessionMode— the mode pre-selected in the new session dialog:draft,bug,promptordesign. Defaults to draft.sessions.maxLive— the most live sessions one daemon holds at once. Defaults to 24.
Releases
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.
Two layers sit over the one graph, toggled rather than shown side by side:
- 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 stillwaitingon an approval is gated, not live, so it is passed over and shown on its ownqueuedline instead. - 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 Staginggoes to theeu-stagingnode rather than thestagingone.
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.
Topology is declared, not derived: assist does not parse workflow YAML at runtime.
releases:
streams:
- name: Web App
repo: owner/name
workflow: release.yml
nodes:
- { id: build, kind: build }
- { id: dev, environment: dev }
- { id: eu-prod, environment: EU Production, label: eu-prod }
edges:
- [build, dev]
- [dev, eu-prod]idnames the node within the stream and is whatedgesrefer to. A node with anenvironmentis a GitHub deployment environment and reads live state;kind(buildorgate) marks a node that deploys nothing.labeloverrides the text on the node, which is otherwise theid./releases-configurederives the block from the repo's own workflows instead of hand-writing it, andassist releases listprints whatever is declared back as assist reads it.
Next
The Next tab (/next) recommends what to do next, in this order:
- Peer PRs — open PRs across
next.reposbynext.peersor requesting your review - Assigned issues — open issues assigned to you across
next.repos - Pickups — unassigned items on
next.projectsboards in anext.pickStatusesstatus, in board order
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.
assist config set next.peers alice,bob -g --repo
assist config set next.repos my-org,other/web -g --repo
assist config set next.projects my-org/3,my-org/5 -g --repo
assist config set next.pickStatuses Ready,Todo -g --repo
assist config set next.excludeLabels blocked,spike -g --repo
assist config set next.excludeTypes Epic -g --repoParallel work
Concurrent sessions in one repo can be isolated with native git worktrees instead of keeping multiple physical clones: see docs/parallel-work.md. All of these keys default off except worktree.install:
worktree.enabled(parallel work) — spill concurrent prompt sessions into adjacent<clone>-Nworktrees instead of sharing the clone's working copy. Assist-command sessions (draft, bug, backlog run, next, review, …) always get a fresh worktree offorigin/<default>.worktree.trunk(trunk-based) — a worktree's branch tracksorigin/<trunk>so commits land on the mainline, and jobs that commit (backlog run, PR checkouts) always run in a worktree, never the clone. Off, worktrees start off the remote default branch with no mainline tracking.worktree.install— how a new worktree installs its deps:true(default) auto-detects pnpm/yarn/bun/npm, a string is the install command,falseskips it, and a list of paths installs in each in order.
None of them leaves permanent state on the clone, so turning parallel work back off leaves the repo as it was.
Iterating on assist itself
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.
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.
Other config keys
harness.codexModel— LiteLLM model every non-review Codex launch uses. Unset, Codex uses its own configured provider.slack.channel— the Slack channelassist slack postand/slack-posttarget when given none.prs.slack— the Slack channel/prs-slackposts pull requests to. Falls back toslack.channelwhen unset.prs.required— cut a fresh branch whenassist backlog runstarts a story with no recorded branch. Defaults totrue.prs.promptJira— haveassist prs raise --helpask the user for a Jira key to resolve. Defaults tofalse.prs.promptGithub— haveassist prs raise --helpask the user for a GitHub issue to resolve. Defaults tofalse.prs.draft— raise PRs as drafts. Defaults tofalse.readTime.wordsPerMinute— the prose reading speedassist read-timeassumes. Defaults to200.prs.readingWordsPerMinute— the former name ofreadTime.wordsPerMinute, read only when that is unset.commit.pull— fast-forward beforeassist draft,bug,refine,nextandbacklog runstart, aborting if that fails. A branch with no upstream (such as a fresh worktree branch) fast-forwards ontoorigin/<default>when it has no commits of its own. Defaults to off.commit.expectedBranch— warn onassist commitwhen HEAD is on any other branch. Unset by default.branch.prefix— prefix for branch names fromassist branch. Unset by default.branch.defaultBranch— the base branch for new branches. Defaults to the remote's default branch.releases.streams— the release promotion streams the Releases page draws.cliHook.blockNpmRun— denynpm runin favour ofassist run. Defaults totrue.
assist browser extension
assist extension prints the directory to load unpacked. The extension is a Manifest V3 content script scoped to https://github.com/*, plus a background script and an options page, built by npm run build from src/commands/extension/ into extension/content.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 MUI theme. 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.
- Run
assist extension— it prints the extension directory. Under WSL it copies the extension toC:\tools\extensionand prints that Windows path instead; re-run and reload the extension after a rebuild. - Load the unpacked extension:
- Chrome: open
chrome://extensions, enable Developer mode, click Load unpacked, and select the extension directory. - Firefox: open
about:debugging#/runtime/this-firefox→ Load Temporary Add-on… → pickmanifest.jsoninside the printed extension directory. Firefox drops a temporary add-on on every restart; see permanent Firefox install to avoid that.
- Chrome: open
- Open an issue, press Edit on the body, and press Outline criteria. The new-issue form works the same way.
Send to assist
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; Enter sends (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? }), 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 }. 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.
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.
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.
Permanent Firefox install
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.
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 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.
- 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 outmain, builds, signs the extension at assist's current version, and uploads the signed add-on to that version's GitHub release asassist-extension.xpi. A failed AMO submission fails the job and attaches nothing. - Download
assist-extension.xpifrom 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 onmain. - Open the
.xpiin Firefox (drag it onto a window, orabout:addons→ gear → Install Add-on From File…). It survives restarts.
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.
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.
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).
assist extension --sign still signs locally f
