Skip to content

Pando API

Shape:

  • A monorepo is owner/name, like GitHub: the owner is a namespace (a person's login, or an organization's), the name is unique within its owner, and a permanent id keys everything stored. A rename or a transfer changes the label only; the old owner/name keeps working (an alias) until its owner gives that name to another monorepo, which the create or rename answer reports (replaced_alias). Owners and names match without case and are stored lower case.
  • In payloads, monorepo is always the owner/name label and monorepo_id always the id (repos, hook payloads, feed lines, needs-you rows, socket frames). The Monorepo object itself has id, owner, name and full_name.
  • Every route is under /v1/monorepos/{owner}/{monorepo}, except the user's own (/v1/user, /v1/monorepos) and the web home's, which span all of the person's monorepos (/v1/events, /v1/branches). A monorepo holds repos. A plain git repo is a monorepo of kind repo holding exactly one repo, at path ., and no meta layer; it uses the same routes. The meta layer's routes (/v1/monorepos/{owner}/{monorepo}/meta/...) are not in this reference.
  • A repo has a path (its folder from the root: projects/web, or . in a plain repo) and a name, its id in URLs: the path with each / turned into - (projects-web). A plain repo's name is the monorepo's name when it was made (a rename does not change it). Names are unique in a monorepo.
  • In a monorepo, the repo named meta (path ., clone_url <host>/<owner>/<monorepo>/meta.git) is the meta layer's own git history. It takes branches, diffs, reviews and merges like any repo, and it is how .pando/** changes: after a merge into it, the merged files go to the live meta layer on every machine. It is not in listRepos.
  • Git goes through the git door at the repo's clone_url: https://<host>/<owner>/<monorepo>/<name>.git for a monorepo's repos, https://<host>/<owner>/<name>.git for a plain repo (smart HTTP; see the git tag). Pushes to the default branch are refused, except the first push that creates it. Every other push goes through.
  • Every other call is JSON with Authorization: Bearer <credential>.

Artifacts repos, in the namespace pando-dev, are named from the monorepo's id and kept on each repo's record (Artifacts has no rename): a project repo is <id>--<name> (m_0123456789abcdef--projects-web), a plain repo <id>--<name>, and the meta layer <id>--meta. New ids are m_ and 16 hex characters; a monorepo made before namespaces kept its old name as its id. Ids and names have no --, so the split is never ambiguous. These names are internal: clients use clone_url.

Required checks: the server reads required_checks from .pando/pando.toml on main. In a monorepo that is the meta layer's main, table [repos."<repo path>"]; in a plain repo, the repo's own main, table [repos."."]. No main or no file means no required checks. When Artifacts fails to read it, or it does not parse, they are unknown, and only the merge fails closed: reads (the repo, the branch list, a branch, a commit's status, CI) answer as usual with the list null and checks_unknown saying why (for a bad file, "pando.toml line N: "), checks state is unknown; an unforced merge is refused with 503 checks_unknown and that reason, a forced one goes through as forced. Nothing is kept, so the next request reads it again.

Identity works like GitHub's. A person has a user account and belongs to monorepos as owner or member. A machine signs in once (pando login) and holds a credential for that user; git and every agent on the machine act as that user, the way gh and git credentials do. A cloud sandbox gets a credential its user makes for it. Credentials are listed and revocable. Commits are authored as the user; Pando's commit trailers name the agent.

Any member may push, review, post statuses, report worktrees and merge (agents included, through the user's credential). Reviews are comments and approvals, not a gate. The merge gate is the checks, and ?force=1 merges past them. Owners also manage members and hooks.

Organizations: anyone signed in creates one (POST /v1/orgs); its name is a namespace in the same space as logins. Roles are owner and member. Everyone in an org can open and push to every monorepo the org owns, and its owners are owners of all of them: a person's role in an org's monorepo is the higher of their own row in the monorepo and their org role. A monorepo can still add people from outside the org itself. People are added at once (by login, or by an email that has signed in), or at that email's first sign-in. Removal from an org takes effect within 15 s, as for a monorepo.

Signing in (pando login): WorkOS AuthKit's CLI Auth, the OAuth device flow, run through the Worker. POST /v1/login/device returns a code and a URL; the person confirms the code in the browser; the CLI polls POST /v1/login/token with the device code until it returns the user and a new machine credential. WorkOS only proves who the person is: Pando keeps its own users, credentials and membership, and keeps no WorkOS token. A user's login comes from their email (ana@x.com is ana, or ana-2 if taken). Invites by email wait until that email first signs in.

In a browser: GET /v1/login/browser?return_to=<path> sends the person to AuthKit's page; WorkOS sends them back to /v1/login/callback, which sets the session cookie __Host-pando_session (HttpOnly, Secure, SameSite=Lax, host-only) and returns them to return_to (a path on this host, else /). The session is a credential of kind browser for the same Pando user, so it sees the same monorepos. It works on /v1 only: never as a Bearer token and never at the git door. With the cookie, a write (any method but GET and HEAD) or a WebSocket upgrade must carry Origin equal to Pando's own origin, else 403 bad_origin. A session ends after 30 days without use, on sign-out (POST /v1/logout, which also ends the WorkOS session), or when revoked.

Self-hosted, one person: the Worker secret PANDO_BOOTSTRAP makes users with POST /v1/users (it works there only). Either way, a user then makes more credentials (POST /v1/user/credentials) and monorepos (POST /v1/monorepos).

Agents: an agent acts as its user, through the user's credential. It may also send X-Pando-Agent: <name> on API calls and pushes; Pando then records the agent on merges (merged_agent) and on events.

Branch names in paths: encode / as %2F (agent-3%2Foauth). Raw slashes are accepted too.

Errors are JSON: {"error": {"code": "...", "message": "..."}}.

Version: 1

Servers

  • https://app.gitpando.com
  • https://pando-dev.{subdomain}.workers.dev
Navigation

Type to search…

↑↓ navigate↵ selectEsc close