Skip to content

Repository files navigation

Chestnut

Chestnut, a pixel-art treasure chest creature

A native macOS desktop companion for Obsidian users. gapmiss.github.io/chestnut

Chestnut is an always-on-top pixel-art treasure-chest creature that reacts to your writing activity and acts as a control surface across all your vaults. It watches the filesystem directly, no Obsidian plugin required, no settings modified.

Native Swift and SpriteKit: ~1.2 MB download, ~2 MB installed, ~3% idle CPU. No Electron, no bundled browser, no network calls.

Important

Project status: Chestnut is pre-1.0 and moving quickly. Expect frequent releases.

Features

  • Vault Hopper lists all your registered vaults. ⏎ opens, ⌘⏎ goes to today's daily note, ⌥⏎ reveals in Finder.
  • Pin a vault so it always sorts first in every list and starts pre-selected for captures and deliveries. Toggle with the pin icon or ⌘P.
  • Note Courier lets you drag files onto the pet and pick a destination vault. Notes land at the vault root with their embedded attachments (![[…]], ![](…)) resolved and carried along, references rewritten to match the destination layout. Other file types go to the attachment folder. Conflict-safe naming, journaled for undo. A plugin never takes a dropped file away from the courier: when both could handle it, Chestnut asks, with the plugin pre-selected and "Deliver to a vault" one arrow key away. Drag folders from Finder: Obsidian's file explorer drags a folder as its name alone, without the path, so Chestnut has nothing to deliver and says so instead. Notes and attachments dragged from Obsidian are fine, including several at once.
  • Quick Capture is a floating panel for jotting markdown into any vault. Formatting toolbar, ⌘B/⌘I/⌘K shortcuts, ⌘1-⌘9 to pick the vault. Drafts survive dismiss/reopen.
  • Plugins let you extend drag-and-drop and a paste hotkey with shell scripts. See the User Guide for the full reference, PLUGINS.md for architecture details, and Examples/plugins/ for ready-made examples.
  • After a capture or delivery, a speech bubble tells you where your text went. Click it to open the note in Obsidian (uses the obsidian CLI when available, falls back to opening the vault).
  • Idle, peek, writing, chomp, carry, deliver, sleep animations. Hand-coded pixel-art frames with swappable color themes.

Install

Homebrew

brew install --cask gapmiss/tap/chestnut

Manual

Download Chestnut.dmg from the latest release, open it, and drag Chestnut.app into Applications.

Chestnut is ad-hoc signed (not notarized), so macOS may block the first launch. To allow it:

  • macOS 15+: System Settings → Privacy & Security, then Open Anyway, or
  • macOS 14: right-click the app, then Open, then click Open in the dialog, or
  • Remove the quarantine flag:
xattr -dr com.apple.quarantine /Applications/Chestnut.app

Whether a later brew upgrade asks again varies by macOS version. If it does, the same fix applies.

To start automatically, right-click the pet and toggle Settings → Launch at Login.

Uninstall

If you turned on Settings → Launch at Login, switch it off before you quit. That deregisters the login item, which deleting the app does not. Then quit Chestnut (right-click → Quit, ⌃⌥M → Quit, or pkill -x Chestnut) and remove the app:

brew uninstall --cask chestnut      # installed with Homebrew
rm -rf /Applications/Chestnut.app   # installed manually

Chestnut writes to four places outside its own bundle, and nowhere else:

Path Contents
~/Library/Application Support/Chestnut/ config.json, state.json, the undo journals journal.jsonl and captures.jsonl, and any backups beside them (.bak, .bak.1, … from a settings file that failed to parse, or a .pre-0.3 left by an old build)
~/.config/chestnut/plugins/ Installed plugins. Created at every launch, so it exists even if you never wrote one
~/Library/Logs/Chestnut/ chestnut.log and chestnut.log.1, written only while debug is on in config.json
$TMPDIR/chestnut-plugins/ Scratch copies of pasted images on their way to a plugin. Swept at every launch, and macOS clears it anyway
rm -rf ~/Library/Application\ Support/Chestnut \
       ~/.config/chestnut \
       ~/Library/Logs/Chestnut

None of those paths holds a vault or a note, so removing them leaves your writing where it is.

Worth knowing whether or not you are uninstalling: the undo journals hold your note text. captures.jsonl keeps the exact text of each capture, and journal.jsonl keeps a note's pre-delivery text whenever a delivery rewrote its links, because that is what Undo puts back. Both are capped at 20 records or 1 MB, so older text rolls off as you keep working, and neither is ever sent anywhere.

Requirements

  • macOS 14+
  • Swift 6 toolchain (Xcode or Command Line Tools), only needed to build from source
  • No Xcode project; builds with SPM + Make

Build & Run

make build          # swift build (CONFIG=debug|release)
make bundle         # build → .build/Chestnut.app (ad-hoc codesign)
make run            # bundle + open the app
make dmg            # release build → .build/Chestnut.dmg
make check          # runtime checks (no XCTest dependency)
make clean

Quit with right-click → Quit, ⌃⌥M → Quit, or pkill -x Chestnut.

Architecture

Single Swift executable bundled into a .app by the Makefile.

Layer Technology Role
Windows AppKit Borderless, transparent, always-on-top pet window
Pet rendering SpriteKit Sprite animation from hand-coded frame matrices
Panels SwiftUI Vault palette, capture panel
Sources/Chestnut/
  main.swift, AppDelegate.swift
  Pet/        # PetWindow, PetScene, Sprites, PetController
  Vaults/     # VaultRegistry, VaultWatcher
  Actions/    # ObsidianBridge, Courier, Capture
  Panels/     # SwiftUI palettes/panels (NSPanel-hosted)
  Plugins/    # PluginManifest, PluginRegistry, PluginRunner, PluginDispatch, DropRouter, PluginPalette
  Support/    # Config, Hotkeys, Journal

Configuration

Two files in ~/Library/Application Support/Chestnut/:

  • config.json is yours: hotkeys, capture destination, custom sprite themes. Chestnut never writes to it, apart from creating it on first run. Hand-editable; changes take effect on next launch. Right-click → Settings → Edit Configuration… opens it.
  • state.json is Chestnut's: window position, size, opacity, theme, notice duration, pinned vault, disabled plugins. Everything in it has a control in the right-click menu.

Using Chestnut with VoiceOver

VoiceOver claims Chestnut's default shortcuts. Control-Option is VoiceOver's own modifier (the "VO key"), so with VoiceOver running ⌃⌥V is speech verbosity, ⌃⌥M is the menu bar, and none of Chestnut's five hotkeys reach Chestnut. That includes ⌃⌥M, which is otherwise the keyboard route to the right-click menu.

Rebind them in config.json to a prefix VoiceOver doesn't use, and relaunch:

{
  "hotkeys": {
    "capture": "control+shift+space",
    "hopper":  "control+shift+v",
    "paste":   "control+shift+c",
    "notice":  "control+shift+o",
    "menu":    "control+shift+m"
  }
}

Until then, the menu is still reachable by right-clicking Chestnut itself (the click has to land on the sprite, not the clear space around it). Once open, the menu, the Quick Capture panel and the vault palettes all read correctly, and arrowing through a palette announces each vault with its path.

Keeping them apart means editing config.json while Chestnut is running is safe. Upgrading is just a new .app: neither file is touched, so nothing resets. If a release ever moves a setting from one file to the other, that one value goes back to its default and the release notes say so; it's always something you can re-pick from the menu. See the User Guide for the full reference.

Design Principles

  • Read-only. Never modifies Obsidian's files or .obsidian/ settings.
  • Vaults keyed by path, not name (names collide).
  • No network calls, no telemetry.
  • The obsidian CLI is optional. Every CLI call has a filesystem fallback.
  • No image assets. Sprites are string matrices mapped through a palette.

Contributing

See CONTRIBUTING.md for build instructions and ground rules.

License

MIT © @gapmiss

About

A tiny always-on-top pixel companion for Obsidian users on macOS. Hop between vaults, deliver notes, capture thoughts. No network, no telemetry.

Topics

Resources

Contributing

Stars

Watchers

Forks

Releases

Sponsor this project

Contributors

Languages