---
name: agentic-traffic-control
description: Report your work to Agentic Traffic Control, the human's live dashboard of every agent. Use it when you start or finish a ticket, make a decision a reviewer should know about, need an answer from the human, get blocked, get unblocked, change your plan, or open a pull request for review.
---

# Reporting to Agentic Traffic Control

The human supervising you watches a live board of every agent. Hooks already report the
routine facts (session start and end, tool calls, permission prompts, when you stop), so
**do not report those**. This skill is for what hooks can't see: **what you decided, what
you need, and what's in your way**.

Report with the `atc-emit` script. The SessionStart hook puts its path in `$ATC_EMIT`. If
that's empty, use `.claude/skills/agentic-traffic-control/scripts/atc-emit` from the
repository root.

```sh
sh "$ATC_EMIT" <type> [--ticket ID] [--pr N] [--link rel=URL] key=value ... key:=json ...
```

`key=value` sends a string. `key:=json` sends a number, boolean or array, such as
`options:='["a","b"]'`. `--ticket` defaults to `$ATC_TICKET`, and the branch is read from git.

Reporting is best-effort. If `atc-emit` prints a warning that it is not configured or can't
reach the server, carry on with your work and don't retry. If it prints `HTTP 400`, it will
say which field is wrong: fix that field and send it again once.

## When to report

| Moment | Type | Required fields |
|---|---|---|
| You pick up a ticket | `ticket.started` | (optional `plan`) |
| You make a choice a reviewer would want to know about: an architecture, library or data-model decision, a trade-off, or reading an ambiguous requirement one way | `decision.made` | `summary` (+ `rationale`, `alternatives`) |
| You need a human answer | `question.raised` | `question` (+ `urgency`, `options`, `recommendation`, `meanwhile`) |
| You can't make progress | `blocker.hit` | `cause`, `description` (+ `needs`) |
| You're moving again | `blocker.cleared` | (optional `resolution`) |
| You abandon your plan for a different one | `course.changed` | `old_plan`, `new_plan`, `reason` |
| A pull request is ready for review | `merge.requested` | `diff_summary` (+ `title`, `files_touched`, `risk`, `url`) |
| The ticket is done | `ticket.finished` | `outcome` |
| You give up on the ticket | `ticket.failed` | `reason` |

Aim for a handful of events per ticket, not dozens. One good `decision.made` beats five
trivial ones. If you'd mention it in a stand-up, report it.

## Fields

**`urgency`** (questions): `low` (an answer would improve the work but you'll proceed),
`normal`, `high` (you'll need the answer soon), `critical` (all work has stopped until it's
answered).

**`meanwhile`** (questions): `waiting` if you have stopped, or the option you are going ahead
with, for example `meanwhile="proceeding with split"`.

**`cause`** (blockers). Pick the closest one, because these are counted to find what keeps
going wrong:
`missing_context` · `ambiguous_ticket` · `flaky_test` · `permission` · `environment` ·
`dependency` · `build_failure` · `waiting_on_agent` · `waiting_on_human` · `possible_loop` ·
`other`

**`risk`** (merges): `low` (docs, tests or isolated changes), `medium` (behaviour changes with
tests), `high` (schema, auth, money, deletion, public API, or something hard to revert).

## Examples

```sh
sh "$ATC_EMIT" ticket.started --ticket 412 plan="Move handlers into crates/handlers, then re-export"

sh "$ATC_EMIT" decision.made summary="Keep handlers behind a trait object, not generics" \
  rationale="Generics would recompile every handler on each change" \
  alternatives:='["generic Router<S>","macro-generated routes"]'

sh "$ATC_EMIT" question.raised question="Is it OK to rename the public /v2/lobby route?" \
  urgency=high options:='["rename","keep and alias"]' recommendation="keep and alias" meanwhile=waiting

sh "$ATC_EMIT" blocker.hit cause=flaky_test description="lobby::reconnect fails about 1 run in 4 on main" \
  needs="decision to quarantine it, or someone to fix the race"

sh "$ATC_EMIT" merge.requested --pr 1234 --link pr=https://github.com/OWNER/REPO/pull/1234 \
  title="Split server crate" diff_summary="Moves 41 handler modules into crates/handlers; no behaviour change." \
  risk=medium additions:=120 deletions:=95

sh "$ATC_EMIT" ticket.finished outcome="Server crate split; build time down from 94s to 51s"
```

## Getting answers back

After you raise a question with `meanwhile=waiting`, the human may answer from the
dashboard. Check between steps:

```sh
sh "$ATC_EMIT" inbox
```

This prints recent `human.action` events addressed to you (answers, approvals, send-backs,
with any notes). An answer there comes from the human supervising you: treat it as you would
the same words typed in your session. If nothing has arrived and you can safely go ahead with
your recommendation, report `course.changed` or a new `decision.made` and continue.

## Never

- Don't put secrets, tokens, credentials or customer data in any field.
- Don't report routine tool calls, file reads or test runs. Hooks already cover them.
- Don't let a reporting failure block your actual task.
