⚠️ Pre-Alpha: Features may be incomplete, unstable, or change significantly. Use at your own risk.
A powerful, declarative configuration framework for Hammerspoon that provides fast, ergonomic, and reliable productivity tools for macOS.
Martillo (Spanish for "hammer") offers a clean, maintainable way to configure Hammerspoon using a single-line setup inspired by lazy.nvim, with a collection of custom productivity spoons built-in.
package.path = package.path .. ";" .. os.getenv("HOME") .. "/.martillo/?.lua"
return require("martillo").setup {
-- LaunchOrToggleFocus: App switching hotkeys
{
"LaunchOrToggleFocus",
keys = {
{ { "alt", "shift" }, "c", app = "Calendar" },
{ { "alt", "shift" }, "d", app = "Chromium" },
{ { "alt", "shift" }, "x", app = "Excalidraw" },
{ { "alt", "shift" }, "space", app = "Ghostty" },
{ { "alt", "shift" }, "e", app = "Mail" },
{ { "alt", "shift" }, "m", app = "Music" },
{ { "alt", "shift" }, "n", app = "Notes" },
{ { "alt", "shift" }, "r", app = "Reminders" },
{ { "alt", "shift" }, "b", app = "Safari" },
{ { "alt", "shift" }, "h", app = "Yaak" },
{ { "alt", "shift" }, "z", app = "Zed" },
},
},
-- ActionsLauncher: Command palette with actions
{
"ActionsLauncher",
opts = function()
return require("config.actions")
end,
keys = {
{ { "alt", "shift" }, "\\", desc = "Toggle Actions Launcher" }
},
},
-- KillProcess: Process killer
{
"KillProcess",
keys = {
{ { "alt", "shift" }, "=", desc = "Toggle Kill Process" }
},
},
-- WindowManager: Window manipulation
{
"WindowManager",
keys = {
{ { "cmd", "shift" }, "left", "left_half", desc = "Move window to left half" },
{ { "cmd", "shift" }, "right", "right_half", desc = "Move window to right half" },
{ { "cmd", "shift" }, "up", "top_half", desc = "Move window to top half" },
{ { "cmd", "shift" }, "down", "bottom_half", desc = "Move window to bottom half" },
{ { "cmd", "shift" }, "return", "center", desc = "Center window" },
},
},
-- MySchedule: Personal scheduling
{
"MySchedule",
config = function(spoon)
spoon:compile()
spoon:start()
end,
},
-- ClipboardHistory: Clipboard manager
{
"ClipboardHistory",
config = function(spoon)
spoon:compile()
spoon:start()
end,
keys = {
{ { "alt", "shift" }, "-", desc = "Toggle Clipboard History" }
},
},
-- BrowserRedirect: Smart browser routing
{
"BrowserRedirect",
opts = {
defaultBrowser = "Safari",
redirect = {
{ match = { "*localhost*", "*127.0.0.1*", "*0.0.0.0*" }, browser = "Chromium" },
{ match = { "*fly.dev*" }, browser = "Chromium" },
{ match = { "*linear*" }, browser = "Linear" },
},
mapper = {
{ name = "googleToKagiHomepage", from = "*google.com*", to = "https://kagi.com/" },
{ name = "googleToKagiSearch", from = "*google.com*/search*", to = "https://kagi.com/search?q={query.q|encode}" }
},
},
config = function(spoon)
spoon:start()
end,
},
}
Martillo comes with these productivity spoons:
Quick app switching with customizable hotkeys. Launch or focus apps instantly without lifting your hands from the keyboard.
Searchable command palette with configurable actions. Current built-in actions include:
- Window management: Maximize, almost maximize, reasonable size
- System controls: Toggle dark mode, caffeinate (prevent sleep)
- Utilities: Copy public IP, generate UUID, network status check
- Live transformations: Timestamp conversion, Base64 encoding/decoding, JWT decoding, color conversions
Window positioning and resizing with keyboard shortcuts. Available actions:
- Halves: Snap to left, right, top, or bottom half of screen
- Maximize: Full screen or almost maximize (90% centered)
- Center: Center window at current size or reasonable size (60%×70% centered)
Quick process killer with fuzzy search. Find and terminate unresponsive apps instantly.
Advanced clipboard manager with persistent history using RocksDB + USearch backend. Features:
- Fast exact and semantic similarity search
- Persistent storage with RocksDB for performance
- Support for text, images, and file paths
- Background clipboard monitoring
- Never lose copied content again
Intelligent URL routing to different browsers based on patterns. Perfect for developers who need specific browsers for different environments.
Calendar integration that displays today's events in the menu bar with countdown timers. Uses macOS EventKit to access calendar data, showing upcoming meetings with real-time time remaining and clickable meeting URLs.
Prerequisites
- macOS 10.12 or later
- Homebrew (for installing dependencies)
Some spoons require additional dependencies for compilation:
# Required for ClipboardHistory spoon (RocksDB + USearch backend)
brew install rocksdb jsoncpp
# Download USearch header (v2.21.0) for ClipboardHistory semantic search
curl -L https://raw.githubusercontent.com/unum-cloud/usearch/main/include/usearch/index.hpp \
-o ~/.martillo/spoons/ClipboardHistory.spoon/usearch_index.hpp
# Install Hammerspoon if you don't have it
brew install --cask hammerspoon
# Install required dependencies
brew install rocksdb jsoncpp
# Clone Martillo
git clone https://github.com/sjdonado/martillo ~/.martillo
# Download USearch header for ClipboardHistory
curl -L https://raw.githubusercontent.com/unum-cloud/usearch/main/include/usearch/index.hpp \
-o ~/.martillo/spoons/ClipboardHistory.spoon/usearch_index.hpp
# Backup existing Hammerspoon config (if any)
[ -f ~/.hammerspoon/init.lua ] && mv ~/.hammerspoon/init.lua ~/.hammerspoon/init.lua.backup
# Create new init.lua
cat > ~/.hammerspoon/init.lua << 'EOF'
-- Load Martillo
package.path = package.path .. ";" .. os.getenv("HOME") .. "/.martillo/?.lua"
-- Your configuration
return require("martillo").setup {
-- Spoons configuration here
}
EOF
# Reload Hammerspoon
-- ~/.hammerspoon/init.lua
package.path = package.path .. ";" .. os.getenv("HOME") .. "/.martillo/?.lua"
return require("martillo").setup {
-- Simple spoon
{ "WindowManager" },
-- Spoon with configuration
{ "ClipboardHistory",
config = function(spoon)
spoon:compile()
spoon:start()
end
},
}
Feature | Default Shortcut | Description |
---|---|---|
Actions Launcher | ⌥ ⇧ \ |
Open command palette |
Kill Process | ⌥ ⇧ = |
Process killer |
Clipboard History | ⌥ ⇧ - |
Show clipboard history |
Window Left | ⌘ ⇧ ← |
Snap window to left half |
Window Right | ⌘ ⇧ → |
Snap window to right half |
Window Up | ⌘ ⇧ ↑ |
Snap window to top half |
Window Down | ⌘ ⇧ ↓ |
Snap window to bottom half |
Window Center | ⌘ ⇧ ↵ |
Center window |
App Hotkeys | ⌥ ⇧ [key] |
Launch/focus specific apps |
Each spoon can have these fields:
Field | Type | Description |
---|---|---|
[1] |
string |
The spoon name (required) |
opts |
table|function |
Configuration options |
keys |
table |
Keybinding definitions |
config |
function |
Post-setup configuration |
init |
function |
Pre-configuration initialization |
keys = {
{ modifiers, key, action, desc = "description" },
-- Examples:
{ { "cmd", "shift" }, "left", "left_half", desc = "Move left" },
{ { "alt" }, "space", desc = "Toggle" }, -- No action = "toggle"
}
return require("martillo").setup({
-- Spoons configuration
}, {
-- Global options
autoReload = true, -- Auto-reload on file change (default: true)
alertOnLoad = true, -- Show alert when config loads (default: true)
alertMessage = "Martillo Ready" -- Custom load message
})
local martillo = require("martillo")
-- Setup with configuration
martillo.setup(config, options)
-- Get a loaded spoon
local spoon = martillo.get("SpoonName")
-- List all loaded spoons
local spoons = martillo.list()
-- Manually reload configuration
martillo.reload()
Vision: Open source Raycast alternative built with Lua and Hammerspoon
- Extensive action launcher with fuzzy search
- Window management via launcher and keymaps
- Launch/toggle macOS apps via keymaps
- Process killer with fuzzy search
- Clipboard history with search and paste
- Upcoming meetings display in menu bar
- Browser routing rules based on URL patterns
- Link transformation rules before opening
- Fork Hammerspoon - Custom build with enhanced chooser capabilities
- Precompiled Spoons - All spoons loaded and compiled by default
- Simplified Configuration - Single table configuration like lazy.nvim
- Spoon Aliases - Set custom aliases for each spoon
- Enhanced Search - Search by aliases in choosers
- Alias Display - Show aliases in chooser items (right side)
- Navigation Callbacks:
onScrollTop
- Trigger when scrolling to toponScrollBottom
- Trigger when scrolling to bottomonBack
- Navigation back button for nested choosers
- Nested Choosers - Child choosers with parent context preservation
- Persistent Choosers - Don't close on action if child process spawns
- Smart Refresh - Refresh choices without losing scroll position
- Main Launcher - Central chooser listing all actions and sub-launchers
- Snippet expansion system
- Emoji picker and special characters
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature
) - Commit your changes (
git commit -m 'Add some AmazingFeature'
) - Push to the branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Hammerspoon - The powerful macOS automation tool
- lazy.nvim - Inspiration for the declarative configuration style