bugcap
Syncs local bug reports, annotated screenshots, and other media to GitHub issues, and can pull GitHub issues into the local report store. Provides GitHub issue integration for filing bugs and keeping agent-readable copies of reports and images.
Why bugcap
Reviewing an app for bugs usually leaves you with two disconnected things: a screenshot and a
mental note. By the time you file the issue, the context is gone. Once the screenshot is attached
to a GitHub issue, it becomes unreadable to an API token. The CDN only resolves in a browser
session, so an agent using gh can read the text but never the picture that explains the bug.
bugcap keeps the whole loop in one place:
πΈ Capture at the moment | Annotated screenshots through |
ποΈ Local record | A SQLite index and PNGs on disk. Nothing depends on GitHub being reachable. |
π€ Agent-readable | A stdio MCP server hands reports, images included, to Claude Code and other agents. |
π Sync when ready | Push to a GitHub issue with the usual inline image, plus a plain copy agents can read. |
ποΈ Record what happens | Short screen recordings as animated GIF, video or keyframes, with size caps. |
π₯οΈ Triage in a browser | A local dashboard on |
πͺ Live mode | An always-on-top window (top-right) to capture or record, stage several items (open or remove any of them), then file a new bug, add to an existing one, or log a note-only bug. |
Related MCP server: Lific
Quick start
# install from PyPI
pipx install 'bugcap[mcp]'
bugcap setup --yes # detects or installs a capture tool
cd ~/code/myproject && bugcap init # scope reports to this repo
bugcap capture --title "Login fails" --note "Error toast after submit" --tag auth
bugcap list
bugcap dashboard --open # browse and triage in the browserThe usage guide covers every command: images
and labels, recording, live mode, @ references, GitHub pull and sync, and the MCP tools.
If a report ID is not found, the error suggests bugcap list --all to see report IDs across all repos.
Connect your agent (MCP)
Requires the mcp extra. Then give your agent access to the reports:
claude mcp add bugcap -- bugcap mcp-serveOr in a project's .mcp.json:
{ "mcpServers": { "bugcap": { "command": "bugcap", "args": ["mcp-serve"] } } }The server exposes six tools: list_reports, get_report (returns the screenshot), request_screenshot,
pull_issues, attach_image, attach_file and update_notes. Logs go to logs/mcp-server.log in the data
directory, never to stdout.
Ask your agent something like "list the open bugcap reports for this repo and fix the one with the error toast". It can read the picture because it's a local file, not a CDN link.
How it works
capture βββΊ local store (SQLite + images/) βββΊ MCP / dashboard / CLI (read by agents and you)
β
ββββΊ sync βββΊ GitHub issue + committed image copy (readable with gh api)capture/attach/recordwrite to the store.mcp-serve,dashboard,list,showread from it.syncis the only thing that talks to a tracker, and only when you run it.
Status
Working. Roadmap items 1β5, 7 and 8 are implemented and tested, along with spec 002 (images,
@ references, recording, live mode and the dashboard). S3/R2 object storage (item 6) and other
trackers (item 9) are deferred. The Destination seam is in place, so they can be added without
changing the CLI. See ROADMAP.md.
Installation
Requires Python 3.10 or newer. The core CLI uses only the standard library (plus tomli before
Python 3.11). The MCP server is an optional extra.
pipx install 'bugcap[mcp]' # recommended
uv tool install 'bugcap[mcp]'
pip install -e '.[dev,mcp]' # developmentSupported capture backends: flameshot (cross-platform, recommended),
satty with grim (Linux/Wayland), and screencapture
(macOS). Run bugcap setup to see what's detected. You can always import an existing image with
bugcap capture --image PATH.
Documentation
Full guide: amenalahassa.github.io/bugcap/usage.html
covers capture, images, recording, live mode, triage, @ references, the dashboard, GitHub
pull and sync, MCP, and where data lives per OS.
Notes on the more involved behaviour:
References. In a note,
@i1is image 1,@v2a video,@g3an animated GIF,@f4a frame set,@d5an attached file (attach --file, any type), and@login-errora labelled item.#3points at report 3 (a missing one is kept as text with a warning). Media references are validated on save, and relabelling or removing a referenced item needs--force.Repo values (
init,sync,config repo set) are checked for format and, withgh, for existence. Changing the repo identity offers to move existing reports.Media sync over
[sync] max_upload_mb(default 25) is skipped with a warning.
Contributing
Contributions are welcome. Read CONTRIBUTING.md for the workflow and project rules, and the Code of Conduct. Report security issues privately, see SECURITY.md.
Development
See DEVELOPMENT.md. Run the tests with:
uv run --extra dev --extra mcp pytest -qArchitecture
Module map (src/bugcap/):
Module | Responsibility |
| Per-OS data/config dirs; |
| Import or capture images ( |
| Capture-tool detection, per-OS install commands, manual guidance. |
| SQLite store ( |
| Shared rules used by the CLI, MCP, dashboard and live mode: media add/relabel/remove, notes validation, reference rewrite, queries. Raises |
| Path/glob/URL inputs: magic-byte validation, size/timeout/redirect limits, atomic copy into |
|
|
|
|
| Tk control window (thin) over a pure state machine; drafts (and the autosaved bug in progress) on disk. |
| Monitors and windows per OS (Win32 via |
| Live mode's shortcut table (bindings, button hints, F1 help); opening a staged item in the OS default app. |
|
|
|
|
| Global |
| Format checks for repo slugs, images path and branch names. |
|
|
| Thin |
|
|
| SDK-free tool logic for the six MCP tools. |
| Lazy-imports the |
| All subcommands. |
The store is the one shared surface. Capture writes to it; the CLI, the MCP server, and the
sync layer only read/update it β nothing talks to a tracker except sync.py (via ghcli.py), and
nothing requires a tracker to exist for capture to be useful.
Extension seam (roadmap 6 & 9): sync.py depends only on the small Destination protocol
(ensure_ready, repo_visibility, get_file, put_file, create_issue, comment,
supports_attach) and on the report's synced_refs. A future object store or tracker implements
that protocol β the CLI and store don't change. Refs are namespaced per destination:
github.issueβowner/repo#Ngithub.comment_hashβ sha256 of the last synced content (so re-sync comments only on change)github.image.<basename>/github.media.<basename>βowner/repo:path@commit(so each file is committed at most once)github.frame.<idx>.<n>andgithub.frames.<idx>β keyframes of a recording (one commit per frame; GitHub's contents API commits one file at a time)
These refs also make pull and sync idempotent and resumable: each step is persisted as it succeeds, so a re-run skips what is already recorded.
Roadmap
See ROADMAP.md.
Design notes / deliberate non-goals
No cloud storage by default, no vendor account. The store is plain files on your disk. Sync (GitHub, and optionally an S3/R2 object store) is opt-in and explicit, per report.
Not a GitHub attachment replacement. The CDN-attached image stays for humans browsing the issue normally; the repo-committed copy exists purely so agents can read it. Both are written on sync, deliberately redundant.
Not using Git LFS for synced copies. GitHub's Contents API returns LFS pointer files, not the real bytes, for LFS-tracked paths β which would silently defeat the entire point of committing the copy. Plain commits are used instead; if screenshot volume ever outgrows that, the right next step is an external object store with its own token-authable download URLs, not LFS.
Annotation UI is not reinvented.
bugcapis glue around an existing capture/annotate tool, not a new one.
License
MIT β see LICENSE.
Available Tools
7 toolsattach_fileAttach files to a reportA
Add files of any type (logs, stack traces, HAR captures, videos, configs) to a bug report as supporting evidence. Use attach_image for pictures so they are returned as images by get_report. Copies each file into bugcap's local store (URLs are downloaded) and appends it to the report; existing media is kept. Attached files are never uploaded to GitHub. Notes can then refer to a file as @d or @label. Returns {"added": [...], "rejected": [{source, reason}]}: one bad source does not stop the others.
Inputs: id (required), sources (required), labels. Returns: result
attach_imageAttach images to a reportA
Add existing images (PNG, JPEG, GIF or WebP) to a bug report, for example a screenshot you saved or a diagram from a URL. Use attach_file instead for logs, videos or other non-image files, and request_screenshot when the user has to take the picture. Copies each image into bugcap's local store (URLs are downloaded) and appends it to the report; existing media is kept. Notes can then refer to it as @i or @label. Returns {"added": [{index, label, kind, size_bytes, source}], "rejected": [{source, reason}]}: one bad source does not stop the others.
Inputs: id (required), sources (required), labels. Returns: result
get_reportGet a bug reportARead-only
Read one bug report in full: title, body, notes, status, tags, linked GitHub issue and the
list of attached media, followed by every screenshot as image content so you can see it.
Use this after list_reports to understand a bug before fixing it. Notes refer to media as
@i1, @d1 or @label; resolved_references maps each of those tokens to its media index.
Read-only and local. Returns {"error": ...} when no report has this id.
Inputs: id (required).
list_reportsList bug reportsARead-only
List bug reports stored by bugcap, newest first. Use this to find a report id; it returns only summaries (id, title, status, tags, repo, created_at, linked GitHub issue) and no notes or images, so call get_report for the full report. Read-only and local: no network access. Returns a JSON array, empty when nothing matches.
Inputs: all, limit, status. Returns: result
pull_issuesImport GitHub issuesAIdempotent
Import open GitHub issues into bugcap as reports, so you can read them with get_report and
attach screenshots to them. Use this when the bug you need lives in GitHub rather than in
bugcap yet. Calls the GitHub API through the user's gh login. Safe to repeat: an issue
that is already imported only has its title and body refreshed, never its notes, tags or
status. Returns {"created", "updated", "unchanged"} counts, or {"error": ...} when no repo
is given or configured, or gh is not signed in.
Inputs: repo, limit, labels. Returns: result
request_screenshotAsk the user for a screenshotA
Ask the human at the machine to take a screenshot (for example to show a bug, or to check a
fix) and attach it to a report. Use this when you need visual evidence you cannot produce
yourself; to attach an image file that already exists, use attach_image. Opens the user's
capture tool and blocks until they finish, cancel or timeout_seconds passes. Adds the image
to the report (and creates a report for issue if needed). Returns {"status": "captured",
"report_id"} plus the screenshot as image content, or a status of "cancelled", "error" or
"non_interactive" (no desktop available, e.g. over SSH or in a container) with a message.
Inputs: note, issue, message, report_id, +1 more.
update_notesReplace a report's notesADestructiveIdempotent
Overwrite a bug report's notes with new text, for example to record a diagnosis, steps to
reproduce or what a fix changed. The previous notes are replaced, not appended to: read
them with get_report first and include whatever should be kept. Every @ reference must
match media attached to the report; an unknown one is rejected with an error and nothing
is saved. #12 links another report; one that does not exist is kept and listed in
warnings. Local only. Returns {"report_id", "notes", "references", "warnings"}.
Inputs: id (required), notes (required). Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelogβ¦
TDQS
Scored across 7 tools
Each tool targets a distinct resource+action: listing vs reading reports, importing issues, requesting a screenshot, attaching images vs files, and updating notes. The only potentially confusable pair (attach_image/attach_file) is explicitly cross-referenced in both descriptions, and request_screenshot is clearly differentiated by requiring human action.
All seven tools follow a consistent verb_noun snake_case pattern: list_reports, get_report, request_screenshot, pull_issues, attach_image, attach_file, update_notes. No deviations in style or casing.
Seven tools is well-scoped for a bug-report capture server, and each tool earns its place in a distinct workflow step (browse, read, import, capture, attach, annotate). No redundant or filler tools.
Core read/import/attach/annotate flow is covered, but status and tags are surfaced in list/get yet no tool can set them, and there is no delete/remove-media operation nor an explicit create_report (only implicitly via request_screenshot). These triage gaps are notable dead ends for a bug-tracking domain.
Maintenance
Related MCP Connectors
Production bugs with replay, network, console and stack, ranked for your coding agent to fix.
Comment on AI-generated webpages; feedback flows back to your coding agent. Free, MIT, local-first.
Bug tracking for AI agents: session replay, console/network logs, repro packs, test plans, evidence.
Voice-powered bug reporting with 13 MCP tools. Record bugs by talking; let AI find and fix them.
Related MCP Servers
- AlicenseAqualityBmaintenanceFeedback ingestion for AI agents. Record your screen and talk; your agent does the rest β files the bugs, writes the spec, builds the backlog.986 PyPI33MIT
- AlicenseBqualityAmaintenanceSelf-hosted issue tracker built for agent-driven development. One binary, SQLite storage, MCP-native, with a web UI, REST API, and CLI for the humans.2784Apache 2.0
- FlicenseNot gradedqualityDmaintenanceA local-first MCP server that gives AI coding agents runtime visibility and AI-managed debug logging. It replaces blind print() debugging by turning runtime execution into causal chains, allowing agents to instantly locate bugs by finding missing .success events in Python and TypeScript code. Single binary with MCP, CLI, and HTTP interfaces.-
- AlicenseNot gradedqualityBmaintenanceAn MCP server that watches for screen recordings, transcribes spoken feedback locally, and attaches each comment to the relevant frame, enabling coding agents to see and fix the issues you mention.6MIT