Icons zentral unter ~/.config/ai-control/icons (pool-/repo-unabhängig), nicht ladbares Icon crasht den Tray nicht mehr; Arbeitsordner nachträglich im ⚙︎-Dialog erfassbar (additionalDirectories + Edit-Permission); Import-Button umbenannt; claudeCommand konfigurierbar + CLAUDE_CONFIG_DIR aus Pool; Pool-Tabellen-Layout; README englisch mit Screenshots; MIT-Lizenz

This commit is contained in:
marcus.hinz
2026-07-05 15:19:58 +02:00
parent b5995da755
commit 0908385a9d
14 changed files with 329 additions and 83 deletions
+68 -39
View File
@@ -1,73 +1,102 @@
# ai-control
Pool- und Session-Verwaltung für [Claude Code](https://claude.com/claude-code) auf macOS — als Tray-App mit eingebautem Terminal. Linux- und Windows-Integration folgen.
Pool and session management for [Claude Code](https://claude.com/claude-code) on macOS — a tray app with a built-in terminal. Linux and Windows integration to follow.
> Der gesamte Code dieses Projekts wurde von Claude (Claude Code) generiert.
> All code in this project was generated by Claude (Claude Code).
## Zweck
<img src="docs/projects.png" width="640" alt="Projects">
Wer Claude Code mit mehreren Accounts bzw. Credential-Sets betreibt, muss pro Session das richtige `CLAUDE_CONFIG_DIR` samt Keychain-Eintrag treffen. ai-control macht daraus Klicks:
## Purpose
- **Pools** — benannte Credential-Sets (OAuth-Login oder API-Key) unter `~/.config/ai-control/pools/<pool>`. Jeder Pool ist ein eigenständiges Claude-Config-Verzeichnis mit eigenem Keychain-Eintrag.
- **Projekte** — beliebige Verzeichnisse, gemappt über eine Registry (`~/.config/ai-control/projects.json`, Name → Pfad; Home-Pfade als `~/…` und damit maschinenübergreifend stabil). Jedem Projekt ist ein Pool zugeordnet; dazu Terminal-Einstellungen (Theme, Icon, Fenstertitel).
- **Sessions** — pro Projekt ein eingebautes Terminal (xterm.js + PTY), das Claude Code mit der Pool-Umgebung startet. Jedes Terminal läuft als eigener Prozess mit eigenem Dock-Icon und Cmd-Tab-Eintrag.
- **Tray** — die App selbst ist eine reine Menüleisten-App ohne Dock-Eintrag. Das Tray-Menü listet alle Projekte mit Icon und Status-Punkt (grün = läuft); Klick startet das Projekt oder holt das laufende Terminal nach vorn.
- **Session-Watcher** — erkennt das Ende einer Session über das Verschwinden des Terminal-Prozesses und synct dann (opt-in) das Git-Repo, in dem das Projekt liegt: add → commit → pull --rebase → push.
Running Claude Code with multiple accounts or credential sets means hitting the right `CLAUDE_CONFIG_DIR` (plus keychain entry) for every session. ai-control turns that into clicks:
## Projektaufbau
- **Pools** — named credential sets (OAuth login or API key) under `~/.config/ai-control/pools/<pool>`. Each pool is a self-contained Claude config directory with its own keychain entry.
- **Projects** — arbitrary directories, mapped through a registry (`~/.config/ai-control/projects.json`, name → path; paths under home are stored as `~/…` and therefore stable across machines). Each project is assigned a pool, plus terminal settings (theme, icon, window title).
- **Sessions** — a built-in terminal per project (xterm.js + PTY) that launches Claude Code with the pool's config directory as `CLAUDE_CONFIG_DIR`. Every terminal runs as its own process with its own Dock icon and Cmd-Tab entry.
- **Tray** — the app itself is a pure menu-bar app without a Dock entry. The tray menu lists all projects with icon and status dot (green = running); clicking starts the project or brings the running terminal to the front.
- **Session watcher** — detects the end of a session by the terminal process disappearing and then (opt-in) syncs the Git repository containing the project: add → commit → pull --rebase → push.
## Screenshots
| Pools | Usage |
|---|---|
| ![Pools](docs/pools.png) | ![Usage](docs/usage.png) |
| Tray menu | Session terminal |
|---|---|
| ![Tray menu](docs/tray.png) | ![Session terminal](docs/terminal.png) |
## Project layout
```
├── index.html Haupt-UI (Projekt-/Pool-Verwaltung)
├── terminal.html Terminal-Fenster (xterm.js)
├── src/ Frontend: Vue 3 + TypeScript
├── index.html main UI (project/pool management)
├── terminal.html terminal window (xterm.js)
├── src/ frontend: Vue 3 + TypeScript
├── src-tauri/
│ ├── src/lib.rs Tauri-Commands: Projekte, Pools, Keychain,
│ │ OAuth-Login, Tray-Menü, Session-Watcher
│ ├── src/terminal.rs PTY-Sessions (portable-pty), Terminal-Fenster,
│ │ Dock-Icon, Fokussieren laufender Terminals
│ └── icons/ App- und Tray-Icons
├── dev.sh Entwicklungsmodus (tauri dev)
└── build.sh Release-Build (.app-Bundle)
│ ├── src/lib.rs Tauri commands: projects, pools, keychain,
│ │ OAuth login, tray menu, session watcher
│ ├── src/terminal.rs PTY sessions (portable-pty), terminal windows,
│ │ Dock icon, focusing running terminals
│ └── icons/ app and tray icons
├── dev.sh development mode (tauri dev)
└── build.sh release build (.app bundle)
```
Zwei Prozessrollen aus einem Binary:
Two process roles from one binary:
- **Haupt-App** (`ai-control`) — Tray, Hauptfenster, Verwaltung, Watcher.
- **Terminal-Prozess** (`ai-control --terminal <projekt>`) — ein Fenster mit eigener PTY; startet Claude Code im Projektverzeichnis mit `CLAUDE_CONFIG_DIR` des zugeordneten Pools.
- **Main app** (`ai-control`) — tray, main window, management, watcher.
- **Terminal process** (`ai-control --terminal <project>`) — one window with its own PTY; launches Claude Code in the project directory with the assigned pool's `CLAUDE_CONFIG_DIR`.
Laufende Projekte werden über die Terminal-Prozesse erkannt (`pgrep` auf `--terminal <projekt>`), ohne Zustandsdatei.
Running projects are detected through their terminal processes (`pgrep` for `--terminal <project>`), without a state file.
## Tooling
| Bereich | Stack |
| Area | Stack |
|-----------|-------|
| Shell | Tauri 2 (Rust) |
| Frontend | Vue 3, TypeScript, Vite |
| Terminal | xterm.js, portable-pty |
| macOS | objc2 / objc2-app-kit (Dock-Icon, Fenster-Fokus, Tray) |
| macOS | objc2 / objc2-app-kit (Dock icon, window focus, tray) |
| Secrets | keyring (macOS Keychain) |
## Entwicklung
## Development
```sh
./dev.sh # tauri dev mit Hot-Reload
./build.sh # Release-Build; Bundle landet in src-tauri/target/release/bundle/macos.noindex/
./dev.sh # tauri dev with hot reload
./build.sh # release build; bundle lands in src-tauri/target/release/bundle/macos.noindex/
```
`build.sh` verschiebt das Bundle in ein `.noindex`-Verzeichnis und trägt es aus Launch Services aus, damit Spotlight nur die installierte Kopie findet. Installation: `ai-control.app` nach `~/Applications` kopieren.
`build.sh` moves the bundle into a `.noindex` directory and unregisters it from Launch Services so Spotlight only finds the installed copy. Install by copying `ai-control.app` to `~/Applications`.
Voraussetzungen: Rust (stable), Node.js/npm, macOS. `dev.sh`/`build.sh` erwarten `CARGO_HOME`/`RUSTUP_HOME` unter `~/tools/`bei Standard-Installation die beiden Exporte in den Skripten anpassen.
Prerequisites: Rust (stable), Node.js/npm, macOS. `dev.sh`/`build.sh` expect `CARGO_HOME`/`RUSTUP_HOME` under `~/tools/`adjust the two exports in the scripts for a standard installation.
## Konfigurationslayout
## Configuration layout
```
~/.config/ai-control/
├── settings.json App-Einstellungen (z. B. syncOnSessionEnd)
├── projects.json Projekt-Registry: Name → Ordner
└── pools/<pool>/ je Pool ein Claude-Config-Verzeichnis
└── pool.json Name + Credential-Typ
├── settings.json app settings (see below)
├── projects.json project registry: name → directory
└── pools/<pool>/ one Claude config directory per pool
└── pool.json name + credential type
<projektordner>/ beliebiger Pfad, per Registry gemappt
├── .claude/ Claude-Code-Projektkonfiguration
└── ai-control.json Pool-Zuordnung + Terminal-Einstellungen
<project directory>/ any path, mapped via the registry
├── .claude/ Claude Code project configuration
└── ai-control.json pool assignment + terminal settings
```
### settings.json
| Key | Default | Meaning |
|--------------------|----------|---------|
| `claudeCommand` | `claude` | Command launched in the project terminal (via `zsh -ic`, so your `.zshrc` PATH applies). |
| `syncOnSessionEnd` | `false` | After a session ends, commit and push the Git repository containing the project. |
## Claude and Anthropic licensing
ai-control is pool management only — it does not change, extend, or circumvent Anthropic's licensing in any way. Using Claude Code through ai-control is subject to the same Anthropic terms as running it directly.
For that reason the app stores no OAuth tokens itself: with an OAuth pool, the first session of a project on that pool goes through the regular Anthropic login (`/login`, browser, against your subscription), run by Claude Code itself. Credentials live where Claude Code puts them — in the macOS keychain, one entry per pool.
## License
[MIT](LICENSE)