Azimuth is a keyboard-driven window manager for macOS, built with Swift and AppKit. It lives in the menu bar and lets you place, resize, move, and throw the focused window across your screens with predictable shortcuts — no mouse, no guesswork.
Design principle: predictability over clever inference. Every command does exactly one well-defined thing, and effects compose. If you can get a result by combining simple commands, Azimuth doesn't add a separate "smart" feature for it.
- Halves & snap-throw — snap the window to a screen half; press again toward the same edge to throw it to the adjacent display.
- Thirds & two-thirds — left/center/right and top/middle/bottom, horizontally or vertically.
- Maximize / center — fill the work area or center at the current size.
- Maximize with gaps — fill the work area but leave a uniform inset on all sides (
⌃⌥⇧↩). - Move (keep size) — nudge the window one step in any direction, clamped to the work area.
- Relative shrink — shrink the window to 1/2 or 2/3 of its current size against a pinned edge (not the screen). Effects compose: 2/3 then 1/2 lands on 1/3.
- Move to next display — send the window to an adjacent monitor, preserving its shape and relative position.
- Fixed-size windows too — a window that can't be resized (e.g. some VPN clients) is placed at its own size: on the edge the target touches, or centered in the target area.
- Multi-step undo — step back through each window's recent frames: 5 by default, adjustable from 1 to 20.
- Multi-monitor aware — position-aware adjacent-display selection (the window goes to the monitor that lines up with where it currently is).
- Two presets — Standard (arrow keys) and Vim (HJKL), each fully customizable with conflict warnings.
- Automatic updates — Azimuth checks for new releases and updates in place (via Sparkle), or check on demand from the menu. Updates are Apple-notarized and EdDSA-signature verified.
- macOS 13 (Ventura) or later. Ventura no longer receives Apple security updates, so use the newest macOS your Mac supports.
- On macOS 10.13–12, use the legacy build (
1.7.2 Legacy) — see Older macOS. - Accessibility permission (Azimuth controls other apps' windows through the Accessibility API).
Azimuth runs entirely on your Mac. It collects no data, has no telemetry or analytics, and makes no network connections other than checking for updates (Sparkle). The Accessibility permission is used solely to move and resize the windows of the app you're using.
- Download the latest
Azimuth-<version>.dmgfrom the Releases page. - Open the DMG and drag Azimuth into your Applications folder.
- Launch it, then enable Azimuth in System Settings → Privacy & Security → Accessibility.
The build is Developer ID–signed and notarized, so it opens without Gatekeeper warnings.
Download Azimuth-1.7.2-legacy-4.dmg (release notes: legacy release) and install it the same way
(on these versions the setting lives in System Preferences → Security & Privacy → Privacy → Accessibility).
- Same core features, no new ones. Window commands, shortcuts, the menu and undo all work, as do most settings; new features ship only in the regular version. Launch at login needs macOS 13, and failure notifications need 10.15.
- Updates itself, then moves on. It checks its own update feed; after you upgrade the Mac to macOS 13 or later, its next update check switches it to the regular version.
- Tested on a real Mac with macOS 10.13.6 (a 2009 MacBook) and in macOS 12 and 13 virtual machines, including the switch to the regular version on 13. macOS 10.14–11 have not been tested on real hardware.
- These macOS versions no longer receive Apple security updates — upgrade macOS if your Mac can.
brew install --cask ai-screams/tap/azimuthThen enable Azimuth in System Settings → Privacy & Security → Accessibility. Updates are handled in-app (Sparkle), so brew upgrade won't fight the built-in updater.
git clone https://github.com/ai-screams/Azimuth
cd Azimuth
make runmake run builds and launches a properly code-signed build (Apple Development identity), which keeps your Accessibility grant stable across rebuilds. make build is ad-hoc signed (compile/CI checks only) and not for daily use.
On first launch, open System Settings → Privacy & Security → Accessibility and enable Azimuth. The menu bar item and the Settings window both show the current permission state and a shortcut to the right settings pane.
Azimuth has no installer, so removing it is just a few steps:
- Quit Azimuth, then drag it from Applications to the Trash.
- Remove its Accessibility entry: System Settings → Privacy & Security → Accessibility → select Azimuth → click −. macOS keeps this entry even after an app is deleted, and no app can remove its own entry through the system — so this step is manual (the same is true for every app that uses Accessibility).
- (Optional) delete its preferences:
defaults delete com.aiscream.Azimuth
If you enabled Launch at login, turn it back off in Azimuth's Settings before deleting the app. macOS
keeps an SMAppService registration after the bundle is gone — by design, so it survives a reinstall — and an
app cannot unregister itself once it is in the Trash. If you already deleted it, remove the leftover entry in
System Settings → General → Login Items.
Azimuth separates command groups by modifier layer:
| Layer | Purpose |
|---|---|
⌃⌥ (Control+Option) |
Halves (snap/throw) · Maximize · Center · Undo · Thirds & two-thirds (number keys) |
⌃⌥⌘ |
Move (keep current size) |
⌃⌥⇧ |
Relative shrink — ½ on arrows, ⅔ on M , . / |
⌃⌥⌘⇧ |
Move to next display |
| Group | Command | Shortcut |
|---|---|---|
| Halves (snap + throw) | Left / Right | ⌃⌥← / ⌃⌥→ |
| Top / Bottom | ⌃⌥↑ / ⌃⌥↓ |
|
| Maximize · Undo · Center | Maximize | ⌃⌥↩ (Return) |
| Maximize · Undo · Center | Maximize with gaps | ⌃⌥⇧↩ (Return) |
| Undo | ⌃⌥⌫ (Delete) |
|
| Center | ⌃⌥C |
|
| Thirds (1/3) | Horizontal left·center·right | ⌃⌥1 / ⌃⌥2 / ⌃⌥3 |
| Vertical top·middle·bottom | ⌃⌥4 / ⌃⌥5 / ⌃⌥6 |
|
| Two-thirds (2/3) | Horizontal left·right | ⌃⌥7 / ⌃⌥8 |
| Vertical top·bottom | ⌃⌥9 / ⌃⌥0 |
|
| Move (keep size) | Left·Right·Up·Down | ⌃⌥⌘← / → / ↑ / ↓ |
| Relative shrink (½) | Left·Right·Up·Down | ⌃⌥⇧← / → / ↑ / ↓ |
| Relative shrink (⅔) | Left·Down·Up·Right | ⌃⌥⇧ M , . / |
| Move to next display | Left·Right·Up·Down | ⌃⌥⌘⇧← / → / ↑ / ↓ |
Only the directional commands and Undo change keys; everything else (Maximize, Center, numbers) matches Standard.
| Difference | Mapping |
|---|---|
| Direction | H = left, L = right, K = up, J = down |
| Undo | U |
Example: ⌃⌥H (left half) · ⌃⌥⌘K (move up) · ⌃⌥⇧J (shrink to bottom half) · ⌃⌥⌘⇧L (move to right display) · ⌃⌥U (undo).
If registering a combination fails — because another app or macOS already holds it, or because the hotkey system could not start — the Settings window marks that row "In use by system." Some combinations macOS reserves register successfully and are simply swallowed before they reach Azimuth; those show no badge and the shortcut just does nothing. Either way, every shortcut can be remapped in Settings.
- Maximize — fills the work area (visible area minus menu bar and Dock).
- Maximize with gaps — like Maximize, but leaves a uniform 12pt inset on all four sides so the window doesn't touch the screen edges. Falls back to a plain maximize if the work area is too small for the gap.
- Thirds / two-thirds — axis-independent: horizontal commands change only x/width, vertical only y/height, so they compose (e.g. horizontal-third then vertical-third → a corner cell).
- Halves + throw — if the window isn't already in that half, it snaps there. If it is, Azimuth throws it to the adjacent display in that direction and places it in the opposite half (throwing right lands it in the target's left half). No adjacent display → it stays put.
- Move — keeps the current size and nudges the window by its own width/height, clamping at the work-area edge. It never resizes or changes display; repeated presses push it to the edge. A window that already sits off-screen past an edge is recovered into the work area, so a directional Move can pull it back onto the screen rather than push it further out.
- Center — keeps size, centers in the work area.
- Relative shrink (½ / ⅔) — based on the current window, not the screen: pins the chosen edge and shrinks toward it. Arrow keys shrink to ½;
M , . /shrink to ⅔ (M=left, ,=down, .=up, /=right). Effects compose: ⅔ then ½ lands on ⅓. - Move to next display — preserves shape and relative position: a centered window stays centered even at a different resolution. It keeps its exact pixel size if it fits the target work area; if it doesn't, both axes shrink by the same factor, so the aspect ratio never changes. No adjacent display → stays put.
- Fixed-size windows — a standard window or dialog that can be moved but not resized (its green zoom button is greyed out) keeps its size, and placement commands only move it: it hugs the work-area edge the target touches and is centered within the target on the other axis (Left ½ → left edge, vertically centered; Maximize → centered on the screen). Pressing the same direction again still throws it to the adjacent display. Relative shrink still fails with "This window can't be resized".
- Undo — restores the window's previous frame; press again to keep stepping back. Each window keeps its own history, 5 steps by default (Settings → General → Behavior, 1–20), for up to 64 recently used windows (1–256). Lowering either limit trims the oldest history on the next window command or Undo. Undo itself is not recorded, so there is no redo. Display reconfiguration discards undo history.
- Failure feedback — a beep on failure (toggleable in Settings) plus a log entry, and the reason is recorded in the menu bar menu. You can also opt in to a notification on failure. Transient failures during Space switches or animations are skipped silently. Two cases differ: if the command failed for lack of Accessibility permission, Azimuth opens the Settings window for you (once per launch), and if the target app took too long to answer, the reason reads "The app is taking too long to respond" — how long Azimuth waits is the Advanced tab's setting.
Note: apps with size increments (e.g. Terminal) may leave a sub-row gap when snapped to a half/maximize, because they round down to their character grid. The work area excludes the menu bar and Dock, so a gap at those edges is expected.
Open Settings from the menu bar item or with ⌘,. It has three tabs — General (permissions, behavior, updates), Shortcuts, and Advanced:
- Switch preset (Standard / Vim).
- Shortcut groups start collapsed; expand a group with its disclosure triangle, or type in the filter to expand matches automatically.
- Record custom shortcuts per command, with conflict warnings and per-command Reset.
- Enable/disable command groups, or unbind individual commands.
- Toggle failure beep, failure notifications, launch-at-login, and hide the menu bar icon.
- Choose how many undo steps each window keeps (1–20, default 5) and how many windows keep a history (1–256, default 64).
- Automatic updates via Sparkle — current version + Check for Updates… in Settings (and the menu bar / App menu).
- Advanced — how long to wait for an unresponsive app before giving up: Quick (0.25s), Balanced (0.5s, default) or Patient (1s). Shorter keeps Azimuth's own menus responsive when an app hangs; longer gives a slow app more time to answer. Leave it alone unless commands fail on apps that are merely slow.
If the menu bar icon is hidden, relaunching Azimuth reopens the Settings window so you always have a way back in.
| Stage | Theme |
|---|---|
| Stable | Stabilization across representative apps — shipped |
| Next | Anchor placement: snap/size the window relative to another window (same display) |
| Later | Workspaces: per-app default positions, named scene save/restore |
| Future | Automation: URL scheme, Shortcuts action, per-app rules |
Azimuth uses:
SwiftLintfor lintingSwiftFormatfor formatting.editorconfigfor basic editor consistency
Install the tools with Homebrew:
brew install swiftlint swiftformat gitleaksCommon make targets, run from the project root:
make run # build a signed app and launch it (use this to actually run Azimuth)
make build # compile-only verification (ad-hoc signed; CI/compile checks only)
make test # run the pure-logic command-engine tests (swiftc)
make coverage # the same tests plus a line-coverage gate on the pure-logic layer (what CI runs)
make lint # SwiftLint (strict)
make format # SwiftFormat
make secrets # gitleaks secret scan
make sparkle-adapter-check # confirm the update-window adapter still matches what Sparkle looks upXcode also runs SwiftLint during builds when it is installed locally. If SwiftLint is missing, the build shows a warning instead of failing.
Install the local Git hooks once:
make install-hooksThe pre-commit hook runs SwiftFormat --lint and SwiftLint --strict.
GitHub Actions runs on pushes to main and on pull requests: the same lint checks, a macOS xcodebuild build, the pure-logic tests with their coverage gate, the Sparkle adapter check, and tests for the release scripts. It also runs gitleaks secret scanning and uploads a SARIF report to GitHub code scanning. CodeQL analysis runs in a separate workflow on pushes to main and weekly, not on pull requests.
Azimuth is free and open source — no paywall, no ads, no telemetry — and it always will be. If it earns a place in your workflow, you can chip in to fund its development:
- 💛 Ko-fi — a one-time tip or a supporter license · ♥ GitHub Sponsors — recurring support
A supporter license is simply a way to say thanks — it unlocks nothing, because every feature is already free for everyone. Entirely optional, always appreciated: there is no paywall and never will be.
Apache License 2.0 — see LICENSE and NOTICE.
Copyright 2026 AiScream. "Azimuth" and the project name/branding are not granted under the license (Apache-2.0 does not grant trademark rights).