Skip to main content
These endpoints expose jj-native VCS operations that have no direct GitHub equivalent. They are proxied through the JJHub API to the Rust repo-host which uses jj-lib natively.

jj VCS API

JJHub is a jj-native platform. All version control operations use jj concepts: Change IDs, Bookmarks, Operation Logs, and stacked changes. These endpoints provide direct access to jj VCS operations on repositories.

Bookmarks

Bookmarks are jj’s equivalent of Git branches. Unlike Git branches, bookmarks are explicit pointers that don’t automatically advance - you must explicitly move them.

List Bookmarks

GET /api/repos/{owner}/{repo}/bookmarks
Response:
[
  {
    "name": "main",
    "target": "abc123def456...",
    "remote": "origin",
    "synced": true
  }
]

Create Bookmark

POST /api/repos/{owner}/{repo}/bookmarks
Request:
{
  "name": "feature-xyz",
  "target": "abc123def456..."
}
Response:
{
  "name": "feature-xyz",
  "target": "abc123def456...",
  "synced": false
}

Get Bookmark

GET /api/repos/{owner}/{repo}/bookmarks/{name}

Update Bookmark

PATCH /api/repos/{owner}/{repo}/bookmarks/{name}
Request:
{
  "target": "newchangeid789..."
}

Delete Bookmark

DELETE /api/repos/{owner}/{repo}/bookmarks/{name}

Changes

A Change is jj’s equivalent of a commit, but with a stable Change ID that persists even when the commit is amended or rebased. Every change has:
  • A Change ID: a stable identifier (e.g. wqnwkozp) that never changes
  • A Commit ID: the underlying Git commit hash (changes on amend)
  • A description: the commit message
  • One or more parents: the change’s ancestors

List Changes

Returns the change tree (commit graph) for a repository.
GET /api/repos/{owner}/{repo}/changes
Query parameters:
ParameterTypeDescription
limitintegerMaximum number of changes to return (default: 100)
bookmarkstringFilter to changes reachable from a bookmark
Response:
{
  "changes": [
    {
      "change_id": "wqnwkozpqjlrsurt",
      "commit_id": "abc123def456...",
      "description": "feat: add webhook retry backoff",
      "author": {
        "name": "Alice",
        "email": "[email protected]"
      },
      "parents": ["prevchangeid..."],
      "is_root": false,
      "created_at": "2025-01-15T10:30:00Z"
    }
  ]
}

Get Change

GET /api/repos/{owner}/{repo}/changes/{change_id}

Diffs

Get Change Diff

Returns the diff for a specific change.
GET /api/repos/{owner}/{repo}/changes/{change_id}/diff
Query parameters:
ParameterTypeDescription
formatstringDiff format: unified (default), stat
contextintegerLines of context (default: 3)
Response:
{
  "change_id": "wqnwkozpqjlrsurt",
  "files": [
    {
      "path": "internal/routes/webhooks.go",
      "status": "modified",
      "additions": 42,
      "deletions": 7,
      "diff": "@@ -1,7 +1,42 @@\n ..."
    }
  ],
  "stats": {
    "files_changed": 1,
    "additions": 42,
    "deletions": 7
  }
}

Operation Log

The Operation Log is one of jj’s most powerful features. Every jj operation (commit, rebase, undo, etc.) is recorded in the operation log, making any operation undoable. This is analogous to Git’s reflog but for all operations, not just branch moves.

List Operations

GET /api/repos/{owner}/{repo}/oplog
Query parameters:
ParameterTypeDescription
limitintegerMaximum operations to return (default: 50)
Response:
{
  "operations": [
    {
      "operation_id": "op123abc...",
      "description": "new empty commit",
      "user": "alice",
      "timestamp": "2025-01-15T10:30:00Z",
      "tags": {
        "args": "jj new"
      }
    }
  ]
}

Stacked Changes

JJHub’s premiere feature is first-class support for stacked changes - a series of changes where each builds on the previous. This enables incremental review and is particularly powerful for AI-assisted development. A stack looks like:
◉  change-c  feat: validate webhook signature

◉  change-b  feat: add webhook delivery queue

◉  change-a  feat: add webhook model

◉  main
Landing requests can target any change in the stack. The landing queue ensures correct ordering when multiple changes in a stack are landed.

Key Differences from Git

ConceptGitjj
PointerBranchBookmark
Commit identitySHA hash (changes on amend)Change ID (stable forever)
History rewritegit rebase (creates new commits)jj rebase (same Change IDs)
UndoPartial (reflog)Full operation log
Staging areaIndexWorking copy is always a commit