GitHub
The io.b3os/github pack: 17 actions and 2 triggers with call snippets, fixture outputs, connection setup and error codes, generated from version 1.0.0.
io.b3os/github 1.0.0 · developer-tools, issue-tracking, source-control · MIT
Work with GitHub repositories using your own token: read repositories, files, commits, releases and Actions runs; search, read, open, comment on, label and close issues; list and inspect pull requests; react to repository events through a webhook B3OS creates and removes for you, or poll for new issues. Uses the REST API version 2022-11-28 at api.github.com (not GitHub Enterprise Server). A fine-grained personal access token or GitHub App token with Contents, Issues, Pull requests and Actions read access covers the read actions; the write actions need Issues write, and the webhook trigger needs Webhooks write (admin:repo_hook for classic tokens).
Every call's result carries upstream_status and timing: validate_ms, inject_ms, render_ms, upstream_ms, map_ms and total_ms. upstream is the service's time; the others are B3OS's own (call actions). The snippets below show no timing values, because a fixture records none.
Connection
token, type bearer: GitHub token.
A fine-grained personal access token, a classic token, or a GitHub App installation token. Grant only the repositories and permissions the actions you use need.
How to get one: docs.github.com.
The credential is sent only to api.github.com.
Store the credential once as a vault connection for this pack and key, then name its id in a call's connections. Leave the key out and B3OS uses the project's newest connection for the pack and key without a subject (connections).
Hosts it reaches: api.github.com.
Actions
| Action | Effect | MCP tool | Title |
|---|---|---|---|
get-repo | read | github__get-repo | Get repository |
list-issues | read | github__list-issues | List issues |
get-issue | read | github__get-issue | Get issue |
search-issues | read | github__search-issues | Search issues and pull requests |
create-issue | write | github__create-issue | Create issue |
add-issue-comment | write | github__add-issue-comment | Comment on issue or pull request |
list-issue-comments | read | github__list-issue-comments | List issue comments |
close-issue | write | github__close-issue | Close issue |
add-labels | write | github__add-labels | Add labels |
list-pull-requests | read | github__list-pull-requests | List pull requests |
get-pull-request | read | github__get-pull-request | Get pull request |
get-file-contents | read | github__get-file-contents | Get file contents |
list-commits | read | github__list-commits | List commits |
get-latest-release | read | github__get-latest-release | Get latest release |
list-workflow-runs | read | github__list-workflow-runs | List Actions runs |
create-webhook | write | github__create-webhook | Create repository webhook |
delete-webhook | irreversible | github__delete-webhook | Delete repository webhook |
get-repo
Get repository. One repository's metadata: description, visibility, default branch, primary language, topics, license, stars, forks, open issue and pull request count, archived flag and last push time.
Ref io.b3os/github/get-repo@1.0.0 · effect read · connection token · MCP tool github__get-repo
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/get-repo@1", "input": {"owner": "acme", "repo": "widgets"}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/get-repo@1", input: { owner: "acme", repo: "widgets" }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/get-repo@1", "input": {"owner": "acme", "repo": "widgets"}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__get-repo", "arguments": {"owner": "acme", "repo": "widgets"} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__get-repo with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Get repository (documented response shape, example values). From the bundle's fixtures/get-repo.json, not a live call.
json{ "full_name": "acme/widgets", "description": "Widget toolkit for the acme storefront", "private": false, "html_url": "https://github.com/acme/widgets", "default_branch": "main", "language": "TypeScript", "topics": ["ui", "components"], "license": "MIT", "stargazers_count": 1380, "forks_count": 42, "open_issues_count": 17, "archived": false, "pushed_at": "2026-10-25T21:14:02Z"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Repository not found, or the token cannot see it. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
list-issues
List issues. Issues in a repository with filters for state, labels, assignee and update time, newest first by default. GitHub counts pull requests as issues; is_pull_request tells them apart. One page per call; increase page to continue.
Ref io.b3os/github/list-issues@1.0.0 · effect read · connection token · MCP tool github__list-issues
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/list-issues@1", "input": { "owner": "acme", "repo": "widgets", "labels": ["bug"], "per_page": 2 }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/list-issues@1", input: { owner: "acme", repo: "widgets", labels: ["bug"], per_page: 2 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/list-issues@1", "input": { "owner": "acme", "repo": "widgets", "labels": ["bug"], "per_page": 2, }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__list-issues", "arguments": { "owner": "acme", "repo": "widgets", "labels": ["bug"], "per_page": 2 } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__list-issues with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: List issues (documented response shape, example values). From the bundle's fixtures/list-issues.json, not a live call.
json{ "issues": [ { "number": 42, "title": "Cart overflows on narrow screens", "state": "open", "state_reason": null, "html_url": "https://github.com/acme/widgets/issues/42", "author": "mona-example", "labels": ["bug"], "assignees": ["hubot-example"], "comments": 2, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "is_pull_request": false }, { "number": 41, "title": "Typo in README", "state": "open", "state_reason": null, "html_url": "https://github.com/acme/widgets/issues/41", "author": "mona-example", "labels": [], "assignees": [], "comments": 0, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "is_pull_request": true } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
get-issue
Get issue. One issue (or pull request) by number with its full Markdown body, labels, assignees, comment count and timestamps. Comments themselves are in list-issue-comments.
Ref io.b3os/github/get-issue@1.0.0 · effect read · connection token · MCP tool github__get-issue
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/get-issue@1", "input": {"owner": "acme", "repo": "widgets", "number": 42}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/get-issue@1", input: { owner: "acme", repo: "widgets", number: 42 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/get-issue@1", "input": {"owner": "acme", "repo": "widgets", "number": 42}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__get-issue", "arguments": {"owner": "acme", "repo": "widgets", "number": 42} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__get-issue with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Get issue (documented response shape, example values). From the bundle's fixtures/get-issue.json, not a live call.
json{ "number": 42, "title": "Cart overflows on narrow screens", "state": "open", "state_reason": null, "html_url": "https://github.com/acme/widgets/issues/42", "author": "mona-example", "labels": ["bug"], "assignees": ["hubot-example"], "comments": 2, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "is_pull_request": false, "body": "Steps to reproduce:\n\n1. Open the cart\n2. Resize to 375px"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | No issue with this number, or the token cannot see the repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
search-issues
Search issues and pull requests. Search issues and pull requests across GitHub with GitHub's search syntax, for example repo:acme/widgets is:open label:bug or is:pr author:mona review:required. Returns matches with total count; at most 1,000 results are reachable through paging.
Ref io.b3os/github/search-issues@1.0.0 · effect read · connection token · MCP tool github__search-issues
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/search-issues@1", "input": { "query": "repo:acme/widgets is:issue is:open label:bug", "per_page": 1 }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/search-issues@1", input: { query: "repo:acme/widgets is:issue is:open label:bug", per_page: 1, }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/search-issues@1", "input": { "query": "repo:acme/widgets is:issue is:open label:bug", "per_page": 1, }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__search-issues", "arguments": { "query": "repo:acme/widgets is:issue is:open label:bug", "per_page": 1 } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__search-issues with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Search issues and pull requests (documented response shape, example values). From the bundle's fixtures/search-issues.json, not a live call.
json{ "total_count": 9, "incomplete_results": false, "items": [ { "number": 42, "title": "Cart overflows on narrow screens", "state": "open", "state_reason": null, "html_url": "https://github.com/acme/widgets/issues/42", "author": "mona-example", "labels": ["bug"], "assignees": ["hubot-example"], "comments": 2, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "is_pull_request": false } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
create-issue
Create issue. Open a new issue with a title, optional Markdown body, labels and assignees. Returns its number and URL. Not idempotent: calling it twice opens two issues.
Ref io.b3os/github/create-issue@1.0.0 · effect write · connection token · MCP tool github__create-issue
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/create-issue@1", "input": { "owner": "acme", "repo": "widgets", "title": "Flaky test in checkout flow", "body": "Seen three times this week on main.", "labels": ["bug"] }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/create-issue@1", input: { owner: "acme", repo: "widgets", title: "Flaky test in checkout flow", body: "Seen three times this week on main.", labels: ["bug"], }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/create-issue@1", "input": { "owner": "acme", "repo": "widgets", "title": "Flaky test in checkout flow", "body": "Seen three times this week on main.", "labels": ["bug"], }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__create-issue", "arguments": { "owner": "acme", "repo": "widgets", "title": "Flaky test in checkout flow", "body": "Seen three times this week on main.", "labels": ["bug"] } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__create-issue with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Create issue (documented response shape, example values). From the bundle's fixtures/create-issue.json, not a live call.
json{ "number": 43, "html_url": "https://github.com/acme/widgets/issues/43", "title": "Flaky test in checkout flow", "state": "open", "created_at": "2026-10-25T18:04:11Z"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
add-issue-comment
Comment on issue or pull request. Add a Markdown comment to an issue or pull request (the conversation tab, not a code review comment). Returns the comment id and URL. Not idempotent.
Ref io.b3os/github/add-issue-comment@1.0.0 · effect write · connection token · MCP tool github__add-issue-comment
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/add-issue-comment@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "body": "Reproduced on main at 3f2c1d0; the flex container overflows below 400px." }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/add-issue-comment@1", input: { owner: "acme", repo: "widgets", number: 42, body: "Reproduced on main at 3f2c1d0; the flex container overflows below 400px.", }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/add-issue-comment@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "body": "Reproduced on main at 3f2c1d0; the flex container overflows below 400px.", }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__add-issue-comment", "arguments": { "owner": "acme", "repo": "widgets", "number": 42, "body": "Reproduced on main at 3f2c1d0; the flex container overflows below 400px." } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__add-issue-comment with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Comment on issue or pull request (documented response shape, example values). From the bundle's fixtures/add-issue-comment.json, not a live call.
json{ "id": 2412345678, "html_url": "https://github.com/acme/widgets/issues/42#issuecomment-2412345678", "created_at": "2026-10-25T18:20:00Z"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
list-issue-comments
List issue comments. Comments on an issue or pull request conversation, oldest first: author, Markdown body and times. Page through long threads with page.
Ref io.b3os/github/list-issue-comments@1.0.0 · effect read · connection token · MCP tool github__list-issue-comments
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/list-issue-comments@1", "input": {"owner": "acme", "repo": "widgets", "number": 42}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/list-issue-comments@1", input: { owner: "acme", repo: "widgets", number: 42 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/list-issue-comments@1", "input": {"owner": "acme", "repo": "widgets", "number": 42}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__list-issue-comments", "arguments": {"owner": "acme", "repo": "widgets", "number": 42} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__list-issue-comments with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: List issue comments (documented response shape, example values). From the bundle's fixtures/list-issue-comments.json, not a live call.
json{ "comments": [ { "id": 2412345678, "author": "hubot-example", "body": "Reproduced on main at 3f2c1d0; the flex container overflows below 400px.", "html_url": "https://github.com/acme/widgets/issues/42#issuecomment-2412345678", "created_at": "2026-10-25T18:20:00Z", "author_association": "MEMBER" } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
close-issue
Close issue. Close an issue as completed or as not planned. Closing an already closed issue succeeds and changes nothing.
Ref io.b3os/github/close-issue@1.0.0 · effect write · connection token · MCP tool github__close-issue
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/close-issue@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "reason": "completed" }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/close-issue@1", input: { owner: "acme", repo: "widgets", number: 42, reason: "completed" }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/close-issue@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "reason": "completed", }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__close-issue", "arguments": { "owner": "acme", "repo": "widgets", "number": 42, "reason": "completed" } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__close-issue with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Close issue (documented response shape, example values). From the bundle's fixtures/close-issue.json, not a live call.
json{ "number": 42, "state": "closed", "state_reason": "completed", "closed_at": "2026-10-26T08:00:00Z", "html_url": "https://github.com/acme/widgets/issues/42"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
add-labels
Add labels. Add labels to an issue or pull request, keeping its existing ones. Labels that do not exist yet in the repository are created. Returns the full label list after the change.
Ref io.b3os/github/add-labels@1.0.0 · effect write · connection token · MCP tool github__add-labels
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/add-labels@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "labels": ["needs-triage"] }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/add-labels@1", input: { owner: "acme", repo: "widgets", number: 42, labels: ["needs-triage"], }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/add-labels@1", "input": { "owner": "acme", "repo": "widgets", "number": 42, "labels": ["needs-triage"], }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__add-labels", "arguments": { "owner": "acme", "repo": "widgets", "number": 42, "labels": ["needs-triage"] } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__add-labels with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Add labels (documented response shape, example values). From the bundle's fixtures/add-labels.json, not a live call.
json{"labels": ["bug", "needs-triage"]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
list-pull-requests
List pull requests. Pull requests in a repository by state, base branch or head (user:branch), sorted by creation, update or popularity. Returns title, author, branches, head commit, draft flag, labels and requested reviewers.
Ref io.b3os/github/list-pull-requests@1.0.0 · effect read · connection token · MCP tool github__list-pull-requests
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/list-pull-requests@1", "input": {"owner": "acme", "repo": "widgets", "per_page": 1}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/list-pull-requests@1", input: { owner: "acme", repo: "widgets", per_page: 1 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/list-pull-requests@1", "input": {"owner": "acme", "repo": "widgets", "per_page": 1}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__list-pull-requests", "arguments": {"owner": "acme", "repo": "widgets", "per_page": 1} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__list-pull-requests with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: List pull requests (documented response shape, example values). From the bundle's fixtures/list-pull-requests.json, not a live call.
json{ "pull_requests": [ { "number": 43, "title": "Fix cart overflow on narrow screens", "state": "open", "draft": false, "html_url": "https://github.com/acme/widgets/pull/43", "author": "mona-example", "head": "fix-cart", "base": "main", "head_sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", "labels": ["bug"], "requested_reviewers": ["hubot-example"], "created_at": "2026-10-25T19:00:00Z", "updated_at": "2026-10-25T20:30:00Z", "merged_at": null } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
get-pull-request
Get pull request. One pull request with its description and merge state: merged, mergeable and mergeable_state (clean, blocked, dirty, ...), commit count, additions, deletions and changed files. mergeable can be null while GitHub is still computing it; ask again a moment later.
Ref io.b3os/github/get-pull-request@1.0.0 · effect read · connection token · MCP tool github__get-pull-request
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/get-pull-request@1", "input": {"owner": "acme", "repo": "widgets", "number": 43}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/get-pull-request@1", input: { owner: "acme", repo: "widgets", number: 43 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/get-pull-request@1", "input": {"owner": "acme", "repo": "widgets", "number": 43}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__get-pull-request", "arguments": {"owner": "acme", "repo": "widgets", "number": 43} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__get-pull-request with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Get pull request (documented response shape, example values). From the bundle's fixtures/get-pull-request.json, not a live call.
json{ "number": 43, "title": "Fix cart overflow on narrow screens", "state": "open", "draft": false, "html_url": "https://github.com/acme/widgets/pull/43", "author": "mona-example", "head": "fix-cart", "base": "main", "head_sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", "labels": ["bug"], "requested_reviewers": ["hubot-example"], "created_at": "2026-10-25T19:00:00Z", "updated_at": "2026-10-25T20:30:00Z", "merged_at": null, "body": "Fixes #42.", "merged": false, "mergeable": true, "mergeable_state": "blocked", "commits": 2, "additions": 18, "deletions": 4, "changed_files": 3}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | No pull request with this number, or the token cannot see the repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
get-file-contents
Get file contents. The raw text of one file at a branch, tag or commit (default branch when ref is omitted), for example README.md or .github/workflows/ci.yml. Directories, symlinks and submodules come back as GitHub's JSON description instead. Very large files can exceed the runtime's response size limit.
Ref io.b3os/github/get-file-contents@1.0.0 · effect read · connection token · MCP tool github__get-file-contents
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/get-file-contents@1", "input": { "owner": "acme", "repo": "widgets", "path": ".github/workflows/ci.yml", "ref": "main" }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/get-file-contents@1", input: { owner: "acme", repo: "widgets", path: ".github/workflows/ci.yml", ref: "main", }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/get-file-contents@1", "input": { "owner": "acme", "repo": "widgets", "path": ".github/workflows/ci.yml", "ref": "main", }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__get-file-contents", "arguments": { "owner": "acme", "repo": "widgets", "path": ".github/workflows/ci.yml", "ref": "main" } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__get-file-contents with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Get file contents (documented response shape, example values). From the bundle's fixtures/get-file-contents.json, not a live call.
json{ "path": ".github/workflows/ci.yml", "ref": "main", "content": "name: CI\non: [push, pull_request]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - run: npm ci && npm test\n"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | No file at this path and ref, or the token cannot see the repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
list-commits
List commits. Commits on a branch or under a path, newest first, optionally by author or within a time window: SHA, first line and full message, author, date and URL.
Ref io.b3os/github/list-commits@1.0.0 · effect read · connection token · MCP tool github__list-commits
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/list-commits@1", "input": {"owner": "acme", "repo": "widgets", "sha": "main", "per_page": 1}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/list-commits@1", input: { owner: "acme", repo: "widgets", sha: "main", per_page: 1 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/list-commits@1", "input": { "owner": "acme", "repo": "widgets", "sha": "main", "per_page": 1, }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__list-commits", "arguments": {"owner": "acme", "repo": "widgets", "sha": "main", "per_page": 1} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__list-commits with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: List commits (documented response shape, example values). From the bundle's fixtures/list-commits.json, not a live call.
json{ "commits": [ { "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", "message": "Fix cart overflow on narrow screens\n\nFixes #42.", "author_name": "Mona Example", "author_login": "mona-example", "date": "2026-10-25T20:11:09Z", "html_url": "https://github.com/acme/widgets/commit/6dcb09b5b57875f334f61aebed695e2e4193db5e" } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
get-latest-release
Get latest release. The latest published release (not a draft or prerelease): tag, name, Markdown notes, publish time and downloadable assets with sizes and download counts. not_found when the repository has no releases.
Ref io.b3os/github/get-latest-release@1.0.0 · effect read · connection token · MCP tool github__get-latest-release
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/get-latest-release@1", "input": {"owner": "acme", "repo": "widgets"}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/get-latest-release@1", input: { owner: "acme", repo: "widgets" }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/get-latest-release@1", "input": {"owner": "acme", "repo": "widgets"}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__get-latest-release", "arguments": {"owner": "acme", "repo": "widgets"} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__get-latest-release with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Get latest release (documented response shape, example values). From the bundle's fixtures/get-latest-release.json, not a live call.
json{ "tag_name": "v2.4.0", "name": "v2.4.0", "body": "## What's changed\n\n- Cart: fix overflow on narrow screens (#43)\n- Buttons: new compact size", "published_at": "2026-10-20T15:04:12Z", "html_url": "https://github.com/acme/widgets/releases/tag/v2.4.0", "assets": [ { "name": "widgets-2.4.0.tgz", "size": 184320, "download_count": 311, "url": "https://github.com/acme/widgets/releases/download/v2.4.0/widgets-2.4.0.tgz" } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | The repository has no published release, or the token cannot see it. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
list-workflow-runs
List Actions runs. Recent GitHub Actions workflow runs, newest first, filtered by branch, triggering event or status (queued, in_progress, completed, success, failure, ...): workflow name, title, status, conclusion, branch, commit and timing.
Ref io.b3os/github/list-workflow-runs@1.0.0 · effect read · connection token · MCP tool github__list-workflow-runs
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/list-workflow-runs@1", "input": {"owner": "acme", "repo": "widgets", "per_page": 2}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/list-workflow-runs@1", input: { owner: "acme", repo: "widgets", per_page: 2 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },});console.log(result.output);
pythonfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/list-workflow-runs@1", "input": {"owner": "acme", "repo": "widgets", "per_page": 2}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},})print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__list-workflow-runs", "arguments": {"owner": "acme", "repo": "widgets", "per_page": 2} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__list-workflow-runs with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: List Actions runs (documented response shape, example values). From the bundle's fixtures/list-workflow-runs.json, not a live call.
json{ "total_count": 2, "runs": [ { "id": 11223344556, "workflow": "CI", "title": "Fix cart overflow on narrow screens", "run_number": 812, "event": "pull_request", "status": "completed", "conclusion": "failure", "branch": "fix-cart", "head_sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e", "html_url": "https://github.com/acme/widgets/actions/runs/11223344556", "created_at": "2026-10-25T19:01:00Z", "updated_at": "2026-10-25T19:07:31Z" }, { "id": 11223344001, "workflow": "CI", "title": "Buttons: compact size", "run_number": 811, "event": "push", "status": "completed", "conclusion": "success", "branch": "main", "head_sha": "f1e2d3c4b5a6978877665544332211aabbccddee", "html_url": "https://github.com/acme/widgets/actions/runs/11223344001", "created_at": "2026-10-25T15:40:00Z", "updated_at": "2026-10-25T15:46:10Z" } ]}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | Not found, or the token cannot see this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
create-webhook
Create repository webhook. Create a repository webhook that POSTs the chosen events (issues, pull_request, push, ...) as JSON to a URL, signed with a secret (X-Hub-Signature-256). The repo-event trigger calls this for you; use it directly only for webhooks B3OS does not manage. Needs admin:repo_hook (classic) or Webhooks write (fine-grained).
Ref io.b3os/github/create-webhook@1.0.0 · effect write · connection token · MCP tool github__create-webhook
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/create-webhook@1", "input": { "owner": "acme", "repo": "widgets", "url": "https://beta-api.b3os.org/v1/actions/hooks/hk_fixture", "secret": "fixture-secret-not-a-real-key", "events": ["issues", "pull_request"] }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/create-webhook@1", input: { owner: "acme", repo: "widgets", url: "https://beta-api.b3os.org/v1/actions/hooks/hk_fixture", secret: "fixture-secret-not-a-real-key", events: ["issues", "pull_request"], }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/create-webhook@1", "input": { "owner": "acme", "repo": "widgets", "url": "https://beta-api.b3os.org/v1/actions/hooks/hk_fixture", "secret": "fixture-secret-not-a-real-key", "events": ["issues", "pull_request"], }, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__create-webhook", "arguments": { "owner": "acme", "repo": "widgets", "url": "https://beta-api.b3os.org/v1/actions/hooks/hk_fixture", "secret": "fixture-secret-not-a-real-key", "events": ["issues", "pull_request"] } }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__create-webhook with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Create repository webhook (documented response shape, example values). From the bundle's fixtures/create-webhook.json, not a live call.
json{ "id": 512345678, "events": ["issues", "pull_request"], "active": true, "created_at": "2026-10-26T12:00:00Z"}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | No such repository, or the token cannot manage its webhooks (needs admin:repo_hook). |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
delete-webhook
Delete repository webhook. Delete a repository webhook by id (from create-webhook). The repo-event trigger calls this when its subscription is deleted.
Ref io.b3os/github/delete-webhook@1.0.0 · effect irreversible · connection token · MCP tool github__delete-webhook
bashcurl -s https://beta-api.b3os.org/v1/actions/call \ -H "Authorization: Bearer $B3OS_API_KEY" \ -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \ -H "Content-Type: application/json" \ -d '{ "ref": "io.b3os/github/delete-webhook@1", "input": {"owner": "acme", "repo": "widgets", "hook_id": 512345678}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"} }'
tsimport { B3OS } from "@b3os/sdk";const b3os = new B3OS();const result = await b3os.actions.call({ ref: "io.b3os/github/delete-webhook@1", input: { owner: "acme", repo: "widgets", hook_id: 512345678 }, connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },}, { idempotencyKey: crypto.randomUUID() });console.log(result.output);
pythonimport uuidfrom b3os import B3OSb3os = B3OS()result = b3os.actions.call({ "ref": "io.b3os/github/delete-webhook@1", "input": {"owner": "acme", "repo": "widgets", "hook_id": 512345678}, "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},}, idempotency_key=str(uuid.uuid4()))print(result["output"])
json{ "method": "tools/call", "params": { "name": "github__delete-webhook", "arguments": {"owner": "acme", "repo": "widgets", "hook_id": 512345678} }}
Expose the pack as tools with --packs github on the local server or ?packs=github on the remote URL, and the agent calls github__delete-webhook with the action's input. The tool uses your newest connection for each key without a subject. Without exposing the pack, actions_call takes the same input with ref.
Output, labeled fixture: Delete repository webhook (documented response shape, example values). From the bundle's fixtures/delete-webhook.json, not a live call.
json{"deleted": true, "hook_id": 512345678}
When the service answers with an error, the call fails with upstream_error and pack_error.code is one of:
pack_error.code | Service status | Retryable | Message |
|---|---|---|---|
not_found | 404 | no | No such webhook in this repository. |
connection_unauthorized | 401 | no | GitHub rejected the token. |
rate_limited | 403, 429 | yes | GitHub rate limit reached; it resets at the time in the x-ratelimit-reset header. |
forbidden | 403 | no | built from the service's response |
gone | 410 | no | Issues are disabled for this repository. |
invalid_request | 422 | no | built from the service's response |
Triggers
repo-event
(trigger)
Repository event. Fires on GitHub repository events as they happen (issues opened or closed, pull requests, pushes, releases, comments, ...): B3OS creates a webhook on the repository with a generated secret, verifies every delivery's X-Hub-Signature-256, and removes the webhook when the subscription is deleted. The event carries the event type, action, repository, sender and GitHub's full payload. Needs a token that can manage webhooks (admin:repo_hook).
Ref io.b3os/github/repo-event@1.0.0 · webhook, signature scheme github with a secret B3OS generates · connection token
with key | Required | Description |
|---|---|---|
owner | yes | Repository owner. |
repo | yes | Repository name. |
events | no | GitHub event names to receive, or * for every event. Default ["issues","pull_request","push"]. |
In a routine:
yamltriggers: - type: action id: repo_event uses: io.b3os/github/repo-event@1 with: owner: acme repo: widgets events: - issues - pull_request connections: token: conn_01m5t6cbgdjs1ketgcqwa2sne8
Event, labeled fixture: the recorded delivery in fixtures/repo-event-issue-opened.json (Repository event (delivery signed with a throwaway test secret)). A routine reads it as trigger.data; its fields are type, action, repository, sender, delivery, payload.
json{ "type": "issues", "action": "opened", "repository": "acme/widgets", "sender": "mona", "delivery": "72d3162e-cc78-11e3-81ab-4c9367dc0958", "payload": { "action": "opened", "issue": { "id": 3051234542, "node_id": "I_kwDOAAAAAM6AAAAA", "url": "https://api.github.com/repos/acme/widgets/issues/42", "html_url": "https://github.com/acme/widgets/issues/42", "number": 42, "state": "open", "state_reason": null, "title": "Cart overflows on narrow screens", "body": "Steps to reproduce:\n\n1. Open the cart\n2. Resize to 375px", "user": { "login": "mona-example", "id": 1000002, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://avatars.githubusercontent.com/u/1000002?v=4", "html_url": "https://github.com/mona-example", "type": "User", "site_admin": false }, "labels": [ { "id": 208045946, "node_id": "MDU6TGFiZWwyMDgwNDU5NDY=", "name": "bug", "color": "d73a4a", "default": false, "description": null } ], "assignees": [ { "login": "hubot-example", "id": 1000003, "node_id": "MDQ6VXNlcjE=", "avatar_url": "https://avatars.githubusercontent.com/u/1000003?v=4", "html_url": "https://github.com/hubot-example", "type": "User", "site_admin": false } ], "comments": 2, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "author_association": "CONTRIBUTOR" }, "repository": { "id": 1296269, "name": "widgets", "full_name": "acme/widgets", "private": false }, "sender": {"login": "mona", "id": 583231, "type": "User"} }}
new-issue
(trigger)
New issue. Fires once for each new issue opened in a repository (pull requests are skipped), optionally only with given labels, checked every 2 minutes by default. The first check records existing issues and emits nothing.
Ref io.b3os/github/new-issue@1.0.0 · poll of list-issues, every 120 s by default (at least 60 s) · connection token
with key | Required | Description |
|---|---|---|
owner | yes | Repository owner. |
repo | yes | Repository name. |
labels | no | Only issues with every one of these labels. |
In a routine:
yamltriggers: - type: action id: new_issue uses: io.b3os/github/new-issue@1 with: owner: acme repo: widgets connections: token: conn_01m5t6cbgdjs1ketgcqwa2sne8
Event, labeled fixture: the first item of list-issues's fixture fixtures/list-issues.json (List issues (documented response shape, example values)) through the trigger's event mapping. A routine reads it as trigger.data; its fields are number, title, state, state_reason, html_url, author, labels, assignees, comments, created_at, updated_at, closed_at, is_pull_request.
json{ "number": 42, "title": "Cart overflows on narrow screens", "state": "open", "state_reason": null, "html_url": "https://github.com/acme/widgets/issues/42", "author": "mona-example", "labels": ["bug"], "assignees": ["hubot-example"], "comments": 2, "created_at": "2026-10-24T17:11:20Z", "updated_at": "2026-10-25T09:02:41Z", "closed_at": null, "is_pull_request": false}