Skip to content
Hoody.com

The Agent: GitHub API surfaces the daemon’s GitHub integration: authentication (device flow or PAT), repository and branch listings, working-tree status, and mutating actions (clone, stage-and-commit, fetch/pull/push sync, open PR). All endpoints run over the container-scoped agent host and accept the standard per-request scope headers. Per-request realm headers are rejected with realm_scope_unsupported on routes that have no realm dimension.

All endpoints share the host template https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com and accept the same five per-request scope params, documented under each endpoint.

Reports the GitHub authentication state from the daemon’s github.auth.status action. Token lives only in env and is never returned. This endpoint has no realm/container/cwd/config_dir dimension, so EVERY per-request scope header returns 400 realm_scope_unsupported.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/auth/status"
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd (e.g. POST /todos; createTodo also accepts a body cwd).
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent): "global" or a 24-hex id. Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
{
"status": "ok",
"active": "github.com/octocat",
"accounts": [
{ "key": "github.com/octocat", "login": "octocat", "host": "github.com", "active": true }
]
}

Begins a GitHub login. With no body token this starts a device flow and returns the non-secret {device_code, user_code, verification_uri, interval, expires_in}; the user authorizes that URL out of band, then POST /api/v1/agent/github/auth/login/poll completes the login. With a body token (a PAT) the service instead validates + persists the token directly (no device flow) and returns the linked {login, host}. For GitHub Enterprise (GHES) set body host (default github.com) on both the device-flow start and the PAT-add. The token lives only in env and is never returned.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/auth/login" \
-H "Content-Type: application/json" \
-d '{}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
tokenstringNoOptional PAT. When present the login validates + persists this token (no device flow); kept in env, never returned.
hoststringNoGitHub host for GitHub Enterprise (GHES); defaults to github.com. Must match the host on the subsequent poll call.
activatebooleanNoWhether the linked account becomes the ACTIVE one. Defaults to false. Send true when recovering from an expired/revoked token so the account is linked and activated in a single call (no follow-up setActiveAccount is needed). The first account ever linked becomes active regardless. A non-boolean value is rejected.
{
"device_code": "3584d83530557fdd1f46af8289938c8f79ce9d5f",
"user_code": "WDJB-MJHT",
"verification_uri": "https://github.com/login/device",
"interval": 5,
"expires_in": 900
}

Polls an in-flight GitHub device-flow login to completion. Forward the {device_code, interval, expires_in} the start reply returned; the call blocks until the user authorizes (or the flow expires/cancels), then validates + persists the resulting token. Required to complete a device-flow login over HTTP — the start call only returns the verification URL / device code. The token lives only in env and is never returned; only the linked {login, host} is echoed.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/auth/login/poll" \
-H "Content-Type: application/json" \
-d '{
"device_code": "3584d83530557fdd1f46af8289938c8f79ce9d5f",
"interval": 5,
"expires_in": 900
}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
device_codestringYesThe device_code returned by POST /api/v1/agent/github/auth/login.
hoststringNoThe GitHub host (default github.com); must match the start call.
intervalintegerNoThe poll interval (seconds) the start reply returned.
expires_inintegerNoThe device-code lifetime (seconds) the start reply returned.
{
"key": "github.com/octocat",
"login": "octocat",
"host": "github.com"
}

Points every subsequent GitHub operation at an already-linked account. key is the account handle from githubAuthStatus’s accounts[].key ("&lt;host&gt;/<login>"). Use this to recover when the ACTIVE account’s token was revoked and another linked account is still good — adding a PAT activates the account it belongs to, but switching between EXISTING accounts needs this route. 400 when the key names no linked account.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/auth/active" \
-H "Content-Type: application/json" \
-d '{ "key": "github.com/octocat" }'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
keystringYesAccount handle from githubAuthStatus accounts[].key, e.g. "github.com/octocat".
{
"status": "ok",
"accounts": [
{ "key": "github.com/octocat", "login": "octocat", "host": "github.com", "active": true }
]
}

Forgets a linked GitHub account and deletes the copies of its token that an interactive clone persisted into checkouts the daemon can currently reach. The purge is BEST-EFFORT and partial by construction — a repository in a stopped container, or one no open session is bound to, keeps its copy — so the reply carries credential_purge:"partial" and a message saying to revoke the token on GitHub for a complete removal. If the removed account was active, the active pointer moves to a remaining account (or clears).

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/auth/logout" \
-H "Content-Type: application/json" \
-d '{ "key": "github.com/octocat" }'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
keystringYesAccount handle from githubAuthStatus accounts[].key, e.g. "github.com/octocat".
{
"status": "ok",
"accounts": [],
"credential_purge": "partial",
"message": "revoke the token on GitHub to invalidate copies stored in stopped containers"
}

Lists known/configured repos (daemon action github.repo.list). Returns the daemon reply verbatim ({status, repos, account}); not paginated.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/repos" \
-H "X-Hoody-Cwd: /home/me/projects/app"
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
{
"status": "ok",
"account": "github.com/octocat",
"repos": [
{ "full_name": "octocat/hello-world", "clone_url": "https://github.com/octocat/hello-world.git", "private": false }
]
}

Lists branches for the requesting cwd’s repo (daemon action github.branch.list). Returns {status, branches} verbatim; not paginated. cwd-scoped, not realm-scoped — a per-request realm header returns 400 realm_scope_unsupported.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/branches" \
-H "X-Hoody-Cwd: /home/me/projects/app"
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
{
"status": "ok",
"branches": [
{ "name": "main", "is_default": true, "sha": "abc1234567890def1234567890abcdef12345678" },
{ "name": "feature/login", "is_default": false, "sha": "def1234567890abc1234567890abcdef12345678" }
]
}

Returns the git working-tree status (daemon action github.status) for the requesting cwd. cwd-scoped (git is repo/cwd-relative), not realm-scoped — a per-request realm header returns 400 realm_scope_unsupported.

Terminal window
curl -X GET "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/status" \
-H "X-Hoody-Cwd: /home/me/projects/app"
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
{
"status": "ok",
"branch": "main",
"clean": true,
"ahead": 0,
"behind": 0,
"staged": [],
"modified": [],
"untracked": []
}

Clones a GitHub repository. The service translates repo (owner/name OR an https github URL) into the server-authoritative {full_name, clone_url}: the clone runs against the ACTIVE account host (a URL whose host does not match is rejected), and the destination is derived traversal-safe under the managed clone root (dir overrides it). Destructive.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/clone" \
-H "Content-Type: application/json" \
-d '{
"repo": "octocat/hello-world",
"shallow": true
}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
repostringNoThe repository to clone: "owner/name" or an https github URL (https://&lt;host&gt;/&lt;owner&gt;/&lt;name&gt;[.git]). Translated to full_name + clone_url against the active account host. Supply this OR the canonical full_name+clone_url; if both, the canonical fields win.
dirstringNoOptional managed clone root override (clone_root); the traversal-safe parent/dest are derived under it.
full_namestringNoCanonical "owner/name" (alternative to repo; used as-is when supplied, taking precedence over a derived value). Requires clone_url.
clone_urlstringNoCanonical https clone URL (alternative to repo; re-validated against the active account host; takes precedence over a derived value). Requires full_name.
shallowbooleanNoShallow clone (default true).

At least one form is required; supplying neither repo nor full_name+clone_url is rejected.

{
"status": "ok",
"dir": "/home/me/projects/app/checkouts/octocat/hello-world",
"full_name": "octocat/hello-world",
"clone_url": "https://github.com/octocat/hello-world.git"
}

Stages all changes and commits in the requesting cwd’s repo (forwarded to github.commit). Destructive.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/commit" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/me/projects/app" \
-d '{ "message": "feat: add remember-me checkbox" }'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
messagestringYesThe commit message.
{
"status": "ok",
"sha": "abc1234567890def1234567890abcdef12345678",
"branch": "main"
}

Runs fetchpullpush as one logical sync, stopping at the first non-ok step so a later push never runs against a half-synced tree. Body direction lets a caller pull-only (fetch+pull) or push-only; default is the full sync. direction is BODY-only — there is no ?direction alias. Destructive. 502 sync_step_failed carries the steps that ran plus the failing one under details.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/sync" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/me/projects/app" \
-d '{ "direction": "pull" }'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
directionstringNoOptional: "pull" (fetch+pull) or "push" (push only). Default is the full fetch→pull→push.
{
"steps": [
{ "step": "fetch", "result": { "status": "ok" } },
{ "step": "pull", "result": { "status": "ok" } },
{ "step": "push", "result": { "status": "ok" } }
]
}

Opens a pull request for the requesting cwd’s repo (forwarded to github.pr.create). Destructive.

Terminal window
curl -X POST "https://{projectId}-{containerId}-agent-1.{server}.containers.hoody.com/api/v1/agent/github/pr" \
-H "Content-Type: application/json" \
-H "X-Hoody-Cwd: /home/me/projects/app" \
-d '{
"title": "Add remember-me checkbox",
"body": "Adds a checkbox so returning users stay signed in for 30 days.",
"base": "main"
}'
NameInTypeRequiredDescription
X-Hoody-CwdheaderstringNoPer-request working-directory scope: the .hoody project layer / record cwd / tool+workflow cwd. Required by routes that resolve a cwd.
X-Hoody-Config-DirheaderstringNoPer-request --config-dir override selecting which on-disk .hoody install a stateless read/write resolves (HoodyPaths).
X-Hoody-ContainerheaderstringNoPer-request bound remote container (omitted = local). Rejected (400) on routes with no container dimension.
X-Hoody-RealmheaderstringNoPer-request realm selector: "global" or a 24-hex id (also accepted as ?realm=). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
realmquerystringNoPer-request realm selector — the in:query alias of the X-Hoody-Realm header (read only when the header is absent). Rejected (400 realm_scope_unsupported) on active-only / no-realm routes.
FieldTypeRequiredDescription
titlestringYesThe PR title (required, non-empty).
bodystringNoThe PR description.
basestringNoOptional base branch (default the repo default).
{
"url": "https://github.com/octocat/hello-world/pull/42",
"number": 42,
"head": "feature/login",
"base": "main"
}