Skip to content

Report what CI and integrations find on a commit as statuses and check runs, see them beside every commit, and require them before a merge.

Every commit can carry checks: what your workflows, your CI, your deployments and any integration say about it. g1t shows them beside the commit wherever it appears, so you can tell at a glance whether a change works and how far along it is.

  • A green check: every check passed.
  • A red cross: at least one failed.
  • An amber dot: at least one is still running or queued.

Select the mark to see the list: a headline (“All checks have passed”, “Some checks were not successful” or “Some checks haven’t completed yet”), how many passed, failed and are running, and each check with how it went, how long it took, and a Details link.

Page Where
Code Beside the latest commit, above the files
Commits Beside each commit
A commit’s page Beside its hash
Branches Beside each branch’s latest commit
Tags Beside each tagged commit
A pull request Beside its head commit, in the sidebar; its merge box lists them too
A project’s overview Beside the latest commit, and each active branch

A page reads the checks of all its commits at once, after the page itself has loaded: each mark shows a placeholder until they arrive.

There are two ways to report a check. Use either, or both.

A status A check run
What it is A state for one context on a commit, such as ci/build One run of one check, with a life of its own
States pending, success, failure, error status: queued, in_progress, completed; once completed, a conclusion: success, failure, neutral, cancelled, skipped, timed_out or action_required
Report A short description and a target_url A title, a Markdown summary and text, up to 1,000 annotations on lines of files, and up to 3 buttons
On g1t Listed with a link to target_url Its own page under the repository, linked from the list
Set again Replaces the context’s status on that commit Update the same run, or create a new one
Use it for A quick pass or fail from any tool Test, lint and scan results someone needs to read

Every job of a workflow run is a check run, named Workflow / job (event) in the list, such as CI / test (push), and its Details opens the job’s log. You do not report those: g1t does.

You need a token with the checks:write scope (see scopes) and the Write role on the repository.

curl -X POST https://api.g1t.sh/repos/<workspace>/<repo>/statuses/<sha> \
-H "Authorization: Bearer $G1T_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"state": "success",
"context": "ci/build",
"description": "Build #4821 passed",
"target_url": "https://ci.example.com/builds/4821"
}'
Field Required What it is
state Yes pending, success, failure or error. error counts as a failure.
context No What reports it, such as ci/build; default when left out. At most 100 characters.
description No A short word on it, at most 140 characters.
target_url No Where to see more: an http or https address.

create_commit_status returns the status. Set a context again to replace it: report pending when a build starts, then success or failure when it ends. get_combined_status gives a commit’s statuses and what they add up to: GET /repos/<workspace>/<repo>/commits/<ref>/status, where <ref> is a commit SHA, a branch or a tag.

A check run is reported in two steps: create it when the work starts, then complete it.

  1. Create it, in progress:

    curl -X POST https://api.g1t.sh/repos/<workspace>/<repo>/check-runs \
    -H "Authorization: Bearer $G1T_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"name": "lint", "head_sha": "<sha>", "status": "in_progress", "details_url": "https://ci.example.com/builds/4821"}'

    The answer has its id, such as cr_01kq4b7c8d9e0f1g2h3j4k5m6n.

  2. Complete it with a conclusion, a report and annotations:

    curl -X PATCH https://api.g1t.sh/repos/<workspace>/<repo>/check-runs/<id> \
    -H "Authorization: Bearer $G1T_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
    "conclusion": "failure",
    "output": {
    "title": "2 problems",
    "summary": "**2** problems in `src/parse.rs`.",
    "annotations": [
    {"path": "src/parse.rs", "start_line": 42, "end_line": 42, "annotation_level": "warning", "message": "unused variable: `depth`"},
    {"path": "src/parse.rs", "start_line": 57, "end_line": 60, "annotation_level": "failure", "message": "this match is not exhaustive"}
    ]
    }
    }'

Giving a conclusion completes the run; started_at and completed_at are filled in when you leave them out. A run can also be created already completed, in one call.

Field What it is
name The check’s name, at most 100 characters. Required to create one.
head_sha The commit it is about. Required to create one.
status queued (the default), in_progress or completed.
conclusion success, failure, neutral, cancelled, skipped, timed_out or action_required.
started_at, completed_at When it started and ended, in RFC 3339.
details_url Your own page for it.
external_id Your own id for it.
output title, summary and text (Markdown, at most 65,535 characters each) and annotations.
actions Up to 3 buttons: label (20 characters), description (40) and identifier (20).
app Who reports it, such as Codecov. By default, your token’s name.

This script runs a command and reports it as a check run, from any CI that has curl and jq:

#!/bin/sh
# check.sh <name> <command…>: report a command as a g1t check run.
set -u
name=$1; shift
api="https://api.g1t.sh/repos/$G1T_REPO"
auth="Authorization: Bearer $G1T_TOKEN"
id=$(curl -sf -X POST "$api/check-runs" -H "$auth" -H "Content-Type: application/json" \
-d "$(jq -n --arg name "$name" --arg sha "$G1T_SHA" '{name: $name, head_sha: $sha, status: "in_progress"}')" | jq -r .id)
if output=$("$@" 2>&1); then conclusion=success; else conclusion=failure; fi
curl -sf -X PATCH "$api/check-runs/$id" -H "$auth" -H "Content-Type: application/json" \
-d "$(jq -n --arg c "$conclusion" --arg log "$(printf '%s' "$output" | tail -c 60000)" \
'{conclusion: $c, output: {title: $c, summary: ("```\n" + $log + "\n```")}}')" > /dev/null
[ "$conclusion" = success ]
G1T_REPO=acme/web G1T_SHA=$(git rev-parse HEAD) ./check.sh lint npm run lint

An annotation points at lines of a file at the run’s commit: path, start_line and end_line (from 1), and for one line, start_column and end_column. annotation_level is notice, warning or failure; message says what is wrong, title names it, and raw_details holds anything longer.

Send at most 50 in one request; each update adds to those the run has, up to 1,000. On the check run’s page they are grouped by file, each linking to its lines. list_check_run_annotations returns them in the order they were reported.

actions puts up to 3 buttons on the check run’s page, such as Fix this or Ignore. When someone with the Write role presses one, g1t sends your webhook a check_run.requested_action event with the button’s identifier in data.requested_action. What happens next is up to you.

Each reporter’s check runs on a commit form one check suite, with a status and conclusion worked out from its latest runs: in progress while any is, then the worst conclusion. A workflow run is the suite of its jobs. list_check_suites_for_ref lists a commit’s suites. A suite completing sends check_suite.completed.

A workflow job reports extra check runs with its own G1T_TOKEN, given checks: write in its permissions:. They report as g1t Actions:

- name: Report coverage
if: always()
env:
G1T_TOKEN: ${{ secrets.G1T_TOKEN }}
run: |
curl -sf -X POST "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/check-runs" \
-H "Authorization: Bearer $G1T_TOKEN" -H "Content-Type: application/json" \
-d "{\"name\": \"coverage\", \"head_sha\": \"$GITHUB_SHA\", \"conclusion\": \"neutral\", \"output\": {\"title\": \"81% covered\", \"summary\": \"Up 2% from main.\"}}"

A pull request’s runs from someone without the Write role get no token that can write, so they cannot report checks.

A required status check, in branch protection or a ruleset, is met by a status of its name or a check run of its name alike:

What reported it Counts as
A status success Passing
A status failure or error Failing
A status pending Running: the merge waits
A check run not yet completed Running: the merge waits
A check run completed success, neutral or skipped Passing
A check run completed failure, cancelled, timed_out or action_required Failing
Nothing yet Expected: the merge waits

A workflow is required by its name, such as CI, which all its jobs report under. To require only what was reported through the API, pin the check to the api integration in a ruleset: {"context": "lint", "integration": "api"}.

A pull request g1t is working on goes back to g1t when a check fails, whatever reported it.

rerequest_check_run and rerequest_check_suite, or Re-run on a check run’s page, ask for it to run again. A check run reported through the API sends its reporter check_run.rerequested (or check_suite.rerequested): run it again and report a new check run. A workflow job’s run runs again, which also needs workflows:write.

Webhooks can be sent:

Event When
status.created A status was set on a commit through the API.
check_run.created A check run was reported.
check_run.completed A check run completed.
check_run.rerequested Someone asked for a check run to run again.
check_run.requested_action Someone pressed one of a check run’s buttons.
check_suite.completed Every latest check run of a suite completed.
check_suite.rerequested Someone asked for a check suite to run again.

These are left out of a repository’s timeline.

Can
Anyone who can read the repository See its checks, and read them through the API with checks:read (no token for a public repository)
The Write role and up, with checks:write Report statuses and check runs, and ask for them to run again
A workflow job, with G1T_TOKEN and checks: write or statuses: write The same, in its repository
g1t’s agents Read checks, never report them

An agent’s own work is never judged by checks it reported: what a check says is up to your CI and integrations.

Route Operation
POST /repos/{owner}/{name}/statuses/{sha} create_commit_status
GET /repos/{owner}/{name}/commits/{ref}/statuses list_commit_statuses
GET /repos/{owner}/{name}/commits/{ref}/status get_combined_status
POST /repos/{owner}/{name}/check-runs create_check_run
PATCH /repos/{owner}/{name}/check-runs/{id} update_check_run
GET /repos/{owner}/{name}/check-runs/{id} get_check_run
GET /repos/{owner}/{name}/check-runs/{id}/annotations list_check_run_annotations
POST /repos/{owner}/{name}/check-runs/{id}/rerequest rerequest_check_run
GET /repos/{owner}/{name}/commits/{ref}/check-runs list_check_runs_for_ref
GET /repos/{owner}/{name}/commits/{ref}/check-suites list_check_suites_for_ref
GET /repos/{owner}/{name}/check-suites/{id} get_check_suite
POST /repos/{owner}/{name}/check-suites/{id}/rerequest rerequest_check_suite

list_check_runs_for_ref gives each name’s latest run and each workflow’s latest run per event; filter=all gives every one. Narrow it with check_name, status and app (a reporter’s slug; actions for workflow jobs).

On the MCP server, the workflow tool has an action for each: combined_status, list_statuses, set_status, list_check_runs, get_check_run, check_run_annotations, create_check_run, update_check_run, rerequest_check_run, list_check_suites, get_check_suite and rerequest_check_suite.