42e4bf5286
The four-rules header read "on create and on edit", naming only the issue-body operations, even though the skill's scope (description, when-to-use table, tea mechanics) covers commenting and rule 4 is written around the comment-anchor reader. Make the binding explicit and carve out rule 3 (a comment has no title).
331 lines
20 KiB
Markdown
331 lines
20 KiB
Markdown
---
|
|
name: issue
|
|
description: Use when creating, editing, commenting on, or closing a Gitea issue or milestone — filing a bug, feature, or idea into the tracker, or turning a finding into a tracker item. Binds every actor that creates or edits an issue or milestone, human or skill, not just an explicit invocation. Covers the issue-writing conventions and the tea-CLI mechanics for the operation.
|
|
---
|
|
|
|
# issue — write and edit Gitea issues
|
|
|
|
> **Violating the letter of these rules is violating the spirit.**
|
|
|
|
## Overview
|
|
|
|
An issue is a durable artefact in the forward-queue, read later by
|
|
humans and by other agents — usually without the conversation that
|
|
produced it, and a human reads it linearly, holding only what is on the
|
|
page. It must stand on its own. This skill unifies how issue text is
|
|
written so every issue reads the same way, and records the `tea`
|
|
mechanics for creating and editing them.
|
|
|
|
An issue states facts and clearly-flagged claims about a concern. It
|
|
is not a chat message.
|
|
|
|
## When to use
|
|
|
|
| Situation | Use this? |
|
|
|---|---|
|
|
| "Open an issue for X" / "file a bug about Y" | Yes |
|
|
| "Edit / re-label / comment on issue #N" | Yes |
|
|
| "Close #N" (outside a `closes #N` commit) | Yes |
|
|
| Create or edit a **milestone** (the container for a big chunk) | Yes |
|
|
| Turning a finding or deferred work into a tracker item | Yes |
|
|
| A note relevant only to the current conversation | No |
|
|
|
|
**This binds every author, not just an explicit invocation.** Any actor
|
|
that creates or edits an issue or a milestone — a person at the keyboard or
|
|
any skill or agent doing it as a side-effect — writes it to these
|
|
conventions; there is no second, looser standard for tracker text written
|
|
in passing. Other skills reach the tracker through them constantly:
|
|
`brainstorm` parks a deferred spec as a backlog issue, `audit` files
|
|
regressions, and `boss` files skill-system deficiencies (with an
|
|
autonomous-provenance body block — see `../boss/SKILL.md` § Skill-system
|
|
feedback) and logs each fork decision on the run's reference issue (§ The
|
|
reference issue). This skill is the shared convention they lean on.
|
|
|
|
## The four writing rules
|
|
|
|
These apply to every issue, on create and on edit — and equally to
|
|
every comment: a comment is tracker text like any other, and rule 4 in
|
|
particular is written around a reader who lands on a bare comment anchor.
|
|
The one carve-out is rule 3 — a comment has no title.
|
|
|
|
1. **Impersonal and tool-neutral.** Declarative voice — no "you", no
|
|
imperative aimed at the reader, and equally no first-person narration of
|
|
the loop's own acts ("I'll now run audit", "I'll hand this off next"):
|
|
an issue is nobody's monologue, neither addressed to a reader nor spoken
|
|
by the loop. State the situation, not what an actor does about it. The
|
|
issue is also a durable, tool-agnostic artefact, so it never carries the
|
|
orchestration loop's own next move — any direction of *what the loop runs
|
|
next*: most blatantly naming a skill or pipeline step ("enter `specify`",
|
|
"dispatch `implement`"), but equally a role-periphrasis for the same
|
|
hand-off that names nothing ("hand it to the spec writer next", "kick off
|
|
the next pipeline stage"). That is session control-flow, meaningless to a
|
|
tracker reader — a human months later, a different tool — who is not the
|
|
loop; rephrasing it in declarative voice does not save it, because the
|
|
*content* is harness-native.
|
|
- The discriminator is **status vs. dispatch**, not whether a skill is
|
|
named. A sentence stating *what is true of the work* — the next
|
|
**work** itself ("next: a breakout-style trend entry") or a durable
|
|
readiness **status** ("design settled — ready for spec production";
|
|
"implementation done — ready for audit", fine even when the phase-noun
|
|
is also a skill name; "blocked on #N") — is legitimate. A sentence
|
|
directing *who runs what next* is out **whether or not it names a
|
|
skill**. Apply it sentence by sentence: does it describe the work's
|
|
condition (keep) or an actor's next move (cut)? "What's next" otherwise
|
|
lives in the issue's open/labelled state, not a prose dispatch of the
|
|
next skill in the body.
|
|
- Avoid: "You need to fix the parser because you broke escaping." /
|
|
"Next step: enter `specify` from this comment." / "Ready to hand off to
|
|
the spec writer next."
|
|
- Use: "The parser drops backslash escapes in quoted strings." / "The
|
|
design is settled here — no open load-bearing fork remains; ready for
|
|
spec production."
|
|
|
|
2. **Validated or flagged.** Every factual statement is either
|
|
verified — carrying its evidence (command output, log line,
|
|
`file:line`, a reproduction) — or explicitly marked as an
|
|
unverified claim, so a reader never mistakes a guess for a fact.
|
|
- Verified: "`parse()` returns `None` for `a\"b` — see
|
|
`parser.rs:84` and the repro below."
|
|
- Flagged: "Claim (unverified): the regression likely landed in
|
|
0b96983; not yet bisected."
|
|
- Where it sharpens the point, drop in a concrete code example —
|
|
the snippet that triggers the failure, or the call as it
|
|
*should* behave. A fenced block beats a prose paraphrase:
|
|
|
|
````
|
|
```rust
|
|
parse("a\"b") // => None, want Some("a\"b")
|
|
```
|
|
````
|
|
|
|
3. **Imperative, concise title.** Verb-first, one line, no trailing
|
|
period — scannable in the list, mirroring commit-message style.
|
|
Checkboxes (`- [ ]`) are allowed in the body for sub-points or a
|
|
small acceptance checklist. A comment carries no title, so this rule
|
|
alone has no comment analogue — the other three bind it unchanged.
|
|
- Avoid: "parser bug" / "There is a problem with the parser."
|
|
- Use: "Preserve backslash escapes in quoted strings"
|
|
|
|
4. **Self-contained — reachable AND comprehensible.** The issue stands on
|
|
its own, without the conversation that produced it. Two tests apply to
|
|
every reference, and a pointer can pass one while failing the other.
|
|
|
|
- **(1) Reachability.** *Starting from this entry alone — a reader may
|
|
have arrived by a direct comment-anchor link, no chat and no sibling
|
|
comments loaded — can they follow it to its target?* If not, it is a
|
|
dangling pointer: reproduce the content inline, or swap in a
|
|
resolvable locator.
|
|
- **(2) Comprehension.** Does the issue make its point *without* the
|
|
reader absorbing what the target says? A human reads linearly and
|
|
holds no context-wide view; unlike an LLM — which usually has the
|
|
referenced sources already in its context — a human has only what is
|
|
on the page. So where the issue's substance leans on what a reference
|
|
*contains*, state that substance inline beside the pointer: the
|
|
reference then corroborates or lets the reader go deeper, it does not
|
|
carry the meaning the issue omits. A pointer can pass (1) and fail
|
|
(2): `#42` resolves, yet a linear reader still does not know what
|
|
`#42` says. A *pure further-reading* pointer — one the issue's point
|
|
does not lean on — needs only to resolve.
|
|
|
|
**Reachable — necessary, not sufficient.** Resolving satisfies test (1)
|
|
only; of the forms below, only *content stated or quoted inline* also
|
|
passes test (2) unaided.
|
|
|
|
**No absolute URL carrying a server name or port** — it rots when the
|
|
host moves and leaks the deployment; every reference below has a
|
|
host-free form:
|
|
- content stated or quoted inline;
|
|
- an issue/PR number (`#42`; a cross-repo ref needs the `owner/repo#N`
|
|
form with no space — `Brummel/Skills#11`, not `Skills #11`, which
|
|
binds `#11` to the current repo) or a commit SHA (`a1b2c3d`, resolves
|
|
on push) — Gitea auto-links these against the current host;
|
|
- a **relative Markdown link** — Gitea resolves it against the repo
|
|
root, so it carries no host in the source or the rendered link: the
|
|
way to make a file section, a line range, or a specific comment
|
|
clickable. The base is the repo root, so a file link needs the `src/`
|
|
segment; without it (`commit/<sha>/…`, `branch/…`) it does not
|
|
resolve:
|
|
- a file at a pinned commit —
|
|
`[what it says](src/commit/<sha>/docs/design.md#user-content-<heading-slug>)`,
|
|
or a line range `…/parser.rs#L84-L90`; prefer `src/commit/<sha>/…`
|
|
(immutable) over `src/branch/<branch>/…` (drifts);
|
|
- a specific comment — `[what it says](issues/N#issuecomment-M)`
|
|
(a plain `issues/…` path, no `src/`; the bare `#issuecomment-M`
|
|
fragment alone only resolves in-page on that comment's own issue);
|
|
- a repo-relative path, optionally with a line range (`parser.rs:84-90`),
|
|
as a plain locator where a clickable link is not worth building;
|
|
- a same-entry section marker (`§5`); a convention-resolvable in-repo
|
|
slug (a `docs/specs/` slug, a cycle number).
|
|
|
|
**Unreachable — rewrite or inline; these never resolve from the
|
|
tracker:**
|
|
- **The producing chat by reference, in any phrasing** — "the
|
|
in-context discussion", "settled before the run", "the session /
|
|
cycle transcript", an in-context juror/panel verdict (`D3`). No
|
|
anchor can ever reach it; the irrecoverable case. (Quoting the
|
|
decision's words inline is fine — see the carve-out below.)
|
|
- **A weak prose pointer** — "above", "below", "earlier", "the prior
|
|
comment", "logged above", "as discussed" — with no resolvable
|
|
locator: a relative link to the target comment
|
|
(`issues/N#issuecomment-M`), a `#N`, or a *same-entry* `§` marker. A
|
|
`§` pointing into another comment or file is itself unreachable —
|
|
link that comment with `issues/N#issuecomment-M`.
|
|
- **An artifact named by role, not locator** — "the OOS harness
|
|
issue", "see the ledger", a `Depends on` target — carrying no `#N` /
|
|
SHA / relative link / repo path.
|
|
- **A path outside this repo** — `/mnt/...`, `~/.claude/...`, a Claude
|
|
auto-memory slug, another project's `BLOCKED.md`. Only a path in
|
|
*this* repo is reachable.
|
|
- **A bare code or ordinal whose defining set the entry does not
|
|
reproduce** — a plan-item / ledger / lens code (`I7`, `C16`), an
|
|
index ("decision #5"). Gloss it in place, or restate the set.
|
|
- **A locator-shaped token that resolves to nothing** — a template
|
|
placeholder (`#(A)`), or a `#`-number in the wrong format (`#0071` —
|
|
issue refs are unpadded integers like `#71`; a leading zero matches
|
|
nothing).
|
|
|
|
A chat decision becomes referenceable only by being **written to the
|
|
tracker first** — log it, then cite that comment; a chat is reachable
|
|
by being written down, never by being pointed at (the `boss`
|
|
reference-issue mechanic, `../boss/SKILL.md` § The reference issue).
|
|
|
|
**These stay self-contained** (don't strip them chasing the rule): an
|
|
inline dated verbatim quote of a chat decision ("`mach es so!`" —
|
|
2026-06-29) — the reader sees the exact words, and only a surplus
|
|
"settled in-context" sentence *beside* it is the violation; an
|
|
enumerated fork `(A)`/`(B)` whose options are restated here; a
|
|
glossary code glossed inline; a provenance sentence whose fact is also
|
|
stated inline, so long as it embeds no unresolvable pointer (keep
|
|
"decided", drop or anchor "logged above"). Flag the *pointer* a
|
|
tracker-only reader can't resolve, never the content it reproduces.
|
|
|
|
- Avoid: "Approach B (the mechanism refinement decided + logged
|
|
above)." — "logged above" points to a sibling comment with no
|
|
resolvable locator, so a reader who landed on this comment can't reach
|
|
the refinement; the violation is the unresolvable pointer, and it
|
|
stands even when the mechanism is restated inline. The bare label
|
|
"Approach B" compounds it — it indexes an A/B fork this entry never
|
|
reproduces, so the letter means nothing to a reader who didn't see
|
|
the fork laid out.
|
|
- Use — drop the chat-native label, name the option on its own terms,
|
|
then inline or link the refinement: "The honest per-held-cycle bleed
|
|
(accrue each held cycle, dump at close) — refined in
|
|
[issue 148's comment](issues/148#issuecomment-2142)."
|
|
|
|
**Language:** title and body are English — an issue is a repo
|
|
artefact mirrored to Gitea ("would it be committed → English", per
|
|
`~/dev/CLAUDE.md`).
|
|
|
|
**Milestones** obey the same conventions, with one adjustment. A milestone
|
|
is a container — a big chunk, usually carrying a spec — so its title
|
|
*names* the container ("Cycle 7 — streaming rewrite") rather than taking
|
|
rule 3's imperative verb form. Its description obeys rules 1 (impersonal
|
|
and tool-neutral), 2 (validated or flagged) and 4 (reachable and
|
|
comprehensible) exactly as an issue body does.
|
|
|
|
## tea mechanics
|
|
|
|
`tea` is pre-authenticated via its own config (`~/.config/tea/`).
|
|
Never read or echo that file — it holds a token. `tea` auto-detects
|
|
the repository from the git remote; override with `--repo owner/name`
|
|
when running outside the repo (the project's issue tracker — its
|
|
CLAUDE.md project facts name the repo slug and the list/show commands).
|
|
|
|
| Operation | Command |
|
|
|---|---|
|
|
| List open | `tea issues ls --state open` |
|
|
| View one | `tea issues <idx>` (body only) — add `--comments` to include the discussion thread: `tea issues --comments <idx>` |
|
|
| Create | `tea issues create -t "<title>" -d "<body>" -L "<labels>"` |
|
|
| Edit body/title | `tea issues edit <idx> -t "<title>" -d "<body>"` |
|
|
| Re-label | `tea issues edit <idx> --add-labels a --remove-labels b` |
|
|
| Comment | `tea comment <idx> "<body>"` |
|
|
| Close / reopen | `tea issues close <idx>` / `tea issues reopen <idx>` |
|
|
| List milestones | `tea milestones ls --state open` |
|
|
| Create milestone | `tea milestones create -t "<title>" -d "<description>"` |
|
|
| Close / reopen milestone | `tea milestones close "<name>"` / `tea milestones reopen "<name>"` |
|
|
|
|
Notes:
|
|
- The body flag is `--description`/`-d`, **not** `--body`. For a
|
|
multi-line body pass a heredoc via command substitution:
|
|
`tea issues create -t "..." -d "$(cat <<'EOF'` … `EOF`\n`)"`.
|
|
- Labels are matched by name (`-L feature,bug`); they must already
|
|
exist in the repo. The project's label vocabulary lives in
|
|
`~/dev/CLAUDE.md` (`BLOCKER`, `feature`, `bug`, `idea`,
|
|
`in-progress`).
|
|
- Before editing, view the issue first (`tea issues <idx>`) — do not
|
|
edit blind. Status/discussion updates go in a `tea comment`, not by
|
|
overwriting the body. Note `tea issues <idx>` prints the **body
|
|
only**; pass `--comments` to read the existing thread first (the bare
|
|
form would otherwise prompt for it interactively, which hangs a
|
|
non-interactive agent).
|
|
- Routine closing is done by a `closes #N` line in the commit body on
|
|
push (per `~/dev/CLAUDE.md`); `tea issues close` is for closing
|
|
without an accompanying commit.
|
|
- `tea milestones` has no `edit` subcommand (create / list / close /
|
|
reopen / delete only). To change a milestone's title or description,
|
|
use the Gitea API (`PATCH /api/v1/repos/<owner>/<repo>/milestones/<id>`,
|
|
the numeric `<id>` from `tea milestones ls --fields title,id`); the
|
|
reachable-and-comprehensible conventions apply to the new description.
|
|
|
|
## Common mistakes
|
|
|
|
| Mistake | Why it's bad | Instead |
|
|
|---|---|---|
|
|
| "You should…" / reader-directed imperative | Breaks rule 1, ages badly | State the situation declaratively |
|
|
| Orchestration next-step in title or body — directing who runs what next, whether a skill is named ("enter `specify`", "dispatch `implement`") or periphrased ("hand it to the spec writer next") | Harness session control-flow, invisible to a tracker reader who isn't the loop; declarative phrasing doesn't save it | Drop it — a tool-neutral readiness status ("ready for spec production"); the issue's open/labelled state carries "what's next" |
|
|
| A guess written as fact | Misleads future actors | Flag it: "Claim (unverified): …" |
|
|
| Title as a noun blob ("parser bug") | Not scannable | Imperative verb phrase |
|
|
| `-d` body with a guessed flag (`--body`) | tea rejects it | `--description`/`-d` |
|
|
| Editing without viewing first | Clobbers others' edits | `tea issues <idx>`, then edit |
|
|
| Reading/echoing tea's config | Token leak | tea is already authenticated |
|
|
| Pointer to the chat that produced the entry ("in-context", "the cycle transcript", a juror code) | The chat is invisible to a tracker reader — never reachable | Quote the words inline, or log the decision to the tracker and cite that comment with a relative link (`issues/N#issuecomment-M`) |
|
|
| "above" / "below" / "the prior comment" with no anchor | A reader on a direct comment link can't tell which entry | Add a relative link to the comment (`issues/N#issuecomment-M`), a `#N`, or a *same-entry* `§` marker |
|
|
| Artifact or path named without a locator — "the harness issue", "see the ledger", `/mnt/...`, `~/.claude/...` | Nothing to navigate to from the tracker | Supply a `#N`, SHA, in-repo path, or relative link — or reproduce the fact inline |
|
|
| Bare un-glossed code or ordinal (`I7`, `C16`, "decision #5") | Its defining set isn't in the entry | Gloss it inline, or restate the set |
|
|
| A reachable ref the point leans on, left un-glossed (`Blocked on #42`; "see `parser.rs:84` for the mechanism") | Resolves (test 1) but a linear reader learns nothing (test 2 fails) | Gloss the substance inline; attach the link as the go-deeper pointer |
|
|
| An absolute URL with a server name or port (`http://host:port/…`) | Rots when the host moves; leaks the deployment | Host-free form — `#N`, a relative `issues/N#issuecomment-M`, or `src/commit/<sha>/path#…` |
|
|
|
|
## Red flags — STOP
|
|
|
|
- The word "you" anywhere in title or body
|
|
- An orchestration next-step in title or body — directing who runs what
|
|
next, whether a skill is named ("enter `specify`", "dispatch
|
|
`implement`") or periphrased ("hand it to the spec writer next") — in
|
|
place of a tool-neutral status (a tool-neutral statement of the next
|
|
*work*, or a readiness status, is not what this flags)
|
|
- A factual statement with neither evidence nor a "claim" flag
|
|
- A title that is a noun phrase or ends with a period
|
|
- A reference with no resolvable locator (`#N`, a commit SHA, a host-free
|
|
relative link like `issues/N#issuecomment-M` or `src/commit/<sha>/path`,
|
|
an existing repo path, a `docs/specs/` slug or cycle number, a
|
|
same-entry `§`, or the fact reproduced inline), or a bare never-glossed
|
|
code whose defining set isn't in the entry — in particular:
|
|
- a pointer to the chat that produced the entry ("in-context", "the
|
|
cycle transcript", a juror code); the chat is never tracker-reachable
|
|
- "above" / "below" / "the prior comment" / "as discussed" with no
|
|
resolvable locator — a relative link to the comment
|
|
(`issues/N#issuecomment-M`), a `#N`, or a same-entry `§`
|
|
- an out-of-repo path (`/mnt`, `~/.claude`, a `memory <slug>`,
|
|
another project's `.md`) cited as the basis
|
|
- a `#`-token that resolves to nothing — a `#(A)` placeholder or a
|
|
wrong-format `#0071`
|
|
- An absolute URL carrying a server name or port anywhere in title or body
|
|
— use the host-free relative form (`issues/N#issuecomment-M`,
|
|
`src/commit/<sha>/path#…`)
|
|
- A reachable reference the entry's point leans on, its substance not
|
|
glossed inline — a linear reader can't grasp the entry without navigating
|
|
away (the comprehension test, rule 4)
|
|
- About to `tea issues edit` without having viewed the issue
|
|
- About to print or `cat` the tea config
|
|
|
|
## Cross-references
|
|
|
|
- `~/dev/CLAUDE.md` — repo-English rule, label vocabulary, the
|
|
`closes #N` commit convention (the tracker is the forward-queue).
|
|
- `../brainstorm/SKILL.md`, `../audit/SKILL.md`, `../boss/SKILL.md` —
|
|
callers that file issues through these conventions. `boss` files
|
|
skill-system feedback with an autonomous-provenance body block
|
|
(§ Skill-system feedback), and its § The reference issue is the
|
|
constructive escape hatch for rule 4: log a chat decision to the
|
|
tracker first, then cite that comment instead of pointing at the chat.
|