factory-work

A workflow command that sends ready Linear tickets to coding subagents, tracks their pull requests, verifies the results, reviews them, and lands the completed changes.

In plain words
What is it for?
Use it to process agent-ready tickets for the current repository, with optional limits on the number of tickets and simultaneous tasks.
Why use it?
It removes the repeated coordination work involved in moving several well-defined tasks from the queue into the repository.

Command

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add commands/watt-mind/factory/factory-work
Clone the repo
git clone --depth 1 https://github.com/watt-mind/factory
Per session 16 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 2,702 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00016 $0.02702
Opus 5 $0.00008 $0.01351
Sonnet 5 $0.00003 $0.00540
Haiku 4.5 $0.00002 $0.00270

Measured 2d ago against content hash 665d7b9c2c9a, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

factory-work scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

plugins/core/commands/factory-work.md · 71 lines

How it starts

The opening of the file, as written. The whole thing — 71 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Work the agent-dispatchable Linear queue for this repository to completion — claimed, implemented, verified, reviewed, and landed — following $FACTORY_ROOT/docs/protocol.md (§7 execution, §14 loops).

Interpret $ARGUMENTS as specific issue IDs, a total ticket cap, and/or an in-flight concurrency cap. Defaults: up to 6 tickets, 3 in flight. no-merge stops after PRs are opened.

1. Build the queue

Resolve the team from this repo (§1 mapping). Query state:Todo AND label:ai:agent-ready AND assignee:none, sorted priority asc then createdAt asc (Linear MCP; on failure retry once, then linear_common GraphQL). Fetch each candidate's full description and confirm it has all five §5 sections — a ticket missing one goes back to Triage with a comment, not into the queue.

Show me the queue (ticket, title, owned paths) before starting, then proceed without waiting for approval.

2. Dispatch — rolling, not batched

Keep up to the concurrency cap in flight. Do not wait for a batch to drain before starting new work: the moment any ticket finishes (PR opened, blocked, or claim lost), re-read the queue and start the next ticket whose Owned Paths don't overlap anything still running. Overlap is checked at each claim against what is actually in flight right now, not against a plan computed at the start.

For each ticket you start:

  1. Claim it yourself first (main agent, before spawning): set assignee = self, state In Progress, add ai:in-progress + agent:claude-code; then re-read the ticket — if the assignee isn't us, another agent won the race: skip it and take the next queue item.
  2. Create the worktree using the repo's own script if it has one (bin/worktree-up.sh <ISSUE-ID> in BJ29 and any repo following that pattern) — it assigns non-colliding ports and a per-ticket database that a hand-rolled git worktree add does not. Only where no script exists: git worktree add ~/Develop/.worktrees/<repo>/<ISSUE-ID> -b <type>/<ISSUE-ID>-<slug>. The repo's AGENTS.md overrides this command on anything worktree- or environment-related.
  3. Spawn a subagent (general-purpose, run in background). When the parent run is Claude Code — identified by CLAUDECODE being set in the environment — pass model: opus — implementation quality is the product while the orchestration stays on the cheaper session model. For every other parent harness, omit the model override so the subagent inherits that harness's configured default. Give it a self-contained prompt containing the full ticket (ID, description, all five sections), the worktree path and its ports/database, and these standing orders:
    • Work only inside the worktree and only on files matching Owned Paths.
    • Heartbeat the Linear ticket at each phase change and at least every 20 minutes, saying what changed since the last one.
    • Verify with the ticket's exact Verification Command; never proceed past a failing verification.
    • Run the UX critique round after verification and before opening the PR when the change introduces or materially changes a user-completable flow, interaction, state transition, error/recovery path, responsive layout, authentication, payment, onboarding, or destructive action. Spawn factory-ux-critic, fix in-scope FIX-FIRST findings, max 2 rounds, and file follow-ups to Triage. Skip it for isolated styling, copy-only edits, static content, icons/assets, and internal/admin-only surfaces unless the ticket identifies UX risk. In every PR, state UX critique: required or UX critique: skipped — <reason>.
      • The critic's spawn prompt must state the environment explicitly: worktree: <absolute path> written out in full (a subagent spawned from a worktree does not reliably inherit that worktree's cwd, and the sibling worktrees of concurrently-running tickets are exactly what it resolves to instead), plus how to launch and reach the app — dev server command and this worktree's assigned port from step 2, not the repo default, or simulator target / electronAppPath, plus bin/dev-login.sh [role] where the repo has it.
      • Before spawning a required critic, create an ux-screenshots/ directory in this run's Factory workspace, alongside (not inside) the repo worktree, and pass its absolute path as artifactDir: <absolute path>. The critic is read-only on the repo. After it returns, retain only the screenshots it actually reports/cites; copy a backend-temporary capture into that directory when necessary. Never commit these images or attach them to Linear.
      • A returned VERDICT: BLOCKED - environment mismatch or unresponsive shell means the spawn prompt was wrong, not that the UX is bad: fix the path or launch details and re-spawn once (it doesn't consume a review round — no review happened). Blocked twice: record UX critique: blocked — <what the environment did> in the PR and Handoff and move on.
    • On success: push the branch, gh pr create --title "..." --body "Fixes <ISSUE-ID>" (append \n\nrun:$FACTORY_RUN_ID to the body when $FACTORY_RUN_ID is set, and omit it in interactive sessions when $FACTORY_RUN_ID is unset), post the mandatory structured ## Handoff comment in the exact format /factory-ticket step 6 defines (PR link, verification command + result, UX critique verdict, files vs Owned Paths, risks) as a mandatory prerequisite before moving the ticket to In Review + ai:needs-review (remove ai:in-progress), and report terminal state STATE: PR_OPEN.
      • When the UX critique captured screenshots, retain at most 4 of them, each ≤ 1 MB (drop or re-capture element-scoped if larger), and declare each retained workspace-relative file in the dispatch result.json as {"kind":"ux-screenshot","path":"ux-screenshots/<filename>.png"}. The ux-screenshot artifact kind marks a PNG capture from the UX critique round: Factory hashes and publishes it through the control API's GET /artifacts/<sha256> endpoint (immutable, content-addressed, operator-reachable only). Compute each file's SHA-256 before writing the PR evidence.
      • Only when $FACTORY_WEB_URL is set, add a bounded ## UX screenshots section to the PR body (or a comment with that heading). The artifact URL $FACTORY_WEB_URL/api/artifacts/<sha256> binds loopback/tailnet with no auth, so GitHub cannot render it: never embed ![…]() images. List one plain-text link per retained screenshot with its sha256 and a one-line caption, for example - [01-upload-list-mobile.png]($FACTORY_WEB_URL/api/artifacts/<sha256>) — sha256 — mobile upload list after fix, followed by the critic verdict. Do not use file://, a temporary browser path, a repository URL, or an unverified guessed hash. When $FACTORY_WEB_URL is unset, skip the whole section (the result.json declarations still stand). Embedding real images is deferred until a GitHub-reachable transport exists.
      • When at least one screenshot was retained, label the PR: gh pr edit <PR> --add-label has-screenshots --add-label type:ui-ux. type:ui-ux is provisioned by factory init --control-plane github; has-screenshots may be missing — if the add fails, create it (gh label create has-screenshots --color 1d76db --description "This pull request has UX-review screenshot evidence") and retry once, or fall back to type:ui-ux alone. Never fail the PR flow on a label error; log it in the Handoff. Apply neither label when no screenshot was captured.
    • On failure or blockage: do not open a PR; comment the ticket with the specific decision or credential needed, move it to Blocked + ai:blocked, and report terminal state STATE: BLOCKED (or STATE: FAILED) back so the orchestrator can notify.
    • The subagent never merges. Discovered out-of-scope work → new Triage issue per §8, not scope creep.

Read the full file on GitHub · 71 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 71 lines · 16 tokens per session scan A 665d7b9c2c9a

Subscribe to this mod's changes

factory-work is a command published in the GitHub repository watt-mind/factory (10 stars, last pushed 2d ago), licensed Apache-2.0. It adds 16 tokens to every session and 2,702 once invoked, about $0.0001 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.