{"id":51429498,"url":"https://github.com/bnomei/zeuxis","last_synced_at":"2026-07-05T03:02:10.121Z","repository":{"id":361690853,"uuid":"1172646847","full_name":"bnomei/zeuxis","owner":"bnomei","description":"Let AI agents capture screenshots themselves via MCP","archived":false,"fork":false,"pushed_at":"2026-06-26T20:46:50.000Z","size":244,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T22:17:39.677Z","etag":null,"topics":["ai","automation","capture","cursor","history","image","local","mcp","offscreen","playwright","rect","screenshot","snapshot","testing","window"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/zeuxis","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bnomei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"bnomei","buy_me_a_coffee":"bnomei"}},"created_at":"2026-03-04T14:44:10.000Z","updated_at":"2026-03-06T21:34:14.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/bnomei/zeuxis","commit_stats":null,"previous_names":["bnomei/zeuxis"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/bnomei/zeuxis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fzeuxis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fzeuxis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fzeuxis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fzeuxis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bnomei","download_url":"https://codeload.github.com/bnomei/zeuxis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fzeuxis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35141966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-05T02:00:06.290Z","response_time":100,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","automation","capture","cursor","history","image","local","mcp","offscreen","playwright","rect","screenshot","snapshot","testing","window"],"created_at":"2026-07-05T03:02:09.503Z","updated_at":"2026-07-05T03:02:10.100Z","avatar_url":"https://github.com/bnomei.png","language":"Rust","funding_links":["https://github.com/sponsors/bnomei","https://buymeacoffee.com/bnomei","https://www.buymeacoffee.com/bnomei"],"categories":[],"sub_categories":[],"readme":"# zeuxis\n\n[![Crates.io Version](https://img.shields.io/crates/v/zeuxis)](https://crates.io/crates/zeuxis)\n[![CI](https://img.shields.io/github/actions/workflow/status/bnomei/zeuxis/ci.yml?branch=main)](https://github.com/bnomei/zeuxis/actions/workflows/ci.yml)\n[![Crates.io Downloads](https://img.shields.io/crates/d/zeuxis)](https://crates.io/crates/zeuxis)\n[![License](https://img.shields.io/crates/l/zeuxis)](https://crates.io/crates/zeuxis)\n[![Discord](https://flat.badgen.net/badge/discord/bnomei?color=7289da\u0026icon=discord\u0026label)](https://discordapp.com/users/bnomei)\n[![Buymecoffee](https://flat.badgen.net/badge/icon/donate?icon=buymeacoffee\u0026color=FF813F\u0026label)](https://www.buymeacoffee.com/bnomei)\n\nZeuxis is a local MCP screenshot server that lets AI agents capture the current desktop, windows, cursor regions, and exact rectangles through MCP tools.\n\nIt runs as one local binary over stdio by default. Capture results stay on the machine as managed image artifacts and are returned to the MCP client as `file://` resource links plus structured metadata. Zeuxis does not upload screenshots, perform OCR, drive the UI, or expose system-control tools.\n\n## Supported platforms\n\n| Platform | Status | Notes |\n| --- | --- | --- |\n| macOS | First-class | Zeuxis preflights Screen Recording permission before capture. Cursor-based tools may also need Accessibility permission. |\n| Linux | Best effort | Behavior depends on the desktop environment, compositor, session type, and backend support. |\n| Other platforms | Unsupported in v1 | Tools return `capture_unsupported_on_platform`. |\n\n## Install\n\nUse one of the following install paths.\n\n### Cargo\n\nRequires Rust `1.88` or newer.\n\n```bash\ncargo install zeuxis\nzeuxis --version\n```\n\n### Homebrew\n\n```bash\nbrew install bnomei/zeuxis/zeuxis\nzeuxis --version\n```\n\n### GitHub Releases\n\nDownload a prebuilt archive from [GitHub Releases](https://github.com/bnomei/zeuxis/releases), extract it, and place `zeuxis` on your `PATH`.\n\nVerify the binary:\n\n```bash\nzeuxis --help\n```\n\n### From source\n\n```bash\ngit clone https://github.com/bnomei/zeuxis.git\ncd zeuxis\ncargo build --release\n./target/release/zeuxis --version\n```\n\n## Quickstart\n\nAdd Zeuxis to an MCP client as a stdio server:\n\n```json\n{\n  \"mcpServers\": {\n    \"zeuxis\": {\n      \"command\": \"zeuxis\",\n      \"args\": []\n    }\n  }\n}\n```\n\nIf you use Codex CLI:\n\n```bash\ncodex mcp add zeuxis -- zeuxis\ncodex mcp list\n```\n\nIf you use Amp CLI:\n\n```bash\namp mcp add zeuxis -- zeuxis\namp mcp list\n```\n\nAfter the client connects, call `get_runtime_diagnostics` first. A healthy result reports `permission_ok=true` and `monitors_ok=true`. Then call `capture_screen` for the first screenshot.\n\nSuccessful capture tools return:\n\n- a short text summary,\n- a `file://` resource link to the local artifact,\n- structured fields such as `path`, `uri`, `output_format`, `mime_type`, `artifact_sha256`, `width`, `height`, `capture_mode`, `captured_at_utc`, `source_scale_factor`, and `target`.\n\n## Choose a capture tool\n\n| User intent | Tool |\n| --- | --- |\n| See the whole screen or get first-pass context | `capture_screen` |\n| Capture the focused app window | `capture_active_window` |\n| Capture the window under the cursor | `capture_cursor_window` |\n| Capture a specific window from a window listing | `list_windows`, then `capture_window` |\n| Capture a tooltip, menu, or small cursor-adjacent area | `capture_cursor_region` |\n| Capture exact global desktop coordinates | `capture_rect` |\n| Capture exact monitor-local coordinates | `capture_monitor_region` |\n| Reuse the last screenshot from this server session | `get_latest_capture` |\n| Inspect or delete Zeuxis artifacts from this session | `list_session_artifacts`, `clear_session_artifacts` |\n\nFor deterministic window capture, call `list_windows` and pass both `snapshot_id` and `window_id` from that same response to `capture_window`. Window IDs are scoped to the snapshot, not durable across listings.\n\n## MCP tools\n\nTool schemas are defined in [`src/mcp/tools.rs`](src/mcp/tools.rs). Result payloads are built in [`src/mcp/result.rs`](src/mcp/result.rs), and stable errors are defined in [`src/mcp/errors.rs`](src/mcp/errors.rs).\n\n| Tool | Parameters | Description |\n| --- | --- | --- |\n| `list_monitors` | none | Lists monitors with IDs, names, logical bounds, and primary/built-in flags. |\n| `list_windows` | `focused_only?`, `include_system_windows?`, `app_contains?`, `title_contains?` | Lists windows and records a snapshot for `capture_window`. System UI surfaces are excluded unless requested. |\n| `get_runtime_diagnostics` | none | Reports OS/session context, permission status, monitor discovery, and cursor availability. |\n| `get_latest_capture` | none | Returns the latest artifact from the current server session without taking a new screenshot. |\n| `list_session_artifacts` | none | Lists artifacts created in the current server session and marks the latest one. |\n| `clear_session_artifacts` | none | Deletes artifacts created in the current server session and resets latest-capture state. |\n| `capture_screen` | `monitor_id?` plus shared capture parameters | Captures a full monitor. Omitting `monitor_id` selects the primary monitor. |\n| `capture_active_window` | shared capture parameters | Captures the focused, non-minimized window. |\n| `capture_cursor_window` | `include_system_windows?` plus shared capture parameters | Captures the non-system window under the cursor by default. |\n| `capture_window` | `snapshot_id`, `window_id` plus shared capture parameters | Captures a window selected from a `list_windows` snapshot. |\n| `capture_cursor_region` | `size` plus shared capture parameters | Captures a square region centered on the cursor. |\n| `capture_rect` | `x`, `y`, `width`, `height` plus shared capture parameters | Captures a global desktop rectangle in logical points. |\n| `capture_monitor_region` | `monitor_id`, `x`, `y`, `width`, `height` plus shared capture parameters | Captures a monitor-local rectangle in logical points. |\n\nShared capture parameters:\n\n| Parameter | Type | Default | Notes |\n| --- | --- | --- | --- |\n| `delay_ms` | integer | unset | Optional pre-capture delay in milliseconds. Range: `0..=30000`. Do not combine with `delay_seconds`. |\n| `delay_seconds` | number | unset | Optional pre-capture delay in seconds. Range: `0..=30`. Do not combine with `delay_ms`. |\n| `play_sound` | boolean | `false` | Plays capture-complete feedback after a successful capture. |\n| `output` | string or object | `\"analysis\"` | Controls artifact format, downscaling, and JPEG quality. |\n\nExamples:\n\n```json\n{ \"delay_ms\": 800, \"play_sound\": true }\n```\n\n```json\n{ \"output\": \"compact\" }\n```\n\n```json\n{\n  \"output\": {\n    \"mode\": \"custom\",\n    \"format\": \"webp\",\n    \"max_dimension\": 2048\n  }\n}\n```\n\n## Output options\n\nPreset output modes:\n\n| Preset | Format | Max dimension | JPEG quality | Use when |\n| --- | --- | --- | --- | --- |\n| `analysis` | PNG | `2560` | n/a | Default LLM analysis with moderate downscaling. |\n| `exact` | PNG | original size | n/a | You need original pixels and lossless output. |\n| `compact` | JPEG | `1600` | `85` | You want smaller artifacts for faster transfer. |\n\nCustom output mode:\n\n| Field | Required | Constraints |\n| --- | --- | --- |\n| `mode` | yes | Must be `\"custom\"`. |\n| `format` | yes | `\"png\"`, `\"jpeg\"`, or `\"webp\"`. |\n| `max_dimension` | no | Longest output side in pixels, `256..=8192`. |\n| `jpeg_quality` | only for JPEG | `40..=95`. Rejected for PNG and WebP. |\n\nIf `ZEUXIS_ARTIFACT_HMAC_KEY` is set, capture results also include `artifact_hmac_sha256`.\n\n## Coordinates and limits\n\nCoordinate inputs use logical desktop points. Captured image dimensions use source pixels. Use the returned `input_units`, `source_units`, and `source_scale_factor` fields to reason about HiDPI scaling.\n\nRuntime limits:\n\n| Limit | Value |\n| --- | --- |\n| `delay_ms` | `0..=30000` |\n| `delay_seconds` | `0..=30` |\n| Capture width or height | `1..=16384` |\n| Capture area | `\u003c= 40000000` pixels |\n| Custom output `max_dimension` | `256..=8192` |\n| JPEG quality | `40..=95` |\n\nRequested delays run before capture work and are additive to the capture timeout. For example, a request with `delay_ms=30000` and the default `--blocking-task-timeout-ms=15000` can take up to about 45 seconds before the client receives a timeout or result.\n\n## Configuration\n\nConfiguration is resolved as `CLI flag \u003e environment variable \u003e default`. Zeuxis does not read config files.\n\nRuntime configuration lives in [`src/runtime_config.rs`](src/runtime_config.rs).\n\n| CLI flag | Environment variable | Default | Range | Description |\n| --- | --- | --- | --- | --- |\n| `--max-concurrent-captures` | `ZEUXIS_MAX_CONCURRENT_CAPTURES` | `2` | `1..=16` | Maximum concurrent capture workers. |\n| `--max-artifacts` | `ZEUXIS_MAX_ARTIFACTS` | `64` | `1..=10000` | Maximum retained Zeuxis temp image files. |\n| `--max-artifact-bytes` | `ZEUXIS_MAX_ARTIFACT_BYTES` | `536870912` | `1024..=10737418240` | Maximum retained artifact bytes. |\n| `--artifact-dir` | `ZEUXIS_ARTIFACT_DIR` | system temp dir | path | Directory for managed capture artifacts. |\n| `--blocking-task-timeout-ms` | `ZEUXIS_BLOCKING_TASK_TIMEOUT_MS` | `15000` | `100..=300000` | Timeout for capture, listing, and storage work. Delays run before this timeout. |\n| `--worker-kill-grace-ms` | `ZEUXIS_WORKER_KILL_GRACE_MS` | `250` | `10..=30000` | Grace period between soft worker termination and hard kill. |\n| `--max-worker-stdout-bytes` | `ZEUXIS_MAX_WORKER_STDOUT_BYTES` | `65536` | `1024..=4194304` | Maximum worker IPC stdout bytes accepted by the parent. |\n| `--capture-sound-file` | `ZEUXIS_CAPTURE_SOUND_FILE` | platform default | path | Optional custom sound file for `play_sound=true`. |\n| n/a | `ZEUXIS_ARTIFACT_HMAC_KEY` | unset | non-empty string | Optional HMAC key for artifact integrity metadata. |\n| n/a | `RUST_LOG` | `info` | tracing filter | Runtime logging filter. Logs go to stderr to keep MCP stdout clean. |\n\nExample:\n\n```bash\nZEUXIS_MAX_CONCURRENT_CAPTURES=4 \\\nZEUXIS_MAX_ARTIFACTS=128 \\\nzeuxis --blocking-task-timeout-ms 30000\n```\n\n## Platform permissions\n\n### macOS\n\nZeuxis checks Screen Recording permission before capture. If permission is missing, Zeuxis asks macOS for access and returns `permission_denied` for that same tool call. Grant Screen Recording permission to the terminal or host app that starts Zeuxis, then retry the tool call.\n\nCursor-dependent tools read the global cursor position and may also require Accessibility permission. If those fail, try `capture_screen` or `capture_rect` while you update permissions.\n\n### Linux\n\nLinux capture support depends on the graphical session and backend capabilities. If capture fails, call `get_runtime_diagnostics` and check `xdg_session_type`, `display`, `wayland_display`, `monitors_ok`, and `cursor_ok`.\n\nOn Wayland, cursor and window capture behavior can be more limited than full-screen capture. Prefer `capture_screen` first, then narrow to regions if the compositor allows it.\n\n## Troubleshooting\n\n### `permission_denied`\n\nCause: The OS denied screen capture permission.\n\nFix:\n\n1. On macOS, grant Screen Recording permission to the terminal or MCP host app.\n2. Retry the same tool call after granting permission.\n\nVerify:\n\n1. Call `get_runtime_diagnostics`.\n2. Confirm `permission_ok=true`.\n\n### `cursor_unavailable`\n\nCause: Zeuxis could not read the global cursor position.\n\nFix:\n\n1. Grant Accessibility permission if your platform requires it.\n2. Use `capture_screen`, `capture_active_window`, or `capture_rect` when cursor position is unavailable.\n\n### `window_not_found`\n\nCause: The focused window, cursor window, or requested snapshot window is no longer available.\n\nFix:\n\n1. Call `list_windows` again.\n2. Retry with a fresh `snapshot_id` and `window_id`, or fall back to `capture_screen`.\n\n### `invalid_region`\n\nCause: The requested rectangle is outside supported bounds or exceeds the size limits.\n\nFix:\n\n1. Check monitor bounds with `list_monitors`.\n2. Reduce `width` and `height`.\n3. Keep the capture area at or below `40000000` pixels.\n\n### `no_capture_yet`\n\nCause: `get_latest_capture` was called before this server session captured an artifact.\n\nFix:\n\n1. Call a `capture_*` tool first.\n2. Retry `get_latest_capture`.\n\n### `storage_failed`\n\nCause: Artifact write, retention cleanup, worker IPC, or timeout handling failed.\n\nFix:\n\n1. Check that `ZEUXIS_ARTIFACT_DIR` is writable, if set.\n2. Increase `--blocking-task-timeout-ms` for slow captures.\n3. Retry the capture. Timed-out worker processes are terminated and reaped before Zeuxis returns.\n\n## Privacy and safety\n\nZeuxis is designed for local observation:\n\n- It serves MCP over local stdio.\n- It returns local `file://` artifact links.\n- It does not upload screenshots to remote services.\n- It does not perform OCR, UI element detection, input automation, shell execution, or window control.\n- It validates tool parameters before capture.\n- Capture work runs in a subprocess worker with parent-enforced timeout and termination.\n- `clear_session_artifacts` deletes only Zeuxis-managed artifacts from the current session.\n\nManaged artifact files use the `zeuxis-` prefix and `.png`, `.jpg`, or `.webp` suffix. Retention pruning is best effort and never deletes the artifact currently being returned.\n\n## Development\n\nUseful source entrypoints:\n\n| File | Purpose |\n| --- | --- |\n| [`src/main.rs`](src/main.rs) | CLI parsing, stdio server startup, hidden worker mode, tracing setup. |\n| [`src/runtime_config.rs`](src/runtime_config.rs) | CLI/env defaults, ranges, and runtime settings. |\n| [`src/mcp/tools.rs`](src/mcp/tools.rs) | MCP tool schemas, validation, capture execution, output settings. |\n| [`src/mcp/result.rs`](src/mcp/result.rs) | MCP result payloads and resource links. |\n| [`src/mcp/errors.rs`](src/mcp/errors.rs) | Stable error codes and retryability. |\n| [`src/capture/backend.rs`](src/capture/backend.rs) | Capture backend trait and monitor/window metadata. |\n| [`src/worker/contract.rs`](src/worker/contract.rs) | Parent/worker JSON contract. |\n| [`skills/capturing-ui-with-zeuxis/SKILL.md`](skills/capturing-ui-with-zeuxis/SKILL.md) | Codex skill guidance for using Zeuxis proactively. |\n| [`specs/`](specs/) | Historical design and requirements specs. |\n\nRun local checks:\n\n```bash\ncargo check\ncargo fmt --all -- --check\ncargo clippy --all-targets --all-features -- -D warnings\ncargo test --all-targets\n```\n\nOn Ubuntu/Linux CI-like environments, install the capture backend build dependencies first:\n\n```bash\nsudo apt-get update\nsudo apt-get install -y \\\n  pkg-config \\\n  libclang-dev \\\n  libxcb1-dev \\\n  libxrandr-dev \\\n  libdbus-1-dev \\\n  libpipewire-0.3-dev \\\n  libwayland-dev \\\n  libegl-dev \\\n  libdrm-dev \\\n  libgbm-dev\n```\n\nThis repo also ships a `prek.toml` for lightweight local commit gates:\n\n```bash\nprek validate-config\nprek run --all-files\nprek install\n```\n\nThe configured hooks run `cargo fmt --all -- --check` and `cargo clippy --all-targets --all-features -- -D warnings`.\n\n## License\n\nZeuxis is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Fzeuxis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbnomei%2Fzeuxis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Fzeuxis/lists"}