I keep writing the same ticket twice.
The first time is in the tracker: "Catch more React issues in lint." Then someone asks which rules, whether we already have a config, which packages. I answer in Slack, because I already knew. The answers were sitting in a browser tab. They just never made it into the ticket.
The second version is always better. It has the outcome and the sentence that would have stopped the question. The tracker started me on a blank form, so I translated from memory and dropped the parts that felt obvious. Those parts came back as a thread.
That thread is the ticket I should have written.
Why the answers land in Slack
A ticket form is a set of empty fields. Filling them is a translation job. You take something you already have, a half-sentence or a customer log, and restate it in the dialect the board expects, usually without the repo open, usually between two other meetings.
The pieces that fall out are the ones that felt too obvious to write down. Which screen the bug is on. What "off" means for a notification toggle. Whether the repo already has an Oxlint config. Those are the questions that come back, because they are not obvious to the person picking the ticket up. They are not obvious to a model either.
The person holding the source is usually not the person who already knows how the product works today. The ticket gets written from what the author can see, and the rest arrives later as a thread.
I do this from the other side too. I open a ticket, I cannot tell what "catch more React issues" means, I ask, and I get slightly annoyed. Then I look at the ticket again and realize I would have filed the same stub. The author was not lazy. The form asked them to invent a spec from memory, and memory is a bad checkout.
A human reconstructs the missing pieces before they start. A coding agent often skips that step and implements a guess, so the clarification shows up as a pull request you close.
Write the reply first, against the repo
The order that works is backwards from the form. Keep the source instead of translating it. Point a model at that source and at a checkout of the real repo, and have it draft the ticket. Then read the draft before anyone else does.
Here is one I actually ran on our monorepo. The prompt on the left is the kind of thing I used to paste into Jira as the entire ticket:
Check oxlint config and available rules from https://oxc.rs/docs/guide/usage/linter/rules.html, we probably need some useful ones related to react, ts, jsdocs
Under it, one extra sentence: "Let's add useful rules if they are missing."
The draft on the right is already a different object. It found there is no committed Oxlint config in the monorepo, so only the defaults apply. The react and jsdoc plugins are off. TypeScript has a pile of high-value rules that stay off unless you opt in. The acceptance criteria start with auditing current usage against the public rules list, then adding a committed config. That is actual work, not a title like "make lint better."
Create Task is still unclicked. I left it that way on purpose.
I would not have written "no committed Oxlint config" from memory. I would have written "enable useful React rules" and waited for someone to ask whether we have a config. The draft found it because it was looking at the repo, not at my recollection of the repo.
You do not need an app for this. Before you post the stub, write the Slack reply you already know is coming. If you can answer "which screen" or "what does off mean" right now, that answer belongs in the ticket body, not in a thread tomorrow.
The model is doing the part that used to require the person who knows where the lint config lives to be in the same room as the person who has the prompt.
Posting the first draft still produces the thread
The model will invent a scope you did not mean, or promote a side comment into a requirement, or be sure about a screen that changed last month.
On this Oxlint draft I have not hit Create Task yet. I still need to cut the stylistic TypeScript rules. The draft found the right problem. It also decided I wanted a much larger lint pass than I did. Posting that first version would have given me a longer ticket that still needed a Slack thread. Extra paragraphs are not the same thing as a ticket someone can pick up.
I treat these drafts like a PR I did not write. I read it, delete the scope it invented, and keep the facts it pulled from the repo. Sometimes that is rewriting a sentence. Sometimes it is adding the case I actually care about.
What I ended up building
This loop is built into DevIntern PM, a desktop app. Prompt, log, or Figma URL on the left, an editable story on the right. Sign in with GitHub clones the repo so you do not have to run git clone. The ticket still lands in the tracker you already use: Jira, Linear, Trello, Asana, Azure DevOps, GitHub Issues, or local markdown.
Free, no signup.

Top comments (0)