andygeek/blackholes

2

stars

7

commits

Rust

primary language

Sep 8, 2026

updated

blackholes.dev/

README

Blackholes

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.

Installing the desktop app

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:

  • Link existing (default): create symbolic links directly in the project root, without a 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.
  • Copy into project: copy Git history and the actual working files, including staged/unstaged changes, untracked files, ignored .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.

Build and run

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.

What you can do

  • Organize projects with one or more Git repositories.
  • Create tasks with separate branches and worktrees for selected repositories.
  • Chat with persistent global, project, or task agents using Claude, Codex, Gemini, or OpenCode.
  • Configure agent providers, authentication, permissions, skills, and MCP servers.
  • Browse and edit files, inspect Git diffs, and search with Cmd+O and Cmd+P.
  • Write project/task notes with BlockNote, synchronized to Markdown for agents.
  • Run native terminals with tabs, splits, scrollback, and session restoration.

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.

Terminal agent permissions

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.

AgentLaunch flagReference
Claude Code--dangerously-skip-permissionsCLI reference
Codex--dangerously-bypass-approvals-and-sandboxCLI reference
Antigravity (agy)--dangerously-skip-permissionsUsing the CLI
OpenCode--autoCLI reference
Gemini--approval-mode=yoloCLI 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.

Architecture

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
  • UI: three independent React roots handle navigation, the central workspace, and quick open. HTML and production bundles are embedded in the application; the UI needs no web server.
  • Terminal: portable-pty runs the shell, alacritty_terminal interprets terminal output, and GPUI draws it. Terminal bytes never pass through React or xterm.js.
  • Agents: Rust starts and controls a local Node process. Provider adapters return streaming text, tool activity, process status, and results.
  • MCP: the same Rust executable runs as a STDIO MCP server with the 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.

Agent providers

ProviderIntegration
ClaudeClaude Agent SDK
CodexCodex app-server --stdio over JSON-RPC
GeminiGemini CLI with ACP over STDIO
OpenCodeOpenCode 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.

Source map

LocationResponsibility
src/main.rs, src/ui/app.rsApplication startup, state, navigation, and UI coordination
src/services/Projects, Git tasks, files, notes, persistence, agents, skills, and MCP settings
src/ui/terminal.rsNative 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.rsLocal 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.

Local data

Application data lives in the macOS Application Support directory resolved by src/paths.rs.

StorageContents
blackholes-local.dbSQLite WAL database for projects, tasks, settings, and events
app-session.jsonSaved UI layout and terminal session metadata
orchestrator-chat.jsonAgent 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.

Connect external AI clients

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.

Further reading

Community and sustainability

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.

Contributors

andygeek

7 commits

andygeek/blackholes

2

stars

7

commits

Rust

primary language

Sep 8, 2026

updated

blackholes.dev/

README

Blackholes

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.

Installing the desktop app

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:

  • Link existing (default): create symbolic links directly in the project root, without a 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.
  • Copy into project: copy Git history and the actual working files, including staged/unstaged changes, untracked files, ignored .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.

Build and run

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.

What you can do

  • Organize projects with one or more Git repositories.
  • Create tasks with separate branches and worktrees for selected repositories.
  • Chat with persistent global, project, or task agents using Claude, Codex, Gemini, or OpenCode.
  • Configure agent providers, authentication, permissions, skills, and MCP servers.
  • Browse and edit files, inspect Git diffs, and search with Cmd+O and Cmd+P.
  • Write project/task notes with BlockNote, synchronized to Markdown for agents.
  • Run native terminals with tabs, splits, scrollback, and session restoration.

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.

Terminal agent permissions

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.

AgentLaunch flagReference
Claude Code--dangerously-skip-permissionsCLI reference
Codex--dangerously-bypass-approvals-and-sandboxCLI reference
Antigravity (agy)--dangerously-skip-permissionsUsing the CLI
OpenCode--autoCLI reference
Gemini--approval-mode=yoloCLI 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.

Architecture

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
  • UI: three independent React roots handle navigation, the central workspace, and quick open. HTML and production bundles are embedded in the application; the UI needs no web server.
  • Terminal: portable-pty runs the shell, alacritty_terminal interprets terminal output, and GPUI draws it. Terminal bytes never pass through React or xterm.js.
  • Agents: Rust starts and controls a local Node process. Provider adapters return streaming text, tool activity, process status, and results.
  • MCP: the same Rust executable runs as a STDIO MCP server with the 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.

Agent providers

ProviderIntegration
ClaudeClaude Agent SDK
CodexCodex app-server --stdio over JSON-RPC
GeminiGemini CLI with ACP over STDIO
OpenCodeOpenCode 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.

Source map

LocationResponsibility
src/main.rs, src/ui/app.rsApplication startup, state, navigation, and UI coordination
src/services/Projects, Git tasks, files, notes, persistence, agents, skills, and MCP settings
src/ui/terminal.rsNative 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.rsLocal 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.

Local data

Application data lives in the macOS Application Support directory resolved by src/paths.rs.

StorageContents
blackholes-local.dbSQLite WAL database for projects, tasks, settings, and events
app-session.jsonSaved UI layout and terminal session metadata
orchestrator-chat.jsonAgent 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.

Connect external AI clients

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.

Further reading

Community and sustainability

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.

Contributors

andygeek

7 commits

Languages

Rust

71.0%

TypeScript

15.2%

CSS

7.4%

JavaScript

5.3%