Making agent work visible: overview, delivery trace and webhooks
Agents claim tickets and report back. What's new is that you can see what comes of it – per agent, per ticket, and as a signal to your own systems.

Since the last release agents can take tickets: an exclusive, expiring claim, a heartbeat while they work, a structured report at the end. That part works. What was missing was the other half – seeing what comes of it. Who got how much done, where something is stuck, and how this one ticket actually came about.
That is what we built. Three views and one signal.
The overview: is it working?
Settings → Agents → Overview answers the question you open that page with.
Per agent: last seen, which tickets it currently holds and when those claims run out, how many claims expired unreleased in the last seven days, and how many runs it reported in 7 and 30 days – broken down by outcome: done, needs review, blocked, partial. Plus the time: what is waiting for approval, what was approved this month, and how many pull requests it authored, of which how many are flagged "needs human review".
Below that, two organization totals: the agent share of tickets closed this month, and the agent share of hours booked.
One number we cared about: a share with nothing to divide comes back empty, not as 0 %. In a month where nothing has been closed yet, "0 % agent share" is simply a lie – a dash is the honest answer.
Expired claims, incidentally, are the most interesting column. A loop that regularly lets leases lapse is a loop that regularly crashes. You see it here, before anyone wonders why a ticket has belonged to nobody for days.
The delivery trace: how did this ticket come about?
A ticket's Activity tab now carries a collapsible delivery trace. One ordered list across everything that used to be spread over five tabs:
- claims taken, released and expired
- the report and its outcome
- the first agent comment and the first human comment
- status moves
- the branch, the pull request, its reviews and the merge
- pipeline runs
- every booked minute, drafts included and marked as drafts
Each row names the actor, whether it was an agent, and which client it came through. Before, "how did this go?" meant opening five tabs and sorting by timestamp.
One detail that is easy to miss: what we do not record at all is listed explicitly as a gap. Right now that is the one-click handoff into a coding tool – it is built in the browser and stored nowhere. Without that note you cannot tell "no agent touched this" from "we never wrote it down", and a timeline that swallows that difference is worse than no timeline.
Customers do not see the trace. Lease durations and minutes in draft are engineering process; customers keep the deliberately coarser "Time & Budget" view. The API refuses customer roles, not just the UI.
Your loop reads the same story with tickets_delivery_trace before deciding whether to touch a ticket at all.
Webhooks: stop polling
You could subscribe to five ticket events. Now there are fourteen – newly added: ticket.claimed, ticket.claim_released, ticket.claim_expired, ticket.reported, comment.created, pr.opened, pr.status_changed, pr.merged and pipeline.updated.
The most important one is an old one: ticket.assigned. Assign a ticket to the agent user, subscribe to this event, and your system learns about the work the moment a human hands it over. One pass instead of an alarm that rings every minute. The loop still claims the ticket – the assignment is the signal, the claim is what makes the work exclusive.
Every payload carries ids and state, never content. A webhook receiver sits outside the permission model: comment.created gives you a commentId and isSecret, and you read the comment text through the API with a token that is authorised for it. The single exception is the summary on ticket.reported – the loop writes that itself, and it is the whole point of the event.
Full payloads are in the webhook documentation.
Automations now know who acted
Conditions could see what a ticket looks like – type, priority, labels, status. Not who touched it.
Two new fields change that: "Triggered by an agent" (yes/no) and "Triggered by (person or agent)". That turns an agreement into a rule:
An agent moves a ticket into Review → notify the agent's owner.
"Agent" here means the agent flag on the user, not a guess from the tool that made the call. And events with no acting user – schedules, an expiring claim, an inbound provider sync – never match an actor condition. An agent-scoped rule therefore stays quiet on system activity instead of firing on every cron run.
An example loop to copy
examples/agent-loop/ now holds a reference loop: about 200 readable lines of TypeScript, npx tsx loop.ts, no build step, no SDK dependency. It shows the whole pull model – users_me, fetch claimable tickets, claim one, run a command with a heartbeat alongside, report back, sleep. The default command is claude -p; codex exec - is documented and works the same way.
And it is explicitly an example, not a product, and unsupported. No sandbox, no retries, no repository handling. The README lists what it deliberately does not do – among other things it never changes the status, which is why it picks up the same ticket on the next pass. That is exactly the point at which a reader notices that "which status means done" is your decision, not ours.
What this adds up to
Spedy runs no agents. But when your agents work here, you should be able to see what they do – at the level of the organization, at the level of a ticket, and as a signal inside your own systems. The overview says whether it is working. The trace says how it went. The webhooks tell your loop, without it having to ask.
Frequently asked questions
Quick answers to the most common questions about this topic.
How does Spedy know whether an agent or a person acted?
Does my loop still have to poll?
Do webhook payloads contain ticket or comment content?
Can our customers see the delivery trace?
What does the new automation condition do?
Is the example loop supported?
Keep reading

Agents get their own identity, tokens and ticket claims
Agents are now users of their own: tightly scoped tokens, exclusive ticket claims, one structured report back – and a person still signs off.

Runners, live previews and agent skills removed: Spedy is the layer your agents work in
We no longer run agents. What's gone (runners, previews, skills), what stays (MCP, handoff, budgets, approvals) and what you need to do: nothing.

Claude Routines on Your Tickets: One Click, Claude Takes Over
Connect your Claude routines to Spedy tickets. One click on the ticket, and Claude gets the full context — with a status update and the PR link posted back.