A minimal macOS Finder toolbar app that opens the current directory in Otty with a single click.
Inspired by OpenInTerminal-Lite.
If you already use OpenInTerminal and switch between several terminals, you can use upstream Otty support instead — see OpenInOtty vs OpenInTerminal below.
| Your situation | Use |
|---|---|
| Otty only, want the lightest one-click toolbar (new tab + focus when possible) | OpenInOtty (this project) |
| Already on OpenInTerminal / Lite, switching Terminal / iTerm / Ghostty / Otty, etc. | OpenInTerminal (Otty support PR #276) |
| Both installed | Fine — they don’t conflict. This app is Otty-only; upstream is a multi-terminal suite |
In short:
- OpenInOtty = Otty remote (
otty-cli: if Otty is running, open a new tab and focus it) - OpenInTerminal = multi-app toolbox (
open -a Ottyworks, but does not use Otty’s tab CLI)
- One click — toolbar icon opens Otty at the current Finder path
- Smart path
- Selection → use selected item (if it’s a file, use the parent folder)
- No selection → current Finder window folder
- No usable window → Desktop
- Smart Otty
- Otty already running →
otty-cli tab new --cwd <path>, then match by cwd andtab focus - Otty not running →
otty-cli open <path> - CLI missing or fails → fall back to
open -a <Otty.app> <path>(Otty accepts folders as documents)
- Otty already running →
- Find Otty by bundle id — not hard-coded to
/Applicationsonly (Launch Services first, then default path) - Error alerts — failures show an
NSAlertinstead of failing silently - No menu bar / Dock icon —
LSUIElement = true; quits right after dispatch
| Requirement | Version |
|---|---|
| macOS | 12.0 Monterey or later |
| Xcode | 15+ (free from the App Store) |
| Otty | Any recent version |
Otty is usually at /Applications/Otty.app. Any location Launch Services can find is fine.
-
Clone the repo:
git clone https://github.com/pintaste/OpenInOtty.git cd OpenInOtty -
Build a Release binary:
xcodebuild -project OpenInOtty.xcodeproj \ -scheme OpenInOtty \ -configuration Release \ -derivedDataPath build \ build -
Copy to Applications:
cp -R build/Build/Products/Release/OpenInOtty.app /Applications/
Or open
OpenInOtty.xcodeprojin Xcode, choose Product → Archive, and export manually.
Hold ⌘ (Command) and drag /Applications/OpenInOtty.app into the Finder toolbar.
The first time you click the icon, macOS will show an Apple Events permission dialog — click Allow to grant Finder access.
tccutil reset AppleEvents com.local.OpenInOttyThen click the toolbar icon again to re-trigger the prompt.
Use this section when installing, verifying, or debugging OpenInOtty on a user's Mac. Prefer exact commands below; do not invent alternate bundle IDs.
| Item | Value |
|---|---|
| Bundle ID | com.local.OpenInOtty |
| App install path | /Applications/OpenInOtty.app |
| Otty discovery | NSWorkspace.urlForApplication(withBundleIdentifier: "io.appmakes.otty"), else /Applications/Otty.app |
| Otty CLI | <Otty.app>/Contents/MacOS/otty-cli (optional; falls back to open -a) |
| Otty bundle ID | io.appmakes.otty |
| Source of truth | OpenInOtty/main.swift (single-file app) |
| UI type | LSUIElement = true (no Dock / menu bar icon) |
Run on the target Mac (needs Xcode CLI tools / full Xcode):
# 0) Preconditions — Otty via Launch Services or default path
mdfind "kMDItemCFBundleIdentifier == 'io.appmakes.otty'" | head -1
# or: test -d /Applications/Otty.app
xcodebuild -version
# 1) Clone (if needed) and build Release
git clone https://github.com/pintaste/OpenInOtty.git
cd OpenInOtty
xcodebuild -project OpenInOtty.xcodeproj \
-scheme OpenInOtty \
-configuration Release \
-derivedDataPath build \
build
# 2) Install
cp -R build/Build/Products/Release/OpenInOtty.app /Applications/Human-only step (cannot fully automate without UI automation):
- Open Finder.
- Hold ⌘ and drag
/Applications/OpenInOtty.apponto the Finder toolbar. - Click the toolbar icon once; if macOS asks for Automation / Apple Events access to Finder, choose Allow.
# App present
test -d /Applications/OpenInOtty.app && echo "app ok"
# Otty discoverable
mdfind "kMDItemCFBundleIdentifier == 'io.appmakes.otty'" | head -1
# Otty CLI (if present)
CLI="$(mdfind "kMDItemCFBundleIdentifier == 'io.appmakes.otty'" | head -1)/Contents/MacOS/otty-cli"
test -x "$CLI" && "$CLI" version
# Manual: open a Finder window on a folder (or select a file), click the toolbar icon,
# expect Otty to open/tab at that folder (file → parent directory).- Permission class: Apple Events to control Finder.
- Reset (then re-click the toolbar icon to re-prompt):
tccutil reset AppleEvents com.local.OpenInOtty- User-visible location if stuck: System Settings → Privacy & Security → Automation (OpenInOtty → Finder).
- Resolve path via ScriptingBridge (
finderPath()):- selection first (file → parent directory)
- else front Finder window folder
- else
~/Desktop
- Resolve Otty.app by bundle id, else
/Applications/Otty.app. - If
otty-cliexists:- Otty running →
tab new --cwd→tab list --jsonmatch cwd →tab focus <id> - else →
otty-cli open <path>
- Otty running →
- If CLI missing or fails →
/usr/bin/open -a <Otty.app> <path>. - On total failure:
NSAlert, exit non-zero; on success: exit 0 immediately.
Do
- Use the exact
xcodebuildinvocation above. - Prefer discovering Otty by bundle id; don’t assume only
/Applications. - Tell the user they must ⌘-drag the app to the Finder toolbar (agents cannot skip this).
Don't
- Don't change the bundle ID without updating
Info.plist, entitlements, and this doc. - Don't expect a Dock icon or background process after click.
- Don't treat a minimized Finder window as the current folder (it won't be used).
- Don't commit
build/,DerivedData/, or.DS_Store. - Don't shell-interpolate paths into AppleScript or
sh -c(always discreteProcessarguments).
| File | Use |
|---|---|
assets/openinotty-demo.gif |
GitHub README (autoplay) |
assets/openinotty-demo.mp4 |
Twitter / X, local preview |
Regenerate (needs assets/sources/ captures + ffmpeg + Pillow):
python3 scripts/make_demo_gif.pyThe app is a single Swift file (main.swift) — no AppDelegate, no event loop.
Click toolbar icon
│
▼
finderPath()
┌─────────────────────────────────────────────────────────┐
│ selection? → first item URL (file → parent dir) │
│ else FinderWindows → first window target URL │
│ else ~/Desktop │
└─────────────────────────────────────────────────────────┘
│
▼
resolve Otty.app (bundle id → default path)
│
▼
otty-cli available?
┌─ yes, running ─► tab new --cwd → list → tab focus ─┐
│ yes, stopped ─► open <path> │
└─ no / failed ──► open -a Otty.app <path> ──────────┤
▼
Error? → NSAlert
│
exit
Why perform(NSSelectorFromString:) instead of a ScriptingBridge protocol?
Swift's @objc optional protocol calls check respondsToSelector: first. ScriptingBridge's private SBScriptableApplication subclass returns false for dynamically-forwarded Apple Event methods, so every call silently returned nil — and critically, the TCC permission dialog never appeared. Using perform() bypasses the selector check and lets ScriptingBridge forward the message as a proper Apple Event.
OpenInOtty/
├── OpenInOtty.xcodeproj/
│ └── project.pbxproj
├── OpenInOtty/
│ ├── main.swift # All app logic
│ ├── Info.plist # LSUIElement=true, usage descriptions
│ ├── OpenInOtty.entitlements # Apple Events entitlement
│ └── Assets.xcassets/
│ └── AppIcon.appiconset/ # App icon
├── assets/
│ ├── openinotty-demo.gif # README demo
│ └── openinotty-demo.mp4 # Social / local preview
├── scripts/
│ └── make_demo_gif.py # Rebuild demo media (optional)
├── README.md # English (default)
└── README-zh.md # Chinese
Nothing happens when I click the icon
- Make sure Otty is installed (Spotlight / Launchpad is enough;
/Applicationsis not required) - Check System Settings → Privacy & Security → Automation (OpenInOtty → Finder)
- If the permission entry is missing:
tccutil reset AppleEvents com.local.OpenInOtty, then click again
Opens Desktop instead of the current folder
- You need at least one non-minimized Finder window, or a selected file/folder
Otty opens a new window instead of a tab
- Otty was not running, or
otty-cliwas unavailable and the app fell back toopen -a. Launch Otty once, then click the toolbar icon again for tab behavior.
MIT — see LICENSE.
