A macOS desktop workspace for coding agents, Git repositories, isolated tasks, and native terminals.
Documentation status: Work in progress.
Version: 0.1.6. Blackholes' original source code is licensed under MPL-2.0; dependencies and third-party assets retain their own licenses.
Packaged releases include Node.js, npm/npx, and the supported agent runtimes. No global Node or provider CLI installation is required. Connect your own provider account in Settings → Accounts. Models, MCPs, and Usage follow that selection; plan limits are queried for the selected account, while local token/cost totals are grouped by provider. Unsupported plan-limit queries are shown as unavailable.
On a Mac without Apple's Git command-line tools, Blackholes opens setup settings with an installation button. Apple's installer requires user confirmation; the app does not silently modify the system. Project-specific dependencies such as Docker, language toolchains, or build SDKs remain requirements of the user's repositories.
New projects live under ~/Blackholes_projects by default. Each project is a
container for repositories, project skills, CLAUDE.md, AGENTS.md, and notes.
Project creation offers two modes for local repositories:
repos/ wrapper or moving/copying the originals. These links
work in Finder, terminals and coding agents without Blackholes or its MCP.
Existing environments and pending changes remain available.
Subsequent edits affect the original repositories; this is not isolation..env files, and installed
dependencies. Preserve the index and local Git excludes without copying Git
hooks or linking Git storage to the original. Symbolic links remain links and
may refer outside the copy. Stop processes that write into the source before
copying; special files such as sockets are rejected rather than silently lost.
This is a filesystem copy, not a portable replacement for external databases,
containers, system dependencies, or machine-specific absolute paths.GitHub imports always clone into a child repository folder. Selected project
skills and instructions apply to linked repositories as well as managed copies;
the project context stays in the container, not in the linked originals.
Use Add repository in the project's + menu for the same local link/copy
options or GitHub imports. A repository's … menu offers removal with an explicit
confirmation and the exact affected path. Removing a link preserves the original;
removing a managed repository moves its full folder to Trash (including uncommitted
changes and environment files). Emptying Trash permanently deletes those data.
Close project terminals and finish active agents first; repositories used by tasks
or other projects and project root folders are protected. Existing project paths and custom project-root settings are
preserved; changing the default is not a migration of previous workspaces.
Create a project by naming it and selecting the repositories to include. Add a local repository or a folder containing repositories, review the detected list, and repeat to add sources from other locations. GitHub URLs can be added one at a time to the same list. Only selected repositories are added; an empty selection creates an empty project container. The same project form is used over native terminals and other workspace views without closing terminal sessions. The compact form reveals GitHub input on demand and keeps location details collapsed. Existing database-only links are materialized when project context is prepared on startup. Existing files and conflicting links are never overwritten.
Terminal rows use the detected provider's icon. They do not show persistent loading dots or green presence badges; launching or focusing a CLI alone is not treated as submitting an agent turn.
The Agents section combines built-in bots and terminal agents. Press and hold a
card by its icon or title, then drag to reorder the mixed list. The cursor changes
only once the hold activates reordering; the insertion marker and edge
scrolling help with long lists. Keyboard users can focus a card and use
Option+Up / Option+Down. The order survives app restarts and does not change
project/task ownership or the project tree.
Closing a terminal agent from Agents, the project tree or its terminal pane requires confirmation. It stops the terminal and removes it from session restoration, without deleting repository files or provider-saved conversations. Removing a built-in bot confirms deletion of its Blackholes conversation history. Both confirmations use the shared modal with the sidebar visible beneath its dimmed, blurred backdrop, including when a native terminal is active. Editing a project's visible name, icon and color uses that same shared modal, preserving the sidebar and current workspace beneath the backdrop. Appearance changes are saved only on confirmation; repository and folder names stay unchanged.
Cmd+O searches projects, tasks, built-in agents and terminal sessions (including
plain shells). Search by agent/provider name, terminal title, project, task or
repository context. Agent and terminal results open the existing session rather
than creating a duplicate; project and task results still open their notes.
The palette accounts for the sidebar when centering and adapts to narrow windows.
Requires macOS 13+, Node.js 20.19+, Git, and the stable Rust toolchain configured in rust-toolchain.toml.
./scripts/build-release
./target/release/blackholes-rust
The build script generates the React bundles for the three WebViews and the lazy-loaded editor, installs missing frontend and agent-runtime dependencies, and compiles the release binaries. It does not launch the application. Use this script for release builds so Rust embeds the current frontend assets.
On macOS it also downloads the pinned, checksum-verified Sparkle framework into
target/ for the native updater bridge. Bare development executables cannot
self-update. Signed .app releases show a title-bar update button and use GitHub
Release assets; see Releasing and updates for packaging,
signing, notarization, and publishing prerequisites. Public downloads are not
available until the maintainer publishes them.
On macOS, the red window button hides Blackholes without discarding its live agents, terminals, or unsaved window state. Click the Dock icon to show the same window again. Quitting the application is separate from hiding its window.
Cmd+O and Cmd+P.Worktrees separate working files and branches. They are not containers or security sandboxes. The file workspace provides focused editing and diffs, not a full IDE or language-server environment.
In Project settings → Terminals, enable Start agents without permission prompts to opt in for that project and its tasks. It is off by default and saved locally per project. Blackholes reads it whenever it starts or restores a terminal agent, including after quitting and reopening the app. Existing Claude/Codex session IDs and profiles are preserved.
| Agent | Launch flag | Reference |
|---|---|---|
| Claude Code | --dangerously-skip-permissions | CLI reference |
| Codex | --dangerously-bypass-approvals-and-sandbox | CLI reference |
Antigravity (agy) | --dangerously-skip-permissions | Using the CLI |
| OpenCode | --auto | CLI reference |
| Gemini | --approval-mode=yolo | CLI reference |
Use only with trusted projects: this allows file changes and commands without confirmation. Codex also disables its sandbox; OpenCode preserves explicit deny rules. This does not change running agents, built-in bots, manually typed commands, or provider configuration files. Turning it off stops Blackholes from adding bypass flags on subsequent launches; the provider's own settings still apply. It does not add new session-resume support to providers.
Rust owns application state, local operations, and processes. React renders the visual workspace inside the system's WebKit. Terminals have a separate native rendering path.
flowchart TD
UI["React / WebKit: navigation, workspace, quick open"] <-->|JSON commands and events| App["Rust / GPUI application"]
App --> Services["Rust services: projects, tasks, files, notes, settings"]
Services --> Data["SQLite, JSON files, Git worktrees"]
App --> Terminal["Native terminal: GPUI + Alacritty + PTY"]
App <-->|STDIO / JSONL| Node["Node process: provider adapters"]
Node --> Providers["Claude, Codex, Gemini, OpenCode"]
Providers <-->|STDIO| MCP["Blackholes MCP"]
MCP --> Services
MCP -->|Local event socket| App
portable-pty runs the shell, alacritty_terminal interprets terminal output, and GPUI draws it. Terminal bytes never pass through React or xterm.js.mcp argument. It exposes project/task management, notes, navigation, agent handoffs, and completion notifications.The UI has no localhost server. OpenCode's runtime is an exception elsewhere in the application: its SDK starts a local HTTP server for agent execution.
| Provider | Integration |
|---|---|
| Claude | Claude Agent SDK |
| Codex | Codex app-server --stdio over JSON-RPC |
| Gemini | Gemini CLI with ACP over STDIO |
| OpenCode | OpenCode SDK with a local server and event stream |
Mercury, Earthy, and Saturny are agent identities, independent of the selected provider. Persistence means the conversation and provider session references are saved; it does not mean an agent process runs forever.
Agents check the Blackholes MCP and resolve the intended project before working. Global and project agents can inspect and change repositories directly: tasks and worktrees are optional. Isolation is used when the user chooses it, selects a task, or their project instructions require it. Task work stays in the attached worktrees. Optional delegation uses handoff_to_agent with a project or task ID. Internal provider subagents and invisible background commands are discouraged by shared instructions, with provider-specific enforcement. Long-lived processes belong in visible terminals.
Authentication can use the system profile or an isolated Blackholes profile per provider. Runtime capabilities differ: the chat's immediate message-redirection path currently applies to Claude; other providers use the app's pending-message queue.
| Location | Responsibility |
|---|---|
src/main.rs, src/ui/app.rs | Application startup, state, navigation, and UI coordination |
src/services/ | Projects, Git tasks, files, notes, persistence, agents, skills, and MCP settings |
src/ui/terminal.rs | Native terminal input and rendering |
frontend/src/ | React navigation, workspace, quick open, and shared components |
agent-sidecar/ | Node entry point and provider adapters |
src/bin/blackholes-mcp.rs | Local MCP server |
The application coordinator is large, and some native rendering code remains alongside React surfaces. Workflow instructions live in the shared runtime prompt, MCP guidance, and generated project context; keep these aligned when changing agent behavior. Startup updates known legacy task-only rules in managed project instruction blocks while preserving custom text.
Application data lives in the macOS Application Support directory resolved by src/paths.rs.
| Storage | Contents |
|---|---|
blackholes-local.db | SQLite WAL database for projects, tasks, settings, and events |
app-session.json | Saved UI layout and terminal session metadata |
orchestrator-chat.json | Agent identities, conversations, and session references |
task-workspaces/ | Task worktrees |
agent-profiles/, blackholes-skills/ | Isolated provider profiles and managed skills |
Project/task notes use Markdown with a rich-block JSON sidecar. Terminal output is not stored in SQLite.
The in-app agents receive the built-in MCP automatically. To register it and its routing skill in detected external Codex and Claude Code profiles:
./scripts/install-ai-integrations
./scripts/install-ai-integrations status
Restart the external client session after installation. The installer supports --codex, --claude, --codex-home PATH, --claude-home PATH, --binary PATH, and uninstall. It honors custom profile locations and manages only its own registrations and skill files.
Blackholes is an independently maintained project. Bug reports, documentation, design feedback, and code contributions are welcome. Read CONTRIBUTING.md before submitting a pull request. Contributions require a Developer Certificate of Origin sign-off and are voluntary unless a separate written agreement provides otherwise. Contributing does not grant equity, royalties, revenue sharing, or repository administration rights.
Commercial use is allowed by MPL-2.0. The project may be supported through sponsorships, paid support, integrations, or separate commercial services. These are possible funding models, not promises of currently available plans. Commercial offerings do not remove the rights granted for existing MPL-covered code or transfer contributors' copyright to the maintainer.
See LICENSING.md for the scope of the license and THIRD_PARTY_NOTICES.md for dependency notices.
7 commits
Rust
71.0%
TypeScript
15.2%
CSS
7.4%
JavaScript
5.3%
A macOS desktop workspace for coding agents, Git repositories, isolated tasks, and native terminals.
Documentation status: Work in progress.
Version: 0.1.6. Blackholes' original source code is licensed under MPL-2.0; dependencies and third-party assets retain their own licenses.
Packaged releases include Node.js, npm/npx, and the supported agent runtimes. No global Node or provider CLI installation is required. Connect your own provider account in Settings → Accounts. Models, MCPs, and Usage follow that selection; plan limits are queried for the selected account, while local token/cost totals are grouped by provider. Unsupported plan-limit queries are shown as unavailable.
On a Mac without Apple's Git command-line tools, Blackholes opens setup settings with an installation button. Apple's installer requires user confirmation; the app does not silently modify the system. Project-specific dependencies such as Docker, language toolchains, or build SDKs remain requirements of the user's repositories.
New projects live under ~/Blackholes_projects by default. Each project is a
container for repositories, project skills, CLAUDE.md, AGENTS.md, and notes.
Project creation offers two modes for local repositories:
repos/ wrapper or moving/copying the originals. These links
work in Finder, terminals and coding agents without Blackholes or its MCP.
Existing environments and pending changes remain available.
Subsequent edits affect the original repositories; this is not isolation..env files, and installed
dependencies. Preserve the index and local Git excludes without copying Git
hooks or linking Git storage to the original. Symbolic links remain links and
may refer outside the copy. Stop processes that write into the source before
copying; special files such as sockets are rejected rather than silently lost.
This is a filesystem copy, not a portable replacement for external databases,
containers, system dependencies, or machine-specific absolute paths.GitHub imports always clone into a child repository folder. Selected project
skills and instructions apply to linked repositories as well as managed copies;
the project context stays in the container, not in the linked originals.
Use Add repository in the project's + menu for the same local link/copy
options or GitHub imports. A repository's … menu offers removal with an explicit
confirmation and the exact affected path. Removing a link preserves the original;
removing a managed repository moves its full folder to Trash (including uncommitted
changes and environment files). Emptying Trash permanently deletes those data.
Close project terminals and finish active agents first; repositories used by tasks
or other projects and project root folders are protected. Existing project paths and custom project-root settings are
preserved; changing the default is not a migration of previous workspaces.
Create a project by naming it and selecting the repositories to include. Add a local repository or a folder containing repositories, review the detected list, and repeat to add sources from other locations. GitHub URLs can be added one at a time to the same list. Only selected repositories are added; an empty selection creates an empty project container. The same project form is used over native terminals and other workspace views without closing terminal sessions. The compact form reveals GitHub input on demand and keeps location details collapsed. Existing database-only links are materialized when project context is prepared on startup. Existing files and conflicting links are never overwritten.
Terminal rows use the detected provider's icon. They do not show persistent loading dots or green presence badges; launching or focusing a CLI alone is not treated as submitting an agent turn.
The Agents section combines built-in bots and terminal agents. Press and hold a
card by its icon or title, then drag to reorder the mixed list. The cursor changes
only once the hold activates reordering; the insertion marker and edge
scrolling help with long lists. Keyboard users can focus a card and use
Option+Up / Option+Down. The order survives app restarts and does not change
project/task ownership or the project tree.
Closing a terminal agent from Agents, the project tree or its terminal pane requires confirmation. It stops the terminal and removes it from session restoration, without deleting repository files or provider-saved conversations. Removing a built-in bot confirms deletion of its Blackholes conversation history. Both confirmations use the shared modal with the sidebar visible beneath its dimmed, blurred backdrop, including when a native terminal is active. Editing a project's visible name, icon and color uses that same shared modal, preserving the sidebar and current workspace beneath the backdrop. Appearance changes are saved only on confirmation; repository and folder names stay unchanged.
Cmd+O searches projects, tasks, built-in agents and terminal sessions (including
plain shells). Search by agent/provider name, terminal title, project, task or
repository context. Agent and terminal results open the existing session rather
than creating a duplicate; project and task results still open their notes.
The palette accounts for the sidebar when centering and adapts to narrow windows.
Requires macOS 13+, Node.js 20.19+, Git, and the stable Rust toolchain configured in rust-toolchain.toml.
./scripts/build-release
./target/release/blackholes-rust
The build script generates the React bundles for the three WebViews and the lazy-loaded editor, installs missing frontend and agent-runtime dependencies, and compiles the release binaries. It does not launch the application. Use this script for release builds so Rust embeds the current frontend assets.
On macOS it also downloads the pinned, checksum-verified Sparkle framework into
target/ for the native updater bridge. Bare development executables cannot
self-update. Signed .app releases show a title-bar update button and use GitHub
Release assets; see Releasing and updates for packaging,
signing, notarization, and publishing prerequisites. Public downloads are not
available until the maintainer publishes them.
On macOS, the red window button hides Blackholes without discarding its live agents, terminals, or unsaved window state. Click the Dock icon to show the same window again. Quitting the application is separate from hiding its window.
Cmd+O and Cmd+P.Worktrees separate working files and branches. They are not containers or security sandboxes. The file workspace provides focused editing and diffs, not a full IDE or language-server environment.
In Project settings → Terminals, enable Start agents without permission prompts to opt in for that project and its tasks. It is off by default and saved locally per project. Blackholes reads it whenever it starts or restores a terminal agent, including after quitting and reopening the app. Existing Claude/Codex session IDs and profiles are preserved.
| Agent | Launch flag | Reference |
|---|---|---|
| Claude Code | --dangerously-skip-permissions | CLI reference |
| Codex | --dangerously-bypass-approvals-and-sandbox | CLI reference |
Antigravity (agy) | --dangerously-skip-permissions | Using the CLI |
| OpenCode | --auto | CLI reference |
| Gemini | --approval-mode=yolo | CLI reference |
Use only with trusted projects: this allows file changes and commands without confirmation. Codex also disables its sandbox; OpenCode preserves explicit deny rules. This does not change running agents, built-in bots, manually typed commands, or provider configuration files. Turning it off stops Blackholes from adding bypass flags on subsequent launches; the provider's own settings still apply. It does not add new session-resume support to providers.
Rust owns application state, local operations, and processes. React renders the visual workspace inside the system's WebKit. Terminals have a separate native rendering path.
flowchart TD
UI["React / WebKit: navigation, workspace, quick open"] <-->|JSON commands and events| App["Rust / GPUI application"]
App --> Services["Rust services: projects, tasks, files, notes, settings"]
Services --> Data["SQLite, JSON files, Git worktrees"]
App --> Terminal["Native terminal: GPUI + Alacritty + PTY"]
App <-->|STDIO / JSONL| Node["Node process: provider adapters"]
Node --> Providers["Claude, Codex, Gemini, OpenCode"]
Providers <-->|STDIO| MCP["Blackholes MCP"]
MCP --> Services
MCP -->|Local event socket| App
portable-pty runs the shell, alacritty_terminal interprets terminal output, and GPUI draws it. Terminal bytes never pass through React or xterm.js.mcp argument. It exposes project/task management, notes, navigation, agent handoffs, and completion notifications.The UI has no localhost server. OpenCode's runtime is an exception elsewhere in the application: its SDK starts a local HTTP server for agent execution.
| Provider | Integration |
|---|---|
| Claude | Claude Agent SDK |
| Codex | Codex app-server --stdio over JSON-RPC |
| Gemini | Gemini CLI with ACP over STDIO |
| OpenCode | OpenCode SDK with a local server and event stream |
Mercury, Earthy, and Saturny are agent identities, independent of the selected provider. Persistence means the conversation and provider session references are saved; it does not mean an agent process runs forever.
Agents check the Blackholes MCP and resolve the intended project before working. Global and project agents can inspect and change repositories directly: tasks and worktrees are optional. Isolation is used when the user chooses it, selects a task, or their project instructions require it. Task work stays in the attached worktrees. Optional delegation uses handoff_to_agent with a project or task ID. Internal provider subagents and invisible background commands are discouraged by shared instructions, with provider-specific enforcement. Long-lived processes belong in visible terminals.
Authentication can use the system profile or an isolated Blackholes profile per provider. Runtime capabilities differ: the chat's immediate message-redirection path currently applies to Claude; other providers use the app's pending-message queue.
| Location | Responsibility |
|---|---|
src/main.rs, src/ui/app.rs | Application startup, state, navigation, and UI coordination |
src/services/ | Projects, Git tasks, files, notes, persistence, agents, skills, and MCP settings |
src/ui/terminal.rs | Native terminal input and rendering |
frontend/src/ | React navigation, workspace, quick open, and shared components |
agent-sidecar/ | Node entry point and provider adapters |
src/bin/blackholes-mcp.rs | Local MCP server |
The application coordinator is large, and some native rendering code remains alongside React surfaces. Workflow instructions live in the shared runtime prompt, MCP guidance, and generated project context; keep these aligned when changing agent behavior. Startup updates known legacy task-only rules in managed project instruction blocks while preserving custom text.
Application data lives in the macOS Application Support directory resolved by src/paths.rs.
| Storage | Contents |
|---|---|
blackholes-local.db | SQLite WAL database for projects, tasks, settings, and events |
app-session.json | Saved UI layout and terminal session metadata |
orchestrator-chat.json | Agent identities, conversations, and session references |
task-workspaces/ | Task worktrees |
agent-profiles/, blackholes-skills/ | Isolated provider profiles and managed skills |
Project/task notes use Markdown with a rich-block JSON sidecar. Terminal output is not stored in SQLite.
The in-app agents receive the built-in MCP automatically. To register it and its routing skill in detected external Codex and Claude Code profiles:
./scripts/install-ai-integrations
./scripts/install-ai-integrations status
Restart the external client session after installation. The installer supports --codex, --claude, --codex-home PATH, --claude-home PATH, --binary PATH, and uninstall. It honors custom profile locations and manages only its own registrations and skill files.
Blackholes is an independently maintained project. Bug reports, documentation, design feedback, and code contributions are welcome. Read CONTRIBUTING.md before submitting a pull request. Contributions require a Developer Certificate of Origin sign-off and are voluntary unless a separate written agreement provides otherwise. Contributing does not grant equity, royalties, revenue sharing, or repository administration rights.
Commercial use is allowed by MPL-2.0. The project may be supported through sponsorships, paid support, integrations, or separate commercial services. These are possible funding models, not promises of currently available plans. Commercial offerings do not remove the rights granted for existing MPL-covered code or transfer contributors' copyright to the maintainer.
See LICENSING.md for the scope of the license and THIRD_PARTY_NOTICES.md for dependency notices.
7 commits
Rust
71.0%
TypeScript
15.2%
CSS
7.4%
JavaScript
5.3%