A macOS floating macro launcher with a built-in HTTP control API designed for AI-assisted operation.
日本語版はこちら · AI Protocol · Specification · Design system · Changelog
FloatingMacro is a small always-on-top panel for macOS that runs user-defined actions — key combos, text paste (AI prompt injection), app launches, terminal expansions, and composite macros — with one click from a non-activating panel that never steals keyboard focus.
What makes it different from other launcher apps: it ships a local HTTP control API and exposes every feature as a tool in multiple protocol dialects (MCP / A2A / OpenAI function calling / Anthropic tool use / plain REST with OpenAPI), so AI agents can observe, configure, and drive the app with no additional glue.
This is a small experiment in what AI-oriented macOS software might look like. Rather than bolting AI onto an existing app, the question is: what happens when you treat an AI agent as a first-class user from day one — able to observe, configure, and drive the app without any extra integration layer? FloatingMacro is one attempt at an answer in the scope of a tiny utility.
- Native macOS UI — SwiftUI +
NSPanel, respects system accent / dark mode - Control from phone / tablet (v0.13) — tap "📱 Send to Device" from the menu bar or the QR button in each floating panel. Scan the QR code with your phone's camera on the same Wi-Fi, and the panel opens in Safari ready to tap buttons. An open-source alternative to a Stream Deck's soft-key area
- Multiple floating panels (v0.12) — independent panels for different use cases, each rendering its own preset with its own position / size / opacity. Add / switch / remove from the menu bar
- Group display types — icon / wide / card (v0.11) — buttons can render as small icons, wide cells, or thumbnail cards. The card +
appendModecombo is ideal for prompt galleries (MidJourney, Stable Diffusion, etc.) - Per-button thumbnails (v0.11) — assign a large image to a card-type button. Stored at
presets/<name>/images/<button-id>.<ext> - 6 action types — key, text, launch, terminal, delay, macro
- Prompt builder (text appendMode) (v0.10) —
textaction can append to the current clipboard instead of replacing it. Stack fragments by clicking buttons in sequence, then Cmd+V the full prompt - Background app icon cache (v0.10.5) — icons for every
.appunder/Applicationsare extracted at launch in the background, so app pickers and DnD show icons instantly - Launchpad-style app picker (v0.10.6) —
LazyVGrid96px cells; double-click or Enter to add - Preset system — groups and buttons, hot-swappable from the menu bar
- Preset memo — record per-preset prerequisites (which app must be frontmost, required OS settings, side effects like clipboard overwrite). Shows as a collapsible block at the top of the panel so future-you can re-confirm before pressing buttons that have stopped working
- Key recorder & special-key picker (v0.9.2) — for key-action buttons, capture any keystroke (Delete, arrow keys, F1–F20 included) by pressing it once, or pick from a dropdown. Replaces the awkward "type the key name into a text field" flow that left Delete/arrows unreachable
- AI integration window — opens from the menu bar ("Connect AI...") or the ⚙ in the floating panel
- One-click MCP registration for Claude Code / Cursor / Gemini CLI / VS Code / Windsurf
- Copies a connection prompt with the Bearer token already embedded (so even non-MCP AIs like ChatGPT can drive the app)
- Existing MCP configs are preserved — entries are merged, not overwritten
- 1700+ icons out of the box
- Lucide SVG pack bundled (ISC licensed, ~1700 icons)
- SF Symbols supported at runtime (6000+, curated in-app picker for ~120)
- App icons auto-resolved from bundle id via
NSWorkspace - Any PNG/JPEG/ICNS path works
- Structured JSON logging with rotation, queryable from
fmcli log tail - GUI editor — full CRUD for presets/groups/buttons, color picker, size, action type
- Local HTTP control API bound to
127.0.0.1only, Bearer token requiredGET /manifest— self-introduction for AI agents (unauthenticated)GET /tools?format=mcp|openai|anthropic— tool catalog in three dialectsPOST /tools/call— unified dispatch (use this from AIs)POST /mcp— JSON-RPC 2.0 / Model Context ProtocolGET /openapi.json— OpenAPI 3.1 documentGET /.well-known/agent.json— A2A Agent Card
- macOS 13 (Ventura) or later
- Swift 5.9 toolchain (bundled with Xcode 15+, only if you build from source)
- Accessibility permission (for the key / text / terminal actions)
- Optional: Automation permission (for Terminal.app / iTerm2 control)
Download the DMG from the releases page, mount it, and drag FloatingMacro.app into /Applications.
To build from source:
git clone https://github.com/veltrea/floating-macro.git
cd floating-macro
bash scripts/build-app.sh # produces build/FloatingMacro.app
open build/FloatingMacro.appFloatingMacro is signed ad-hoc (it is not paid Apple notarization), so the first time you open the downloaded app macOS shows this warning and refuses to launch it:
This is expected for any ad-hoc–signed app — it does not mean the app is malware. Click Done (not "Move to Trash"), then allow it once with either method:
- System Settings → Privacy & Security, scroll down to the "FloatingMacro was blocked…" line and click Open Anyway. (Easiest — mouse only.)
- Or in Terminal:
xattr -dr com.apple.quarantine /Applications/FloatingMacro.app
Once allowed, it opens normally every time after that. The block comes from a download flag macOS attaches to files from the internet; the app itself is untouched.
After it opens, macOS asks for Accessibility permission (needed to send keystrokes). Grant it from System Settings → Privacy & Security → Accessibility.
swift run fmcli help
swift run fmcli config init # create default config
swift run fmcli preset list
swift run fmcli log tail --since 5m --json
swift run fmcli action launch shell:echo helloThe control API binds to 127.0.0.1:17430 automatically when the app starts. All endpoints require a Bearer token (except discovery endpoints like /manifest). The token is auto-generated on first launch and stored in ~/Library/Application Support/FloatingMacro/control_api_token (mode 0600), with a Keychain mirror for security CLI compatibility — you don't have to set anything up.
TOKEN=$(cat ~/Library/Application\ Support/FloatingMacro/control_api_token)
# Self-introduction (no auth needed)
curl -s http://127.0.0.1:17430/manifest | jq
# Read state
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:17430/state | jq
# Call a tool (this is the shape AIs should use)
curl -s -X POST http://127.0.0.1:17430/tools/call \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"window_opacity","arguments":{"value":0.7}}'Hitting individual endpoints like
/window/opacitydirectly works but is the lower layer. From AIs, always go through/tools/call. See CLAUDE.md and AI_PROTOCOL.md for the full story.
Open the AI integration window from the ⚙ in the floating panel (or the menu bar's "Connect AI...") and press the button on the row of the client you use.
- For Claude Code / Cursor / Gemini CLI / VS Code / Windsurf: CLI register (recommended, stdio MCP)
- For the same clients: HTTP register (HTTP MCP, advanced)
- For non-MCP AIs like ChatGPT: Copy connection prompt (the AI calls
/tools/callviacurl)
Pressing the button reads the Bearer token from Keychain and writes the entry into the client's config (~/.claude.json / ~/.cursor/mcp.json / ~/.gemini/settings.json / etc.). Existing MCP entries are kept.
Per-client guides are in manual/mcp/:
{
"mcpServers": {
"floatingmacro": {
"type": "http",
"url": "http://127.0.0.1:17430/mcp",
"headers": {
"Authorization": "Bearer <token from Keychain>"
}
}
}
}Get the token with cat ~/Library/Application\ Support/FloatingMacro/control_api_token.
TOKEN=$(cat ~/Library/Application\ Support/FloatingMacro/control_api_token)
curl -s -H "Authorization: Bearer $TOKEN" \
'http://127.0.0.1:17430/tools?format=openai' | jq '.tools'Paste the returned tools array into the tools parameter of your Chat
Completions / Responses API call.
See AI_PROTOCOL.md for the full endpoint reference.
Configuration lives in ~/Library/Application Support/FloatingMacro/
(override with FLOATINGMACRO_CONFIG_DIR):
config.json # window geometry, active preset, controlAPI settings
presets/
default.json # a preset: groups -> buttons -> actions
writing.json
dev.json
logs/
floatingmacro.log # JSON one-event-per-line, rotates at 10 MB
floatingmacro.log.old
See SPEC.md §6 for the full schema. The GUI editor
(Menu Bar → "Button Edit…" or ⌘E) covers everything you normally need.
Don't edit
presets/*.jsonby hand while the app is running. The app overwrites them from in-memory state, so your edits will vanish. Use AI integration (/tools/call) or the GUI editor.
{ "type": "key", "combo": "cmd+shift+v" }
{ "type": "text", "content": "ultrathink" }
{ "type": "launch", "target": "/Applications/Slack.app" }
{ "type": "launch", "target": "com.tinyspeck.slackmacgap" }
{ "type": "launch", "target": "https://claude.ai/code" }
{ "type": "launch", "target": "shell:open ~/Downloads" }
{ "type": "terminal", "app": "iTerm", "command": "cd ~/dev && claude" }
{ "type": "delay", "ms": 300 }
{ "type": "macro", "actions": [ ... ] }{ "icon": "sf:star.fill" } // SF Symbol (runtime)
{ "icon": "lucide:rocket" } // bundled Lucide SVG
{ "icon": "com.apple.Safari" } // macOS bundle id — auto fetch
{ "icon": "/Applications/Slack.app" }// any .app path
{ "icon": "/path/to/custom.png" } // any image fileIf icon is omitted and the action is a launch to an app, the app's icon
is auto-detected.
# Unit tests (fast, no permissions required)
swift test
# fmcli smoke (permission-free CLI surface)
bash scripts/fmcli_smoke.sh
# Control API smoke (spins up the GUI + curl against it)
bash scripts/control_api_smoke.shIf swift test fails with "no such module XCTest", point DEVELOPER_DIR
at Xcode (not Command Line Tools):
DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer swift testSources/
FloatingMacroCore/ Pure logic, UI-free. Actions, logging, control-API protocol surfaces.
FloatingMacroCLI/ fmcli binary
FloatingMacroApp/ GUI (SwiftUI + NSPanel), settings editor, icon loader, AI integration window
Tests/ Unit tests
scripts/ Build, smoke-test, release, and translation shell scripts
App/ Info.plist template for build-app.sh
npm/ stdio MCP server for CLI registration (bundled in the DMG)
manual/ User-facing manuals (basic usage, AI examples, images)
.github/ GitHub Actions workflows (CI)
SPEC.md Full specification
DESIGN.md Design system notes
CHANGELOG.md Release history
Latest release: v0.16.7 (2026-06-13). See CHANGELOG.md for the change history and SPEC.md §17 for the roadmap. Public release, but the author makes no guarantees of stability.
Note on pull requests: The codebase is currently under heavy active development — typically 1,000–5,000 lines change per day. Pull requests are very likely to conflict before they can be reviewed. Please hold off on PRs until the project enters maintenance mode. Issue reports and feature suggestions are welcome.
Intel (x86_64) builds: Universal binaries including Intel are included in every release, but the author's Intel Mac is currently out of service due to an OS issue. Intel builds are cross-compiled on Apple Silicon and cannot be tested on real hardware for the time being. If you encounter Intel-specific issues, please file an issue.
- Built with Swift 5.9, SwiftUI, AppKit, Network.framework.
- Lucide icons (ISC) are bundled in
Sources/FloatingMacroApp/Resources/lucide/. - SF Symbols provided by Apple, used at runtime only.
- Inspired by Windows-side utilities such as FloatingButton by Trifolium Studio, re-designed from scratch for macOS (clean-room policy — no code referenced, only external behavior).
See THIRD_PARTY_LICENSES.md for full attribution.
MIT License — Copyright (c) 2026 veltrea
- AI Protocol Manual — how AI agents talk to this app
- MCP per-client guides — Claude Code / Cursor / Gemini CLI / etc.
- Full Specification
- Design System
- Changelog
