Skip to content
Back to skills

Hammerspoon

ASecurity

Operate macOS via Hammerspoon, either one-off `hs -c` Lua (launch, quit, or focus apps and browser tabs; volume, wifi, caffeinate, alerts, clipboard) or persistent hotkeys, watchers, and menubar items in ~/.hammerspoon. Use when asked to control an app, tab, or Mac system state, keep the Mac awake, or write a Hammerspoon module. Not for web page content.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 11, 2026
ai-agentsgoshellbashsecurity

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 23, 2026

npx -y skills add wilbeibi/wilbeibi-skills --skill hammerspoon --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Hammerspoon?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Hammerspoon
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wilbeibi-hammerspoon/badge)](https://www.skillsdirectory.com/skills/wilbeibi-hammerspoon)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: hammerspoon
description: Operate macOS via Hammerspoon, either one-off `hs -c` Lua (launch, quit, or focus apps and browser tabs; volume, wifi, caffeinate, alerts, clipboard) or persistent hotkeys, watchers, and menubar items in ~/.hammerspoon. Use when asked to control an app, tab, or Mac system state, keep the Mac awake, or write a Hammerspoon module. Not for web page content.
---

# hammerspoon

Host scope: mini/macOS. Keep this skill disabled on joi/Linux; shared source may remain in the repository. Do not sync activation links between hosts or switch to SSH merely because the local host lacks Hammerspoon. Remote actions follow the session's host-authorization policy.

One-off action = one `hs -q -c '<lua>'` call. Lasting behavior (hotkeys, watchers, menubar) = a module in `~/.hammerspoon/`. Recipes: [REFERENCE.md](REFERENCE.md).

## Readiness

`hs -q -c 'return "ok"'` must print `ok`. If not:

- exit 69 / "can't access message port" → Hammerspoon not running (`open -a Hammerspoon`) or `hs.ipc` not loaded → ensure `require("hs.ipc")` is in `~/.hammerspoon/init.lua`; the pathwatcher auto-reloads config, retry after ~2s.
- `hs` binary missing → tell the user to run `hs.ipc.cliInstall("/opt/homebrew")` in the Hammerspoon console.
- Window/app calls silently no-op → `hs -c 'return hs.accessibilityState()'` must be true; if false, user grants it in System Settings → Privacy & Security → Accessibility.

## One-off mode

```bash
hs -q -c 'hs.application.launchOrFocus("Obsidian") return "ok"'
hs -q -t 15 -c '<anything touching AppleScript or many windows>'   # default IPC timeout is 4s; busy main loop can also cause one-off "receive timeout" — retry
```

- `return` the final value or you get no output; tables print as addresses — `return hs.json.encode(tbl)` (`hs.geometry` rects need `.table`; NaN values make encode silently return nil — `tostring()` is the safe fallback).
- Single-quote the shell argument, double quotes inside Lua. Multiline: heredoc `hs -q <<'EOF' ... EOF` or `hs -q /path/file.lua` (path must start with `~`, `./`, or `/`).
- Exit codes: 65 = Lua error (message on stderr), 69 = not running / ipc missing.
- One-shot state dies: timers, watchers, and callbacks created via `hs -c` are GC'd after the call and never fire — anything that must persist or fire later is persistent mode.
- Sequencing: async state (focus change, tab load) won't settle inside one chunk, and `hs.timer.usleep` blocks Hammerspoon itself. Act in one call, `sleep` in the shell, read state in the next call.

## Persistent mode

For hotkeys/watchers/menubar items: write `~/.hammerspoon/<name>.lua`, add `require("<name>")` to `~/.hammerspoon/init.lua`. **Read `~/.hammerspoon/AGENTS.md` first** — it has the house conventions.

- Anchor timers/watchers/menubar objects in globals or module-level vars, or GC destroys them silently.
- The pathwatcher reloads config on every file save — write complete files (Write, not incremental edits), and expect `hs.reload()` to wipe all interactive globals.
- Verify after save: `hs -q -c 'return "alive"'` (reload takes ~1-2s), then check for load errors with `hs -q -c 'return hs.console.getConsole()' | tail -20`.

## Safety

- Prefer `:kill()` (graceful quit) over `:kill9()`; confirm with the user before quitting apps that may hold unsaved work.
- Never open modal dialogs (`hs.dialog`) or trigger alerts in other apps — they block event processing.
- `hs.execute` blocks Hammerspoon's main loop (freezes all its hotkeys/menubar); prefer running shell commands directly, or `hs.task` from a module.
- `hs.eventtap.keyStrokes`/clicks go to whatever is focused — only use when the user asked for exactly that.

Files in this skill

  • REFERENCE.md5.7 KB
  • SKILL.md3.4 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…