Docs
Reporting from a runner
A CI job, a server or a cloud agent with no FEATit bridge reports that it is working and what tokens it used, with its own agent key.
On a developer’s machine the bridge reports each agent session for you. A runner with no bridge, such as a CI job, a server or a cloud agent, reports its own session instead, with its own agent key. It then shows in the Agents view as working, and its token usage is counted and priced like any other.
1. An agent key
Create the agent the runner works as, let it act in a work area, and mint its key:
featit agent-new ci-runner --name "CI runner"
featit work-area-agents grant-access ci-runner --work-area <work area>
featit agent-credential mint ci-runner --label "CI runner"
The mint prints the key’s access token once. Give it to the runner as the secret FEATIT_TOKEN, and every featit command there acts as the agent. A runner that outlives the access token exchanges the refresh secret the mint printed at POST /api/auth/refresh.
The key reports for its own agent’s sessions and for no other. A session another agent already holds is refused, and a report never takes a session from another agent. A key made before agents could report their own sessions is refused: the answer says the key “may not report presence or token usage” and asks for a new one. Mint it as in the first step and give the runner the new token:
featit agent-credential mint ci-runner --label "CI runner"
2. Name the session
Every report names the session as <harness>:<id>: a name for the runner, a colon, and an id that stays the same for the life of the run.
export FEATIT_SESSION_REF="ci-runner:build-4812"
The harness name is lowercase letters, digits and hyphens. The same variable attributes the runner’s items, comments and commits to the same session. A commit is placed in the session once the runner has reported it, which its first event does. A commit made before then counts as the agent’s, in no session.
3. Say that it is working
featit agent event SessionStart
featit agent event UserPromptSubmit # it takes on a task
featit agent event PreToolUse --tool shell # around each step, the step's name only
featit agent event PostToolUse --tool shell
featit agent event PermissionRequest --tool shell # it waits for its person to allow a step
featit agent event Stop # it hands back
featit agent event SessionEnd
PermissionRequest shows the session as waiting for you in the Agents view until the runner reports its next step, prompt or Stop.
--folder <repository folder name> on an event places the session in the work area that declares that folder.
4. Report the tokens it used
featit agent usage --model claude-sonnet-5 \
--input 12000 --output 3400 --cache-read 880000 --cache-write 40000
The numbers are the totals so far in the current reporting interval, ten minutes unless your deployment changed it. A second report for the same interval replaces the first, so a runner reports its running totals, and a repeated report is safe. Leave out --cache-write when the provider reports none: it is then shown as not reported, never as 0.
5. Record its commits
In the runner’s checkout, with the key and the session variable already set, install the commit hook before the job commits, and send what it recorded before the job ends:
featit git-hooks install --work-area <work area>
# … the job commits …
featit commit-sync
The hook notes each commit and uploads it in the background. featit commit-sync sends anything still waiting, so a commit is not lost when the job exits first. Where FEATIT_API_BASE_URL names your server, the hook sends its uploads there too.
The API
Both commands call the API directly, so a runner can do the same without the CLI. Authenticate with the agent key as a bearer token.
POST /api/agents/activity says what the session is doing:
{
"epoch": "<run id>",
"events": [
{ "provider": "ci-runner", "sessionRef": "build-4812", "event": "SessionStart",
"occurredAt": "2026-09-28T10:00:00Z", "sequence": 1 }
]
}
POST /api/agents/usage reports its tokens, one bin per model and interval:
{
"bins": [
{ "provider": "ci-runner", "sessionRef": "build-4812", "model": "claude-sonnet-5",
"binStart": "2026-09-28T10:00:00Z", "binSeconds": 600, "inputTokens": 12000,
"outputTokens": 3400, "cacheCreationInputTokens": 40000,
"cacheReadInputTokens": 880000, "apiCalls": 9 }
]
}
GET /api/agents/usage/reporting answers the interval to cut bins at, binSeconds, and the sizes allowed. An event may also carry toolName and launchFolder.
sequence increases within an epoch, so a repeated event is recognised and applied once. binStart is a multiple of binSeconds since the Unix epoch. A usage receipt lists any bin it set aside and why: another-agents-session for a session another agent holds.
Each key may report up to 120 times a minute to each call. Above that the answer is 429 with Retry-After in seconds.
What it costs
Usage reported this way is priced like any other: from your organisation’s own price per model, on the items the session worked on. See it with featit cost, on an item, on a release and in the Agents view.