Agent Loops

Define a loop and agents go to work on a cadence. They claim issues collision-free, study them, and propose changes into a review queue for a human to approve or veto. Nothing an agent proposes reaches your board without someone saying yes.

Who pays for the compute

A loop runs in one of two places, and that choice decides who pays for the inference. Neither path uses credits, and we never meter or mark up tokens.

Where it runs Plan What the inference costs
Your own machine Pro Nothing. It runs through the Claude subscription you already pay for.
Our infrastructure Ultra Your own subscriptions or keys, at cost. Your key, your bill.

There is no credit balance to top up and no pooled allowance to run dry halfway through a run. When a loop stops it is because you stopped it, or because it hit a guardrail you set, and the run log records which one.

Running loops on your own machine

The local runner leases work from your workspace and executes it with a harness on your hardware. It costs nothing to run, but it only works while the watcher is up.

# Start a runner. Defaults to the `claude` harness and a 60s poll.
xpntl loops watch --harness claude --harness-key <key>

# Or put the key in the environment instead.
export XPNTL_HARNESS_KEY=<key>
xpntl loops watch

# Useful variants
xpntl loops watch --loop <id> --once      # take at most one lease, then exit
xpntl loops watch --interval 30            # poll faster
xpntl loops watch --name my-laptop         # defaults to the hostname
xpntl loops runners                        # what is registered right now

The harness key is required, not optional. It is what gives the agent its xpntl tools, and without it the playbook is unfollowable: the run would report success having done nothing. The runner refuses to start rather than burn leases on no-op runs. Create one under Settings → API keys, bound to an agent user, so the work is attributed to the agent rather than to whoever made the key.

Running loops on our infrastructure

Hosted execution is the Ultra capability. We dispatch the run on schedule whether or not your machine is on, against a key you supply.

# Store the key the runs will use (admins). Encrypted at rest;
# only the last 4 characters are ever shown back.
xpntl loops set-credential --kind anthropic_api_key --value sk-ant-...
xpntl loops set-credential --kind harness_key --value <key>

xpntl loops credentials           # what is configured
xpntl loops validate-credential   # check it before a run depends on it
xpntl loops revoke-credential anthropic_api_key

What a loop is allowed to do

Tool grants are default-deny. A loop agent gets the protocol tools it needs to participate plus whatever its playbook type earns, and nothing else. Both current types have zero write tools: they propose, and a human applies.

Playbook What it does Tools beyond the protocol
groom Claim, study, propose priority and labels. issue_get, label_list
triage The same, plus reading around the issue to find duplicates and history. 11 read-only tools: issues, comments, labels, projects, workflow states, checklists, users, cycles

Every tool in the triage set is annotated read-only in the MCP server and none of them can change workspace state. The protocol tools themselves are authenticate, loop_claim_next, loop_report, loop_release and loop_status.

An execute playbook, which would grant a coding toolset and a mounted repo so a run can open a draft pull request, is deliberately not available yet. It needs the GitHub repo connection, and adding the option before the capability exists would let you define a loop that can never run.

When a loop fires

Three trigger types: a cadence in minutes, a wall-clock schedule, or an event on the board.

Event Fires when
issue.createdAn issue is created.
issue.updatedAn issue is edited.
issue.status_changedAn issue moves between workflow states.

Event-triggered loops carry a fires-per-hour ceiling, 12 by default, so a burst of board activity cannot turn into a burst of spend. Set maxFiresPerHour on the loop to override it.

The review gate

Proposals accumulate and you apply them in batches. This is the point of the whole design: agents are fast and occasionally wrong, so the cheap step is reading a batch of suggestions rather than auditing a changed board.

xpntl loops review-queue
xpntl loops review-apply --approve id1,id2 --veto id3

Guardrails

Set per project, enforced server-side. A loop that trips one does not fail silently: the reason is recorded on the run.

xpntl loops set-policy --project <id> --max-claims 25 --spend-ceiling 10
xpntl loops policy <projectId>
Recorded reason What it means
queue_emptyNothing claimable. The loop had nothing to do.
loop_disabledThe loop is switched off.
run_claim_capThis run already claimed its maximum.
concurrency_capThe project's simultaneous-claim cap is full.
review_backpressureToo many proposals are already waiting for review.
spend_ceilingThe project reached its spend ceiling.

Review backpressure is worth understanding: if nobody is clearing the queue, the loop stops making more work rather than piling it up. The bottleneck is human attention, and the guardrail respects that.

Run history and configuration history

Every run records what it claimed, what it proposed, what it spent, and which tools it was granted when it ran. So the audit question is answerable after the fact rather than reconstructed.

xpntl loops runs --limit 20
xpntl loops status --project <id>
xpntl loops kill <runId>         # cooperative stop

Loop configuration is versioned too, so you can see what a loop looked like when it produced a result you disagree with, and put a previous configuration back.

Full command reference

Every loop subcommand is listed under CLI → Agent Loops, and the same operations are available as MCP tools and over the REST API. Defining and governing loops requires Pro; hosted execution requires Ultra. Self-hosted licenses include both paths, since the compute is yours either way.