bugstweet 0.4.0
bugstweet: ^0.4.0 copied to clipboard
Testers report bugs from inside your Flutter app as GitHub issues an AI coding agent can fix. Tester builds only: store builds never contain it.
bugsTweet #
Testers report bugs from inside your Flutter app, on the phone. They tap a button, mark the bug on the screenshot, and send. Each report arrives as a GitHub issue with everything a developer or an AI coding agent (Claude Code, Codex, Cursor and the like) needs to fix it.
- No account, no server, no cost.
- Your app's code is never changed.
- Store builds never contain bugsTweet. Only tester builds do.
How it stays out of your app #
bugsTweet comes in two packages. You only ever add and type the first one.
bugstweet: the tool. You add it to yourpubspec.yamlas a development package. It has no phone parts, and your app never uses its code, so nothing of it is packed into any build.bugstweet_reporter: the button and the phone parts testers use. You never add it. The tool adds it to tester builds only.
How a tester build is made:
- Your app gets one small file,
.bugstweet/tester.dart. The folder name starts with a dot, so your normal code checks and IDE skip it. dart run bugstweet buildcopies your app to a cache folder on your computer, addsbugstweet_reporterto that copy only, and builds the tester app from the copy.- For a store build, you run
flutter buildas always. Your app does not listbugstweet_reporter, so none of it can be packed into the store app.
What is inside each build (checked on Android and iPhone builds):
| Inside the app | Store build | Tester build |
|---|---|---|
| bugsTweet code (button, screens, sending) | no | yes |
| bugsTweet phone parts (screenshot and shake listeners) | no | yes |
| Android "detect screen capture" permission | no | yes |
| iPhone motion permission text | no | yes |
Set up (once per app) #
You need Flutter 3.38 or later. In your app's folder:
-
Add the tool as a development package:
flutter pub add --dev bugstweet -
Create the tester file:
dart run bugstweet init -
Try it on a phone or emulator:
dart run bugstweet runIt starts on the first phone, emulator or simulator it finds, and tells you how to open one if none is there. The app starts with a round bugsTweet button. Reports go out through the phone's share sheet until you connect GitHub (step 4).
-
Send reports to GitHub as issues: create a reports repository and a key, as described in The GitHub key, then open
.bugstweet/tester.dartand check the two repository names.
That is all. Apart from the one bugstweet line under dev_dependencies,
your pubspec.yaml, lib/ folder and platform files stay as they were.
Make a tester build #
dart run bugstweet build apk --dart-define=BUGS_TWEET_GITHUB_TOKEN=github_pat_...
dart run bugstweet build ipa --dart-define=BUGS_TWEET_GITHUB_TOKEN=github_pat_...
You can build apk, appbundle, ipa or ios. Every option you would give
flutter build works here too (flavors, build numbers, export options).
The finished tester build goes to build/bugstweet/, for example
build/bugstweet/apk/app-release.apk. It is kept apart from store builds,
which stay in their usual place. Give tester builds to testers only (for
example TestFlight internal testing or Firebase App Distribution), never to
a store.
The first tester build takes a few minutes longer, because the copy starts empty. Later builds reuse it.
What testers get #
- Tap the round button: the screen is saved, and a thumbnail waits in the corner for four seconds. Tap the thumbnail to mark it up right away, or swipe it away and keep testing.
- Hold the button: a fan of choices, from the bottom up: Tray, Report now, 4 versions and Hide.
- 4 versions: one tap captures the same screen in light, dark, large text and Arabic right to left, in one report. Layout bugs that show in only one of them are caught early. The Arabic picture needs an app that offers Arabic.
- Shake the phone: a screenshot, or the hidden button comes back.
- Screenshot with the phone's own buttons: bugsTweet asks "Report this?". Works on iPhone and on Android 14 or later.
- Marks: arrow, line, box, circle, pen, highlight, spotlight, magnify, blur, text, numbered steps, stamps (Wrong text, Misaligned, Too slow, Crash...). Tap an element with a shape tool and the shape snaps to it.
- Design tools: Ruler (in points), Color (hex), Contrast (WCAG AA/AAA).
- Tray: review, add notes, merge several screenshots of one problem, and send all at once. It also lists reported issues with their status (Open, In progress, Pending, Done); tap one to open it in the GitHub app.
- Retest: every reported issue offers Retest. A card shows the way back to the bug (old screenshot, screen name, last steps); Capture compares the new screen with the old one on a before/after slider. Fixed closes the issue, Still broken reopens it.
- Answer the agent: when a coding agent writes its plan (Actual, Expected, Fix) on an issue, the tray shows it as a card. Tap Go to agree, or Not quite and say what is different.
- Copy for agents: copy one or several open reports as one message for a coding agent.
- Recap: today's test session on one card, ready to share.
- Voice notes: the keyboard's own dictation key. bugsTweet never handles audio.
Every report also carries, without any typing: the screen name, the taps before the bug, a filmstrip of the last 30 seconds, phone settings (text size, dark mode, language), phone model and system, app version, recent app errors, the file and line of each widget, a draft test that replays the taps, and a check for duplicate reports.
Where reports go #
- GitHub (
GitHubDelivery): one issue per report, labeledfrom-bugsTweet. Screenshots are stored on abugs-tweet-mediabranch of the same repository and linked from the issue. Sending starts nothing else: you decide when to hand an issue to a coding agent. - Share sheet (
ShareDelivery): the screenshot and report text go to any app the tester picks. Used by itself when no GitHub key is given. - Your own place: implement
ReportDelivery.
The GitHub key, and why reports get their own repository #
The key is built into the tester app, so anyone who has the tester app can read it. Keep the damage small:
-
Create a private repository that holds only reports, for example
my-app-reports, with a README (GitHub cannot add the screenshots branch to an empty repository). Never point bugsTweet at your code repository. -
Create a fine-grained personal access token for that one reports repository only, with Issues: read and write and Contents: read and write, and a short expiry.
-
Pass the key at build time, never in a file in git:
--dart-define=BUGS_TWEET_GITHUB_TOKEN=github_pat_.... -
Create the labels once in the reports repository:
gh label create from-bugsTweet --color 0B7A6E gh label create "bugsTweet: in progress" --color 2FBFA9 gh label create "bugsTweet: pending" --color F2B84B
When a test period ends, or a tester build reaches someone it should not, delete the key on GitHub. That build can then no longer send.
Optional: the relay (no GitHub key in the app) #
A small Cloudflare Worker that you deploy for free holds the GitHub key. The
tester app holds only a send code, which can do nothing but bugsTweet's own
calls in one reports repository. Setup steps:
relay/README.md.
In .bugstweet/tester.dart, use:
GitHubDelivery.relay(
url: 'https://bugs-tweet-relay.<you>.workers.dev',
sendCode: const String.fromEnvironment('BUGS_TWEET_SEND_CODE'),
repo: 'me/my-app-reports',
codeRepo: 'me/my-app',
)
The tester file #
dart run bugstweet init writes .bugstweet/tester.dart. It is plain Dart, so you
can change it freely. Common settings in BugsTweetConfig:
delivery: where reports go (see above).redact: cleans text before a report leaves the phone, for exampleredact: (text) => text.replaceAll(RegExp(r'[\w.+-]+@[\w-]+\.[\w.]+'), '[email]').readFirst: which doc a coding agent should read first for a report.autoBlurTextFields: blur every text field in screenshots (off by default; password fields are always blurred).shakeToReport,screenshotToReport: turn those off.reproTestApp,reproTestImport: let the draft test start your app.
To blur a part of the screen in every screenshot, wrap it in
BugsTweetPrivate from the tester file, for example through a hook your app
already has. Your store code never needs to import bugsTweet.
Before each tester build, bugsTweet writes .bugstweet/widget_map.g.dart
into the copy, so reports name the file and line of each widget. It never
appears in your app.
For the coding agent #
Each issue ends with the steps an agent follows: find the cause, write back Actual, Expected and the proposed fix, wait for the tester to agree, then fix, test, and say what is done and what is not. AGENT.md has the details, including how to fetch the screenshots.
Uninstall #
In your app's folder:
-
Delete this app's tester copy from the cache folder:
dart run bugstweet clean -
Remove the tool:
flutter pub remove bugstweet -
Delete the
.bugstweetfolder.
There is nothing else to undo: bugsTweet never changed your code or your platform files. If you set up GitHub, you can also delete the reports repository and the key.
Limits #
- Captures what Flutter draws. Platform views (maps, web views) show blank.
- Widget names in reports come from class names, so
--obfuscatebuilds lose them. dart run bugstweet runstarts the app from the copy, so hot reload does not see edits you make in your app while it runs. Stop and run again.
License #
MIT. See LICENSE.