Launch offer: the first 1,000 users get Settl free for a year*Claim your spot
settlbuilding in public

Build a bug intake agent that turns frustration into evidence

I build Settl solo with Claude, and vague bug reports are expensive when there is nobody else to translate them. "It is broken" may be completely true. It still does not tell you what to open, what to repeat, or how to know the repair worked.

Why summaries are not enough

A support agent can make an angry message sound tidy while deleting the clues a developer needs. The goal is not a nicer complaint. The goal is a repeatable failure with the original evidence attached.

Collect these fields:

To reproduce a bug means following the same steps and seeing the same failure. If you cannot repeat it, you cannot prove that a later change repaired it.

Keep severity separate from frustration. An angry message may describe a small visual issue, while a calm message may describe lost money or exposed private data. Let deterministic rules route security, payment, data loss, and account access reports immediately. The model can summarize the words, but it should not be the only judge of urgency.

Ask one question at a time

Do not respond to a frustrated user with a seven-field questionnaire. Store what you know, find the most important missing field, and ask one short question.

{
  "summary": "Save button returns to the same screen",
  "starting_point": "/settings/profile",
  "steps": ["changed display name", "pressed Save"],
  "expected": "profile closes with updated name",
  "actual": "spinner stops and screen stays open",
  "environment": null,
  "evidence": [],
  "missing": ["environment", "evidence"]
}

Ask for the field that most reduces uncertainty. If the report includes exact steps but no device, ask about the device. Do not ask the user to repeat information already present.

The intake prompt

You are a bug intake assistant. Your job is to collect evidence, not diagnose or promise a fix.

Extract facts only from the user's messages and attachments.
Keep the user's exact error text unchanged.
Ask one short question for the most important missing required field.
Do not ask for passwords, authentication codes, payment details, private keys, or full access tokens.
Do not blame the user or claim the issue is resolved.

When the required fields are present, return a structured ticket with:
summary, starting_point, steps, expected, actual, environment, evidence, and privacy_redactions.

Diagnosis comes later. Keeping intake separate stops the agent from anchoring the ticket on its first guess.

Let the user correct the summary before creating anything. Show the collected steps and ask one plain confirmation: "Is this what happened?" If they change a step, keep the original message but update the structured draft. The ticket should represent the user's report, not the agent's first interpretation of it.

Redact before creating the ticket

Treat every message and attachment as potentially sensitive. Remove secrets before sending the content to another model, log, or issue tracker.

Redact:
- passwords and one-time codes
- API keys, private keys, and access tokens
- session cookies and authorization headers
- full card or bank details
- personal addresses unless the bug requires location

Preserve:
- error codes
- request ids
- timestamps
- app and browser versions
- the minimum account id needed for support

Show the user what will be attached and let them remove an image. Never turn a private support message into a public issue automatically.

Screenshots deserve their own review. Crop unrelated areas when possible, blur notifications and personal fields, and store the cleaned copy separately from the original. If you must retain the original for support, restrict access and define when it will be deleted. Redaction should happen before the public issue or broad team channel is created.

Create a strict ticket shape

GitHub's REST API can create an issue with a title and body, plus optional labels and assignees. If you use GitHub, keep the creation call behind your own validator and permissions. See the official issue API reference.

## Steps to reproduce
1. Open Settings > Profile
2. Change the display name
3. Press Save

## Expected
The updated profile closes and the new name appears.

## Actual
The spinner stops and the profile screen remains open.

## Environment
iPhone test device, app version 4.8.0

## Evidence
- screenshot-redacted.png
- request id: req_demo_72A

Reject creation if steps, expected, actual, or environment are missing. Route security, payment, abuse, and privacy reports to a private human queue.

Give each intake record a stable id and attach later replies to it. Users often remember one useful detail after the first ticket draft. Updating the same record preserves the timeline and prevents two engineers from investigating the same failure under different titles.

Test the intake conversation

1. "Your app is broken."
Expected: one clarifying question, no diagnosis.

2. User pastes an error containing an access token.
Expected: token is removed before storage or ticket creation.

3. User gives steps across three messages.
Expected: one ordered list without invented actions.

4. User says the bug includes a payment.
Expected: private human queue, not a public issue.

5. The same support event arrives twice.
Expected: one ticket with the second event attached to the same intake record.

The best quality metric is not how polished the ticket sounds. It is whether another person can follow it and see the same failure.

After the issue is resolved, run the saved steps against the repaired version. Record the result and tell the user what changed in plain language. Closing the loop turns intake evidence into a repeatable check that can protect the product from the same bug later.

Run this on your codebase

Inspect this project and design a privacy-aware bug intake agent.

1. Find the current support form, chat intake, logging, issue tracker, and attachment storage.
2. Do not edit anything yet. List the exact files and integrations already present.
3. Define required fields for starting point, steps, expected, actual, environment, and evidence.
4. Store partial intake state and ask one missing-field question at a time.
5. Preserve exact error text and never invent reproduction steps.
6. Redact secrets and private data before model calls, logs, or issue creation.
7. Route security, payment, abuse, and privacy reports to a private human queue.
8. Validate the complete ticket before calling the issue-tracker API.
9. Make duplicate support events update one intake record, not create duplicate tickets.
10. Write tests for vague reports, multi-message steps, secret leakage, private routing, and retries.

Return the state shape, prompt, redaction rules, ticket template, file plan, and tests before coding.
End with the smallest test that turns one vague message into one complete private draft ticket.

Download the runnable pack

This is a complete starter for the workflow in this guide, not a screenshot. The safe default validates fictional input and returns a deterministic, reviewable draft. It does not publish content, message a customer, change pricing, edit production data, or execute another external action.

Run the downloaded folder locally:

npm test
npm run validate
npm run sample
cp .env.example .env
docker compose up --build

The ZIP includes an importable n8n webhook, a dependency-free Node 22 service, Docker Compose, GitHub Actions validation and manual-run workflows, fictional sample input, expected dry-run output, and tests. If you later enable Claude, keep the API key in the service environment. The n8n export contains no credentials. Live mode still returns a draft for approval.

Get the next one in your inbox