# Ticket System

> Ticket system and work logs for context anchoring. Use when creating tickets, managing work logs, or anchoring context across multi-step tasks or sessions. Do NOT use for simple patches or single-step tasks.

- Skill: `arcadeai/ticket-system` (Agent Skill)
- Install (CLI): `npx skillmds@latest add arcadeai/ticket-system`
- Raw SKILL.md: https://api.skillmd.com/api/skills/arcadeai/ticket-system/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: ArcadeAI (https://skillmd.com/u/arcadeai)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/arcadeai/ticket-system

---


# Ticket System

**Purpose:** Context anchor to prevent LLM loops during complex work. Colocates all artifacts.

**Namespace root:** Resolve from `paths.projectRoot` in `.safeword/config.json`; if unset, use `.project/` by default, falling back to legacy `.safeword-project/` only when that directory already exists. Substitute the resolved root in every path below.

**Creating a ticket:** Resolve the Safeword CLI locally first, then run `ticket new` through that resolver:

```bash
if [ -x node_modules/.bin/safeword ]; then
  SW="node_modules/.bin/safeword"
elif [ -f packages/cli/src/cli.ts ]; then
  # Only true inside safeword's own repo (dogfooding) — runs from source
  # instead of requiring a build.
  SW="bun packages/cli/src/cli.ts"
else SW="bunx safeword"; fi

$SW ticket new <slug> # --type=patch|task|feature|epic, --title="...", --goal="...", --why="...", --issue="<existing-key>"
```

`--goal` fills the Goal field for any type; `--why` fills the rationale for task/patch/epic (features keep motivation in spec.md, so `--why` is rejected there). `--type=epic` scaffolds a container ticket with an empty `children:` list.

With `ticketBridge.provider: none`, the CLI mints a 6-char Crockford Base32 ID. With GitHub or Linear connected, a non-epic ticket creates its tracker issue first and uses the tracker key as its ID; `--issue="<existing-key>"` adopts that issue without creating one. Epics always remain local Crockford-ID containers. Every route creates the folder atomically and writes a starter ticket.md. **Do not scan the tickets directory and pick the next ID yourself** — that races between parallel sessions and silently collides across git branches. If the resolver cannot run, stop and report that the CLI is unresolvable; do not hand-mint a fallback ID.

**`ticket new` pre-populates ticket.md (and spec.md for features) with placeholder content.** Pass real values with `--goal`/`--title`/`--why` at creation, or **Edit** the scaffolded fields — do not blind-**Write** the whole file, which fails because the freshly-created file hasn't been Read yet.

**Location:** `<namespace-root>/tickets/{ID}-{slug}/` for tickets created by the resolved `ticket new` command above. `{ID}` is a 6-char Crockford value for local tickets and epics, a GitHub issue number for GitHub-connected tickets, or a tracker key such as `ENG-45` for Linear. The slug is always normalized. Lookup remains backward-compatible with older `{ID}/` Crockford folders and legacy `{numeric-id}-{slug}/` folders — all formats remain reachable by their frontmatter ID.

**Folder structure:**

```text
<namespace-root>/
├── tickets/
│   ├── 7K9M3P-login-bug/       # Current format: Crockford ID + normalized slug
│   │   ├── ticket.md           # Ticket definition (frontmatter + work log)
│   │   ├── test-definitions.md # BDD scenarios (Given/When/Then)
│   │   ├── spec.md             # Product spec (features only; auto-created)
│   │   └── design.md           # Design doc for complex features (optional)
│   ├── ENG-45-login-bug/       # Connected/adopted tracker key + normalized slug
│   │   └── ticket.md
│   ├── 7K9M3P/                 # Historical Crockford ID-only format, still readable
│   │   └── ticket.md
│   ├── 080-ticket-id-collision/  # Legacy numeric format, still readable
│   │   └── ticket.md
│   └── completed/              # Archive for done tickets
├── learnings/                  # Extracted knowledge (gotchas, discoveries)
└── tmp/                        # Scratch space (research, logs, etc.)
```

**Artifact Levels:**

| Level       | Artifacts                                    |
| ----------- | -------------------------------------------- |
| **epic**    | ticket.md (frontmatter `children:`), no spec |
| **feature** | ticket.md + spec.md + test-definitions.md    |
| **task**    | ticket.md with inline tests                  |
| **patch**   | ticket.md (minimal), existing tests          |

**Create a ticket** when any of these holds: multiple attempts are likely,
the work is multi-step with dependencies, it needs investigation/debugging, or
there's a risk of losing context mid-session. Otherwise skip it.

**Examples:** "Fix typo" → skip. "Debug slow login" → ticket. "Add OAuth" → ticket.

**Minimal structure:**

```markdown
---
id: 7K9M3P
slug: feature-name
status: in_progress
---

# [Title]

**Goal:** [one sentence]

## Work Log

- [timestamp] Started: [task]
- [timestamp] Found: [finding]
- [timestamp] Complete: [result]
```

**Frontmatter values:**

- `status`: `in_progress | done | cancelled | superseded | wontfix | blocked`
- `phase`: `intake | define-behavior | scenario-gate | plan-implementation | implement | verify | done` (see ticket-template.md)
- `phase_skips`: `["<phase>: <reason>", ...]` (optional; feature tickets only) — one entry per phase a feature was born into or advanced past without traversing it. Block sequence, non-empty reason each; the phase-provenance gate requires it when a feature skips phases (see glossary "Gate")
- `phase_anchors`: `["<phase>: <artifact-path>", ...]` (optional; feature tickets only) — one entry per phase entered on a forward advance, recording the repo-relative path of the exit artifact of the phase being left (define-behavior ← spec.md · scenario-gate ← the feature source · implement ← impl-plan.md · verify ← test-definitions.md · done ← verify.md). Append one entry per phase; on a re-advance the latest entry for a phase wins (it names the phase's current output). The boundary gate verifies the artifact exists (and looks right) in the tree being shipped — never against git history, so anchors survive amend, rebase, squash-merge, and shallow clones. Hex commit-SHA anchors on pre-redesign tickets are grandfathered at rest
- `parent`: `<id>` (optional)
- `epic`: `<slug-or-id>` (optional)
- `blocked_on`: `[<id>, <id>]` (optional)
- `depends_on`: `[<id>]` (optional)
- `external_issue`: `<https://.../issues/nnn>` (optional; one canonical issue/link)
- `external_prs`: `[<https://.../pull/nnn>, ...]` (optional; active or relevant PR links)

**Rules:**

- Log immediately after each action
- Re-read ticket before significant actions
- For detailed scratch notes, use a separate work log (see Work Logs below)
- **Cite durable anchors, not raw line numbers.** `file.md:18-22` goes stale
  after any unrelated merge (#799). Anchor each edit site to something that
  survives drift — heading text, a unique grep pattern, or a function name —
  and re-grep before editing if you must quote a line number.
- **CRITICAL:** Never mark `done` without user confirmation

---

## Work Logs

**Purpose:** Scratch pad and working memory during execution. Think hard. Keep notes.

**Location:** `.safeword/logs/{artifact-type}-{slug}.md`

**Naming convention:**

| Working on...                | Log file name            |
| ---------------------------- | ------------------------ |
| Ticket `7K9M3P` (slug: foo)  | `ticket-7K9M3P-foo.md`   |
| Legacy ticket `080-fix-auth` | `ticket-080-fix-auth.md` |
| Spec `task-add-cache`        | `spec-task-add-cache.md` |
| Design doc `oauth`           | `design-oauth.md`        |

**One artifact = one log.** If log exists, append a new session. Don't spawn multiple logs for the same work.

**Create a log** when executing a plan, ticket, or spec, or when
investigation/debugging spans multiple attempts. Skip it for a quick
single-action task.

**Think hard behaviors:**

1. **Re-read the log** before each major action
2. **Pause to review** your approach periodically
3. **Log findings** as you discover them, not after
4. **Note dead ends** so you don't repeat them

**Log what helps you stay on track:** findings, decisions, hypotheses, blockers, scratch calculations. Use your discretion.

**Edge cases:**

| Situation                       | Action                                                                       |
| ------------------------------- | ---------------------------------------------------------------------------- |
| Multiple artifacts at once      | One log per artifact (don't combine)                                         |
| No clear artifact (exploratory) | Create `explore-{topic}.md`, convert to proper artifact when scope clarifies |

---

## Templates

**Use the matching template when ANY trigger fires:**

| Trigger                                                                | Template                                                              |
| ---------------------------------------------------------------------- | --------------------------------------------------------------------- |
| Planning new feature scope OR creating feature spec                    | `spec-template.md` (auto-scaffolded at intake; JTBD + Numbered Rules) |
| Writing a feature spec by hand in the older user-story format (legacy) | Use the legacy feature fields described below                         |
| Bug, improvement, refactor, or internal task                           | Use the task fields described below                                   |
| Need test definitions for a feature OR acceptance criteria             | Use the `$safeword:bdd` workflow                                      |
| Feature spans 3+ components OR needs technical spec                    | Use the implementation-plan sections in `$safeword:bdd`               |
| Making decision with long-term impact OR trade-offs                    | Use the configured architecture document                              |
| Recording a structural or hard-to-reverse decision as its own record   | Use the configured architecture document's ADR format                 |
| Planning a feature's implementation before TDD starts                  | Use the `$safeword:bdd` implementation-plan phase                     |
| Guarding a temporary upstream workaround so its removal isn't missed   | Use the `$safeword:testing` tripwire procedure                        |
| Task needs context anchoring                                           | Use the ticket fields described below                                 |
| Starting execution of a plan, ticket, or spec                          | Append a timestamped entry to the ticket's work log                   |

