# dsh-screenshot [English](README.en.md) | [中文](README.md) **Zero-dependency screen capture for DeepSeek Harness**: **Lightweight**: zero deps, zero binaries; **Stage & shoot**: one-click full screen, window layout, hover-snap capture of occluded windows; **Agent self-service**: path-only delivery; paths are universal, pair with modlens (optional) for one-call structured evidence. - **Lightweight** — pure PowerShell, zero dependencies, zero binary payload; capture is maintained independently and never breaks on upstream updates. - **Stage & shoot** — one-hotkey full-screen capture, or keep the desktop live and arrange *any* window before box-selecting a region; **hover any window and it glows with a snap outline — one click captures that window's full content, even when occluded** (except a standalone PowerShell, see below) — what you stage is what you get. - **Agent self-service** — the model can capture the screen on its own; with modlens (optional) installed, capture + read happen in one call, returning structured content (OCR/layout/semantics) that text-only models can consume directly. ## Quick start ```sh dsh plugin --profile web add @paicat1/dsh-screenshot # restart dsh web ``` - `Ctrl+Alt+S` — capture: once armed, **click the desktop = full screen**; **hover a window = snap outline, one click captures that window's full content (even when occluded, except a standalone PowerShell)**; **drag = free region** (Esc to cancel) - `Ctrl+Shift+Alt+S` — full-screen capture: no interaction, captures the whole virtual desktop - Want the agent to screenshot on its own? Just tell it to use the `modlens_screenshot` tool. Video tutorial (Bilibili): [Using DeepSeek Harness to build a Dsh screenshot plugin for DeepSeek Harness](https://www.bilibili.com/video/BV1bF8G6oE66/) ## Two doors: hotkey for humans, tool for agents | Entry | Best for | Notes | |---|---|---| | Browser hotkey (human) | "Here's the screen I want to show you" | Full / region capture; the PNG path is auto-inserted into the DSH input box and copied to the clipboard | | `modlens_screenshot` tool (agent) | "Let me look at the screen myself" | Model-invoked: capture + (with modlens present) in-call structured read, returning evidence + the shot path | | Manual capture demo | Agent self-capture demo | Window-snap demo | |---|---|---| | ![Manual capture demo](assets/demo-manual.gif) | ![Agent self-capture demo](assets/demo-agent.gif) | ![Window-snap demo](assets/demo-window-snap.gif) | ## Why pass the path, not the image? Screenshots are saved to `%USERPROFILE%\Downloads\modlens-screenshots\` (a dedicated, easy-to-clean directory), and **only the PNG path is handed to the agent** — not the image stuffed into a chat box or temp directory. Deliberate design: - **No image litter**: many agent frameworks copy pasted images into their own temp/attachment directories, accumulating untrackable junk. A path keeps the image in exactly one place (`modlens-screenshots/`); cleaning up is deleting one directory. - **Paths are universal**: any image-capable agent (native multimodal models, or modlens-style bridges) can read an image from a path — paths are universal, image formats are not. - **Clean context**: a path is tens of bytes of text; an image is hundreds of KB of binary. Paths keep the context clean and traceable. Capture once, reuse the path in any agent, produce zero junk. ## Capability split: what's the plugin's, what's modlens's | Layer | Capability | Owned by | |---|---|---| | Capture | Full / region / **window-snap capture** / staged-window layout, zero-dep PowerShell | This plugin | | Delivery | Path-only, clipboard, dedicated save dir | This plugin | | Entry points | Browser hotkeys + agent-callable capture tool | This plugin | | Reading | OCR / layout / semantics structured evidence | modlens (optional) | | Consumption | Who understands the image | any multimodal model / vision bridge — agnostic | Capture and delivery are fully self-contained and work standalone; reading is an ecosystem combo — install modlens (or hand the path to any image-capable model/bridge) to unlock it. Without modlens, capture still works. **Why can window-snap capture "occluded" windows?** On hover the plugin enumerates the on-screen windows and outlines the one under the cursor; on click it uses `PrintWindow` to ask the window to **render itself** — the shot is the window's own content, not the on-screen pixels, so being covered by other windows or wrapped in a DWM shadow doesn't matter. It then crops to the DWM content bounds to drop the shadow, for clean edges. **Known exception: a standalone PowerShell window**: its console (conhost) implementation **does not respond to `PrintWindow`**, and **does not render its GDI surface while covered** — both see-through-occlusion paths are unavailable, so it falls back to the visible on-screen pixels (including whatever covers it). Bring it to the foreground and click, or just drag-select over it. **All other windows (including cmd and other console windows) capture normally.** ## Configuration Optional cordis config (all enabled by default): - `route: false` — disable the browser capture route - `tool: false` — disable the `modlens_screenshot` tool `MODLENS_DSH_CLI` explicitly sets the modlens CLI path (default probe: `~/.dsh/profiles/{web,headless}/node_modules/@liustack/modlens/dist/main.js`). ## Platform & License - **Platform**: Windows (relies on PowerShell `System.Drawing.CopyFromScreen`) - **License**: MIT ## Relationship with modlens | Layer | Depends on modlens? | Notes | |---|---|---| | Capture action | **No** | Pure PowerShell `CopyFromScreen`, zero dependencies | | Browser hotkeys / path insert | **No** | Standalone route `/dsh-screenshot/screenshot` | | `modlens_screenshot` tool reading | **Yes (optional)** | If the modlens CLI is missing, the tool is not registered; capture still works | | Multimodal models | No | After the path is inserted, multimodal models (e.g. go-mimo) can read the image directly, no modlens needed | ## Background & credits The capture capability was originally implemented as an enhancement to the dsh plugin of [@liustack/modlens](https://github.com/liustack/modlens) (by Leon Liu): the original modlens dsh plugin integrated capture (this repo's fork of the `feat/dsh-screenshot` branch), and the author marked it as not planned in [issue #48](https://github.com/liustack/modlens/issues/48). It was split into this standalone plugin to decouple capture from modlens updates. **Many thanks to the original author for giving DSH image-reading ability** — modlens lets text-only models (DeepSeek/GLM) "see" images, and this plugin's `modlens_screenshot` tool reuses the modlens pipeline to combine "capture + read" into one step. The capture half is maintained separately, but the image-reading ability always belongs to the modlens project.