Revue
DocumentationCommand line

Command line and environment variables

Start Revue from a terminal to open pull requests straight away, try a build without touching your data, or point it at your own OAuth apps.

Most people never need any of this: Revue is a desktop app, and everything is set in Settings. This page is for scripts, terminals and people who build Revue themselves.

Starting Revue from a terminal#

revue [--immutable] [--version | -V] [--probe [LINK]] [LINK …]
revue --pull-request [DIR] [--branch NAME]
revue --pulls [DIR]
revue LINK --file PATH [--line N]
revue LINK --file PATH --line N [--start-line M] [--side LEFT|RIGHT] --write-comment
revue --branch-pull [DIR] [--branch NAME]
revue --pending LINK
revue --comment LINK --file PATH --line N [--start-line M] [--side LEFT|RIGHT] --body TEXT
revue --sides LINK --file PATH
revue --review LINK
revue --edit-comment LINK --id ID --body TEXT
revue --delete-comment LINK --id ID
revue --reply LINK --thread ID --body TEXT
revue --resolve LINK --thread ID [--off]
revue --viewed LINK --file PATH [--off]
revue --react LINK --comment ID --reaction CONTENT [--off]
revue --submit-options LINK [SLACK]
revue --submit LINK --event COMMENT|REQUEST_CHANGES|APPROVE [--body TEXT] [--resolve-mine] [SLACK]
ArgumentWhat it does
LINK …Opens each pull request in a tab. If Revue is already running, the links go to that window instead of a new one.
--immutableRuns on a throwaway copy of your settings and data. Nothing you change is kept. See Trying Revue without changing anything.
--version, -VPrints revue <version>, then editor <N> (see What editors can ask), and exits.
--pull-request [DIR] [--branch NAME]Opens the pull request of the branch checked out in DIR (the current folder if left out), or of NAME. If it has none, opens the New pull request page for it. See Opening your branch's pull request.
LINK --file PATH [--line N]Opens the pull request at that file, and at line N of its new side. See Opening a pull request at a file.
LINK --file PATH --line N … --write-commentOpens the pull request at those lines with the comment box open on them. See Writing a comment from an editor.
--pulls [DIR]Prints the open pull requests of DIR's repository as JSON, as the running Revue sees them, and exits. For editor plugins. See Listing a repository's pull requests.
--branch-pull [DIR] [--branch NAME]Prints the open pull request of the branch checked out in DIR (or of NAME) and its files as JSON, and exits. See Your branch's pull request as JSON.
--pending LINKPrints the pull request's comments you haven't sent yet as JSON, and exits. See Comments not sent yet.
--comment LINK …Adds a pending comment to the pull request in the running Revue, and exits. See Adding a comment.
--pull LINKPrints the pull request, whether it can be merged, its checks, files, conversation, commits, Slack threads and stack as JSON, and exits. See A pull request as JSON.
--sides LINK --file PATHPrints a file the pull request changes as it was before and is at its head, as JSON, and exits. See A changed file's two sides.
--review LINK … --submit LINK …A review from the editor: what it shows, editing and deleting pending comments, replying, reacting, marking files viewed, submitting. See Reviewing from an editor.
--worktree LINK [--dir CLONE]Finds or creates the pull request's worktree in the clone, prints where as JSON, and exits. See A pull request's worktree.
--fetch-branch LINK [--dir CLONE]Brings the clone's branch of the pull request to its head without checking it out, prints it as JSON, and exits. See A pull request's branch, fetched.
--accountPrints whether you're signed in to your Revue account and where each sign-in is kept, as JSON, and exits. See Your Revue account.
--account-sign-in [--server URL] [--device NAME]Signs this computer in to your Revue account through the browser, prints the account as JSON, and exits. See Signing in to your Revue account.
--companion KIND --pid PID …Records an editor's running Revue Companion (VS Code, Zed, Neovim), so Open in editor can reach it, and exits. --companion-gone --pid PID removes it. For editor plugins. See Telling Revue an editor runs.
--probe [LINK]A GitHub connection check for diagnostics. Prints timings and exits. See Checking the GitHub connection.

Arguments Revue doesn't recognise are ignored.

Advanced: argument details
  • --immutable can go anywhere on the line and combines with everything else.
  • --headless can go anywhere on the line of an editor's question (--pulls, --branch-pull, --pending, --comment, --pull, --sides, --review, --edit-comment, --delete-comment, --reply, --resolve, --viewed, --react, --submit-options, --submit, --worktree, --fetch-branch, --favorite): with no Revue running, the revue command answers by itself. See Answers without the app.
  • --version / -V and --probe only count as the first argument (after --immutable is taken out). Anywhere else they're ignored.
  • On Windows, release builds have no console window, so --version and --probe may print nothing in Command Prompt or PowerShell. Redirect the output to see it, for example revue.exe --version > version.txt.
  • Development builds (made with task dev) print the same version but use their own folders and window name, Revue Dev, so they never mix with an installed Revue.

Opening pull requests from the command line#

Pass one or more pull request links:

revue https://github.com/acme/web/pull/12
revue acme/web#12 https://codeberg.org/acme/app/pulls/3
  1. Revue checks whether it's already running.
  2. If it is, the links open as tabs in that window, and the window comes to the front.
  3. If not, Revue starts and opens them.

You must be signed in to the account that can see the pull request. Otherwise Revue tells you to Sign in to … (Settings → Accounts) to open ….

All link forms Revue understands
FormExample
GitHub pull request addresshttps://github.com/acme/web/pull/12
GitHub short formacme/web#12, acme/web/pull/12
Bitbucket Cloud pull request addresshttps://bitbucket.org/acme/web/pull-requests/7
Forgejo, Codeberg or Gitea addresshttps://codeberg.org/acme/app/pulls/3, http://git.example.com:3000/o/r/pulls/3
A revue:// linkrevue://open?url=<encoded address>, or revue://github.com/acme/web/pull/12
  • Anything after ? or # in a web address is ignored, so a link copied from a comment (…/pull/12#discussion_r1) or a tab (…/pull/12/files) still works.
  • A server that isn't github.com or bitbucket.org is treated as Forgejo, Codeberg or Gitea.
  • revue:// links are what browsers and other apps hand to Revue once it's registered as their handler. See Links and opening from anywhere.
Advanced: how a link reaches the running Revue

The running Revue listens on a random port on 127.0.0.1 (your computer only) and writes the port number to a file called instance-port in its data folder (see Privacy and security). A second revue LINK reads that file, sends the links there and exits once the running Revue answers. If nothing answers within a moment (Revue closed, or the port is stale), the new process opens its own window.

On macOS, revue:// links opened by the system (from a browser, say) arrive through the app bundle instead.

Opening your branch's pull request#

From a clone (or worktree) of a repository:

revue --pull-request                 # the branch checked out here
revue --pull-request ~/code/web      # the branch checked out there
revue --pull-request . --branch feature/login
  1. Revue reads the folder's git remotes and picks the repository on a service you're signed in to.
  2. If the branch has an open pull request, it opens in a tab.
  3. If not, the New pull request page opens in the Pull requests tab, filled in from the branch (see Opening a pull request). A branch that's only in your clone is pushed when you open the pull request.

Like links, this goes to the running Revue if there is one. The same thing as a link is revue://branch?path=<encoded folder>&name=<encoded branch>.

Advanced: which remote counts
  • To find the pull request, Revue looks in the repositories of upstream, then origin, then the other remotes, the ones on services you're signed in to. A pull request from your fork counts when the fork is one of the clone's remotes.
  • A new pull request is opened in the repository of the remote the branch is pushed to (its upstream in git), else origin, else the first one.
  • A remote through an SSH host alias (git@github-work:acme/web.git) is followed to its real host with ssh -G.

Listing a repository's pull requests#

revue --pulls ~/code/web
revue --pulls ~/code/web --show involved --no-drafts --page 2 --per-page 25

Asks the running Revue for the open pull requests of the folder's repository and prints them as one line of JSON. Editor plugins use it (see Editors).

OptionLists
--show all (default)Every open one
--show involvedYours, the ones awaiting your review and the ones you reviewed before
--show mineYours
--show reviewThe ones awaiting your review
--show to-reviewAs the To review tab: the ones awaiting your review first, then the ones you reviewed before
--show reviewedThe ones you reviewed before, nobody having asked you again
--no-draftsWithout drafts
--search TEXTThe ones the service's search finds (a title, #12…)
--page N, --per-page NPage N (from 1) of N each, at most 200 (the default)
{"repo":"acme/web","host":"GitHub","web":"https://github.com/acme/web","branch":"feature/login","me":"alice",
 "show":"all","page":1,"per_page":200,"more":false,
 "pulls":[{"number":12,"title":"Fix login","url":"https://github.com/acme/web/pull/12","author":"alice",
           "branch":"feature/login","base":"main","draft":false,"updated":"2026-10-20T10:00:00Z",
           "mine":true,"review_requested":false,"reviewed":false,"head_sha":"abc123…",
           "avatar":"https://avatars.githubusercontent.com/u/1","author_name":"Alice Smith",
           "tickets":[{"key":"WEB-42","url":"https://acme.atlassian.net/browse/WEB-42"}],
           "comments":3,"review":"approved","checks":"success"}]}
Exit codeOutput
0The page, last updated first (branch is the one checked out, me your login, more whether a next page follows; a pull request's state is open, merged or closed, favorite says you starred it (favorites), mine that you wrote it, review_requested that it awaits your review, reviewed that you reviewed it before and nobody asked you again, head_sha its head commit, avatar and author_name its author's picture and name, tickets the tickets its title and branch name with their links, url null where no ticket link covers the project; comments how many comments it has, as the pull request list counts them; review its reviews' verdict, approved, changes_requested or review_required; checks how its head commit's checks came out overall, success, failure or pending; author, branch, base, updated, head_sha, avatar, author_name, tickets, comments, review and checks may be missing)
1{"error":"…"}: not a git repository, no remote on GitHub, Bitbucket or Forgejo, the service failed
3{"error":"Revue isn't running"} (without --headless)
4{"error":"…","sign_in":true}: you aren't signed in to the service of the folder's repository (or of the pull request)

It never starts Revue: the running app answers, or, with --headless, the revue command itself. With --show all or mine, review_requested and reviewed are marked as far as the page goes, and left false when the service can't say.

What editors can ask#

revue --version prints a second line, editor <N>: the version of the commands on this page that editor plugins use (--pulls with every --show, --branch-pull, --pending, --comment, --pull, --sides, the review's (--review … --submit), --worktree, --fetch-branch, --open-slack, --favorite, --account, --account-sign-in, --companion, --companion-gone, LINK --file and LINK --file … --write-comment). A plugin checks it before using them: a Revue from before them prints no such line, and would open its window on an option it doesn't know. N goes up only when they change in a way an older plugin can't follow.

$ revue --version
revue 0.42.0
editor 10
editorWhat's new for plugins
1The commands above, answered by the running Revue.
2--headless: answered by the revue command itself when no Revue is running (Answers without the app), and exit code 4 for a repository or pull request you aren't signed in for.
3--sides: a changed file's text before and after, for the editor's own diff viewer.
4A review from the editor: --review, --edit-comment, --delete-comment, --reply, --submit, and --comment --in-review.
5--resolve; --submit-options, and --submit with all of the Submit review dialog: --resolve-mine and the reply in Slack.
6Your Revue account: --account and --account-sign-in.
7Viewed marks: --viewed, and each file's viewed in --review's files.
8Reactions: --react, and each comment's reactions in --review's threads; who can be @-mentioned, its mentionable.
9Telling Revue an editor runs: --companion and --companion-gone, so Open in editor reaches VS Code, Zed and Neovim.
10LINK --file PATH --line N --write-comment: the pull request opened with Revue's comment box on those lines, for editors that can't ask for a comment's text themselves.

Answers without the app#

revue --headless --pulls ~/code/web
revue --headless --comment acme/web#12 --file src/a.rs --line 42 --body "Why?"

With --headless, a question no running Revue can answer is answered by the revue command itself, the same way the app would. Revue must be installed, but not running, and no token ever goes to the editor:

  • It signs in with this computer's sign-ins (and those of your Revue account, synced before answering, so a sign-in renewed on another computer is used, and again after, so one renewed here reaches your other computers).
  • Drafts go to the same files the app uses: a comment added this way is there when Revue opens the pull request.
  • Lists, branch status, pending comments, details, worktrees, fetching branches and stars all work. What only an open tab knows (its Slack threads or stack found already) is looked for again.
  • One revue command answers at a time: another one waits for it (up to 90 seconds), so a single-use sign-in renewal is never spent twice. A Revue starting up waits for it too, then reads what it wrote.
  • When Revue is running, it answers, as without --headless. When it starts while a command waits, it answers that one.

Without --headless, nothing changes: with no Revue running, the command exits with 3.

Telling Revue an editor runs#

revue --companion vscode --pid 41234 --port 51234 --token "$TOKEN" --app "Visual Studio Code" --version 0.1.0
revue --companion zed --pid 41300 --port 51300 --token "$TOKEN" --app "Zed Preview"
revue --companion nvim --pid 41400 --socket /run/user/1000/nvim.41400.0 --version 0.1.0
revue --companion-gone --pid 41234

JetBrains IDEs are found on their built-in server. VS Code, Zed and Neovim have none Revue can look for, so their Revue Companion tells Revue it's running: once it's ready to answer, it runs revue --companion, and on the editor's shutdown, revue --companion-gone. Open in editor then asks it what it has open and opens the pull request there (see Which editor opens). Check for editor 9 in revue --version first.

The revue command itself records it, as a file in this computer's data folder (companions/<kind>-<pid>.json, readable only by you): no Revue needs to be running, and the companion never needs to know where that folder is. A Revue that starts later finds it.

Option
KINDvscode (VS Code and the editors built on it: Cursor, VSCodium, Windsurf…), zed or nvim
--pid PIDThe process that answers: VS Code's extension host (process.pid), Zed's companion server, Neovim (vim.fn.getpid()). It must be running.
--port PORT --token TOKENvscode and zed (and only they): the port the companion listens on, on 127.0.0.1 only (1024 to 65535), and a secret every request carries. The token is 16 to 256 letters, digits, - or _: make it 32 random bytes in base64url, new each time the editor starts.
--socket PATHnvim (and only it): Neovim's RPC address, v:servername: an absolute path to a Unix socket, which must be there, or a named pipe on Windows (\\.\pipe\…).
--app NAMEThe editor's own name, up to 100 characters: Visual Studio Code, Cursor, Zed Preview, Neovim. Tells which installed editor it is, for your default editor.
--version VThe companion's version (letters, digits, ., _, +, -).

Registering again with the same kind and pid replaces the record (a new port after a restart). --companion-gone --pid PID removes every record of that process.

Exit codeOutput
0{"registered":"<the record's path>"}; {"removed":N} for --companion-gone (0 when there was none)
1{"error":"…"}: an option missing, not allowed for the kind, or out of range; the process isn't running; Neovim's socket isn't there

A record whose process has exited is deleted the next time Revue looks; one that doesn't answer (the port or socket refusing, the token refused, no answer in time) is left out, so an editor that crashed never matters. Nothing in a record is ever run: Zed opens through the Zed Revue found installed, given only absolute paths.

What VS Code and Zed answer#

Revue asks over HTTP on http://127.0.0.1:PORT, with the token in an X-Revue-Token header. Listen on 127.0.0.1 only, and answer 401 to a request without the right token (Revue leaves out an editor that answers anything but 2xx). Revue waits 150 ms for the connection, 800 ms for /revue-projects (all editors are asked at once, a second at most) and 3 seconds for /revue-open.

GET /revue-projects answers what the window has open (a VS Code window's extension host is one registration, with its workspace folders):

{
  "app": "Visual Studio Code",
  "version": "0.1.0",
  "projects": [
    {
      "name": "web",
      "path": "/home/me/code/web",
      "focused": true,
      "repos": [
        {
          "root": "/home/me/code/web",
          "branch": "feature/login",
          "head": "1f3c…",
          "remotes": ["[email protected]:acme/web.git"]
        }
      ]
    }
  ]
}

focused says the window has the focus (or had it last); branch is null on a detached head; remotes are the URLs of all the repository's remotes. Every field can be left out; app falls back to --app. It's the shape the JetBrains plugin answers, without ide and product.

GET /revue-open?path=…&repo=…&branch=…&file=…&line=… (VS Code only) opens the pull request: bring forward the window with a repository of repo (owner/name) on branch, or with the folder path (the pull request's worktree or clone) open, at file (relative to the repository, with /) and line (from 1); else open path in a new window. Only path is always there; line only with file. Answer {"opened":"existing"} or {"opened":"new"}, or {"error":"…"} (any status) when it couldn't, and Revue starts your default editor instead.

Zed can't bring a window forward from its extension, so Revue doesn't ask Zed's /revue-open: with the window /revue-projects names (the one whose repository is on the branch, or that has path), it runs zed --existing <root>/<file>:<line>; without one, zed <path> <path>/<file>:<line>, in a new window.

What Neovim answers#

Revue connects to the socket and sends a MessagePack-RPC request, nvim_exec_lua, running your plugin's Lua module revue_companion (one request per connection; notifications Neovim sends in between are skipped). The same timeouts apply.

  • require("revue_companion").projects() returns the table /revue-projects answers: { app = "Neovim", projects = { { path = …, focused = …, repos = { { root = …, branch = …, remotes = { … } } } } } }. An empty table is taken as no projects.
  • require("revue_companion").open({ path = …, repo = …, branch = …, file = …, line = … }) opens it as /revue-open does (keys left out as there; line a number) and returns { opened = "existing" } or { opened = "new" }. To say it couldn't, return { error = "…" } or raise a Lua error.

A terminal program can't bring its own window forward, so Revue then brings forward the window of the program Neovim runs in (its terminal, or Neovide): on macOS the app it runs in, on Linux under X11 with xdotool installed. When it can't (Wayland, Windows, Neovim inside tmux), it says so: Neovim has it open: switch to its window.

Opening a pull request at a file#

revue https://github.com/acme/web/pull/12 --file src/login.rs --line 42
revue acme/web#12 --file src/login.rs

Opens the pull request like any link (in the running Revue if there is one), then, once its files are in, shows PATH (relative to the repository) at line N of its new side. Without --line, the whole file. A line outside the diff's hunks shows the file's unchanged lines around it, and a file the diff doesn't have opens in the Code tab.

The same thing as a link is revue://open?url=<encoded link>&file=<encoded path>&line=<N>. A Revue from before this just opens the pull request.

Writing a comment from an editor#

revue acme/web#12 --file src/login.rs --line 42 --write-comment
revue acme/web#12 --file src/login.rs --start-line 40 --line 42 --side LEFT --write-comment

For an editor that can't ask for a comment's text itself: opens the pull request at those lines, as above, with the comment box open on them and focused, the same box Revue's diff opens when you choose those lines. What you write there is a pending comment, as any written in Revue. Revue comes forward, in the running Revue if there is one.

The lines are given as --comment takes them, on the pull request's head: --line N (from 1) is the line the comment is on or ends on, --start-line M the one it starts on, for several, and --side the old side (LEFT) or the new one (RIGHT, the default). --file and --line are needed; --start-line and --side only go with --write-comment. Otherwise, it prints the error (on stderr) and exits with 1.

A comment goes on lines the diff shows. When they aren't (outside its changes, across two of them, in a file it doesn't change, or while the diff shows only some of the pull request's commits), the file opens at the nearest line it can, without the comment box, and a note says why.

The same thing as a link adds &start_line=<M>&side=LEFT|RIGHT&write=1. A Revue from before editor 10 opens the file at the line, without the comment box.

Your branch's pull request as JSON#

revue --branch-pull                       # the branch checked out here
revue --branch-pull ~/code/web --branch feature/login

Asks the running Revue for the open pull request of the folder's branch, found as --pull-request finds it, and prints it with its changed files as one line of JSON:

{"repo":"acme/web","host":"GitHub","web":"https://github.com/acme/web","branch":"feature/login","me":"alice",
 "pull":{"number":12,"title":"Fix login","url":"https://github.com/acme/web/pull/12","author":"alice",
         "branch":"feature/login","base":"main","draft":false,"updated":"2026-10-20T10:00:00Z",
         "mine":true,"review_requested":false,"reviewed":false,"head_sha":"abc123…"},
 "files":[{"path":"src/a.rs","status":"modified","additions":3,"deletions":1,
           "changes":[{"start":12,"end":14,"kind":"added"},{"start":30,"end":30,"kind":"deleted"}]},
          {"path":"src/b.rs","previous_path":"src/old.rs","status":"renamed","additions":0,"deletions":0}]}
  • pull is null and files is [] when the branch has no open pull request; repo is then the repository its pull requests are looked for in first.
  • pull is the same as a pull request of --pulls, with head_sha, the head commit. Its head_sha, comments, review and checks are the pull request's as of now when the service could be asked; comments then counts as its Conversation tab does (comments, review threads and reviews with a text).
  • A file's status is added, modified, removed or renamed; previous_path is where a renamed file was; additions and deletions count its lines.
  • A file's changes are what the pull request changes in it, by its new version's lines: added and modified lines start to end, and deleted where lines were removed before line start. Missing when the service sent no patch (a binary or very large file).

Exit codes are those of --pulls. A detached HEAD without --branch is an error.

Comments not sent yet#

revue --pending https://github.com/acme/web/pull/12

Prints the pull request's comments that wait to be sent with your next review: Revue's pending comments (drafts, the same as in its tab) and, on GitHub, the comments of the review you started on the website.

{"url":"https://github.com/acme/web/pull/12","head_sha":"abc123…","complete":true,
 "comments":[{"id":"1761…","kind":"draft","path":"src/a.rs","line":42,"start_line":40,"side":"RIGHT",
              "body":"Why?","file_level":false,"created_at":"2026-10-20T10:00:00Z"},
             {"id":"PRRC_…","kind":"pending_review","path":"src/a.rs","line":7,"start_line":null,"side":"RIGHT",
              "body":"Typo","file_level":false,"created_at":"…"}]}
  • kind is draft (Revue's) or pending_review (on the service). side is LEFT (the old side) or RIGHT (the new one). line and start_line are null on a comment on the whole file; start_line is null on one line.
  • head_sha is the pull request's head commit, null when the service can't be reached and Revue knows nothing of it.
  • complete is false when the service couldn't be asked: the review you started there is missing (and head_sha may be old).

Exit codes are those of --pulls.

Adding a comment#

revue --comment acme/web#12 --file src/a.rs --line 42 --body "Why not a constant?"
revue --comment acme/web#12 --file src/a.rs --start-line 40 --line 42 --side RIGHT --body - < note.md

Adds a pending comment to the pull request in the running Revue, on lines of its current head: it goes with your next review, as one you wrote in Revue. When the pull request is open in a tab, it shows there at once.

Option
--file PATHThe file, relative to the repository
--line NThe line it's on (from 1), or ends on
--start-line MThe line it starts on, for several
--side LEFT|RIGHTThe old side or the new one (the default)
--body TEXTThe comment, in Markdown; - reads it from stdin
--in-reviewInto your pending review on GitHub (which stays pending) rather than Revue's drafts; an error when you have none

It prints the comment as --pending lists it:

{"comment":{"id":"1761…","kind":"draft","path":"src/a.rs","line":42,"start_line":null,"side":"RIGHT",
            "body":"Why not a constant?","file_level":false,"created_at":"2026-10-20T10:00:00Z"}}

Exit codes are those of --pulls; an empty body, a line below 1 or a start after the end are errors (1), a pull request you aren't signed in for is 4.

A pull request as JSON#

revue --pull https://github.com/acme/web/pull/12

Prints one pull request, open or not, with what its tabs in Revue show, as the running Revue has it (its tab's when it's open, else the service's, else as last fetched):

{"pull":{"number":12,"title":"Fix login","url":"https://github.com/acme/web/pull/12","author":"alice",
         "branch":"feature/login","base":"main","draft":false,"updated":"2026-10-20T10:00:00Z",
         "mine":true,"review_requested":false,"reviewed":false,"head_sha":"abc123…",
         "comments":4,"review":"changes_requested","checks":"failure"},
 "mergeable":"conflicting","checks_detail":{"passed":5,"failed":1,"pending":0},
 "files":[{"path":"src/a.rs","status":"modified","additions":3,"deletions":1,
           "changes":[{"start":12,"end":14,"kind":"added"}]}],
 "conversation":[{"kind":"comment","id":"IC_…","author":"bob","author_name":"Bob Brown","avatar":"https://…",
                  "created":"2026-10-20T11:00:00Z","body":"Thanks!","replies":[]},
                 {"kind":"review","id":"PRR_…","author":"carol","avatar":"https://…","created":"2026-10-21T10:00:00Z",
                  "body":"A few things","state":"changes_requested","replies":[]},
                 {"kind":"thread","id":"PRRT_…","author":"carol","avatar":"https://…","created":"2026-10-21T09:59:00Z",
                  "body":"Why?","path":"src/a.rs","line":42,"resolved":false,"outdated":false,
                  "replies":[{"author":"alice","avatar":"https://…","created":"2026-10-22T08:00:00Z","body":"Because"}]}],
 "commits":[{"sha":"abc123…","title":"Fix login","author":"alice","author_name":"Alice Smith",
             "avatar":"https://…","date":"2026-10-20T09:00:00Z","checks":"failure"}],
 "slack":[{"channel":"web","text":"@Ann please look at #12","author":"Bob Brown",
           "url":"https://acme.slack.com/archives/C1/p1761…","app_link":"slack://channel?team=T1&id=C1&message=1761…",
           "replies":3,"last":"2026-10-21T08:00:00+00:00"}],
 "slack_complete":true,
 "slack_tickets":[{"ticket":"WEB-42","threads":[{"channel":"support","text":"WEB-42 is back","author":"Ann",
                   "url":"https://acme.slack.com/archives/C2/p1761…","app_link":"slack://channel?team=T1&id=C2&message=1761…",
                   "replies":0,"last":"2026-10-21T07:00:00+00:00"}]}],
 "slack_tickets_complete":true,
 "stack":[{"number":11,"title":"Login API","url":"https://github.com/acme/web/pull/11","branch":"login-api",
           "base":"main","state":"merged","current":false},
          {"number":12,"title":"Fix login","url":"https://github.com/acme/web/pull/12","branch":"feature/login",
           "base":"login-api","state":"open","current":true}],
 "stack_complete":true}
  • pull is the same as --branch-pull's, its comments counted as its Conversation tab counts them.
  • mergeable is mergeable, conflicting (it conflicts with its base branch) or unknown (the service hasn't worked it out, or doesn't say: Forgejo says only when it conflicts).
  • checks_detail counts its head commit's checks by how their latest runs came out, as its Checks tab does; skipped and neutral ones are in none.
  • files are its changed files, as --branch-pull lists them.
  • conversation is its Conversation tab, oldest first: comments, reviews (their summary, with state approved, changes_requested, commented or dismissed) and review threads (their first comment, its path and line, line missing on a comment on the whole file; whether it's resolved and outdated; then its replies). A review's inline comments are its threads, right after it. Bodies are the service's Markdown; author_name and avatar are missing where there are none.
  • commits is its Commits tab, oldest first: each one's first line (title), its author's login (else the name in the commit) and name as the tab shows it, and how its checks came out (checks, missing without checks).
  • slack is its Slack threads tab, newest first: each thread by its newest message that links the pull request (text in plain text, who wrote it, a link to it, its slack:// link for --open-slack, the thread's replies and when it was written). [] without Slack. When its tab hasn't found them yet, Revue waits a few seconds at most; slack_complete is false when Slack didn't answer by then, or failed (never an error).
  • slack_tickets is the tab's Jira ticket mentioned part: for each Jira ticket the pull request names (its title, branch, commits and description; only the connected Jira sites' projects when there are some; ten at most), the Slack threads that mention it, newest first, as slack lists them. A thread slack lists already isn't listed again, and a ticket with no threads is left out. slack_tickets_complete is false when Slack didn't answer in a few seconds, as with slack.
  • stack is its PR stack tab, bottom first, current the pull request asked about; state is open, draft, merged or closed. Missing when it's in no stack. As with Slack, stack_complete is false when it couldn't be looked for in a few seconds.

Exit codes are those of --pulls; a pull request you aren't signed in for is 4.

Opening a Slack thread#

revue --open-slack 'slack://channel?team=T1&id=C1&message=1761…' --web https://acme.slack.com/archives/C1/p1761…

Opens a Slack thread of --pull's slack (its app_link, and its url after --web) as Open in Slack does in Revue: in Slack's app or the browser, as Settings → Apps → Slack says (see Slack). It works in the revue command itself: no running Revue is needed.

The Slack app is started by Revue; the browser is left to the editor, which gets the page to open:

AnswerMeaning
{"opened":"app"}Opened in the Slack app.
{"opened":"browser","url":"…"}Open url in the browser: chosen in Settings, or no Slack app was found.
{"opened":"browser","url":"…","app_error":"…"}The Slack app didn't start (app_error says why): open url instead.

Exit code 1 with {"error":…} for a link that isn't a Slack thread's. It reads only this computer's settings: no sign-in is needed, and --headless changes nothing.

Starring a pull request#

revue --favorite https://github.com/acme/web/pull/12          # star it
revue --favorite https://github.com/acme/web/pull/12 --off    # unstar it

Adds the pull request to your favorites, or takes it out, as its star in Revue does: the list, its header and your other computers (through settings sync) follow. Answers {"favorite":true} or {"favorite":false}, what it is now. It asks the running Revue, which keeps the favorites (with --headless and none running, the settings file); exit codes are those of --pulls.

A pull request's worktree#

revue --worktree https://github.com/acme/web/pull/12 --dir ~/code/web

Gives the pull request's worktree in the clone CLONE (the current folder if left out), as its tab's Create worktree does: the one there is (the one Revue made for it, else one with its branch or its head checked out), else a new one beside the clone (~/code/web-feature-login), on a local branch of the pull request's branch name (pr-<n> for a fork's branch with the base branch's name). A local branch of that name that's only behind is brought to the pull request's head first.

{"path":"/home/alice/code/web-feature-login","branch":"feature/login","created":true}
  • created is false for a worktree that was there; its branch is null when it has the pull request's head checked out without a branch.
  • When the clone's branch of that name has commits the pull request doesn't, nothing is made, and the error says so ({"error":"feature/login in your clone has 1 commit that isn't in the pull request."}): open the pull request in Revue to choose what happens to them.

Exit codes are those of --pulls; a folder that isn't a clone of the pull request's repository is an error (1).

A changed file's two sides#

revue --sides https://github.com/acme/web/pull/12 --file src/login.rs

Prints a file the pull request changes (PATH as it names it: the new one when renamed) as it was before and as it is at the pull request's head, for an editor to show in its own diff viewer. It doesn't need the branch checked out.

{"url":"https://github.com/acme/web/pull/12","head_sha":"abc123…",
 "file":{"path":"src/login.rs","status":"modified","additions":3,"deletions":1,
         "changes":[{"start":40,"end":42,"kind":"modified"}]},
 "base":"fn login() {\n…","head":"fn login() {\n…"}
  • file is the file as --branch-pull lists it.
  • head is the file at head_sha; null for a file the pull request removes.
  • base is the file before the pull request, as its diff in Revue shows it (from the head and the service's diff, so the two always line up); null for a file it adds. Its lines end as the file's do (\r\n or \n); the last one has none only when the file had none.

Exit codes are those of --pulls. A file the pull request doesn't change, one the service has no diff of (binary or too large) and a head pushed to while answering are errors (1).

Reviewing from an editor#

What an editor needs to review a pull request the way Revue does: comment, edit and take back what you haven't sent, reply in conversations, react to comments, mark files viewed, and submit the review. Comments not sent yet are both Revue's drafts and your pending review on GitHub, as in Revue; whatever changes here shows in the open Revue at once, and the other way round the next time the editor asks.

revue --review https://github.com/acme/web/pull/12
revue --edit-comment acme/web#12 --id 1761234567890 --body "Why not a constant?"
revue --delete-comment acme/web#12 --id PRRC_kwDOA…
revue --reply acme/web#12 --thread PRRT_kwDOA… --body - < reply.md
revue --resolve acme/web#12 --thread PRRT_kwDOA…
revue --viewed acme/web#12 --file src/a.rs
revue --react acme/web#12 --comment PRRC_kwDOA… --reaction +1
revue --submit-options acme/web#12
revue --submit acme/web#12 --event APPROVE --body "Looks good" --resolve-mine \
  --slack-thread T01/C02/1761000000.000100 --slack-tag U03

--review prints what a review of it shows:

{"url":"https://github.com/acme/web/pull/12","head_sha":"abc123…","me":"alice","own":false,
 "summary":"","files":[{"path":"src/a.rs","status":"modified","additions":3,"deletions":1,"changes":[…],"viewed":true},…],
 "threads":[{"id":"PRRT_…","path":"src/a.rs","line":42,"start_line":40,"side":"RIGHT",
             "file_level":false,"outdated":false,"resolved":false,"can_reply":true,"can_resolve":true,
             "comments":[{"id":"PRRC_…","author":"bob","created":"2026-11-10T09:00:00Z","body":"Hm?","pending":false,
                         "reactions":[{"content":"+1","count":2,"mine":true}]}]}],
 "pending":[…],"pending_review":false,
 "choices":[{"event":"COMMENT","label":"Comment","enabled":true},
            {"event":"REQUEST_CHANGES","label":"Request changes","enabled":false,"why":"Write a summary or add a comment on the code: …"},
            {"event":"APPROVE","label":"Approve","enabled":true}],
 "complete":true,
 "mentionable":[{"login":"bob","name":"Bob Ross","avatar":"https://…"},…]}
  • files are its changed files as --branch-pull lists them, each with viewed: whether it's marked viewed, as the Files tab shows it (see --viewed below). pending are its comments not sent yet as --pending lists them.
  • A thread's line is of the head on the RIGHT side, of the base on the LEFT one; null on the whole file (file_level) or when its lines are gone (outdated). A comment's pending says it's in your pending review.
  • A comment's reactions are those Revue's conversation shows under it, in the service's order, each kind someone reacted with: content is +1, -1, laugh, hooray, confused, heart, rocket or eyes, count how many reacted so, mine whether you're one of them; [] when nobody has. Left out where the service has no reactions (Bitbucket), so Revue can't tell.
  • mentionable is who a comment can @-mention, as Revue's @ list suggests them: the pull request's people first (its author, the reviewers asked and who reviewed, who commented, who it's assigned to), then the others who can review in the repository; never you. name and avatar may be missing. On Bitbucket, which mentions accounts rather than nicknames, each has a mention to write instead of @login (@{account_id}), and only those it can mention are listed. Who can review is asked of the service once and kept, as for Revue's own @ list; when it can't be asked, the list holds the pull request's people only.
  • own: you wrote it, so you can't approve it or request changes. summary is the review's summary written in Revue, not sent yet; pending_review that you have a pending review on GitHub.
  • choices are the Submit review dialog's buttons, in its order: what --submit --event takes, whether it can be used now, and why not.

--edit-comment and --delete-comment take a pending comment's id: a draft of Revue's, or a comment in your pending review on GitHub. They answer {"comment":…} (as --pending lists it) and {"deleted":true}. --reply answers {"in_pending_review":true} when the reply went into your pending review on GitHub (as in Revue: published when you submit it).

--resolve resolves a conversation (--off: opens it again), as its Resolve button in Revue does; it answers {"resolved":true}.

--react adds your reaction to a comment (--off: takes it back), as Revue's conversation does: --comment is a comment's id in --review's threads (a comment of the pull request's conversation works too), --reaction one of the contents above. It answers {"reacted":true} (false with --off), and the pull request's open tab shows it. Bitbucket has no reactions, so there it's an error, as is a comment the pull request doesn't have.

--viewed marks a file of the pull request viewed (--off: not viewed), as the Files tab's checkbox does on All changes, and answers {"viewed":true}. The marks are the same as Revue's: synced with GitHub's own Viewed checkboxes, kept by Revue for Bitbucket and Forgejo (see Viewed files). A mark counts while the file's diff is the one it was made on, so a file changed since shows not viewed again. A path the pull request doesn't change is an error.

--submit-options prints what Revue's Submit review dialog shows before it goes:

{"choices":[…],"own":false,"summary":"","drafts":[…],"pending_review_comments":null,
 "stranded":["login.rs:40–42"],"resolvable":2,"others_open":["bob"],
 "slack":{"on":true,"complete":true,"threads":[{"id":"T01/C02/1761000000.000100","channel":"reviews",
          "private":false,"text":"Up for review…","author":"ann","url":"https://acme.slack.com/archives/…"}],
          "picked":"T01/C02/1761000000.000100","author":"alice","author_name":"Alice Smith",
          "who":"certain","tags":[{"id":"U03","name":"Alice"}],"members":[],
          "replies":{"APPROVE":"<@U03> I approved your pull request …","COMMENT":"…","REQUEST_CHANGES":"…"}}}
  • stranded are the drafts whose lines changed since you wrote them: they go on their whole file, quoting their old lines.
  • resolvable is how many open conversations you started and may resolve (--resolve-mine resolves them after an approval), others_open who started the rest (they stay open).
  • slack is its Notify in Slack part (null without Slack): the threads that link to the pull request, the one picked (last time's, or the only one), who to tag (who: certain from the People list or their email, picked as asked, none for no mention, unsure: pick from members, the channel's people likeliest first), and each verdict's reply as Settings → Slack messages formats it. on is last time's choice for this pull request.

The Slack part is picked with the same options as --submit's, and the replies follow:

OptionWhat
--slack-thread IDReply in that thread (a threads id)
--slack-tag USERTag that Slack user (repeat for more); without it, the author found
--slack-no-mentionName the author in plain text instead
--slack-text TEXTThe reply as written by hand, instead of as formatted
--slack-rememberRemember who was tagged as the author (the People list)
--slack-offNo reply, and unticked for next time

--submit sends the review with its verdict, your drafts and pending review in it, as Revue's Submit review does: the same checks (nothing to send, requesting changes without saying what, your own pull request, a Slack reply with no thread or nobody to tag), #channels linked to Slack, and the drafts sent leaving Revue. With --resolve-mine, an approval then resolves your open conversations; with --slack-thread, the reply goes to Slack with its files, as Notify in Slack posts it. It answers:

{"event":"APPROVE","comments":2,"moved_to_file":0,"in_pending_review":false,"resolved":2,
 "slack":{"posted":true,"link":"https://acme.slack.com/archives/…"}}

comments is how many drafts went with it, moved_to_file how many of them went on their file as their lines changed since, resolved how many conversations were resolved (resolve_errors: those that couldn't be). slack says whether the reply went (error when it didn't: the review is in all the same). When Bitbucket stops part-way, the error says how many went; the rest stay drafts.

Exit codes are those of --pulls.

A pull request's branch, fetched#

revue --fetch-branch https://github.com/acme/web/pull/12 --dir ~/code/web

Makes the clone's local branch of the pull request (named as --worktree names it) point at the pull request's head, fetched as --worktree fetches it, without checking anything out: the editor checks it out itself.

  • A new branch tracks the remote's (origin/feature/login) when the pull request's branch is in the repository itself; a fork's is made at the pull request's head, fetched from where the service keeps it, and tracks nothing.
  • A branch that's there and only behind is fast-forwarded. One with commits the pull request doesn't have is left as it is, and the error says so, as with --worktree.
  • A branch checked out somewhere (the clone itself or one of its worktrees) is never moved: git won't. When it lacks some of the pull request's commits, checked_out_in says where it's checked out, to pull there.
{"branch":"feature/login","remote_branch":"origin/feature/login","created":true,"updated":false,"checked_out_in":null}

remote_branch is the remote branch it tracks (null: none), created that it was made now, updated that it was moved to the pull request's head. Exit codes are those of --pulls.

Your Revue account#

revue --account

Prints whether this computer is signed in to your Revue account, and every sign-in Revue has here, as one line of JSON:

{"signed_in":true,"email":"[email protected]","server":"https://revue.cleangame.dev","device":"alice-laptop",
 "sign_ins":[{"service":"github","account":"alice","where":"account"},
             {"service":"forgejo","account":"[email protected]","where":"computer"}]}
  • email and device (this computer's name in the account) are null when you aren't signed in; server is then the account server a sign-in would use (null: none).
  • A sign-in's service is github, bitbucket, forgejo, jira, slack or slack-app, and account who it is, as Settings shows it. where is account for one kept In your Revue account, and computer for one on This computer only. Sign-ins from the gh CLI or GITHUB_TOKEN aren't listed.
  • No token or other secret is ever printed.

The running Revue answers; with none running, the revue command answers by itself, as with --headless (which it doesn't need). Exit code 0 with the answer, 1 with {"error":…}.

Signing in to your Revue account#

revue --account-sign-in
revue --account-sign-in --server https://accounts.example.com --device "Work laptop"

Signs this computer in to your Revue account as Sign in with browser does (see Revue account): your browser opens the account server's page, where you approve this computer with your password. Revue never sees the password.

  1. It prints the page's address first, {"url":"https://…/account/approve?ticket=…"}, and opens it in your browser. An editor can show it, to open it again.
  2. Once you approve it, it prints the account as --account does, and exits with 0.
  • --server is the account server (if left out, this computer's, else the built-in one). One given is kept as this computer's account server, as under Advanced in Settings.
  • --device is this computer's name in the account's list of computers (if left out, the host name).
  • The sign-in is kept where Revue keeps it: Revue opens signed in, as the same computer.
  • It waits for the browser for up to 10 minutes. To cancel, end the process.
  • While Revue is running, it doesn't sign in: it prints {"error":"Revue is running: sign in to your Revue account there, in Settings.","app_running":true}. The same when Revue starts while the browser is open.
  • Saving the sign-in waits for a --headless answer to finish, and a Revue starting up waits for it.
Exit codeOutput
0{"url":…}, then the account, signed in
1{"error":…} (after {"url":…} once the page was there): cancelled on the page, not approved within 10 minutes, Revue running ("app_running":true), the server refused or couldn't be reached

Trying Revue without changing anything#

--immutable starts Revue on a temporary copy of your settings and data. Use it to try a new build, a setting or a risky action without any of it sticking.

revue --immutable

The terminal says where the copy is, for example revue: --immutable, on a copy in /tmp/revue-immutable-12345. When Revue quits, the copy is deleted.

With a Revue account, sign-ins added, moved or signed out of stay in the trial run, while renewed tokens still reach the account (the service no longer takes the old ones). Creating, signing in to or out of the account and its security changes aren't available.

Exactly what --immutable does

What's copied when it starts:

WhatHow
The config folder (settings, sign-ins without their tokens, drafts, themes)Copied whole
The data and cache foldersOnly the files directly inside them (this computer's settings, what it found out). Their subfolders start empty: downloaded language servers, saved API responses, avatars, source checkouts.
The running Revue's instance-port fileNot copied, so this Revue stays apart from the one already running
Tokens (the file or the system credential store)Read once into memory. Changes stay in memory.

While it runs:

  • Automatic updates are off, and Update to … doesn't appear. Checking for updates still works.
  • Register as handler and Unregister (for revue:// links, in Settings → Apps) are refused with "not with --immutable".
  • Links given on the command line open in this window, never in the Revue that's already running.
  • One thing is saved for real: when an OAuth sign-in (Bitbucket, Jira, Forgejo, Slack) renews its token, the new one goes into your real files too. The service no longer accepts the old one, so throwing it away would sign your normal Revue out.
  • Language servers you use start downloading again, into the copy.

When it ends:

  • The copy is deleted on quit, however Revue quits (the Quit action or closing the last window).
  • If Revue can't make the copy, it prints revue: --immutable: couldn't copy the settings and data: … and exits with code 1.
  • The copy lives in the system temporary folder, in a folder readable only by you on Linux and macOS.

Checking the GitHub connection#

--probe is a quick diagnostic for GitHub. It doesn't open a window.

revue --probe
revue --probe https://github.com/acme/web/pull/12

It prints, to the terminal:

  1. where the token came from;
  2. how long your pull request list took, and how many pull requests are in each part of it;
  3. for one pull request (the link you gave, or the first one in your list): load time, and counts of commits, threads, reviews, comments, files and force pushes;
  4. any file whose diff Revue can't parse (PARSE FAIL …);
  5. a compare between the first commit and the head, when there are at least two commits;
  6. the rate-limit numbers GitHub reported.
Advanced: --probe details
  • It uses the same token Revue would: REVUE_GITHUB_TOKEN if set; else, with Also sign in with the gh CLI or GITHUB_TOKEN / GH_TOKEN on, GITHUB_TOKEN, GH_TOKEN or the gh CLI; else your first GitHub sign-in in Revue.
  • Without any GitHub token it prints probe failed: no token.
  • Only GitHub is probed: a Bitbucket or Forgejo link doesn't work here.
  • Diff parsing is checked for the first 200 files.

Exit codes#

CodeWhen
0Normal quit, --version, a successful --probe, an editor's question answered (--pulls, --branch-pull, --pending, --comment, --pull, --worktree, --fetch-branch, --favorite, --open-slack, --account), --account-sign-in signed in, --companion recorded or --companion-gone done, or links handed to the running Revue
1--probe failed (probe failed: …), --immutable couldn't make its copy, an editor's question answered with an error, --account-sign-in not signed in, --companion refused, or --write-comment without the lines it needs
3An editor's question without --headless: no Revue is running
4An editor's question: you aren't signed in for the repository or pull request ("sign_in":true)

Environment variables#

Revue reads a few environment variables when it starts. You don't need any of them for normal use.

Accounts and tokens#

VariableWhat it doesDefault
REVUE_GITHUB_TOKENA GitHub token used alone, instead of every other GitHub sign-in. For scripts and testing.Not set
GITHUB_TOKEN, GH_TOKENUsed as a GitHub sign-in, but only when Also sign in with the gh CLI or GITHUB_TOKEN / GH_TOKEN is on (Settings → Accounts). GITHUB_TOKEN is tried first, then GH_TOKEN, then gh auth token.Not used
More about GitHub tokens
  • With REVUE_GITHUB_TOKEN set (and not blank), Revue's own GitHub sign-ins and the system ones are all ignored. The account shows via REVUE_GITHUB_TOKEN in Settings → Accounts and has no Sign out button.
  • Tokens from GITHUB_TOKEN, GH_TOKEN or gh show via environment or via gh CLI. Stop using turns the switch off; your gh login itself is left alone.

OAuth apps for "Sign in with …"#

The Sign in with … buttons need an OAuth app registered on each service. Official releases come with them built in. If you build Revue yourself, or want to use your own apps, set these. A service without one only offers token sign-in.

VariableFor
REVUE_GITHUB_CLIENT_IDSign in with GitHub (an OAuth app with Device Flow enabled)
REVUE_GITHUB_CLIENT_SECRETRenewing GitHub sign-ins made on the web account, which revue-server makes with the same app
REVUE_BITBUCKET_CLIENT_ID, REVUE_BITBUCKET_CLIENT_SECRETSign in with Bitbucket (both are needed)
REVUE_JIRA_CLIENT_ID, REVUE_JIRA_CLIENT_SECRETSign in with Atlassian for Jira (both are needed)
REVUE_FORGEJO_CLIENT_IDSSign in with browser on Forgejo, Codeberg and Gitea servers, one app per server
REVUE_SLACK_CLIENT_IDSign in with Slack
REVUE_SLACK_CLIENT_SECRETOnly for a Slack app without PKCE
REVUE_SLACK_REDIRECT_URLOnly for a Slack app without PKCE: an HTTPS page that forwards to Revue
Formats, callback addresses and build time vs run time

Run time or build time. Each of these is read from the environment when Revue starts. If it isn't set there (or is empty), Revue uses the value it was built with, if any. So you can override a release's built-in app without rebuilding.

Callback addresses to register with each service:

ServiceCallback / redirect URL
Bitbucket, Jira (Atlassian)http://localhost:47392/callback
Forgejo, Codeberg, Giteahttp://127.0.0.1:47392/callback (a public client: "Confidential client" unticked)
Slack (PKCE app)http://localhost:47392/callback
GitHubnone: it uses the device flow (you type a code on github.com)

REVUE_FORGEJO_CLIENT_IDS lists server=client id pairs, separated by commas (semicolons and new lines work too):

REVUE_FORGEJO_CLIENT_IDS="https://codeberg.org=1a2b…,https://git.example.com=3c4d…"

A server that isn't listed asks for a client ID on the sign-in form (OAuth app client ID on this server).

REVUE_SLACK_REDIRECT_URL: Slack only lets PKCE apps come back to http://localhost. An app without PKCE needs its secret and an HTTPS page that forwards the browser to http://localhost:47392/callback. Without this variable, Revue uses the loopback address. Setup is in Slack.

The step-by-step guide to registering each app is OAuth setup. A template with every variable is .env.example.

Revue's server and image uploads#

VariableWhat it doesDefault
REVUE_SERVER_URLThe revue-server that stores images pasted into comments, and hosts the pages behind Copy Revue link and Slack's Revue linkshttps://revue.cleangame.dev (built in)
REVUE_IMAGES_TOKENThe upload token for that server. Without it, image upload is off.Built into official releases

Both are read at run time first, then at build time. Point them at your own server to keep images in-house: see Self-hosting revue-server.

Error reports#

VariableWhat it doesDefault
REVUE_SENTRY_DSNWhere crash and error reports go. Set it to an empty value to turn reports off.Official releases: Revue's own error tracker. Other builds: off.
More about REVUE_SENTRY_DSN
  • Set at run time, it wins over everything: empty turns reporting off, any other value sends reports there, even from a build that wouldn't report otherwise.
  • Not set at run time: only official release builds report (they're built with REVUE_RELEASE set), to the address built into them.
  • An address Revue can't parse prints REVUE_SENTRY_DSN: … to the terminal, and nothing is reported.
  • What's in a report: Privacy and security.

Language#

Revue's Language setting has a System choice. "System" first follows the usual locale variables, the way gettext does:

VariableUsed
LANGUAGEA list like cs:en. The first language Revue has wins. Ignored when the locale is C or POSIX.
LC_ALL, LC_MESSAGES, LANGThe first one set is the locale.

If none of them is set to a language Revue has, macOS and Windows fall back to the system's own language settings (apps started from the desktop usually have no locale variables there). Otherwise Revue is in English. Revue currently has English and Czech. See Themes, fonts, focus mode and languages.

Finding your apps, shell and folders#

Revue uses these to find your editor, terminal and shell, and where things are on disk. They're the standard ones your system already sets.

VariableUsed for
TERMINALThe default terminal on Linux, if you haven't picked one (KDE's configured terminal is used too)
SHELLThe shell commands run in. When it's missing (started from a desktop launcher), your account's login shell, else /bin/sh.
USER, LOGNAMEYour user name, to look up your login shell
PATH, PATHEXTFinding programs (editors, language servers, git, gh)
XDG_CONFIG_HOMEWhere the config folder is ($XDG_CONFIG_HOME/revue instead of ~/.config/revue), on every OS. Must be an absolute path.
XDG_DATA_HOME, XDG_CACHE_HOMELinux: where the data and cache folders are
XDG_DATA_DIRSLinux: where installed apps' desktop entries are
LOCALAPPDATA, ProgramFiles, ProgramW6432, ProgramFiles(x86), SCOOP, SCOOP_GLOBALWindows: where installed apps are
APPIMAGELinux: when Revue runs as an AppImage, the revue:// handler points to the AppImage file rather than its temporary mount
DBUS_SESSION_BUS_ADDRESS, XDG_RUNTIME_DIRLinux: whether there's a desktop session to reach the Secret Service. Without one, Revue doesn't wait for it.
TMPDIR (Linux, macOS), TEMP / TMP (Windows)Where --immutable makes its copy

The folders themselves are listed in Files, sync and settings for one computer and Privacy and security.

For testing and development#

These point Revue at mock servers in automated tests. Leave them unset.

VariableDefault
REVUE_API_BASEhttps://api.github.com
REVUE_BITBUCKET_API_BASEhttps://api.bitbucket.org/2.0
REVUE_SLACK_API_BASEhttps://slack.com/api
Build-time only variables

These matter only when building Revue from source (Building from source and contributing):

  • Every variable in the project's global.env (REVUE_SENTRY_DSN, REVUE_SERVER_URL) is compiled in. A variable of the same name in the build's environment wins; an empty one leaves it out.
  • The OAuth variables, REVUE_IMAGES_TOKEN and REVUE_SENTRY_DSN are also compiled in when they're set during the build. task dev loads them from an untracked .env file.
  • REVUE_RELEASE: set by the release workflow. Only builds made with it send error reports by default.
  • REVUE_THEME_SRC: used by a maintainer task that regenerates the built-in code themes.

There's no RUST_LOG or other log-level variable: Revue doesn't use a logging framework. See Troubleshooting and FAQ for where its messages go.