Skip to content

The monorepo's event stream (JSON pages, or a WebSocket)

Every change a screen shows is an event, written in the same step as the change itself: a seq, a kind, and the changed row in its REST shape, with the client-side collection, key and op (upsert or delete) it applies to, so a client store (TanStack DB) can apply it directly. Every event is kept; the one limit is the monorepo object's storage (10 GB per Durable Object; an event is 0.3 to 1.3 KB).

Kinds, by collection:

  • branches: branch.opened, push, branch.updated, merged (upsert), branch.deleted (delete). The row has the branch's stored fields only (name, head, author, title, description, state and the merge facts) and the event says partial: true: ahead, behind, base, mergeable and checks are computed per request, so refetch getBranch for them.

  • default_heads: push (the first push of main) and default_head.updated (a merge). Row {repo, default_branch, default_head}. When main moves, every open branch's ahead, behind and mergeable change: refetch the branch list.

  • statuses: status (Status row).

  • ci_builds: ci.build (CiBuild row, upsert), on the build's repo.

  • ci_jobs: ci.job (CiJob row, upsert; key <build>/<job>), on the build's repo.

  • ci_connections: ci.connection (CiConnection row; delete on disconnect, row {id}).

  • tags: tag.created (a Tag row with its repo; also a moved tag), tag.deleted (delete, row {repo, name}).

  • releases: release.created, release.updated (also a file added or deleted), release.published (a Release row), release.deleted (delete, row {repo, tag}).

  • reviews: review (Review row).

  • artifacts: artifact.added, artifact.versioned (an Artifact row), artifact.deleted (delete, row {repo, branch, id, name}); each carries branch.

  • artifact_comments: artifact_comment.added, .edited, .resolved, .reopened (an ArtifactComment row; the thread's root for a state change; a body over 16 KB is null), and artifact_comment.deleted (delete with {id, artifact, thread}, or an upsert with the body null for a root that keeps its replies); each carries branch.

  • worktrees: worktree.reported (upsert), worktree.removed (delete).

  • meta_files: meta.saved (a meta history entry, no bytes; not sent during pando init's first upload).

  • presence: machine.connected, machine.disconnected. Row {connections: [...]}, the whole list of who is connected now (as in meta/status), plus connection, the one that changed.

  • machines: machine.updated (upsert, a Machine row; key <login>/<credential_id>). Sent at once for a new machine, a connect, a disconnect or a change of its worktrees; for activity alone at most once a minute per machine (every activity event already names its actor and machine).

  • issues: issue.opened, issue.commented, issue.closed, issue.reopened, issue.updated (everything else: title, body, project, labels, assignees, links, reactions, a comment edited or deleted, a merge naming a closed issue). Key <n>, with number, row (the IssueRow), body_version, items (the new timeline items; a comment's body is null over 16 KB), and when they apply removed (item ids), comment (a comment edited or whose reactions moved) and reactions (the issue's own).

  • labels: label.updated (upsert, a Label, from its name before a rename; delete, row {name}).

Topics (?topics=, comma-separated, at most 10): all (default), issues (every issue and label event), issue:<n> (one issue's; also repo:<repo> for its project and its linked branches' repos), main (every default_heads event), main:<repo>, repo:<repo>, meta (meta_files and presence), kind:<kind>, feed (the activity lines as the person's feed shows them, as {"type": "feed", "n", "event": FeedEvent} frames: the home uses it for a monorepo of more than 100 members, and a monorepo's pages may). pando worktree follow needs only main:<repo>.

The feed topic's lines are numbered n in the order they go out (a push's line goes out when its commit count is known, so n is not seq order). caught_up then carries feed_n, the last number sent. A socket that drops reconnects with feed_since=<the last n it saw> and first gets every line sent after it (at most 500, else one {"type": "feed_resync", "feed_n"}: refetch, then reconnect with that feed_n).

Presence (the home's machines_active and worktrees_active): a follower sends, after the socket opens and whenever a worktree is added or removed on its machine, {"type": "hello", "machine": "<machine>", "worktrees": ["<worktree id>", ...]}: the ids it reported with putWorktree for its branch worktrees in this monorepo (not read-only mains), at most 1,000, each 1 to 64 of A-Z a-z 0-9 _ -. machine is optional (default: the credential's name). Each hello replaces the last one of that socket; presence ends when the socket closes. The hello also marks the socket's credential connected in listMachines, with these worktrees. Answer: {"type": "hello_ok", "machine", "worktrees", "machines_active", "worktrees_active"}, or {"type": "error", "message"} (the socket stays open).

Without Upgrade: JSON, ?since=<seq>&limit=<n> (at most 500), or the latest limit with no since, oldest first either way. The pull also takes before=<seq> (only events before it: page back through the log with the first event's seq), repo=<repo> (that repo's events; meta for the meta layer's) and kinds=<kind>,<kind> (at most 20), each answered from an index on (repo, seq) or (kind, seq), and with topics (matched over at most 5,000 rows). With Upgrade: websocket: events after ?since= (at most 500, else one {"type": "resync", "seq", "oldest_seq"} frame: refetch, then resume from seq), then {"type": "caught_up", "seq"}, then live {"type": "event", "seq", ...} frames. The text ping gets pong. Close code 4404: the monorepo was deleted. Close code 4403: you no longer have access to it (an owner removed you, you left the org that owns it, or a transfer moved it away from that org); do not reconnect.

Numbers and shas: seq, oldest_seq are stream sequence numbers. In an event, head and before (push and default_head events) are commit shas. Set EVENT_STREAM false in worker/src/monorepo/stream.ts and it answers 501 event_stream_on_hold.

GET
https://app.gitpando.com/v1/monorepos/{owner}/{monorepo}/events

Authorisation

  • credentialoptionalHTTP
  • sessionoptionalAPI key in cookie

Path parameters

  • ownerstringrequired

    The monorepo's owner, a namespace (a person's login or an organization). Matched without case.

    pattern: ^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){0,38}$
  • monorepostringrequired

    The monorepo's name within its owner (or an old name). Matched without case.

    pattern: ^[a-z0-9](?:[a-z0-9._]|-(?!-)){0,38}$

Query parameters

  • sinceoptionalinteger
    minimum: 0
  • limitoptionalinteger
    maximum: 500, minimum: 1
    Default: 100
  • topicsoptionalstring
    Default: "all"
  • feed_sinceoptionalinteger

    With topics including feed, on a WebSocket: replay the feed lines numbered after this.

    minimum: 0
  • beforeoptionalinteger

    JSON only: events before this seq (the latest limit of them, oldest first).

    minimum: 1
  • repooptionalstring

    JSON only: one repo's events (its name as in its URL; meta for the meta layer).

  • kindsoptionalstring

    JSON only: these kinds, comma-separated, at most 20.

Returns

101

The WebSocket.

200

A page of events

JSON
  • eventsarray ofobjectrequired
    12 properties
    • seqintegerrequired
    • atstringrequired
      format: date-time
    • kindstringrequired
    • collectionstring | nullrequired
    • keystring | nullrequired
    • opupsertordeleteornullrequired
    • rowunknownrequired

      The changed row in its REST shape; on a delete, the last row (or its key fields).

    • repooptionalstring | null
    • actoroptionalstring | null

      The user's login.

    • machineoptionalstring | null

      The credential's name.

    • agentoptionalstring | null
    • partialoptionalboolean

      True on branch events: the row has the branch's stored fields only.

  • seqintegerrequired

    The newest event's seq (0 when none).

  • oldest_seqintegerrequired

    The oldest kept.

  • resyncbooleanrequired

    True when since is not in the stream; refetch everything.

501

event_stream_on_hold

JSON
  • errorobjectrequired
    4 properties
    • codestringrequired
    • messagestringrequired
    • pathsoptionalarray ofstring
    • checksoptionalobject

      GitHub's combined status, plus the required contexts and which are missing.

      6 properties
      • shastring | nullrequired
      • statesuccessorpendingorfailureorerrorormissingorunknownrequired

        success when the merge gate passes; missing when a required context has not reported; unknown while the required checks are (an unforced merge is refused).

      • requiredarray | nullrequired

        Null while unknown.

      • checks_unknownstring | nullrequired

        Why the required checks are unknown, in plain words: "Pando couldn't read this monorepo's required checks; try again", or "pando.toml line 3: expected comma or end of structure; fix it on main, or merge with force". Null otherwise.

      • statusesarray ofobjectrequired

        The latest status per context.

        8 properties
        • shastringrequired
        • contextstringrequired
        • statependingorsuccessorfailureorerrorrequired
        • created_atstringrequired
          format: date-time
        • target_urloptionalstring | null
        • descriptionoptionalstring | null
        • creatoroptionalstring

          The member who posted it (a login); app:<slug> for a status posted with a status token or by a CI integration; hook:<hook id> for a status token from a web hook with no app.

        • appoptionalstring | null

          The CI service that reported it (buildkite, github-actions, ...), stamped by Pando from a status token or a CI integration, never from the body or target_url. Null when a member posted it with their own credential. The web shows the service's mark for a slug it knows.

      • missingoptionalarray ofstring
Navigation

Type to search…

↑↓ navigate↵ selectEsc close