Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The web console

The console is a web app for watching and reviewing work on a Grovedock server: browse code with blame and history, follow every change as it lands, see who (person or agent) landed what, review change requests, and see which files are locked. It runs entirely in the browser and talks to pandod directly over gRPC-Web; there is no backend of its own.

Try it: the live demo runs a simulated organisation in your browser: four repositories, a dozen agents landing changes every few seconds, change requests with reviews, checks and conflicts. Nothing leaves your machine.

Connect it to your server

  1. Allow the site that serves the console to call your server:

    PANDO_TOKENS="me:$(openssl rand -hex 24)" pandod server --listen 0.0.0.0:7440 --web-origins https://console.example.com
    

    --web-origins (or PANDO_WEB_ORIGINS) takes a comma-separated list. Browser access is the web feature flag, on by default; turn it off with PANDO_FLAGS=web=off.

  2. Open the console, choose Connection, and enter the server’s address and, if the server requires one, a token. The token stays in the tab unless you choose to remember it.

Sign in

When the console is served from the same address as a server with sign-in pages (pandod server --login-listen, behind one proxy that routes /login/* to them), the Connection screen shows Sign in with Google (one button per configured provider) and an email-link form instead of the address and token fields; Use a token instead brings those back. Signing in creates your account the first time and returns you to the console signed in: the session arrives once in the address (#pando_session=…), is kept as this site’s connection, and is wiped from the address bar and history straight away. Sign out, in the account menu, revokes that session’s token on the server and forgets it in the browser. The email form shows a Cloudflare Turnstile check only when the server is configured with a site key; only then does the console load Cloudflare’s script.

The console’s Content Security Policy allows exactly that: scripts and frames from https://challenges.cloudflare.com, and forms posting to the console’s own origin or any https: address. A host that sends its own CSP header must allow the same.

Set up an organisation

Someone signed in who belongs to no organisation lands in a three-step set-up, also reachable from New organisation in the sidebar:

  1. Name your organisation: its short name (used in addresses) and a display name. A taken, reserved or invalid name, or reaching the most organisations the server lets one person create, is explained in place.
  2. Invite teammates (optional): an email address and a role per person. Each invitation is a single-use link valid for 7 days; it is emailed when the server sends mail, and shown to copy either way.
  3. Connect an agent (optional): a token for an agent (agent/NAME, answering to you) or for yourself, write access for 90 days, shown once, with the MCP address (default SERVER/mcp; change it to wherever your pando mcp --http gateway answers, see Agents) and a ready-to-paste claude mcp add command.

Later, the organisation’s People tab invites people by email and lists invitations not yet accepted (expired ones are marked), each with Revoke.

A link of the form https://console.example.com/?server=https://pando.example.com opens the console already pointed at a server.

Host it yourself

The console is static files. Every release attaches them as pando-console-vVERSION.tar.gz (with a .sha256 and the same signed provenance as the binaries), or build them yourself:

cd console && pnpm install && pnpm build   # into console/dist

From pandod itself. --console-dir DIR (PANDO_CONSOLE_DIR) serves the files at / on the server’s own address, next to gRPC and gRPC-Web, so no other web server and no --web-origins are needed:

curl -LO https://github.com/kabirnarang39/pando/releases/download/v3.5.0/pando-console-v3.5.0.tar.gz
tar xzf pando-console-v3.5.0.tar.gz
pandod server --platform sqlite:///var/lib/pando/platform.db … --console-dir pando-console-v3.5.0

Every GET is a file, and a path that isn’t one is index.html. Files under assets/ (named by their content hash) are cached for a year; everything else, index.html included, is checked on each visit, so a new release shows at once. Each file carries a Content Security Policy header that adds frame-ancestors 'none' to the build’s own policy and keeps connect-src to the server, plus nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer and Cross-Origin-Opener-Policy: same-origin. It needs the web flag (on by default). Put TLS (and HSTS, compression) in front with any proxy, or use --tls-cert.

From a web server. Serve the unpacked directory from anywhere (Caddy, nginx, an object store, a CDN, GitHub Pages) and send the same headers. With Caddy, proxying gRPC to pandod on the same host name:

pando.example.com {
  @grpc header Content-Type application/grpc*
  handle @grpc {
    reverse_proxy h2c://127.0.0.1:7420
  }
  handle {
    root * /srv/pando-console
    header Content-Security-Policy "connect-src 'self'; frame-ancestors 'none'; base-uri 'none'; object-src 'none'; form-action 'self'"
    header X-Content-Type-Options nosniff
    @assets path /assets/*
    header @assets Cache-Control "public, max-age=31536000, immutable"
    @app not path /assets/*
    header @app Cache-Control no-cache
    encode zstd gzip
    try_files {path} /index.html
    file_server
  }
}

form-action must allow 'self': the email sign-in form posts to /login/.

URLs use the fragment (/#/server/repo/changes), so no server-side routing is needed and deep links work from any path.

What works where

Featurepandodpandod --platformComing next
Code, blame, file history, search by pathyesyes
Changes as they land, word-level diffsyesyes
Locks, branch switching, fleet timelineyesyes
Many repositories, grouped by ownerone repositoryyes
People, agents, teams, roles and tokensyes (3.2)
Sign in, new organisations, invitationsyes, with --login-listen
Change requests, reviews, line comments, land gate, rebaseyes (3.3)
Inbox, activity, protected branchesyes (3.3)

The console asks the server what it supports and shows only that: a server without hosting shows its one repository, and a server without review hides reviews and the inbox. The demo shows everything. The platform contract is pando_platform.proto; the plan is in Platform.

Keyboard

KeysDoes
⌘K or Ctrl K, /search files, repositories, reviews and actions
tgo to a file in this repository
g then h, i, c, l, r, khome, inbox, code, changes, reviews, locks
j, knext and previous item in a list
n, pnext and previous file in a review
areview the change request
b, h, ublame, file history, unified or split diff
?all shortcuts

Performance and privacy

  • The first screen needs about 167 KB of gzipped JavaScript; each screen after that loads its own code on first visit (and is preloaded on hover). The build fails if the first screen grows past its budget.
  • Syntax highlighting runs in a worker. Parts of a file far from the screen are plain text until they come near it, yet every line stays in the page, so the browser’s find works: a 50,000-line (1.7 MB) file opens within 1.5 seconds in the end-to-end tests. Files over 1 MB show without colours, and say so.
  • Fonts and icons are bundled: the console makes no request to any third party.
  • Untrusted content (READMEs, descriptions, comments) is rendered without HTML: markdown is turned into elements, raw HTML shows as text, and only http(s), mailto and relative links are followed.