Skip to content

The Branches API manages the git branches that make up an agent workspace. Each branch is an isolated git worktree with its own filesystem directory, lifecycle status, and disk usage. Use these endpoints to discover branches, inspect their state, create or delete them, sync them with a remote, and open or check pull requests.

All endpoints are scoped to a workspace. The workspace ID is supplied as a path parameter for every operation.


GET /api/v1/workspaces/{workspaceID}/branches

Section titled “GET /api/v1/workspaces/{workspaceID}/branches”

Returns every branch registered to the current project. Each branch is an isolated git worktree with its own directory, status, and disk usage. The list is bounded by the project’s branch count (typically fewer than 50) and is not paginated; callers receive the full array in a single response. Response objects are sanitised — start_command, last_stale_notify, and last_disk_notify are stripped.

NameInTypeRequiredDescription
workspaceIDpathstringYesThe workspace that owns the branches.
[
{
"id": "br_01HXYZABCDEF",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HXYZABCDEF",
"branch": "feature/add-oauth",
"name": "Add OAuth provider",
"status": "ready",
"base_branch": "main",
"base_commit": "f3a9c12d4e5b6789",
"created_at": 1715000000000,
"updated_at": 1715090000000
},
{
"id": "br_01HXYZGHIJKL",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HXYZGHIJKL",
"branch": "fix/null-pointer",
"name": "Fix null pointer in parser",
"status": "resetting",
"base_branch": "main",
"base_commit": "a1b2c3d4e5f60718",
"created_at": 1715100000000,
"updated_at": 1715100500000
}
]
await client.agent.branches.listBranches({
workspaceID: "ws_main"
});

GET /api/v1/workspaces/{workspaceID}/branches/remote

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/remote”

Returns the git remotes configured for the project, including provider detection, repository coordinates, and whether the stored credentials are valid.

NameInTypeRequiredDescription
workspaceIDpathstringYesThe workspace whose remotes should be inspected.
{
"remotes": [
{
"name": "origin",
"url": "git@github.com:acme/widgets.git",
"provider": "github",
"owner": "acme",
"repo": "widgets",
"authenticated": true
},
{
"name": "upstream",
"url": "https://github.com/official/widgets.git",
"provider": "github",
"owner": "official",
"repo": "widgets",
"authenticated": false
}
],
"defaultRemote": "origin"
}
await client.agent.branches.getRemoteInfo({
workspaceID: "ws_main"
});

GET /api/v1/workspaces/{workspaceID}/branches/remote-refs

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/remote-refs”

Fetches the set of branches and tags visible on a configured git remote via git ls-remote. The remote query parameter selects which remote to inspect; when omitted, the router uses the project’s default (origin when present). The response is a point-in-time snapshot of remote refs and is not paginated — very large mirrors may return a sizeable payload. Rate-limited per remote to avoid upstream abuse.

NameInTypeRequiredDescription
remotequerystringNoThe name of the remote to inspect. Defaults to the project’s default remote.
workspaceIDpathstringYesThe workspace whose remote refs should be listed.
{
"branches": [
"refs/heads/main",
"refs/heads/release/2024-q1",
"refs/heads/feature/agent-branches"
],
"tags": [
"refs/tags/v1.0.0",
"refs/tags/v1.1.0"
]
}
await client.agent.branches.listRemoteRefs({
workspaceID: "ws_main",
remote: "origin"
});

GET /api/v1/workspaces/{workspaceID}/branches/disk-usage

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/disk-usage”

Returns the on-disk size of one or all branches in the workspace. When the id query parameter is omitted, the response contains an entry for every branch.

NameInTypeRequiredDescription
idquerystringNoThe branch id to measure. Omit to measure every branch in the workspace.
workspaceIDpathstringYesThe workspace whose branches should be measured.
[
{
"id": "br_01HXYZABCDEF",
"directory": "/var/hoody/workspaces/ws_main/branches/br_01HXYZABCDEF",
"bytes": 482310984
},
{
"id": "br_01HXYZGHIJKL",
"directory": "/var/hoody/workspaces/ws_main/branches/br_01HXYZGHIJKL",
"bytes": 15728329
}
]
await client.agent.branches.getBranchDiskUsage({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

GET /api/v1/workspaces/{workspaceID}/branches/{id}/status

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/{id}/status”

Returns the live git status of a single branch — its name, how far ahead or behind its upstream it is, the count of staged/unstaged/untracked files, and a clean flag.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.
{
"branch": "feature/add-oauth",
"ahead": 3,
"behind": 0,
"staged": 4,
"unstaged": 1,
"untracked": 0,
"clean": false
}
await client.agent.branches.getBranchStatus({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

GET /api/v1/workspaces/{workspaceID}/branches/{id}/diff

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/{id}/diff”

Returns the diff between the branch and its base (or another reference). The format parameter controls whether the response is a summary or full hunk data; the file parameter scopes the diff to a single path.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
basequerystringNoThe base ref to diff against. Defaults to the branch’s base branch.
filequerystringNoRestrict the diff to a single file path.
formatquerystringNoOutput format. One of summary, full.
workspaceIDpathstringYesThe workspace that owns the branch.
{
"base_commit": "f3a9c12d4e5b6789",
"head_commit": "9b8c7d6e5f4a3210",
"files": [
{
"path": "src/oauth/provider.ts",
"status": "modified",
"insertions": 42,
"deletions": 7,
"hunks": [
{
"old_start": 12,
"old_lines": 5,
"new_start": 12,
"new_lines": 8,
"lines": [
{ "type": "context", "content": "import { Client } from './client';" },
{ "type": "remove", "content": "const TOKEN_TTL = 3600;" },
{ "type": "add", "content": "const TOKEN_TTL_MS = 60 * 60 * 1000;" },
{ "type": "context", "content": "" }
]
}
]
}
],
"truncated": false
}
await client.agent.branches.getBranchDiff({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF",
format: "full"
});

GET /api/v1/workspaces/{workspaceID}/branches/{id}/remote-status

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/{id}/remote-status”

Returns whether the branch has an upstream tracking ref and, if so, how many commits it is ahead or behind.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.
{
"hasUpstream": true,
"ahead": 3,
"behind": 1,
"remoteBranch": "origin/feature/add-oauth"
}
await client.agent.branches.getRemoteStatus({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

GET /api/v1/workspaces/{workspaceID}/branches/{id}/pr

Section titled “GET /api/v1/workspaces/{workspaceID}/branches/{id}/pr”

Returns the current state of a pull/merge request for the branch — whether one exists, its URL and number, its provider state, CI status, and review status.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.
{
"exists": true,
"url": "https://github.com/acme/widgets/pull/42",
"number": 42,
"state": "open",
"ci": {
"status": "success",
"url": "https://github.com/acme/widgets/actions/runs/123456"
},
"reviewStatus": "approved"
}
await client.agent.branches.getPRStatus({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

POST /api/v1/workspaces/{workspaceID}/branches

Section titled “POST /api/v1/workspaces/{workspaceID}/branches”

Creates a new branch as an isolated git worktree. The new branch can be given a name, a base branch to fork from, and an optional start command that runs after the worktree is provisioned.

NameInTypeRequiredDescription
workspaceIDpathstringYesThe workspace in which to create the branch.
NameTypeRequiredDescription
namestringNoThe human-readable display name for the branch.
startCommandstringNoA command to run inside the new worktree once it is provisioned.
baseBranchstringNoThe branch to fork from. Defaults to the project’s default branch.
{
"id": "br_01HMNOPQRSTU",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HMNOPQRSTU",
"branch": "feature/billing-portal",
"name": "Billing portal MVP",
"status": "creating",
"base_branch": "main",
"base_commit": "f3a9c12d4e5b6789",
"created_at": 1715200000000,
"updated_at": 1715200000000
}
await client.agent.branches.createBranch({
workspaceID: "ws_main",
data: {
name: "Billing portal MVP",
baseBranch: "main",
startCommand: "pnpm install && pnpm dev"
}
});

PATCH /api/v1/workspaces/{workspaceID}/branches/{id}

Section titled “PATCH /api/v1/workspaces/{workspaceID}/branches/{id}”

Renames the branch’s human-readable display name. The underlying git branch ref is not changed.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.
NameTypeRequiredDescription
namestringYesThe new display name for the branch.
{
"id": "br_01HXYZABCDEF",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HXYZABCDEF",
"branch": "feature/add-oauth",
"name": "Add OAuth provider (rev 2)",
"status": "ready",
"base_branch": "main",
"base_commit": "f3a9c12d4e5b6789",
"created_at": 1715000000000,
"updated_at": 1715210000000
}
await client.agent.branches.renameBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF",
data: { name: "Add OAuth provider (rev 2)" }
});

DELETE /api/v1/workspaces/{workspaceID}/branches/{id}

Section titled “DELETE /api/v1/workspaces/{workspaceID}/branches/{id}”

Deletes a branch and its underlying git worktree.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint takes no parameters beyond the path above.

await client.agent.branches.deleteBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/reset

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/reset”

Resets a branch back to its base commit. While the reset is in progress the branch’s status is set to resetting; once complete it returns to ready.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint takes no parameters beyond the path above.

{
"id": "br_01HXYZABCDEF",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HXYZABCDEF",
"branch": "feature/add-oauth",
"name": "Add OAuth provider",
"status": "resetting",
"base_branch": "main",
"base_commit": "f3a9c12d4e5b6789",
"created_at": 1715000000000,
"updated_at": 1715300000000
}
await client.agent.branches.resetBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/retry

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/retry”

Retries a branch whose provisioning or operation previously failed. Only branches in the failed state are eligible.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint takes no parameters beyond the path above.

{
"id": "br_01HXYZGHIJKL",
"path": "/var/hoody/workspaces/ws_main/branches/br_01HXYZGHIJKL",
"branch": "fix/null-pointer",
"name": "Fix null pointer in parser",
"status": "creating",
"base_branch": "main",
"base_commit": "a1b2c3d4e5f60718",
"created_at": 1715100000000,
"updated_at": 1715310000000
}
await client.agent.branches.retryBranch({
workspaceID: "ws_main",
id: "br_01HXYZGHIJKL"
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/pull

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/pull”

Pulls the latest commits from the branch’s upstream (or a specified remote) into the local worktree. Returns any conflict paths if the pull cannot be fast-forwarded.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint accepts an empty body.

{
"success": true,
"conflicts": [],
"message": "Already up to date."
}
await client.agent.branches.pullBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/push

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/push”

Pushes the branch to its remote. When successful the response includes the pushed ref and the remote name. This endpoint is rate-limited; callers that exceed the limit receive a 429 response with a retryAfterMs hint.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint accepts an empty body.

{
"success": true,
"ref": "refs/heads/feature/add-oauth",
"remote": "origin",
"url": "https://github.com/acme/widgets",
"message": "Branch pushed successfully."
}
await client.agent.branches.pushBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/merge

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/merge”

Merges the branch into its base. The strategy field selects squash, rebase, or a true merge commit. Set dry_run to validate the merge without applying it, and deleteBranch to remove the source branch on success.

NameInTypeRequiredDescription
idpathstringYesThe branch id to merge.
workspaceIDpathstringYesThe workspace that owns the branch.
NameTypeRequiredDescription
strategystringNoMerge strategy. One of squash, rebase, merge.
messagestringNoCustom commit message.
dry_runbooleanNoWhen true, validates the merge without applying it.
deleteBranchbooleanNoWhen true, deletes the source branch on a successful merge.
{
"success": true,
"sha": "9b8c7d6e5f4a3210",
"head_commit": "9b8c7d6e5f4a3210",
"already_merged": false,
"target": "main",
"conflicts": [],
"message": "Merge successful."
}
await client.agent.branches.mergeBranch({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF",
data: {
strategy: "squash",
message: "feat: add OAuth provider",
deleteBranch: true
}
});

POST /api/v1/workspaces/{workspaceID}/branches/{id}/pr

Section titled “POST /api/v1/workspaces/{workspaceID}/branches/{id}/pr”

Opens a pull (or merge) request from the branch against its target. The input body is empty by contract — the PR is created from the branch’s current state.

NameInTypeRequiredDescription
idpathstringYesThe branch id.
workspaceIDpathstringYesThe workspace that owns the branch.

This endpoint accepts an empty body.

{
"success": true,
"url": "https://github.com/acme/widgets/pull/43",
"number": 43,
"provider": "github",
"message": "Pull request opened."
}
await client.agent.branches.createPR({
workspaceID: "ws_main",
id: "br_01HXYZABCDEF"
});