Research Decision Room
nexu-io/open-design
Turn messy user research notes, interviews, support tickets, surveys, and product context into an evidence-backed decision room: a single HTML artifact with an evidence ledger, theme map, confidence…
A skill your agent uses when given a Linear ticket (URL or ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown, or a change request nobody has…
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install getlago/lago-front triage-frontend-ticket --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .claude/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .claude/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticketType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install getlago/lago-front triage-frontend-ticket --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .agents/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .agents/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install getlago/lago-front triage-frontend-ticket --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .cursor/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .cursor/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/getlago/lago-front.git --path .agents/skills/triage-frontend-ticket--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install getlago/lago-front triage-frontend-ticket --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .gemini/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .gemini/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install getlago/lago-front triage-frontend-ticketInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .github/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .github/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .github/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add getlago/lago-front --skill triage-frontend-ticket -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install getlago/lago-front triage-frontend-ticket --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/getlago/lago-front.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.agents/skills/triage-frontend-ticket .opencode/skills/triage-frontend-ticket && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "triage-frontend-ticket" agent skill from https://github.com/getlago/lago-front/tree/main/.agents/skills/triage-frontend-ticket into .opencode/skills/triage-frontend-ticket/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "triage-frontend-ticket", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
triage-frontend-ticketA skill your agent uses when given a Linear ticket (URL or ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown, or a change request nobody has…
Triage Frontend Ticket is an agent skill from getlago/lago-front. Use when given a Linear ticket (URL or ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown, or a change request nobody has costed against the code. Typically a Front-end ticket in Triage/Backlog/Scoping. Triggers on "/triage-frontend-ticket <ticket", "triage this ticket", "fai analisi tecnica di questo ticket", "is this actually a bug?", "is this feasible?".
Its SKILL.md is about 9.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `LEARNINGS.md`).
It sits in Frontend & Design, covering Customer support. The repository describes itself as: Open Source Metering and Usage Based Billing. The licence is AGPL-3.0.
9 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit cfe24ee. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
pnpmnodeFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use pnpm, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Triage Frontend Ticket loads about 9.3k tokens when it runs. Until then it costs about 109 tokens; SKILL.md has 4,978 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from getlago/lago-front at commit cfe24ee, republished under its AGPL-3.0 licence (© getlago). 4,978 words, ~9,252 tokens.
.claude/skills/triage-frontend-ticket/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.Input: one Linear ticket URL or identifier (e.g. <ISSUE-ID>). If none was given, ask with AskUserQuestion and stop until given.
Repo: the lago-front checkout (front/ in the lago monorepo). If the session is not in lago-front, STOP — this skill reasons about this codebase only.
Output: one comment posted on the ticket, and — only for a ticket sitting in Triage
that the analysis actually resolved — a move to Backlog. Nothing else on Linear is touched.
Who reads that comment: whoever picks the ticket up next — a human deciding whether to schedule it, a developer opening the editor, or an agent implementing it. Assume none of them will redo the analysis. So the comment is a handoff document: everything needed to start work is in it, in a form that reads as well to a person as it parses to an agent. That is what step 6's Implementation handoff block is for.
This skill is deliberately pipeline-agnostic. It ends at the posted comment and makes no
assumption about how the work gets done afterwards — by hand, by an agent, or by an
automated pipeline. If your team uses one that reads ticket comments (/loop-run does,
through loop-spec), the handoff block is already in the shape it needs; if not, it is
simply a well-specified ticket.
Read LEARNINGS.md (alongside this file) before you judge anything. It holds rules learned
from real outcomes and overrides the defaults here where they conflict — within the limits stated
in that file: a learning may tune judgement, never soften a guardrail.
Create a todo per numbered step below before starting.
Extract the issue id ([A-Z]+-\d+), then reset the review budget so a re-triage starts clean:
front/scripts/iter-budget.sh <ISSUE-ID> reset triage-review
front/scripts/analysis-depth.sh <ISSUE-ID> resetFetch via Linear MCP get_issue (with includeRelations) and list_comments — repro steps, scope changes and decisions often live only in comments, and a Slack attachment subtitle often holds the original report.
Then enumerate the attachments and say what you could and could not read. A Loom or a screenshot is frequently the only place the actual gesture exists. You cannot watch a video: state that, ask the operator to describe what happens in it, and never replace it with a plausible reconstruction — a repro you invented is how an analysis ends up explaining a defect nobody reported.
Check every gate in order. Exactly one of them posts anything; the rest stop silently. Do not improvise a third outcome.
| Gate | Check | On failure |
|---|---|---|
| Already triaged | Any comment body contains <!-- triage-frontend-ticket: or opens with a ## Technical analysis heading (a hand-written or pre-footer analysis counts) | Footer present → recompute both fingerprints (step 8). Both unchanged → STOP, report "already triaged, nothing new". Either changed → re-triage, and open the comment by saying which one moved. Footer absent → STOP and report that a human analysis already exists. |
| Not already in flight | The status is a pre-dev state (Triage, Backlog, Next to scope, Ready for dev) and the ticket carries no claude-* label and no linked PR | Started, completed or cancelled (Dev in progress, In Review, Under QA, Done, …) → STOP: somebody or something is already on it, and an analysis arriving now is noise on work in progress. Scoping → STOP, a human is actively scoping it. A claude-* label or an attached PR → STOP, the org pipeline already picked it up. |
| Frontend | The responsible logic actually lives in lago-front. Do not decide this from the Front-end label — whoever files a ticket often cannot tell which layer owns the behaviour, and a UI symptom is regularly an API bug. Check the described behaviour against the code before accepting it | Logic lives in the API → STOP, say so, and name what you found so the ticket can be re-routed. Genuinely split across both → STOP and ask the operator which half to scope. |
| Analyzable | Enough to locate the code: a named surface plus either a symptom (defect) or a desired outcome (change request) | Too vague → post the Needs info variant (step 6), then stop. Never guess a repro or invent requirements. |
| Not a duplicate | Search open tickets for the same problem — same Sentry issue, same error, same surface plus same symptom, or shared distinctive identifiers. Use Linear list_issues with a query, restricted to open states | Clearly the same problem → STOP, report possible duplicate of <ID>, post nothing. Two analyses of one bug is worse than none, and merging them is a human call. Superficial keyword overlap is not a duplicate — confirm it is genuinely the same problem before stopping. |
Then classify the ticket, because it decides what the analysis has to prove:
| Type | Signals | The question to answer |
|---|---|---|
| Defect | Bug label; "wrong", "broken", "shows X instead of Y"; a repro | Is the reported behavior real, and why does it happen? |
| Change request | Improvement / Feature label; "should also", "add", "allow", "rename", "instead of" | What exists today, what has to change, and what stands in the way? |
Mixed ticket ("it's wrong, and while we're there make it configurable") → treat the defect as primary, and cover the request under Scope beyond the defect. When the label and the wording disagree, the wording wins; say which you picked.
Some tickets already name what to change and where — "change this wording to that". An analysis would only restate them. Record that and stop:
front/scripts/analysis-depth.sh <ISSUE-ID> set skipPost a one-line comment saying it is already actionable, or nothing at all, and finish.
Everything else gets the analysis. How deep it goes is not decided here — you cannot know what a change touches before reading the code. That call comes at step 5, once you do.
The repo documents itself, and skipping that is how an analysis ends up correct about the symptom and wrong about the fix.
CLAUDE.md and the lago-frontend-patterns skill it points to are not only style - they record defect
classes together with the symptom they produce. The table below turns a reported symptom into the first place to look. Nothing
in it is a conclusion: a row that matches is a hypothesis, and the analysis stands or falls
on confirming it at the actual call site.
| Reported symptom | Documented cause |
|---|---|
| A list loads page 1 then stops; page 2 is empty | Field not registered in queryFieldPolicies with createSinglePageFieldPolicy() |
| Another org's data, logo flashing the wrong org, a webhook URL baking the wrong UUID, a value from another tab | A feature component reading currentOrganizationVar instead of useParams + memberships - the lago-frontend-patterns skill (references/organization-slug.md) names this a known bug pattern |
| Route matching never fires | useMatch from react-router - the raw pathname includes the slug. Use matchPath + strippedPathname |
| The "X-Y of N" label disagrees with the rows | PaginatedContent pageSize ≠ the query limit |
| A previously-viewed page flashes when re-entering a customer tab | List query missing fetchPolicy: 'network-only' |
| The pager is missing entirely | metadata not passed to PaginatedContent, so totalCount is 0 |
| A menu / popper / tooltip "never opens", or opens in the wrong place | the element is usually in the DOM but positioned out of view: offsets computed from viewport rects while the element is absolutely positioned inside a scrolled position: relative container (the offset needs scrollTop/scrollLeft), clipping, or z-index. Reproduce with the container scrolled — at scroll 0 the broken math looks correct |
How to use a match: open the call site and check whether the documented cause is actually present there. Confirmed → cite the rule and take the prescribed fix rather than inventing one. Not present → the row was a wrong guess; drop it and keep reading the code. The symptom in a report is a description of what someone saw, and several causes produce the same description.
A row that matches never enters the comment as the cause on its own. It has to survive step 3 like any other claim: the evidence is what makes it a finding, and "the symptom matches a documented pattern" is not evidence.
No match means nothing at all — most defects are not in this table.
CLAUDE.md at the root — always. It is prescriptive, not advisory.CLAUDE.md points to, whenever the area is one of its topics:
lago-frontend-patterns. It carries the full rules those sections used to hold inline..agents/docs/ for the area involved: folder-architecture,
graphql-fragments, testing-practices, documentation. (typescript-conventions is
already loaded in every session.)Two things this changes about the fix, not just the analysis:
use<Feature>Drawer hook, never a forwardRef + DrawerRef; a dialog is one of the three
hooks; a new translation key comes from pnpm translations:add, never hand-written.lago-frontend-patterns
skill (references/drawers.md) says this outright, and it holds generally: three
generations coexist and only one is allowed in new code. Cite the reference site the docs
name, so whoever implements it copies from the right place.For a change request, conventions are part of the answer, not a footnote: a request that fights a documented convention is a caveat at minimum, and sometimes the reason the honest verdict is feasible with caveats rather than feasible as asked.
Generated files are read with a scalpel. src/generated/graphql.tsx holds single lines
tens of thousands of characters long — one permissions blob repeated per operation. A bare grep
for a common word there returns those whole lines and burns a large share of the run's budget
for nothing. Match the shape you want and print only that:
# the argument list of one query, not every line mentioning it
grep -n "QueryMembershipsArgs" -A 6 src/generated/graphql.tsx
# a field's declared type, without the surrounding blob
grep -o "issuingDate[A-Za-z]*?*: [A-Za-z'\[\]]*" src/generated/graphql.tsx | sort -uThe same applies to lockfiles, snapshots and translation bundles.
Read the actual code. Grep for the feature, the filter key, the component, the translation key — whatever the ticket names — and follow the chain end to end. Name real symbols and file.ts:line paths.
For a defect, the two ends are usually in different files and the bug is the disagreement between them:
A default argument on the display side (fallback timezone, locale, currency, empty state) is the single most common root cause: producer and consumer each look correct in isolation.
For a change request, map instead:
CLAUDE.md conventions that dictate the shape, translations, migrationsAn analysis that describes behavior without citing code is not done.
A conclusion with no evidence beyond prose is not a conclusion. Produce at least one artifact a reader can re-run or point at:
node -e one-liner through the real library (luxon, intl, currency helpers) showing input → actual vs expectedpnpm test <path> run — never the full suitesrc/generated/graphql.tsx, the existing component that already does the thing, the full grep of call sites to be touchedBuild the input from what the code actually stores, not from the ticket's screenshot. Reconstruct that value from step 2 first.
A jest harness or a node -e snippet proves a mechanism exists. It cannot prove that mechanism is what
the reporter hit — jsdom has no layout, no scroll and no paint, which is exactly where this class of defect
lives. When the symptom is "the menu doesn't open", "nothing happens when I click", "it's in the wrong
place", the evidence has to come from the running app on the reported surface (the /qa-session skill
resolves the worktree and port). Until then every code-derived cause is a hypothesis, however well it reads.
The single check that catches a plausible-but-wrong analysis. For each cause you propose, write down:
| Cause | <the mechanism> |
| Exact precondition | <the state or gesture required to trigger it, in code terms> |
| Reporter's steps satisfy it? | yes, because … / no, because … |
A cause whose precondition is narrower than the report explains less than it looks like it does — say so instead of letting the reader assume it covers the ticket. If no cause is triggered by the reported steps, the real cause is still unfound: the verdict is cannot determine on the reported symptom, plus whatever adjacent defects you did confirm, listed as adjacent. Never present them as the answer.
Worked failure this rule exists to prevent: a report said "paste markdown, the block menu never opens". The
analysis found two genuine defects — a stale captured position in a widget, and an unwrapped <hr> — and
both were real. But the first needs an edit that leaves doc.childCount unchanged and the second only ever
affected dividers, while a plain multi-block paste rebuilds every decoration and works fine on unfixed code.
The reported symptom was a third defect, in a file the analysis had explicitly fenced off as correct.
A ticket reporting several symptoms gets a verdict per symptom. They routinely have different causes and different answers — one fixable today, another blocked on an API change. Collapsing them blocks work that could ship, or promises work that cannot. Decompose the report into its separate claims and judge each on its own; a combined "partly X, partly Y" headline is fine, the body has to keep them apart.
Defect — pick one:
Change request — pick one:
Whatever mechanism is involved, grep for every other call site sharing it. Split into affected and unaffected, and say why each unaffected one is safe.
When the mechanism is a shared key or identifier — a URL param, a localStorage key, a constant, a cache key, an enum value — enumerate both directions: every consumer that reads it, and every producer that writes it, deep links built in unrelated pages included. Grep the exported constant, then the bare literal too in case somewhere hardcodes it.
Changing the shape of a shared value while missing one producer is a silent break: the writer keeps emitting the old shape, the reader matches nothing, and no test fails because the two live in different files. A fix list that changes a key's format without naming every writer is incomplete.
A file may be declared out of scope only after the symptom has been reproduced, and only for code proven unrelated to that reproduction. "This guard is correct" is a claim about one line, not a licence to stop reading the file — the defect is regularly a few lines below the part you verified, and a non-goal written early becomes a blindfold the implementer inherits.
This is where triage earns its keep — the reporter sees one surface, the code usually has more. Report affected siblings even when out of the ticket's scope. For a change request the same sweep answers "where else does this have to change to stay consistent", which is usually the real cost of the ticket.
You know what the change touches, so this is the moment to decide whether it needs an independent review. That review is the expensive part of this skill: spend it where being wrong would go unnoticed, not on everything.
front/scripts/analysis-depth.sh <ISSUE-ID> set <shallow|full>full — the review runs. Any one of:
shallow — the review is skipped. The change is contained to one area, nobody else reads or
writes the value, and being wrong is obvious to whoever opens the page. CLAUDE.md and the
conventions are check enough at this size.
Do not count files. A source file and its test are one unit of work, not two — counting them
would put everything in full and make shallow unreachable, which is not the intent. Count
areas: a component plus its own test is one; a component, a hook and a cache policy is three.
The test is the failure mode, not the size of the diff. One line changing how an amount is
formatted is full — trivial diff, invisible when wrong, and the review is what catches it. A
twenty-line layout rewrite can be shallow — wrong is obvious at a glance.
Uncertain between the two → full.
Escalation is one-way and enforced. analysis-depth.sh refuses to move back down: shallow
is the tier that skips the review, and the moment to be tempted into skipping it is exactly when
the work turns out bigger than hoped. If anything surfaces while drafting — a second area to
touch, a value read somewhere else, a way to be wrong unnoticed — escalate and take the review.
Markdown, English, these sections in order. Omit a section only when it would be empty.
Defect:
## Technical analysis — <confirmed bug | not a bug | cannot determine>
### Reported repro
<the reporter's steps, and how they were reproduced: running app on <surface> | harness only | not reproduced
| media unread (video). Then, per cause: precondition, and whether the reported steps satisfy it (step 3b).
Not reproduced, or a cause narrower than the report → say which part of the ticket stays unexplained.>
### Root cause
<the disagreement, stated once. Files, symbols, line refs.>
### Evidence
<the step-3 artifact. Table of input → current output → expected, or the quoted test/code.>
### Blast radius
- ❌ <affected surface> — <why>
- ✅ <unaffected surface> — <why it is safe>
### Proposed fix
<numbered, per file, with the actual snippet. Explain why the edge cases hold.>
### Rejected alternatives
<the approach a reader would reach for first, and the specific way it fails.>
### Implementation handoff
<the block specified below.>
### Open questions
<only genuine blockers for a human, each marked (blocking) or (non-blocking). Omit if none.>Change request:
## Technical analysis — <feasible as asked | feasible with caveats | blocked>
### Current behavior
<what the code does today, with file:line. Correct the ticket if it assumes otherwise.>
### What has to change
<numbered, per file, what changes there and why. Include the actual snippet where it clarifies.>
### Constraints
<schema gaps, conventions that force a shape, translations, migrations. "None" is a valid answer — say it.>
### Scope
- <every call site that must change to stay consistent>
- <what is deliberately left out>
### Rejected alternatives
<the approach a reader would reach for first, and the specific way it fails.>
### Implementation handoff
<the block specified below.>
### Open questions
<product/design decisions this cannot settle, each marked (blocking) or (non-blocking). Omit if none.>Both templates end with this block. It is the part someone acts on, so it states one chosen approach in directly actionable form — exact paths, exact symbols, runnable commands. It is written to serve either reader: a developer can work straight through it, and an agent can parse it without inference.
(It also happens to map 1:1 onto the spec.md that /loop-run's spec phase writes, so
that pipeline consumes it as-is. Nothing here depends on using it.)
### Implementation handoff
**Approach:** <one sentence: the single chosen approach. Not a menu.>
**Precedent:** <one of — `<path>` plus the spec covering it, when the fix transplants an
existing, test-covered pattern · `no precedent — designed`, when the shape is new here. State
which; a reader cannot tell a copied pattern from an invented one by looking at the snippet, and
it is the difference between low-risk and needs-a-second-opinion.>
**Files to touch** (paths relative to `front/`):
- `src/path/to/file.ts` — <what changes here, naming the exact symbol>
- `src/path/to/other.test.ts` — <the cases to add>
**Acceptance criteria:**
1. <testable statement: given <input>, <surface> shows <exact expected value>>
2. <...>
**Non-goals:**
- <what a reasonable implementer might touch and must not>
**Verification:**
- `pnpm lint`
- `pnpm types`
- `pnpm translations:inspect` · `pnpm translations:ensure-consistency`
- `pnpm test src/<scoped path>` <only the touched domain, never the full suite>
- `pnpm codegen` <only if a GraphQL document changed — then the diff must be clean>
**Conventions that apply:** <the rules this change is subject to, from `CLAUDE.md` and the
`lago-frontend-patterns` skill - new translation keys via `pnpm translations:add <n>` and never
hand-written, pagination field policy registration, slug-aware router imports, direct MUI
imports, and so on.
Cite only the ones that actually bind here; "none beyond the defaults" is valid.>Rules for the block, in order of how often they are what goes wrong:
front/, no globs, no "and related files", no "etc.". If the sweep in step 5 found six call sites, all six are listed.... inside lines that change. The surrounding context must be enough to locate the edit unambiguously.8/20/2026 for a +02:00 bound" — not "the chip shows the right date". Two traps: translate is mocked in jest, so a criterion phrased against user-facing copy ("the label reads Admin") cannot be asserted — phrase it against the translation key or an exported data-test constant. And every criterion needs a concrete expected value, so "restores the full list" has to name the rows or the count.CLAUDE.md and the lago-frontend-patterns skill are there for whoever implements this, but stating which rules bind this change prevents the classic misses (hand-written translation keys, missing cache field policy, barrel MUI imports) - an agent skips them, a developer new to the area does not know them.list.includes(undefined) is false for every row, which renders as a confidently empty screen rather than an error. Decide it in the handoff, or raise it as blocking.Two checks, both cheap, both over the whole comment and not just this block. Reference rot is the failure that sends an implementer hunting, and it discredits the analysis around it.
Every path resolves:
# every path in "Files to touch"; a missing one is a defect in the analysis, not a typo to ignore
ls front/src/path/to/file.tsA path that must be created by the change is fine — mark it (new) in the list so the check
is not mistaken for a miss.
Every file:line still points at what you say it does. Line references drift the moment
you read around a file, and a citation off by two lands on a closing brace or an if. Print
each one and confirm the symbol is there:
# for every file:line the comment cites, in every section
sed -n '41p' front/src/path/to/file.tsCite the line where the value originates, not where the enclosing block starts — that is
the line the implementer has to edit. If a claim spans a range, cite the range (:66-76). A
citation you did not print is a citation you did not verify.
Omit the whole block for cannot determine and blocked verdicts — there is nothing to hand off yet, and a speculative handoff is worse than none. For not a bug, omit it too unless a small clarifying change (a tooltip, a label) is genuinely warranted.
For cannot determine / blocked, replace the middle sections with Needs info: the exact missing facts as a checklist (org timezone, browser, exact steps, expected vs actual, the product decision owner), plus what was already ruled out.
Never propose closing the ticket, changing its state, assigning it, or editing code. Analysis only; the decision stays human.
full depthRead the latch first, and do what it says rather than what you remember choosing:
front/scripts/analysis-depth.sh <ISSUE-ID> getfull → review, no exceptions. shallow → skip this step and go to step 8; there is no
finding here whose cost of being wrong justifies the review. Anything else means the tier was
never recorded: go back to step 5 and record it.
The cap is MECHANICAL, not a number you keep in your head. front/scripts/iter-budget.sh
is a standalone repo utility — an attempt counter on disk, no pipeline attached — and it is
what refuses the round past the cap.
Before every review, the first one included, charge the budget:
front/scripts/iter-budget.sh <ISSUE-ID> triage-reviewExit 0 → run the review. Exit 1 → the budget is spent: go straight to the exhausted path
below. Do not review again. The triage-review counter is capped at 2, so the sequence is
at most: review → fix → review.
If the script is missing (a checkout that predates it), cap at 2 by hand and say so in the report to the operator — never silently drop the cap.
Each review dispatches a fresh subagent with codebase access (Agent tool, general-purpose). Give it: the ticket text, the draft comment, the repo path. Do not give it your reasoning — it must re-derive. On the second review, also give it the previous review's defects and what you changed.
Instruct it to return, per claim: CONFIRMED / REFUTED / UNVERIFIABLE, with the file:line it checked, plus an overall PASS / FAIL, plus any missed call site. Tell it explicitly that agreeing without opening the cited files is the failure it must avoid.
It must also review the Implementation handoff block as its own deliverable, answering:
(new))?CLAUDE.md, .agents/docs/ and the
lago-frontend-patterns skill prescribe for this area - rather than whatever the neighbouring code happens to do?A FAIL on the handoff counts exactly like a FAIL on the analysis. An analysis that is
correct but hands off badly still produces a wrong implementation.
PASS → proceed to step 8.
FAIL, budget left → fix the specific defects, then charge and review again.
FAIL, budget exhausted → post the analysis with this leading line, and do not attempt another review:
⚠️ Automated analysis — independent review could not confirm: <what>. Needs human verification.
Never post a silently-failed review as clean, and never re-run a review the script refused.
Post with Linear MCP save_comment (issueId = the identifier), no confirmation needed — the operator invoked this deliberately.
Close the comment with a provenance line, above the footer:
---
Generated by `/triage-frontend-ticket` · independently reviewedAt shallow depth, drop · independently reviewed — it did not happen. State what the output
is; never tell a reader or another system what weight to give it. That is their rule to
write, not this skill's to impose.
Then append this footer as the last line, so the step-1 gate can recognise it:
<!-- triage-frontend-ticket: v1 · type=<defect|change-request> · desc-sha=<hash> · cmt-sha=<hash> -->Two fingerprints, because a ticket changes in two places. Step 1 fetches the comments precisely because scope changes, repro details and decisions land there and never make it back into the description — so a description-only key reports "nothing new" on a ticket whose comments have since redefined the work.
# what the ticket says
printf '%s' "$DESCRIPTION" | shasum -a 256 | cut -c1-12
# which comments exist, in order — ids only, so editing prose in a comment is not a re-triage
# trigger while a NEW comment is. Exclude comments carrying this skill's footer, otherwise
# posting immediately invalidates the fingerprint it just wrote.
printf '%s' "$COMMENT_IDS" | shasum -a 256 | cut -c1-12With no qualifying comments, use cmt-sha=none.
Then report to the operator in chat: type, verdict, one-line reason, review outcome, comment URL, and whether the status moved (step 9). Short and plain — the analysis already lives on the ticket.
A ticket in Triage is waiting for someone to establish whether there is work here. A
resolved analysis answers that, so the ticket can move on to Backlog — where the team
prioritises it. Anything further (Ready for dev, an assignee, a cycle) is a scheduling
decision this skill does not make.
Re-fetch the ticket immediately before moving it. The analysis takes minutes, and a human
may have triaged it in the meantime; acting on the status captured at step 1 would overwrite
their decision. If the re-fetch no longer says Triage, leave it alone and report that
somebody moved it first.
Move it only when every one of these holds:
Triage — a ticket already in Backlog,
Scoping or beyond is left alonePASSsave_issue: { id: <ISSUE-ID>, status: "Backlog" }Leave the ticket in Triage for every other outcome, and say why in the report:
| Outcome | Why it stays in Triage |
|---|---|
| not a bug | Someone has to decide whether to close it, and that is not a technical call |
| cannot determine / blocked | Still waiting on the missing facts the comment asked for |
review exhausted its budget without PASS | The analysis is unconfirmed; promoting it would launder that |
A failed status update is a warning, never a failure of the run: the comment is the deliverable and it is already posted. Report that the move did not go through and move on.
Triage → Backlog move. No assignee, no labels, no cycle, no closing, and never a status change from anywhere other than Triage.
Why the label ban is not arbitrary: an ai-augmented or claude-* label, and the
Scoping state, are entry gates for the org's existing automated pipeline — it skips any
ticket carrying them. Applying one here would make the ticket permanently invisible to that
pipeline, silently. Backlog is safe because it is a pre-dev state that pipeline accepts.
Do not add a convenience label to mark analysed tickets; the footer already does that.file:line you cite before posting. An unverified citation is reference rot waiting to happen.CLAUDE.md is a finding to reject, not to propose.iter-budget.sh; a non-zero exit is final.© getlago, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in .agents/skills/triage-frontend-ticket of getlago/lago-front.
Open the folder on GitHubat commit cfe24ee
Triage Frontend Ticket next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Triage Frontend Ticket this skillgetlago/lago-front | 163 | — | ~9.3k | Automated safety check: Pass | AGPL-3.0 | |
| Research Decision Roomnexu-io/open-design | 100k | — | ~1.6k | Automated safety check: Pass | Apache-2.0 | |
| Miniprogram DevelopmentTencentCloudBase/CloudBase-AI-Toolkit | 1.1k | 1 repos | ~3.7k | Automated safety check: Pass | MIT | |
| Mulmoterminal Helpreceptron/mulmoterminal | 237 | — | ~2.4k | Automated safety check: Pass | MIT | |
| Siftranknoperator/siftrank | 225 | — | ~2.9k | Automated safety check: Pass | MIT | |
| Analyze Dotnet Agent Logsnewrelic/newrelic-dotnet-agent | 117 | — | ~1.5k | Automated safety check: Pass | Apache-2.0 |
nexu-io/open-design
Turn messy user research notes, interviews, support tickets, surveys, and product context into an evidence-backed decision room: a single HTML artifact with an evidence ledger, theme map, confidence…
TencentCloudBase/CloudBase-AI-Toolkit
WeChat Mini Program development skill for building, debugging, previewing, testing, publishing, and optimizing mini program projects (小程序开发、调试、预览、发布).
receptron/mulmoterminal
Help desk for questions about MulmoTerminal itself — what it can do, how a feature or a part of the screen works, how to set something up, what is new in this version or in the latest one.
noperator/siftrank
Find needles in haystacks with SiftRank. An agent skill from noperator/siftrank.
newrelic/newrelic-dotnet-agent
Parse and diagnose New Relic .NET agent logs (newrelicagent.log) and profiler logs (NewRelic.Profiler.<pid.log) from a support ticket.
DrDroidLab/open-index
Install and configure Open Index as the read/write context layer for a domain-specialized agent.
getlago/lago-front
A skill your agent uses when asked to babysit, monitor, shepherd, or keep working on a GitHub pull request until it is green, review-ready, approved, mergeable, or ready to merge.
getlago/lago-front
Triage a CVE / Dependabot alert in a JS/TS project and recommend the least-invasive fix.
getlago/lago-front
Extract a Formik form section into a TanStack Form drawer with Zod validation, following the plan form migration pattern.
getlago/lago-front
Phase 2 of the loop pipeline for lago-front. An agent skill from getlago/lago-front.
getlago/lago-front
Cleanup phase of the loop pipeline for lago-front, for the worktree layout only.
getlago/lago-front
You are an advanced Docker containerization expert with comprehensive, practical knowledge of container optimization, security hardening, multi-stage builds, orchestration patterns, and production…
Categories
A skill your agent uses when given a Linear ticket (URL or ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown, or a change request nobody has…. Triage Frontend Ticket is an agent skill from getlago/lago-front. Use when given a Linear ticket (URL or ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown, or a change request nobody has costed against the code.
Triage Frontend Ticket fits situations like: given a Linear ticket (URL; ID) for lago-front and the technical groundwork is missing — a defect report whose validity is unknown; A change request nobody has costed against the code; /triage-frontend-ticket <ticket.
Run `npx skills add getlago/lago-front --skill triage-frontend-ticket -a claude-code`. Or copy the skill folder (.agents/skills/triage-frontend-ticket in getlago/lago-front) into .claude/skills/triage-frontend-ticket in your project. Claude Code loads it when a task matches its description.
Run `npx skills add getlago/lago-front --skill triage-frontend-ticket -a codex`. Or copy the skill folder (.agents/skills/triage-frontend-ticket in getlago/lago-front) into .agents/skills/triage-frontend-ticket in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add getlago/lago-front --skill triage-frontend-ticket -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/triage-frontend-ticket, .gemini/skills/triage-frontend-ticket, .github/skills/triage-frontend-ticket and .opencode/skills/triage-frontend-ticket in your project.
Going by SKILL.md and its folder, Triage Frontend Ticket needs the command-line tools its instructions call (pnpm and node).
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Triage Frontend Ticket is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 9.3k tokens (SKILL.md is roughly 37k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Triage Frontend Ticket: Research Decision Room (nexu-io/open-design, 100k stars), Miniprogram Development (TencentCloudBase/CloudBase-AI-Toolkit, 1.1k stars), Mulmoterminal Help (receptron/mulmoterminal, 237 stars) and Siftrank (noperator/siftrank, 225 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
getlago (a GitHub organization) maintains it in getlago/lago-front, which has 163 GitHub stars. The repository holds 17 skills in this directory. The repository was last updated on October 10, 2026.
Source: getlago/lago-front on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.