Back to Discover

plonk

connector

ostapondo

Mac window manager your AI agent can drive: layouts, workspaces, snap zones, screenshots.

View on GitHub
0 starsSynced Aug 7, 2026

Install to Claude Code

/plugin marketplace add ostapondo/plonk

README

Plonk

The Mac window manager your AI agent can drive.
To plonk is to set a thing down exactly where it belongs. This menu bar does it to your windows.

Version macOS 13+ Swift 6 MCP No dependencies MIT

An agent is told where the windows go, arranges them, saves the setup as a workspace, and launches it back onto an empty desktop

Drag a window, the zones light up, drop it in. Or skip the dragging and say it:

browser on the left 60%, terminal top right, notes bottom right

save that as a workspace called "review"

keep the screen awake for the next hour

screenshot the screen and tell me what looks off

Everything runs on your Mac. No account, no cloud, no telemetry.

Install

macOS 13+.

brew install --cask ostapondo/plonk/plonk

Or download the latest release, unzip, and drop Plonk.app into Applications. The build is not notarized yet, so macOS will balk at the first launch — approve it under System Settings → Privacy & Security → Open Anyway.

Grant Accessibility when asked, then relaunch. Screen Recording is asked for separately, the first time you capture. Nothing else — no Full Disk Access, no Automation, no Keychain.

If you later move or rename Plonk.app (or its folder), macOS quietly ties the old grant to the old path: windows of newly launched apps stop being seen. Remove Plonk from Privacy & Security → Accessibility and grant it again.

To let an agent drive it (Node 18+):

claude mcp add plonk -- npx -y plonk-mcp   # Claude Code
codex mcp add plonk -- npx -y plonk-mcp    # Codex CLI

Any MCP client works the same way — give it npx -y plonk-mcp as a stdio server. One-pagers: Cursor (with a one-click install button), Zed, Cline. Several clients at once is fine; see Agents below.

A client that cannot spawn a process connects over HTTP instead: npx -y plonk-mcp --http serves Streamable HTTP at http://127.0.0.1:43918/mcp (loopback only, many clients per process, --port to change).

Or build everything from source: clone the repo, run ./scripts/build.sh, and point claude mcp add plonk -- node …/mcp/dist/server.js at a locally built server (cd mcp && npm install && npm run build).

Workspaces

A workspace of four windows, saved, closed to an empty desktop, then launched back into place

A workspace is a desk you can put away. It remembers the apps, the frame of every window, the monitor each one belongs on, and what each app should open on the way up. Launching one opens whatever is closed, waits for the windows, and puts them back — from the Workspaces page, or right-click the menu bar icon. Rename, recapture or delete from the workspace's menu.

Per appFiles, folders or URLs to open with it: a project folder for an editor, a set of tabs for a browser
Per monitorWindows return to the display they were captured on, keyed by display UUID so unplugging a monitor does not scramble them. Or pull the whole workspace onto one screen
Already openRunning apps get moved, not relaunched. Turn that off to leave them alone and only open what is missing
The catchmacOS cannot open an app straight into a position, so windows appear first and jump a moment later. A second window of the same app cannot be conjured — give it a file to open instead

Zones

A screen split into three zones, with a window being dragged into the highlighted one

Five built-in zone sets and a sixth, irregular one drawn by hand

Five sets ship with it. Everything past that you draw yourself: any number of zones, any size, overlapping if you want — a narrow rail for chat, a wide middle split in two, a strip for the terminal. Or describe it and let the agent build it.

EditorClick to split, -click to split vertically, drag a divider to resize neighbours, to delete and let them heal over the gap
Per monitorEach screen gets its own set, remembered by display, not by index
OverlapAllowed — the smallest zone under the cursor wins
TriggerOn drag, or only with a modifier held. Holding it inverts the mode, so a free move stays one keypress away
Or noneEdge snapping instead: middles are halves, top is maximize, corners are quarters

Hotkeys

Where each hotkey puts the front window

All on ⌃⌥. Plus ⌃⌥Z to flash the zones and ⌃⌥S to grab a region.

And the rest

Keep awakeIOKit power assertions, not a jiggler. Display-on or system-only, pause on battery, auto while charging, timed sessions, and a menu bar icon that glows while it holds
ScreenshotsRegion, window or screen through the native picker, then pen, arrow, rectangle, ellipse and highlighter. Saves at native resolution
NoticesA panel in the top-right corner, not Notification Center: no permission to ask for, nothing left in your history, and it can show the screenshot instead of describing it

For agents

Frames are fractions of a monitor's visible area, origin top-left — which is why "left 60%" is just {x: 0, y: 0, w: 0.6, h: 1}.

Tool
get_stateMonitors, every open window and where it sits, zone sets, saved workspaces, awake status
apply_layoutPlace any set of windows, across any number of monitors, in one call
save_workspace · launch_workspace · delete_workspaceNamed desktops, launched from nothing
snap_windowDrop a window into a numbered zone
save_zone_set · assign_zone_set · delete_zone_setSnap zones, per monitor
set_awakeKeep-awake, optionally time-limited
take_screenshot · annotate_screenshotCapture, mark up, hand the image back
select_agentMake an agent the user's active one, optionally the only one allowed to control

Several agents can be connected at once. Every client registers itself, so get_state lists who is online; the user picks an active agent from the menu bar or the settings — or an agent does it with select_agent. An optional strict mode locks changes to the active agent: everyone else keeps reading state and taking screenshots, but gets a clear 409 on anything that moves windows or edits config. Set PLONK_AGENT_NAME in a client's MCP config to tell two sessions of the same client apart.

Under the hood

Claude talks to the MCP server over stdio, which calls the app's loopback HTTP API

  • The app is the single source of truth; the MCP server is a stateless bridge.
  • The API binds to 127.0.0.1 and refuses anything carrying browser headers, so an open web page cannot drive your desktop.
  • No outbound connections, no analytics, zero third-party Swift dependencies.
  • Config is plain JSON at ~/Library/Application Support/Plonk/config.json.

Build

cd App && swift build     # the app
./scripts/test.sh         # 149 unit tests
./scripts/build.sh        # produces Plonk.app
cd mcp && npm run build   # the MCP server

App/ is the Swift menu bar app, mcp/ the TypeScript MCP server. Point an agent at AGENTS.md before it touches either.

build.sh signs with a Plonk Dev keychain identity when one exists and falls back to ad-hoc. Ad-hoc signatures change every build, and macOS ties the Accessibility grant to the signature — so create that certificate once (Keychain Access → Certificate Assistant → Create a Certificate → type "Code Signing", name it Plonk Dev) and rebuilds stop resetting permissions.

Releases: bump MARKETING_VERSION and BUILD_NUMBER in version.env. scripts/build.sh reads both into Info.plist.

License

MIT © ostapondo

Rendered live from ostapondo/plonk's GitHub README — not stored, always reflects the source repo.

1 Install Method

NameDescriptionCategorySource
npm packageInstall via npm (stdio transport)mcp-serverplonk-mcp

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet — be the first to share an update.