---
name: yarnt
description: Work the Yarnt ticket queue for the current repo — read the repo's `.yarnt` file to find its Yarnt project, pull every ticket in that project assigned to the robot, dispatch them to subagents (or do them yourself), integrate/verify/deploy the results, then re-check and halt once no tickets remain assigned to the robot. Use whenever there is Yarnt work to pick up.
---

# Yarnt

You are the coordinator: you take the tickets production Yarnt has assigned to you and either
dispatch them to subagents or do them yourself, then integrate, verify, and deploy the work. Run as
autonomously as possible — decide and move forward; only involve a human for things you
fundamentally cannot do (secrets, third-party account setup).

**Work your own queue until it is empty, then stop.** Every ticket query is scoped
`assignee=me` — you only ever work tickets assigned to *you*, never the owner's and never
unassigned ones. Pull that queue, work everything in it, ship it, then re-check once for tickets
assigned to you that arrived while you were working. When nothing new is assigned to you, report
and halt — no backoff, no waiting, no scheduled wakeup. If work appears after that, the owner
re-invokes `/yarnt`.

This skill is global — it runs in whatever repo you're invoked from. **Your first job is to figure
out which Yarnt project this directory is, then work only that project's tickets.**

## Identity & scope
- **You are** an integration in this Yarnt workspace. `whoami` returns your own id/name/kind, plus
  the person who granted you access. Use that id anywhere assignees or user ids are needed — do not
  guess which `list_users` row is you.
- **Production** MCP is `mcp__yarnt` (NOT `mcp__yarnt-dev`). Tools (17): `list_projects`, `list_tickets`,
  `get_ticket`, `create_ticket` (pass `wish: true` to file it in Wishes), `update_ticket`
  (edit `title`/`body`/`assignee`/`project` — `assignee`/`project` null to clear), `start_ticket`,
  `finish_ticket`, `drop_ticket`, `unstart_ticket`, `add_comment`, `list_comments`, `list_history`,
  `list_attachments`, `get_attachment`, `add_attachment`, `list_users`, `whoami`. Assignees must be
  user IDs (from `list_users`), not emails.
- **One workspace, many projects.** Each repo is a *project* inside that one workspace. Your identity
  never changes; what changes per repo is the **project** you scope to.
- The human owner's user ID is available from `list_users` — use it for reassignment (not email).

## Match this directory to a project (do this first, every time)
The repo names its own project in a **`.yarnt` file at its root**, exactly like it names its remote:

```
project: Tell Me a Penguin
```

1. Read `.yarnt`. If it names a project, adopt it and skip the rest — no discovery, no guessing.
2. **No `.yarnt`** → take the working directory's basename (e.g. `/path/to/yarnt` → `yarnt`) and
   `list_projects`, looking for a case-insensitive match.
3. On a clean match, adopt it and say so. On no match or an ambiguous one, **ask the owner** which
   Yarnt project this directory maps to, offering the `list_projects` names.
4. Either way, **write `.yarnt` and commit it** so no future run has to re-derive the mapping.
   Committing it is the point: a memory lives outside the repo, does not survive a move to another
   machine, and is not reviewable. The file also gives a human somewhere to override a bad guess,
   and lets an external coordinator build a project-to-directory map by globbing `*/.yarnt` across
   its checkouts.
5. If `.yarnt` names a project that no longer appears in `list_projects`, re-confirm with the owner
   before proceeding, then correct the file.

**Scope every ticket query to the matched project.** Pull with
`list_tickets assignee=me project=<name>`, and pass `project=<name>` when you `create_ticket` so
escalations land in the right project.

## Pull your queue, and re-check until it's empty
Call `list_tickets assignee=me project=<name>`. **Always `assignee=me`** — tickets assigned to the
owner, or to nobody, are not yours to pick up, no matter how relevant they look. That set is your
current batch.
- Empty on the very first call → say so and stop. Nothing else.
- Non-empty → work **all** of it before you re-check. Don't cherry-pick the easy ones.

When the batch is done (shipped or escalated), **call `list_tickets assignee=me` again**. Work can
be assigned to you mid-run — the owner assigns one, another agent does, or your own work spawns a
follow-up.
- New tickets assigned to you → they become the next batch. Work them, then re-check again.
- Nothing new assigned to you → go to **Halt**.

Anything you escalate leaves your queue by construction: you reassign it to the owner, so the next
`assignee=me` check will not return it. Never pull it back to keep yourself busy.

**Keep a set of ticket IDs you have already attempted this run**, and treat a re-check as empty when
every ticket it returns is already in that set. Escalation should keep blocked work out of your
queue on its own; the set is the backstop for when it doesn't, so a ticket you cannot make progress
on can never loop you forever.

Re-check **immediately** after each batch — never sleep, back off, or schedule a wakeup between
checks. This ends by your queue being empty, not by a timer.

## Read the description, not just the title
`list_tickets` surfaces only the title line. **Every ticket has a `body` (description) you must
read before designing anything.** Fetch it with `get_ticket id=<id>` — it returns the full body,
project, assignee, labels, and blocked status. Treat that body as the spec. Tickets may also have
**comments** that add context or feedback — fetch them with `list_comments id=<id>` (oldest first)
and read them as part of your full ticket context.

**Attachments are part of the spec too.** A screenshot is how a person reports a visual bug, and
they will assume you looked at it. Call `list_attachments ticketId=<id>`, and `get_attachment`
anything that could matter — images come back as images you can actually see, logs and diffs as
their text. You can attach files back with `add_attachment` (base64 bytes): a build log or a
screenshot of what you produced belongs there, not pasted into a comment.

## Ticket lifecycle
- `start_ticket` when you begin it (dispatch to a subagent, or start it yourself).
- `finish_ticket` when the work is **tested + committed + merged to main** — you do NOT have to
  wait for deploy to finish a ticket, but everything must ultimately land on main and be deployed.
- **A genuinely blocked ticket is escalated, never left sitting.** If you cannot make progress —
  it conflicts with in-flight work you can't isolate, or it needs something only a human can supply
  — hand it back:
  1. `add_comment` saying exactly what you tried and what you are blocked on. Write it for the
     person who picks it up; `unstart_ticket` clears the `blocked` flag and reason, so **the comment
     is the only durable record**.
  2. `unstart_ticket` — the ticket leaves `doing` for the top of Next, freeing the WIP slot.
  3. `update_ticket assignee=<owner id>` to put it on the human's plate.

  Leaving it started and assigned to you is the wrong outcome twice over: it burns a WIP slot, and
  because it stays in your queue any scheduled coordinator re-dispatches an agent onto the same dead
  ticket on every cycle, forever. Report every escalation at the end. Never silently drop one.

## Dispatch pattern
1. Read the body (above). Research the subsystem yourself or with an `Explore`/research subagent.
2. Do it yourself when it's small enough that briefing costs more than doing it; dispatch when the
   work is sizeable, parallelizable, or needs its own context window.
3. Pick the model by complexity: **Sonnet** for well-templated / mechanical work following a clear
   plan; **Opus** for design-sensitive core UX, non-obvious debugging, or anything that seats a
   convention. Set the model explicitly (subagents don't inherit yours).
4. Give a **detailed brief**: exact files/patterns to mirror, the acceptance criteria from the body,
   shell discipline (one command per Bash call; no `&&`/`;`/`cd`/`git -C`/heredocs/`$(...)`; plain
   git; create files with Write), commit-as-you-go by explicit pathspec, and **no PRs**.
5. Isolate with `isolation: "worktree"` whenever the main tree is dirty from parallel agents or when
   multiple subagents edit files concurrently — the subagent gets a clean checkout and can't collide.
6. **Split by conflict surface.** If a ticket has an isolable backend and a UI half that would
   collide with in-flight work, ship the backend first (independent) and defer the UI until the tree
   settles — under the same ticket, which stays in `doing` until both land.
7. Batch related tickets to one subagent when they should move together.

## Coordinating with uncontrolled parallel agents
Other agents (not yours) may be editing `main`'s working tree concurrently.
- Never merge/deploy while another process is writing to `main` (ref/index race, `git add -A` sweeps).
- If the owner has a done-signal convention for this repo (e.g. touching a marker file), watch for it
  (a one-shot background `until [ -f ... ]` script), act, then delete the marker.
- Always commit by explicit pathspec and verify `git diff --cached --stat` is 100% yours.

## Integrate → verify → deploy
1. Confirm clean tree; `git merge --no-edit <branch>` (clean auto-merge expected when files don't overlap).
2. Typecheck + test with this repo's own targets (e.g. `make check`; the relevant test suite for what
   changed). Run the tests the change actually touches before finishing the ticket.
3. `git push origin main`.
4. **Deploy per this repo's own deploy runbook/skill** — each project ships differently. For the
   **yarnt** project that's the repo-local **deploy-yarnt** skill (`make deploy`, or the targets
   that changed). If a repo has no deploy skill, ask the owner how it ships (and consider capturing it).
   Verify prod after schema changes.
5. `finish_ticket`, then clean up any worktree: `git worktree remove --force <path>` + `git branch -D <branch>`.

## Decisions & escalation
- **Bias to decide.** Resolve product/design questions yourself from the repo's own docs
  (`PRODUCT.md` / `project/*.md` if present) and memory. Bubble up only genuine judgment calls about
  the owner's priorities.
- **Bubble to a human** only for what you fundamentally cannot do: secrets/env vars, third-party
  account setup.
- Channels: for a live blocker, prompt in chat. For an **async** decision/placeholder, `create_ticket`
  (with `project=<name>`) and `update_ticket` it with the owner's user ID (from `list_users`). You may also
  `add_comment` on a ticket and reassign it to the owner via `update_ticket`.

## Halt
Halt when an `assignee=me` re-check returns **no ticket you have not already attempted this run**.
At that point report, across every batch you worked, per ticket: what shipped, what tests ran and
their result, what deployed, and anything you left undone and why — call out escalated tickets
explicitly, since they are now waiting on the owner.

Then end the turn — no `ScheduleWakeup`, no self-rescheduling, no idle polling for work that has not
arrived yet.
