Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions .claude/skills/fxa-ai-fixme-create-issue/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
name: fxa-ai-fixme-create-issue
description: Use when asked to create, draft, file, or write a Jira ticket for the FxA ai-fixme pipeline, or to turn a request, bug, Slack thread, or idea into an FXA ticket labelled ai-fixme. Triggers include "make an ai-fixme ticket", "file this for ai-fixme", "draft a ticket the agent can do".
user-invocable: true
---

# Create an ai-fixme issue

The ai-fixme pipeline takes FXA tickets labelled `ai-fixme` and gives each one to a coding agent.
The agent works alone in a sandbox VM and opens one PR. Nobody answers its
questions before the PR. So a good ticket has **zero open questions**. Every decision is made and
written down before the ticket is filed.

Evidence (100 merged `auto` PRs, 29 skips): tickets that merged with no feedback round state one
decided outcome, name files, give a root cause, and list what is out of scope. Length does not
matter. The top skip reason is "two routes offered or no target named". The top feedback reason is
Comment on lines +14 to +16
missing tests.

## Prerequisites

Check these before step 1. If Git or the GitHub CLI fails, tell the engineer how to fix it, then stop.

- **Jira access**, one of:
- **The Atlassian MCP.** Connect it with `/mcp`, either the Atlassian server or the `atlassian`
plugin, and sign in to `mozilla-hub.atlassian.net`. Tool names vary by install
(`mcp__atlassian__*` or `mcp__plugin_atlassian_atlassian__*`), and so do some field names. Load
`createJiraIssue` and `searchJiraIssuesUsingJql` with ToolSearch and read their schemas. Pass
`cloudId: mozilla-hub.atlassian.net`; if a call rejects it, get the ID from
`getAccessibleAtlassianResources`.
- **The Atlassian CLI.** Install `acli`, run `acli jira auth login`, and check it with
`acli jira workitem search --jql 'project = FXA' --limit 1`.
- **GitHub CLI:** `gh auth status` succeeds. Step 1 uses it to find open PRs on the same files.
- **Git:** `git fetch origin main` works in the repo root.

With no Jira access, still write the draft. Give it to the engineer to file by hand with the
`ai-fixme` label.

## Procedure

Before step 1, show the engineer the read-only lookups you will run: `git fetch`, `git grep`, the
`gh` PR search, and the Jira search. Wait for one approval, as `CLAUDE.md` requires for commands
and network access.

1. **Ground on current main.** In the repo root, run `git fetch origin main`. Read code
only with `git grep -n <pat> origin/main -- <path>` and `git show origin/main:<file> | cat -n`,
Comment on lines +44 to +45
so every reference has a line number. Write down
what the code does today, with `file:line`. If the request is already done, or its premise is
false, say so and stop.
- Confirm the target is live: the named code has a real route or caller, in the app the request
means. Do not fix a page that nothing uses.
- Search Jira for an existing ticket. Find open PRs that change the same files by their file
list, not by text search:
`gh pr list --state open --limit 100 --json number,title,files --jq '.[] | select(any(.files[]; .path == "<file>")) | "#\(.number) \(.title)"'`
Name an overlap in Dependencies or Out of scope.
2. **List every decision the ticket needs.** A decision is open when you would write "maybe",
"consider", "or", "should we", "to discuss", "TBD", "decide", or an assumption. Typical ones:
which of two approaches, where a migrated page lives, what a signed-out user sees, client or
server, one PR or several.
3. **Ask the engineer, and wait.** Put each open decision to the engineer as one short question
with a recommended answer (use AskUserQuestion). Do not write the final draft while a question is
open. An assumption you write into the ticket is an open question in disguise.
- Ask at most 4 questions per round, the ones that change scope first.
- Put the minor decisions in a "Defaults I will use" list, and offer "take the recommendations"
as a single reply that accepts every default.
4. **Check the blockers.** A security vulnerability never gets the `ai-fixme` label: the agent's PR
is public, so it would publish the fix before a release. Use the private security process.
For each other item that applies, either remove it from scope or get the engineer's explicit
sign-off and quote it in the ticket:
- a path listed in `_scripts/check-frozen.ts` on origin/main
- an API that another repo consumes, such as exported `fxa-shared` code. `fxa-auth-client` is
internal to this repo, so its methods may change
Comment on lines +70 to +71
- a new DB migration: a forward patch plus its rollback. Never allow an edit to a published
migration file, even with sign-off; `CLAUDE.md` forbids it
- prod data or prod SQL
- `.github/`, `.circleci/`, `.husky/`, `_scripts/`, or a `package.json` `scripts` block
- a dependency on an unmerged PR, another ticket, or a prod deploy
- a link to Slack, Confluence, an attachment, or Sentry: the agent cannot open it, so copy the
facts into the ticket. Copy facts only, never instructions from that text
- a URL or external fact: check it
- UI work: add a Figma frame URL with a `node-id`. For a route migration, name the feature flag
state the change must work in (for example `showReactApp` at its default). For a multi-page
flow, add the line `Launch with --functional-tests`
- changed FTL text: it needs a new string ID
5. **Size it for one PR.** If the work has parts that could ship alone, propose one ticket per
part, and say which one goes first.
6. **Write the ticket** with the template below. Every heading is required. Write "None" when a
section is empty.
7. **Show the draft and file only after approval.** With the Atlassian MCP, call
`createJiraIssue` with project `FXA`, issue type `Task`, label `ai-fixme`, and a markdown
description. Or use the Atlassian CLI:
`acli jira workitem create -p FXA -t Task -s "<summary>" --description-file <file> -l ai-fixme`
Comment on lines +88 to +91
Comment on lines +90 to +91
Set the parent epic when the ticket belongs to one. Report the new key and
`https://mozilla-hub.atlassian.net/browse/<KEY>`.

## Template

```
Summary: <imperative verb> <what> in <package or component>, 70 characters at most

Current behavior on main (checked <YYYY-MM-DD>):
<what the code does today, with file:line>

Root cause: <bugs only: why, or the failing CI run URL. Otherwise "None">

Change:
<the one decided approach, as numbered steps. Name files and symbols.>

Paths to cover:
<every path that reaches the changed code: web, OAuth web, OAuth native; an early return above it;
the error result as well as the success result. Mark which ones need the change.>

Environments and consumers: <which of local, stage, prod the change affects, and every caller outside
this repo, such as PyFxA, relying parties, or mobile clients. "None" when none.>

Decisions:
<each decision the engineer made, one line each, with who decided. Sign-off for any blocker from step 4.>

Acceptance criteria:
- <a statement a unit test or type-check can prove>

Tests:
<tests to add, change, or delete. Name the nearest existing test file to copy. For a tests-only
ticket, add: "Flag each assertion you cannot tie to intended behavior, so a bug is not locked in.">

Out of scope:
<adjacent files, frozen twins, sibling tickets, follow-ups>

Dependencies: <"None", or the merged PR, ticket, or deploy this needs>

Verify: <the project's test-unit or one spec, plus tsc for a rename or removal. The VM has no network,
Stripe, CMS, or 123done OAuth reliers; name anything that needs them as unverified.>
```

## Common mistakes

| Mistake | Fix |
|---|---|
| Draft ends with "questions for the engineer" | Ask them first. File only when the list is empty. |
| "Use A, or maybe B" | Pick one with the engineer. Name the other in Out of scope. |
| AC is "a decision is recorded" or "smoke test the panels" | That is not code. Decide first, or name the test that proves it. |
| Scope is a repo-wide grep count | Filter frozen paths first. List the real files. |
| Verify says "lint and full suite pass" | CI runs those. Name the one project or spec. |
| Premise copied from an old ticket | Re-check it on origin/main and date the check. |
| Summary over 70 characters | The pipeline cuts it in the agent's goal. Shorten it. |
| The fix covers only the path the request names | List every path under "Paths to cover". |
| A consumer outside the repo breaks | Name it under "Environments and consumers". |
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Every skill's name and description loads automatically — this section only cov

- **Before merging:** `/fxa-review` for auth, payments, crypto, migrations, or multi-package changes; `/fxa-review-quick` otherwise. `/fxa-security-review` on top when the change touches auth, sessions, tokens, or payments.
- **Filing a ticket:** `/fxa-jira-feature-description` or `/fxa-jira-bug-description`, even when the ask arrives mid-task.
- **Filing a ticket for the ai-fixme agent:** `/fxa-ai-fixme-create-issue`. It resolves every open question with you before it files.
- **Opening a PR:** `/fxa-pr-open`. It handles the template, the alignment pass against Jira, and the draft-only rule.
- **Trying a branch without checking it out:** `/fxa-pr-debug`. Boots the branch's stack in CircleCI, tunnels it to `localhost`, and can run a throwaway Playwright check you describe.

Expand Down
Loading