assign

A backlog-routing command that turns an item such as ID-123, or a free-form request, into a scoped goal draft. It writes the draft to the repository and selects the appropriate workflow lane without implementing the work.

In plain words
What is it for?
Use it to prepare backlog work for implementation, create a goal from an informal request, and route it to the correct workflow.
Why use it?
It turns vague or committed work into a defined starting point and prevents planning from being mixed with execution.

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/dwarvesf/dwarves-kit/assign
Clone the repo
git clone --depth 1 https://github.com/dwarvesf/dwarves-kit
Per session 34 Only the description is in the session, so the agent can decide to use it. The body loads when it is invoked.
When invoked 4,721 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.00034 $0.04721
Opus 5 $0.00017 $0.02361
Sonnet 5 $0.00007 $0.00944
Haiku 4.5 $0.00003 $0.00472

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

Security

Grade A, and why

assign 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.

commands/assign.md · 196 lines

How it starts

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

Self-intro (AGENTS.md "Self-intro" convention): open your first reply with exactly one banner line, [kit:assign] Turn a backlog item into a scoped goal draft and route it into the right lane., then proceed.

You are a goal dispatcher. Turn a committed backlog item into a runnable goal draft and hand it to the right lane. You do NOT implement anything; you set up the goal and route.

Process

Step 1: Resolve the argument (two shapes)

$ARGUMENTS is one of two shapes. Trim it, then branch:

  • ID shape: the trimmed argument matches ^ID-[0-9]+$. Take the ID-first path below (Step 1b onward), unchanged. This is the path that has always existed.
  • Freeform shape: anything else (intent text like "apply SDD to X" or a vague brief). Take the freeform path in Step 1a, which crystallizes the intent into an ID + BACKLOG row first, then rejoins the ID-first tail at Step 4.

A future third intake shape (e.g. an imported issue) is another branch of this same resolver, not a new command. The resolver is the only place that decides ID vs freeform; everything downstream is shared.

Step 1a: Freeform path (delegate, gate, sanitize, allocate, write)

When the argument is freeform intent (does NOT match ^ID-[0-9]+$), run these ordered steps. /assign stays a light mutator-dispatcher (SPEC-006): it does NOT run a multi-turn interview itself. Two invariants govern this path, and both come before any file is written:

  • approve-before-allocate: pause for human approval of the crystallized objective BEFORE allocating an ID. A vague brief never auto-creates a row (DEC-002).
  • row-before-draft: write the BACKLOG Active-queue row before the goal draft, so ID traceability exists first (the row before draft order is the invariant; never write a .claude/goals/ draft for an un-rowed intent).
  1. Delegate crystallize to /kit:think. Hand the freeform intent to /kit:think (the 6-forcing-questions idea challenger). It runs the interview and returns a crystallized objective + a lane. /assign does NOT embed that interview (DEC-003); it only consumes /think's result. If the intent is too vague to name an outcome, /think loops; do not allocate anything until it converges.
  2. Approval gate (approve-before-allocate). Present the crystallized objective and pause for explicit human approval. Until the human approves, allocate nothing and write nothing. This is the gate that keeps half-baked rows out of the queue.
  3. Dedup by slug. Derive the slug from the approved objective (per the sanitize rule in Step 1a.4). If a .claude/goals/<slug>.md draft or a BACKLOG row with that slug already exists, surface it instead of allocating a second ID (filesystem-is-truth idempotency, SPEC-005). On a near-match slug, ask rather than silently merge or duplicate.
  4. Sanitize (DEC-004). Before the freeform text touches any file, sanitize it:
    • Table cells: escape | (write it as \|) and replace newlines with spaces in every BACKLOG row cell, so a freeform string cannot break the _meta/BACKLOG.md pipe table.
    • Slug: reduce the derived slug to [a-z0-9-]+ only. Lowercase, replace spaces with -, then strip /, .., and anything outside [a-z0-9-], so the slug cannot traverse out of .claude/goals/. The kebab convention is unchanged; it is just hardened to [a-z0-9-]+.
  5. Atomic allocate + write the row (DEC-005, row-before-draft). Allocate the next ID-NNN by re-reading the current max ID in _meta/BACKLOG.md Active queue in the same step that writes the row (do not cache a max read earlier). The new ID is max + 1, zero-padded. Append a sanitized Active-queue row with Status: queued and Source: freeform intake (<YYYY-MM-DD>), filling Title / Target artifact / Lane from the crystallized objective + /think's lane. After writing, re-read the queue and check no two rows share the new ID; if a collision exists (a concurrent allocation picked the same max + 1), fail loud and tell the operator to re-run, rather than leaving two rows with one ID. This mirrors the existing SPEC/ADR dup-number guard.
  6. Rejoin the ID-first tail. With the row written and the ID allocated, proceed exactly as for an ID-NNN: Step 4 (draft write), Step 5 (lane + activator), Step 6 (status + hand-off). The freeform path adds no new tail; it reuses the ID path's.

Read the full file on GitHub · 196 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 · 196 lines · 34 tokens per session scan A dbfff03d1213

Subscribe to this mod's changes

assign is a command published in the GitHub repository dwarvesf/dwarves-kit (11 stars, last pushed 2d ago), licensed MIT. It adds 34 tokens to every session and 4,721 once invoked, about $0.0002 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-30.