Docs

desk

desk makes PR reviews the same every time, for people and for AI agents. It works in any repository, with any language and build tool.

It has three parts:

  1. A CLI (desk). It does the mechanical steps: the size and scope gates, the review packet, the report, the post to GitHub.
  2. Skills, agents, an MCP server and a hook for your AI client. They tell the AI when to call the CLI.
  3. The repository's own rules in .desk/. desk init writes them.

Quick start

  1. Install the kit on your machine (one time). See Install.
  2. Set up the repository (one time for each repository). See Set up a repository.
  3. Start a new session of your AI client in the repository, and ask for what you want. See Use it.

Decisions

desk decisions serves a page of the questions that wait for the owner. Each option shows its pros, its cons and what it changes, and an answer goes back to the issue as a comment. See docs/decisions.md.

Requirements

A review checks a change against the owner's own words: the owner's prompts, the linked issues, the specs and a register of standing requests. A quote in a PR that no prompt holds refuses the PR, and a change that no word of the owner asks for blocks it. See docs/requirements.md.

A review also gives a verdict with proof for each guideline of the owner: scalability, modularity and code quality. A guideline with no verdict makes the review incomplete, and a verdict with no file and line is a finding. See docs/guidelines.md.

Install

You need git with SSH access to munhq/desk. Use one of these commands:

You have Run
Node.js 20 or later npx -y github:munhq/desk
Node.js 20 or later, and npx fails git clone --depth 1 git@github.com:munhq/desk.git /tmp/desk && /tmp/desk/install.sh
No Node.js, and gh is logged in See The single binary

Each command does two things:

  1. It installs the desk CLI. If the CLI folder is not on PATH, the command tells you the line to add to your shell profile.
  2. It runs desk install. This command finds each AI client on the machine and installs the kit into it.

What each client gets:

Client Skills Reviewer agents MCP server PR and issue hook
Claude Code (each config folder) yes yes yes yes
Codex yes yes yes yes (approve it once with /hooks)
OpenCode reads the Claude Code and Codex skills yes yes —
Cursor yes yes yes yes
Antigravity yes — yes yes
Hermes yes — yes yes (approve it once at the next start)
Gemini CLI (paths from docs, not tested) yes — yes —
Kilo (paths from docs, not tested) reads the Claude Code and Codex skills — yes —

docs/clients.md gives the paths for each client.

Check the install: run desk doctor. It shows one line for each client, with the skills version.

Connect an AI client to a desk server (one time, no install): an admin of an org adds your email on the page /orgs/<org>, and you set your password from the one-time link. Then connect your AI client to https://<server>/mcp:

  • Claude Code:
    1. Run claude mcp add --transport http --scope user desk-server https://desk.example.com/mcp.
    2. Start Claude Code, type /mcp, pick desk-server and choose Authenticate.
    3. Sign in to desk in the browser that opens, and click Allow on the consent page.
  • claude.ai:
    1. Open Settings → Connectors → Add custom connector.
    2. Enter the name desk-server and the URL https://desk.example.com/mcp, then click Connect.
    3. Sign in to desk and click Allow.

The name desk-server keeps it apart from desk, the local MCP server that desk install adds. The client stays signed in. Each call runs as you, with the rights of your org role, through the 28 desk_* tools: the repositories, files, search, blame, diff, landings, desk_land_change, proposals, issues, decisions, releases and runs (docs/ui.md).

Work on a repository in a folder on your machine: install desk, log in once, then check out by name.

desk login            # https://desk.munhq.com: shows a code and opens the browser; approve it there
desk checkout houseking               # the files of main in ./houseking

You need an account in the UI of the server first: an admin of an org adds your email on the page /orgs/<org> and gives you a one-time link to set your password. A member of an org works on every repository of the org. desk login then gets a token for you after you approve the code in the browser. With no address it signs in to https://desk.munhq.com, the server of the fleet; DESK_SERVER or desk login <server> names another one. The token goes to sealkeep when it is installed, else to ~/.config/desk/token, which only you can read. desk login also writes ~/.config/desk/login.json (the server and where the token is). For an agent with no browser, desk login --token-stdin reads a token that the owner made with identity add (docs/server.md).

Options: desk install --dry-run shows the plan and changes nothing. --client claude,hermes installs into the named clients only. --no-hooks, --no-mcp and --no-agents leave out a part. Before the kit changes a client config file, it writes a backup (<file>.bak-<time>).

Update: run desk update. It gets the newest release of your desk server and installs it again into each client; --no-server reads the GitHub release instead.

The single binary

The binary needs no Node.js. gh downloads it from the release:

gh release download --repo munhq/desk \
  --pattern "desk-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" --output /tmp/desk \
  && chmod +x /tmp/desk && /tmp/desk install

The binary copies itself to ~/.local/bin/desk (set DESK_BIN_DIR to use a different folder). Binaries are available for Linux (x86_64, aarch64) and macOS (x86_64, arm64).

Set up a repository

Run this one time in each repository, on a branch:

cd your-repository
desk init

You can also ask your AI client: "set up desk for this repo". The desk-setup skill runs init and then adds the parts that need judgment: the units, the boundaries between components and the rules from the review history.

init detects the units, the test commands, the context files (AGENTS.md, CLAUDE.md), the GitHub name and the rule packs. It writes these files:

Path What it is
.desk/config.json Base branch, size limits, generated files, pattern checks, validation commands, review settings, PR types
.desk/REVIEW.md The review contract: load order, severity, limits, the "do not post" list, the areas for people only
.desk/rules/*.md The rules. Each file starts with paths: ['src/**']. A review loads each file whose globs match a changed path.
.desk/profiles/*.md The review profiles: full, security, architecture, smart-contract, devops, reliability
.github/pull_request_template.md The PR body format
.github/ISSUE_TEMPLATE/task.yml, config.yml The issue form with required fields. Blank issues are off.
.github/workflows/desk.yml The CI check for PRs and issues
.github/workflows/desk-ai.yml The AI review of each PR, with an OpenRouter model

Then do these steps:

  1. Set validation in .desk/config.json to the repository's own commands. A command with paths runs only when the change touches those paths:

    "validation": [
      { "name": "lint", "command": "make lint" },
      { "name": "api", "command": "go test ./api/...", "paths": ["api/**"] }
    ]
    

    On a desk server, each landing runs these commands as checks on the runners (docs/runs.md). A runner starts from a fresh checkout, so setup names what the command needs first, for example "setup": "npm ci"; desk validate in a work folder skips it. cwd is a folder of the repository. checkouts (for example [{"repo": "owner/lib", "path": "../lib"}]) names other repositories of the server that a check reads next to the checkout.

  2. Optional: add rules from published guidance with desk packs add <name>. See docs/packs.md.

  3. Optional: add rules from the repository's own review history with desk learn fetch, then desk learn extract --engine <client>.

  4. Commit the files, and open a PR for the setup.

  5. In the branch rules of the default branch, make desk / pr a required check. See docs/enforcement.md.

Use it

Start a new session of your AI client in the repository. A session that started before the install does not have the skills. Then ask in your own words:

You say Skill What happens
"use desk and continue the work", "what is open?", "what should I do next?" desk-continue Reads the project state (desk state) and, when the chat-recall tools exist, the past sessions. Continues the first open item in the worktree or the PR that already holds it.
"ready for review", "is this ready?" pr-preflight Runs the gates, the pattern checks and the tests. Does a self-review: you fix each finding or keep it with a reason, and the kept ones go into the PR body. Proposes a split if the PR is too large. Drafts the PR body.
"open the PR", "fix the PR description" pr-describe Writes the title and the body in the repository's format, then opens or updates the PR.
"review PR 123" pr-review Reviews with the full profile and writes the review document (report.md). Then it asks you about each finding (accept, accept as nit, reject), four at a time, with the exact comment text. At the end you choose: post as a review, post as one comment, keep the document, or discuss first. It posts only after you agree to the preview.
"review PR 123 with all relevant profiles" pr-review Starts one reviewer agent for full and one for each profile that matches the changed paths. Then it verifies each blocker and important finding.
"review PR 123 as a smart contract auditor" pr-review Reviews with one profile: security, architecture, smart-contract, devops or reliability.
"audit PR 123" pr-audit A security audit with the security profile. For a contract change, it also uses the smart-contract profile.
"post the review" pr-review Shows each finding in the chat for your decision (accept, reject with a reason, or edit). Then it shows the exact text and posts only the accepted findings, as one GitHub review with inline comments, when you agree.
"address the approved comments on PR 123" pr-address Fixes only the comments that the PR author approved, runs the validation, pushes one commit for each fix and replies on each thread.

The human gate: a review writes findings; it never posts them. A person decides each finding, in the chat or in a terminal. desk gate gives the next questions as data, and each AI client asks them with its own question prompt (in Claude Code, a choice with the comment as the preview); desk decide records the answers. post sends only the accepted findings, and it refuses while one is open. The decisions stay in decisions.json in the run folder, with the name of the person and the reason for each rejection.

How the PR author approves a comment: reply 👍 or /fix to approve it. Reply 👎 or /dismiss <reason> to reject it.

The PR and issue hook: when an agent runs gh pr create, gh pr edit --body, gh issue create or gh issue edit, the hook checks the title and the body. If the format is wrong, the hook refuses the command and tells the agent how to fix it.

The AI review in GitHub Actions: desk init writes .github/workflows/desk-ai.yml. Add the repository secret OPENROUTER_API_KEY and the repository variable DESK_MODEL (an OpenRouter model id). On each ready PR, a judge model (Jev) first rates the risk and the profiles that the PR needs; by default it runs in shadow mode and changes nothing (docs/enforcement.md). Then OpenCode reviewers review the change with the all profiles and a verification pass. They can read the files of a read-only checkout of the PR, and they have no shell. If the OpenCode run fails, the job reviews the diff only. The job posts one GitHub review: a numbered line for each finding (at most 150 characters, with a link to the line and to the full report in the job summary), the details folded, and an inline comment on each finding in the diff. A push with no new finding posts nothing. Until the secret and the variable are set, the job skips with a warning.

A review with no person (a CI job, a scheduled agent): desk review --pr 123 --engine claude|codex|opencode --repo-access. The engine gets read-only access to a checkout of the PR, and none of your settings, hooks or MCP servers. See docs/clients.md.

The size gate: a review stops when the PR has more than 5,000 changed lines in existing files (new files and tests do not count). The report then asks for a split. --force reviews the PR. A maintainer can add the size/override label to a PR that cannot be split.

Commands

The skills call these commands. You can also run them yourself.

Command What it does
desk preflight Size, mixed-scope and pattern gates on the committed diff against the base branch. Exit 1 on a blocking check.
desk state [--json] [--repo <owner/repo>] [--limit <n>] The current state of the project and what to do first: the questions that wait for the owner, the owner's feedback, the open PRs with the rules that stop each merge, the open issues, the worktrees with unfinished work, the PRs merged lately and the owner's newest prompts. See state.md.
desk merge --pr <n> [--dry-run] Merges a PR only when the rules hold: a review of the current head by a reviewer who is not the author, the verdict "Ready to merge", no open finding, the owner's quotes found, green checks. Runs merge.after after the merge. See enforcement.md.
desk workspace Fails on a detached HEAD, and on a primary checkout that holds work, in a repository whose workspace.worktrees asks for linked worktrees. desk hook workspace and desk hook gh refuse an edit and a git command in such a checkout. See enforcement.md.
desk validate Runs the validation commands for the changed paths. --all runs every command.
desk requirements [--pr <n>] [--issue <n>] [--terms <words>] [--body-file <f>] [--no-issues] The owner's prompts that hold the words, the linked issues, the specs and the register. With a PR body file, it checks each quote against the prompts.
desk review [--pr <n>] [--profile <p>|all] Writes a run folder in .desk/out/: packet.md, diff.patch and run.json. The AI reviews the packet and writes findings.json.
desk review ... --engine <e> [--model <m>] --repo-access A headless review. The engines are claude, codex, opencode and openai (any OpenAI-compatible endpoint in DESK_BASE_URL).
desk verify --engine <e> [--run <dir>] Checks each blocker and important finding against the code. A false positive goes to "Dropped after verification".
desk report [--run <dir>] Checks findings.json, sorts by severity, removes duplicates and writes report.md, with the fix, the decision and the ID of each finding, and the "checked and found correct" list.
desk triage [--run <dir>] The findings with their IDs and the decision on each: open, accepted or rejected.
desk gate [--run <dir>] [--json] The next open findings as questions, with the exact comment text and the options. When none is open, the outcome question.
desk decide <id...> --accept|--reject --reason <r>|--reopen Records a person's decision in decisions.json. --accept can change the severity, title, body or fix that is posted. --all-open applies to each open finding.
desk post --confirm [--as review|comment] [--skip-open] Posts the accepted findings to the PR. It refuses while a finding is open. A second run does not post a finding two times.
desk threads --pr <n> The review threads, and the decision of the PR author on each.
desk profiles [--pr <n>] The profiles, and the profiles whose paths match the change.
desk packs, desk packs add <name...> The rule packs, and the command that copies a pack into the repository.
desk pr template|check|create The PR body format, its check, and gh pr create with the label type: <type>.
desk issue template|check|create The issue format, its check, and gh issue create with the label type: <type>.
desk learn fetch|extract Rules from the review history.
desk ci The CI check. The GitHub action runs it.
desk ci review The AI review of a PR in GitHub Actions. The munhq/desk/review action runs it.
desk install [--scope repo] [--git-hook] Installs into the AI clients. --scope repo writes the skills and agents into the repository. --git-hook adds a pre-push hook with the gates.
desk update Gets the newest release of the desk server and installs it again.
desk mcp The CLI as an MCP server over stdio.
desk doctor Checks the CLI, the clients, the configuration, the rules and the GitHub access.

More documentation

Document Content
docs/clients.md The paths for each AI client, the headless engines and the model choice
docs/profiles.md The review profiles, and how to add a profile
docs/packs.md The rule packs and their sources
docs/enforcement.md Where the kit checks PRs, issues and reviews, and the CI setup
docs/requirements.md The check against the owner's words: sources, quotes, the reviewer, the settings
docs/guidelines.md The guidelines: scalability, modularity and code quality, with proof for each verdict
docs/decisions.md The decisions page: the section in the issue, the settings, what an answer does
docs/baseline.md The script that times the clone, the install and the checks of a repository, with a cold and a warm cache

Development

npm install
npm test          # builds dist/ and runs the unit and end-to-end tests

npm run build writes dist/ and src/embedded.ts. scripts/embed.mjs puts the skills, templates and packs into src/embedded.ts, so the npm package and the binary carry the same files. npm install github:... runs the CLI from the repository with no build step, so commit dist/ and src/embedded.ts with each change. CI checks that they match the source.

npm run build:bin builds the four binaries with Bun into $BIN_OUT (default bin/). A tag v* starts .github/workflows/release.yml. It builds the binaries and attaches them to a GitHub release with SHA256SUMS.