Back to catalog
SkillProductivityOfficial Verified

Ticket Writing

Write tickets someone else can pick up in five minutes. Bugs, features, and security findings.

#tickets#issues#linear#jira#bug-reports#gherkin#product-management#triage

Install

With the Zana CLI
$ zana add ticket-writing

The checker is stdlib-only Python 3.9+, so there is nothing to install: `python3 scripts/ticket_check.py ticket.md`. Use `--strict` to gate in CI, and `--type bug|feature|security` when a draft is too unstructured to detect. Edit `references/house-rules.md` before using this anywhere but Amini. It is the only file that carries organisation-specific detail. Internal note: `references/house-rules.md` section 2 lists internal team keys and product names. Scrub or genericise it before this repo is made public.

How it runs

A ticket someone who was not in the conversation can start in five minutes.

  1. 01

    Shape

    Bug, feature, or security finding. They fail differently

  2. 02

    Route

    File under the team that owns it, not the one that noticed

  3. 03

    Title

    Behaviour plus condition. The condition is the lead

  4. 04

    Fill

    Every field, or an explicit reason it does not apply

  5. 05

    ticket_check

    Missing fields, vague verbs, leaked credentials

  6. 06

    Ready

    Read it once as someone who was not there

Marked steps are enforced by a script.

Sample work

What this skill actually produced. Not mockups.

Worked example: a real bug ticket, before and after

examples/deep-research-timeout

A Bridge bug as it was actually filed, and the same underlying report rewritten under this skill. Nothing was invented in the rewrite that a reporter would not have had in front of them.

01-as-filed.md30/100453 B
## Deep research tool not working across all Bridge environments (prod, staging, dev)

The deep research tool is not working properly in any Bridge environment. Prod,
staging, and dev are all affected.

Evidence of the problem

- Timeouts when generating templates.
- Bridge fails to return a response when it gets a difficult question in the
  research section, because that triggers deep research.

Environments affected

- Production
- Staging
- Dev
02-rewritten.md100/1002.2 KB
## [Bridge] Deep research requests time out with no response in all environments

## Summary

Deep research requests never return. Affects prod, staging, and dev, which points
to a shared upstream dependency rather than per-env config. Blocks template
generation and any research question that escalates to deep research.

## Environment

- Env: prod, staging, and dev
- Service and repo: bridge-backend (aminitech/bridge-backend)
- Image sha: prod `sha-4c1a2b`, staging `sha-9f0e77`, dev `main @ a3f9c21`
- Deployed via the container platform; upstream deep-research-svc in us-west-2
- Browser and OS: Chrome 138 on macOS 15.4, all requests via the Bridge web UI
- Account used: qa-bridge-03

## Steps to reproduce
check-after.txt189 B

02-rewritten.md
===============
  type      bug
  title     [Bridge] Deep research requests time out with no response in all environ

  nothing flagged

  score 100/100, ready to pick up

check-before.txt2.3 KB

01-as-filed.md
==============
  type      bug
  title     Deep research tool not working across all Bridge environments (prod, sta

  structure
      -   -6   no recognisable ticket shape                 no headings named the fields; checked as a bug, pass --type to override

  missing fields
      -   -12  impact                                       who is blocked and how many; this is what sets priority
      -   -12  steps to reproduce                           without them the first hour goes on guessing
      -   -12  expected                                     separates a bug from a design disagreement
      -   -12  actual                                       separates a bug from a design disagreement
      -   -6   summary                                      one or two lines on what breaks or what is missing, for whom, how bad
      -   -6   environment                                  prod, staging, dev, or on-prem, and which service
      -   -6   build identity                               the sha or tag proves which build is actually running
      -   -6   reproducibility                              10 out of 10 and 1 out of 10 point at different root causes

18 files. Read them here, or pull the folder without the CLI.

Copy the folder into your skills directory
$ npx degit aminitech/amini-zana/catalog/skills/ticket-writing ~/.claude/skills/ticket-writing

No clone, no history. Just this folder.

Sparse checkout (private repos, uses your git auth)
$ git clone --depth 1 --filter=blob:none --sparse https://github.com/aminitech/amini-zana.git && cd amini-zana && git sparse-checkout set catalog/skills/ticket-writing
Single file (SKILL.md)
$ curl -sL https://raw.githubusercontent.com/aminitech/amini-zana/main/catalog/skills/ticket-writing/SKILL.md
SKILL.md
---
name: Ticket Writing
description: >-
  Write tickets someone else can actually pick up. Use whenever a bug, feature, chore, or
  security finding is being filed, rewritten, triaged, or groomed, in Linear, Jira, or GitHub
  Issues. Also fires on "file a ticket for this", "turn this thread into an issue", "write
  acceptance criteria", "is this ticket ready?", "this ticket is unworkable". Ships templates
  for bugs, features, and security findings, plus a checker that scores a draft and names the
  missing fields.
license: MIT
metadata:
  author: Amini
  version: "1.0.0"
---

# Ticket Writing

A ticket is a handoff of context. Whoever picks it up, maybe you in three weeks, maybe a new
hire, maybe an on-call engineer at 02:00, should be able to reproduce it, verify it, and close
it without reopening a chat thread that has since scrolled away.

The bar is one question: **could someone who was not in the conversation start work in under
five minutes?**

Most tickets fail that bar for boring reasons. The reporter had the failure in front of them
and wrote down the part they found surprising, which is rarely the part that locates the cause.
This skill fixes the shape of the ticket, not the writing style.

## Read these as needed

- `references/house-rules.md` is the only file you have to edit to retarget this. Tracker,
  team routing, house style, build identity, confidentiality. **Read it first**, because
  team routing and style rules change what you write.
- `references/bug-tickets.md`, `references/feature-tickets.md`, and
  `references/security-findings.md` cover the three shapes in depth.
- `references/severity-and-priority.md` is the two-axis rule that stops the arguing.
- `references/ready-and-done.md` has the ticket-level Definition of Ready and Definition of Done.
- `references/anti-patterns.md` is the list of things to stop doing, with what to do instead.
- `templates/` has the three templates as paste-ready markdown.
- `examples/deep-research-timeout/` is a real ticket as filed (30/100), the same ticket
  rewritten (100/100), both checker reports, and a gap-by-gap breakdown of what each missing
  field cost.

## Pick the shape first

Three shapes, and they fail differently.

| Shape | Fails because | Template |
| --- | --- | --- |
| Bug | Under-specified. Nobody can reproduce it. | `templates/bug.md` |
| Feature | Specified but untestable. "Done" gets decided by argument in review. | `templates/feature.md` |
| Security finding | Neither of the above. Needs CVSS, a sanitized proof of concept, and closure with proof. | `templates/security-finding.md` |

A chore, a dependency bump, or a config tweak is a small feature. Use the feature template and
a checklist instead of Gherkin.

## How to write one

1. **Pick the shape and the owning team.** File under the team that owns the work, not the team
   that noticed. Cross-team work goes to the owner with blocked-by and blocks relations for the rest.
2. **Write the title as behaviour plus condition.** `[Team or Component] <what breaks> <under
   what condition>`. The condition is the part people leave out and the part that locates the bug.
3. **Fill the template.** Every field, or an explicit statement of why it does not apply.
   "Not reliably reproducible, 1 in 20, trace from the one capture below" is a filled field.
   A blank one is a question you have deferred onto someone else.
4. **State impact separately from severity.** Impact sets priority. Severity is technical
   damage. See `references/severity-and-priority.md`.
5. **Run the checker.** Fix what it flags, then read it once as someone who was not there.
6. **Link the thread, do not paste it.** Extract the facts first.

## The rules that carry most of the weight

**One ticket per thing.** If the "and" in your title joins two unrelated failures, split it.
Bundled tickets get half-fixed and closed. One cause with several symptoms is still one ticket,
and listing all the symptoms is what points at the shared cause.

**Quote the error.** Verbatim, in a code fence, with the status code. "It failed" is not
searchable. A gateway 504, an app 500, and a proxy 404 point at completely different layers.

**Give the build identity.** Commit, tag, or image sha. Container names are opaque hashes and
prove nothing. This is also how you close a ticket honestly: the fix is not done when it is
merged, it is done when the sha carrying it is the one running.

**Put a timezone on every timestamp.** Distributed team, UTC logs, dashboards rendering local
time. Without a timezone, three readers search three different log windows.

**Describe the problem, not the fix.** "Add a retry button" has already made the design
decision and hidden the real failure. Sometimes the answer is a retry button. Sometimes the
answer is that the request should not have failed.

**Reproducibility rate is data.** 10 out of 10 and 1 out of 10 point at different root causes.
If you cannot reproduce it, say so explicitly. That is diagnostic information, not a gap.

## Check the draft

```bash
python3 scripts/ticket_check.py ticket.md
python3 scripts/ticket_check.py ticket.md --type feature   # skip detection
python3 scripts/ticket_check.py tickets/*.md --strict      # non-zero exit below 85
cat ticket.md | python3 scripts/ticket_check.py -
```

Stdlib only, no install. Paths are relative to this skill's directory.

It detects the shape from the headings, checks the fields that shape needs, and reports missing
fields, vague language, unfilled template placeholders, timestamps with no timezone, severity
and priority stated together, procedural Gherkin, happy-path-only acceptance criteria, and
anything that looks like a live credential pasted into a proof of concept. Then a score out of
100.

Rough calibration: a structured but under-specified ticket, which is the most common case,
lands around 30. A copied template with the headings still empty is clamped to 35 and labelled
as unfilled, so it cannot read as ready. Above 85 is pick-up-able.

The score is a smoke alarm, not a grade. It cannot tell whether the steps actually reproduce,
whether the acceptance criteria describe the right behaviour, or whether the impact claim is
true. Passing it is the floor.

**One hard failure.** Anything matching a live credential costs 25 points on its own and should
be fixed before the ticket is saved, not before it is submitted. Redact it and rotate the key.

## Reviewing someone else's ticket

Run the checker, then check the one thing it cannot: does the ticket describe a problem, or a
solution someone has already picked? Send it back against `references/ready-and-done.md` if it
fails the Definition of Ready. That is not obstruction. It is cheaper than finding the gap
halfway through the implementation, and much cheaper than finding it in review.

Be specific about what is missing and why it costs something. "Needs more detail" is the same
anti-pattern the ticket is guilty of.

## What not to do

Do not invent the missing fields. If the reporter did not give you a request ID, a timestamp,
or a reproduction rate, the ticket says so and asks. A confidently wrong environment sends
someone to the wrong logs, which is worse than an empty field.

Do not paste real credentials, tokens, session cookies, or user data into a ticket, including
into a security proof of concept, on the reasoning that the tracker is internal. Exports,
screenshots, and integrations all leak.

Do not restate release-stage gates in a ticket. Ticket-level Ready and Done are about one
ticket. Whether the whole product can advance to beta or GA is a different document, owned by
the engineering owner. Link it.

About

A ticket is a handoff of context. Whoever picks it up, maybe you in three weeks, maybe an on-call engineer at 02:00, should be able to reproduce it, verify it, and close it without reopening a chat thread that has since scrolled away. This skill fixes the shape of the ticket rather than its prose. It covers the three shapes that fail in different ways. Bugs are under-specified, so the first hour goes on guessing: the template forces steps, expected against actual, verbatim error text, reproducibility rate, build identity, and last known good. Features are specified but untestable, so "done" gets decided by argument in review: acceptance criteria are written as Gherkin scenarios before the work starts, with rules for keeping them declarative and a note on when a checklist is the honest answer instead. Security findings are neither, and need CVSS and CWE, a sanitized proof of concept, and closure with proof rather than "should be fixed". Two rules carry most of the weight. Severity and priority are separate axes, technical damage against order of work, which is why a cosmetic typo on a public page can be S4 and Urgent while a broken internal tool is S2 and Low. And build identity, the commit or image sha, because merged is not deployed and a container name proves nothing. Ships `scripts/ticket_check.py`, a stdlib-only checker that detects the ticket shape from its headings, scores it out of 100, and names what is missing: absent fields, vague language, unfilled template scaffolding, timestamps with no timezone, procedural Gherkin, happy-path-only criteria, and anything matching a live credential pasted into a proof of concept. A ticket copied out of a chat thread scores around 30. The worked example rewrites a real one from 30 to 100 and shows what each missing field cost. Retarget it by editing one file, `references/house-rules.md`: tracker, team routing, house style, build identity, confidentiality. The method works the same in Linear, Jira, or GitHub Issues.

docs
Author

Amini 路 Manila, Philippines