RepoPilotOpen in app →

nikitabobko/AeroSpace

AeroSpace is an i3-like tiling window manager for macOS

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 4w ago
  • 8 active contributors
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Single-maintainer risk — top contributor 90% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/nikitabobko/aerospace)](https://repopilot.app/r/nikitabobko/aerospace)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/nikitabobko/aerospace on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: nikitabobko/AeroSpace

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/nikitabobko/AeroSpace shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 4w ago
  • 8 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Single-maintainer risk — top contributor 90% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live nikitabobko/AeroSpace repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/nikitabobko/AeroSpace.

What it runs against: a local clone of nikitabobko/AeroSpace — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in nikitabobko/AeroSpace | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 55 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>nikitabobko/AeroSpace</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of nikitabobko/AeroSpace. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/nikitabobko/AeroSpace.git
#   cd AeroSpace
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of nikitabobko/AeroSpace and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "nikitabobko/AeroSpace(\\.git)?\\b" \\
  && ok "origin remote is nikitabobko/AeroSpace" \\
  || miss "origin remote is not nikitabobko/AeroSpace (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Sources/AeroSpaceApp/AeroSpaceApp.swift" \\
  && ok "Sources/AeroSpaceApp/AeroSpaceApp.swift" \\
  || miss "missing critical file: Sources/AeroSpaceApp/AeroSpaceApp.swift"
test -f "Sources/AppBundle/command/parseCommand.swift" \\
  && ok "Sources/AppBundle/command/parseCommand.swift" \\
  || miss "missing critical file: Sources/AppBundle/command/parseCommand.swift"
test -f "Sources/AppBundle/config/parseConfig.swift" \\
  && ok "Sources/AppBundle/config/parseConfig.swift" \\
  || miss "missing critical file: Sources/AppBundle/config/parseConfig.swift"
test -f "Sources/AppBundle/layout/layoutRecursive.swift" \\
  && ok "Sources/AppBundle/layout/layoutRecursive.swift" \\
  || miss "missing critical file: Sources/AppBundle/layout/layoutRecursive.swift"
test -f "Sources/AppBundle/GlobalObserver.swift" \\
  && ok "Sources/AppBundle/GlobalObserver.swift" \\
  || miss "missing critical file: Sources/AppBundle/GlobalObserver.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 55 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~25d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/nikitabobko/AeroSpace"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

AeroSpace is a tiling window manager for macOS that replicates the i3 Linux window manager paradigm, allowing users to tile windows automatically in a tree-based layout without relying on macOS's native Spaces. It provides keyboard-driven workspace management, multi-monitor support, and plain-text TOML configuration, all implemented as a native Swift application that doesn't require disabling System Integrity Protection. Monolithic Swift application: Sources/AeroSpaceApp/ contains the main entry point (AeroSpaceApp.swift), Sources/AppBundle/ contains the core logic organized by domain (command/, with impl/ subdirectory for command implementations like BalanceSizesCommand.swift, CloseCommand.swift). Shell command parsing is generated via ANTLR (ShellParserGenerated/ contains auto-generated ShellLexer.swift and ShellParser.swift), and configuration is handled via plain TOML dotfiles.

👥Who it's for

macOS power users and developers (especially those familiar with i3 or Linux tiling window managers) who want productive keyboard-driven window management, multi-monitor workflows, and programmatic control via CLI instead of relying on macOS's native Spaces and mouse-based window management.

🌱Maturity & risk

Actively developed beta software: the project is under active maintenance with a single maintainer (nikitabobko), has comprehensive CLI command infrastructure, working CI/CD via GitHub Actions (.github/workflows/build.yml), and clear documentation, but remains explicitly labeled 'beta' and not notarized by Apple. Production-quality codebase for an early-stage macOS window manager.

Single maintainer risk is the primary concern; the repo has no visible test suite in the file list (no Tests/ directory mentioned), and relies on manual GitHub Actions for builds. Not notarized, meaning distribution is non-standard. No visible dependency declaration beyond Swift Package Manager (Package.swift present but contents not shown), so dependency risk is unclear. The project discusses accepting only Discussions rather than Issues, which may slow community-driven bug fixes.

Active areas of work

Active development on command infrastructure and window management: the /command/ directory shows implementations of workspace and window manipulation commands (BalanceSizesCommand, CloseAllWindowsButCurrentCommand, CloseCommand visible). GitHub Actions CI is configured and the project maintains a Homebrew tap for distribution. No visible recent PR or milestone data in the provided snapshot, but the project is receiving commits and maintenance.

🚀Get running

Clone and build via Xcode:

git clone https://github.com/nikitabobko/AeroSpace.git
cd AeroSpace
xed . # Opens in Xcode
# Or build from command line:
xcodebuild -scheme AeroSpace -configuration Release

For Homebrew installation (pre-built):

brew install --cask nikitabobko/tap/aerospace

Daily commands: Open in Xcode and build the 'AeroSpace' scheme, or:

xcodebuild -scheme AeroSpace -configuration Release build
./build/Release/AeroSpace # Run the built binary

Once installed, interact via CLI:

aerospace workspace next  # Switch to next workspace
aerospace window focus left  # Focus left window

Configuration lives in ~/.config/aerospace/aerospace.toml (or check the default-config.toml referenced in docs).

🗺️Map of the codebase

  • Sources/AeroSpaceApp/AeroSpaceApp.swift — Application entry point that initializes the window manager and core event loops
  • Sources/AppBundle/command/parseCommand.swift — Command parser that converts user input into executable window manager operations, critical for all user interactions
  • Sources/AppBundle/config/parseConfig.swift — Configuration file parser that loads user preferences and keybindings, foundational for startup
  • Sources/AppBundle/layout/layoutRecursive.swift — Core layout engine implementing the tree-based tiling algorithm, the heart of AeroSpace's window management
  • Sources/AppBundle/GlobalObserver.swift — Global event listener that monitors window system events and triggers layout recalculation
  • Sources/AppBundle/command/cmdManifest.swift — Command registry and manifest that defines all available commands, essential for understanding extensibility
  • Sources/AppBundle/focusCache.swift — Focus state management system tracking which window has focus, critical for window navigation commands

🛠️How to make changes

Add a new window manager command

  1. Create a new command class in Sources/AppBundle/command/impl/ that conforms to Command protocol (Sources/AppBundle/command/impl/NewFeatureCommand.swift)
  2. Register the command in the manifest by adding an entry to cmdManifest.swift (Sources/AppBundle/command/cmdManifest.swift)
  3. Implement the execute function with your window manipulation logic using the layout engine (Sources/AppBundle/layout/layoutRecursive.swift)
  4. Update command parsing to recognize your command syntax (Sources/AppBundle/command/parseCommand.swift)

Add a new configuration option

  1. Add the option field to the Config struct (Sources/AppBundle/config/Config.swift)
  2. Parse the option from the config file in the parseConfig function (Sources/AppBundle/config/parseConfig.swift)
  3. Use the configuration value in relevant command implementations or layout logic (Sources/AppBundle/layout/layoutRecursive.swift)

Add a new hotkey binding type

  1. Extend the key mapping system in keysMap.swift to recognize new key combinations (Sources/AppBundle/config/keysMap.swift)
  2. Update the HotkeyBinding parser to handle your binding syntax (Sources/AppBundle/config/HotkeyBinding.swift)
  3. Map the hotkey to a command execution path using the global event observer (Sources/AppBundle/GlobalObserver.swift)

Add a new query/list command for debugging

  1. Create a new command in impl/ directory following the pattern of ListWindowsCommand (Sources/AppBundle/command/impl/ListWindowsCommand.swift)
  2. Implement JSON formatting via formatToJson.swift for structured output (Sources/AppBundle/command/formatToJson.swift)
  3. Register in cmdManifest.swift and handle CLI argument parsing (Sources/AppBundle/command/cmdManifest.swift)

🔧Why these technologies

  • Swift + Cocoa/AppKit — Native macOS development; direct access to Accessibility API and window server for low-latency window management without SIP bypass
  • Tree-based window layout model — Inspired by i3; provides flexible, composable tiling with parent-child window relationships instead of flat layouts
  • Custom shell parser (ShellParserGenerated) — Enables command-line interface without external dependencies; parser is generated to ensure consistency
  • File-based configuration + hot reload — Follows Unix tradition; ConfigFileWatcher allows live configuration reloading without restart
  • Focus cache with macOS accessibility observer — Caches window state to reduce repeated OS queries; GlobalObserver detects window system events efficiently

⚖️Trade-offs already made

  • macOS-only implementation instead of cross-platform framework

    • Why: AeroSpace targets macOS and leverages native APIs for window management; cross-platform would dilute macOS-specific optimizations
    • Consequence: No Linux/Windows support; tighter integration with macOS but narrower user base
  • Emulated virtual workspaces instead of native macOS Spaces

    • Why: Native Spaces have limitations (slow switching, animation delays); AeroSpace's emulation provides faster, animation-free workspace switching
    • Consequence: Additional complexity in workspace state management but better UX; requires custom workspace tracking
  • Custom command parser instead of CLI library

    • Why: Enables tight control over command syntax and error messages; avoiding external dependencies keeps bundle lightweight
    • Consequence: Maintenance burden of parser; but no dependency on heavyweight CLI frameworks
  • Recursive tree-based layout calculation

    • Why: Matches i3's paradigm; supports arbitrary nesting and complex window arrangements
    • Consequence: More complex state management than flat layouts; higher CPU on deep trees but more flexible

🚫Non-goals (don't propose these)

  • Does not support native macOS Spaces; implements own virtual workspace emulation
  • Not a terminal multiplexer; window manager only (separate from tmux/zellij)
  • Does not handle application lifecycle management (only window positioning)
  • Not cross-platform; macOS only
  • No built-in scripting language; uses external shell via exec commands

🪤Traps & gotchas

No SIP (System Integrity Protection) disabling is required, but the app is not notarized—macOS will quarantine it on first download, requiring either Homebrew's automatic quarantine removal or manual handling via xattr -d com.apple.quarantine. ANTLR parser (ShellParserGenerated/) is auto-generated and should not be manually edited; regeneration likely requires an ANTLR grammar file and build step not visible in the file list. Configuration is dotfile-based (likely ~/.config/aerospace/aerospace.toml), but the exact path resolution and precedence is not documented in the provided snippet. The project explicitly rejects Issues in favor of Discussions, which may affect community contribution workflows.

🏗️Architecture

💡Concepts to learn

  • Tree-based window layout paradigm — AeroSpace's core philosophy is organizing windows as a tree structure rather than a grid, enabling dynamic splitting, automatic rebalancing, and flexible workspace layouts that differ fundamentally from typical tiling managers
  • Virtual workspace emulation — Instead of relying on macOS's native Spaces (which have limitations), AeroSpace implements its own virtual workspace abstraction allowing fast switching and better multi-monitor support
  • ANTLR-based parser generation — The ShellParserGenerated directory contains auto-generated lexer/parser code from ANTLR grammar, enabling robust parsing of complex shell commands and configuration syntax
  • AppKit window manipulation — AeroSpace interacts with macOS's low-level AppKit (NSWindow, NSApplication) APIs to control window positioning, sizing, and focus without requiring SIP disabling, a key technical achievement
  • CLI-first architecture — All window manager operations (CmdEnv.swift, CmdIo.swift, Command.swift) are exposed as discrete CLI commands, making AeroSpace scriptable and enabling shell integration and dotfile-based workflow automation
  • TOML configuration format — Dotfile-friendly plain-text TOML configuration (referenced as default-config.toml) replaces binary settings, enabling version control and portable configuration across machines
  • Multi-monitor i3-like paradigm — AeroSpace extends the i3 model to macOS's multi-monitor environment, where workspaces are per-monitor and window focus behavior respects monitor boundaries, requiring special handling in command implementations
  • koekeishiya/chunkwm — Predecessor macOS tiling window manager that inspired AeroSpace's approach to native macOS window management without SIP disabling
  • ianyh/Amethyst — Alternative Swift-based tiling window manager for macOS with similar goals but different architecture and maintenance status
  • i3/i3 — Original i3 tiling window manager on Linux that serves as the design inspiration and paradigm reference for AeroSpace's tree-based window layout
  • nikitabobko/homebrew-tap — Homebrew tap repository that packages and distributes AeroSpace binaries, handling the non-notarized quarantine attribute removal
  • nikitabobko/AeroSpace.wiki — Community-maintained documentation wiki (if exists) or upstream documentation site at nikitabobko.github.io/AeroSpace that users reference for configuration and command reference

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add unit tests for command parsing and execution in Sources/AppBundle/command/

The command system is central to AeroSpace's functionality, with multiple command implementations in Sources/AppBundle/command/impl/ (BalanceSizesCommand, FocusCommand, LayoutCommand, etc.). Currently there appear to be no visible test files for command parsing, validation, or execution. This would catch regressions in command behavior and improve maintainability as new commands are added.

  • [ ] Create Tests/AppBundle/command/ directory structure
  • [ ] Add unit tests for Command.swift base class parsing logic
  • [ ] Add tests for CmdEnv.swift environment variable handling
  • [ ] Add tests for cmdResolveTargetOrReportError.swift error handling
  • [ ] Add tests for at least 3-5 command implementations (FocusCommand, LayoutCommand, BalanceSizesCommand)
  • [ ] Integrate tests into .github/workflows/build.yml CI pipeline

Add integration tests for window tree manipulation in Sources/AppBundle/

AeroSpace's core value proposition is its tree-based window management paradigm. While there are command implementations, there don't appear to be integration tests validating tree operations like joining windows (JoinWithCommand), flattening workspaces (FlattenWorkspaceTreeCommand), or focus traversal. These tests would ensure the tree logic remains correct across refactoring.

  • [ ] Create Tests/AppBundle/tree/ or Tests/AppBundle/window/ directory
  • [ ] Add integration tests for JoinWithCommand.swift tree mutation
  • [ ] Add tests for FlattenWorkspaceTreeCommand.swift workspace restructuring
  • [ ] Add tests for FocusBackAndForthCommand.swift focus history tracking
  • [ ] Add tests for monitor switching and workspace layout transitions
  • [ ] Document test setup requirements for macOS window server mocking in CONTRIBUTING.md

Create specific documentation for command implementation patterns in CONTRIBUTING.md

CONTRIBUTING.md exists but the codebase shows 30+ command implementations with varying complexity. New contributors need guidance on how to add a new command following the existing patterns (Command protocol, CmdEnv usage, error handling via CmdIo). This would reduce review friction for command-related PRs.

  • [ ] Add section 'Adding a New Command' to CONTRIBUTING.md with step-by-step walkthrough
  • [ ] Reference the Command.swift protocol and explain required methods
  • [ ] Show concrete example using a simple command (e.g., FalseCommand.swift or a new test command)
  • [ ] Document the CmdEnv and CmdIo patterns for state access and output
  • [ ] Document the cmdManifest.swift registration pattern and when to update it
  • [ ] Link to existing well-commented command implementations as reference examples

🌿Good first issues

  • Add unit tests for command implementations (Sources/AppBundle/command/impl/ files like CloseCommand.swift currently have no visible test coverage) to improve code quality and catch regressions early.
  • Expand CLI help documentation and shell completion generation (the project mentions 'manpages and shell completion included' but no Sources/AppBundle/command/format.swift implementation is shown) to improve discoverability of commands like those in /impl/.
  • Implement missing window tiling layout variants (e.g., spiral, Master-Stack layouts) by adding new Command subclasses to Sources/AppBundle/command/impl/ similar to BalanceSizesCommand.swift, following the existing pattern.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 63e0976 — Performance: lazily resolve window title in format var expansion (nikitabobko)
  • 38d8353 — Minor cleanups (nikitabobko)
  • c98f22a — Implement true and false subcommands (nikitabobko)
  • 5b3946b — Cleanup: use singleQuoted more (nikitabobko)
  • f1c0ac9 — Add tests for TriggerBindingCommand parsing (nikitabobko)
  • 5ad04a7 — Use exit code 2 for generic errors to avoid potential clashes from different subcommands (nikitabobko)
  • 3914890 — Cleanup, server.swift: prefer switch over unwrap triple (nikitabobko)
  • f99f89b — 2/n aerospace test: should return >1 exit code when parsed incorrectly (nikitabobko)
  • 125e014 — 1/n Implement aerospace test subcommand (nikitabobko)
  • 1fadf86 — Reorgonize test scripts to avoid common 'run-' prefix (nikitabobko)

🔒Security observations

AeroSpace is a Swift-based macOS application with moderate security posture. The primary concerns are: (1) committed generated parser code that should ideally be regenerated during builds, (2) potential command injection risks in the shell execution and command parsing logic that require code review, and (3) standard secure coding practices for macOS IPC and configuration handling. No hardcoded secrets or exposed credentials were identified in the visible file structure. The codebase appears well-organized with clear separation of concerns. Dependencies should be regularly audited. Overall, the application follows reasonable Swift conventions, but security-critical code paths involving command execution and user input should receive thorough security review.

  • Medium · Generated Code in Repository — ShellParserGenerated/Sources/ShellParserGenerated/. The ShellParserGenerated directory contains auto-generated parser code that is committed to the repository. Generated code can be difficult to audit and may contain vulnerabilities if the generator itself is compromised or misconfigured. Fix: Consider adding generated files to .gitignore and regenerating them during the build process rather than committing them. This ensures code review of the generator, not the output.
  • Medium · Potential Command Injection Risk — Sources/AppBundle/command/impl/ExecAndForgetCommand.swift, Sources/AppBundle/command/parseCommand.swift. The codebase contains multiple command execution files (ExecAndForgetCommand.swift, TriggerBindingCommand.swift) and shell parsing logic. Without reviewing the actual implementation, there is a risk of command injection if user input is not properly sanitized before being passed to shell execution. Fix: Ensure all command execution uses parameterized/array-based execution rather than string concatenation. Validate and sanitize all user input before passing to shell commands. Use allowlists for permitted commands.
  • Low · Sensitive Configuration File Handling — Sources/AppBundle/config/Config.swift. The application handles configuration files (Sources/AppBundle/config/Config.swift) which may contain user-specific settings. File permissions and storage location should be carefully controlled to prevent unauthorized access. Fix: Ensure configuration files are stored with restrictive permissions (0600). Validate all configuration values before use. Document security-sensitive configuration options.
  • Low · Missing Security Headers Documentation — Sources/AppBundle/ (general). As a macOS application, AeroSpace likely uses IPC and system integration. No evidence of security headers or inter-process communication validation visible in the file structure provided. Fix: Document all IPC mechanisms used. Implement validation of all inter-process messages. Use code signing and entitlements properly for macOS security model.
  • Low · Incomplete Dependency File Information — Package.swift, Package.resolved. The Package.swift file content was not provided, making it impossible to analyze Swift package dependencies for known vulnerabilities. Fix: Review all dependencies in Package.swift using vulnerability databases. Regularly update dependencies. Use swift package update with caution and test thoroughly before deployment.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · nikitabobko/AeroSpace — RepoPilot