README überarbeitet: aiCentral-Branding, alle sechs MCP-Tools, UUID-Registry, Sicherheitsmodell (CSP/Capabilities), dreistufiges Projekt-Löschen, Build/Deploy-Stand, Installer-Teststand mit offenen X11-Befunden

This commit is contained in:
marcus hinz
2026-07-20 20:43:09 +02:00
parent cf2c25df79
commit e6226cfc9f
+56 -27
View File
@@ -1,6 +1,6 @@
# aICentral
# aiCentral
**Get Claude Code organized** — pool and session management for [Claude Code](https://claude.com/claude-code), as a tray app with a built-in terminal and a draft panel. macOS and Linux; Windows support follows soon. (Repository and binary name: `ai-control`.)
**Get Claude Code organized** — pool, project, and session management for [Claude Code](https://claude.com/claude-code), as a tray app with a built-in terminal, a draft panel, and a per-project document archive. macOS and Linux; Windows support follows. (Repository and binary name: `ai-control`.)
> All code in this project was generated by Claude (Claude Code).
@@ -8,23 +8,32 @@
## Purpose
Running Claude Code with multiple accounts or credential sets means hitting the right `CLAUDE_CONFIG_DIR` (plus keychain entry) for every session. aICentral turns that into clicks:
Running Claude Code with multiple accounts or credential sets means hitting the right `CLAUDE_CONFIG_DIR` (plus keychain entry) for every session. aiCentral turns that into clicks:
- **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).
- **Projects** — arbitrary directories carrying their own identity in `<project>/.ai-control/config.json` (UUID, display name, terminal settings, archive home — this file syncs with the project). The machine-local registry `~/.config/ai-control/projects.json` maps that UUID to the directory and the assigned pool; paths under home are stored as `~/…` and therefore stable across machines.
- **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 — on macOS with its own Dock icon and Cmd-Tab entry, on Linux as its own window with its own app id.
- **Tray** — the app itself is a pure tray app. Clicking the tray icon opens a popup listing all projects with icon and status dot (green = running); clicking a project starts it or brings the running terminal to the front.
- **Text panel** — a draft panel beside the terminal. Claude writes longer texts (ADRs, emails, commit messages, specs) into it through a bundled MCP tool instead of flooding the chat; the panel text is mouse-selectable, copyable via button, and archivable per project.
- **Text panel** — a workspace beside the terminal with four tabs: command tiles, the current draft, an archive wiki, and archive search. Claude writes into it through a bundled MCP server instead of flooding the chat.
- **Archive** — drafts can be archived as Markdown files into a per-project archive home, curated with folder, description, and tags at archiving time; browsable as a wiki and searchable via full-text search.
- **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.
## Text panel
## Text panel and MCP tools
The app ships an MCP stdio server (`ai-control --mcp-panel`, server key `text-panel`) and provisions it into every pool, including the tool permission — no per-pool setup:
The app ships an MCP stdio server (`ai-control --mcp-panel`, server key `text-panel`) and provisions it into every pool, including the tool permission — no per-pool setup. Six tools:
- **`write_panel`** — Claude places a Markdown draft in the panel next to the terminal instead of printing it as chat prose.
- **`archive_panel`** — saves the current draft as a Markdown file into the project's archive directory (`archiveHome` in the project's `.ai-control/config.json`).
| Tool | Purpose |
|---|---|
| `write_panel` | Place a Markdown draft in the panel instead of printing it as chat prose; accepts inline text or a file path (the server reads the file itself). |
| `write_commands` | List shell commands for the user as copyable tiles (command + optional note), appended to the session's command history. |
| `show_commands` | Show the command history (tile view). |
| `archive_panel` | Save the current draft as a Markdown file into the project's archive home; takes `folder`, `description`, `tags` for the frontmatter. |
| `show_archive` | Render the archive overview as a wiki page — documents grouped by folder, with descriptions and clickable tag links; with `tag`, that tag's page. |
| `search_archive` | FTS5 full-text search over the archive (words, "phrases", prefix*); hits appear as tiles in the panel. |
The panel docks into the terminal window and can be detached into its own window; the title is taken from the draft's first heading and can be edited, the content is editable too. Spell checking follows `spellcheckLang` (per-text override in the panel).
The panel docks into the terminal window and can be detached into its own window. The header tab bar switches between **Befehle** (command tiles), the current **document**, **Wiki**, and **Suche** (live search, `#tag` filtering); without a configured archive home the archive tabs stay hidden. The draft's title is taken from its first heading and is editable, as is the content. Spell checking follows `spellcheckLang` (per-text override in the panel).
The archive lives in the project's `archiveHome` (set in `.ai-control/config.json`); documents are plain Markdown files with frontmatter — no database, the search index is built in-memory per query.
## Screenshots
@@ -50,20 +59,34 @@ Or avoid the topic entirely and build from source (below) — self-built apps ar
### Linux
Releases carry a `.deb` and an AppImage.
Releases carry a `.deb`, an `.rpm`, and an AppImage.
- **deb** — recommended. It also installs the GNOME Shell extension and the KWin script that provide the tray/popup integration on GNOME and KDE Wayland.
- **AppImage** — runs on desktops with a standard tray (KDE, XFCE, Cinnamon). On GNOME it refuses to start and points to the deb: the tray there needs the shell extension, which an installation-free AppImage cannot provide.
- **deb / rpm** — recommended. Both also install the GNOME Shell extension and the KWin script that provide the tray/popup integration on GNOME and KDE Wayland (into `/usr/share/gnome-shell/extensions/` and `/usr/share/kwin/scripts/`).
- **AppImage** — runs on desktops with a standard tray (KDE, XFCE, Cinnamon). On GNOME it refuses to start and points to the deb/rpm: the tray there needs the shell extension, which an installation-free AppImage cannot provide.
Tray integration by desktop: GNOME via the bundled shell extension, KDE Wayland via StatusNotifierItem plus the bundled KWin script for popup placement, KDE X11/XFCE/Cinnamon via StatusNotifierItem directly.
### Installer tests
The installers are hand-tested per release. Current state: Ubuntu 26.04 (GNOME), Kubuntu (KDE Plasma, Wayland) and Linux Mint (Cinnamon) via deb — on Mint install through the graphical installer; macOS re-test of the current build is in progress.
The installers are hand-tested per release. Current state: Fedora 44 via rpm on GNOME, KDE Plasma, Cinnamon, and XFCE (VM test fleet); Ubuntu 26.04 (GNOME), Kubuntu (KDE Plasma, Wayland) and Linux Mint (Cinnamon) via deb in earlier rounds. Two known issues from the current round are open: on Cinnamon the tray popup opens at the top-left corner instead of at the tray icon, and on the X11 desktops (Cinnamon, XFCE) clicking outside the popup does not close it. macOS re-test of the current build is in progress.
### Windows
Follows soon.
Follows.
## Security model
- **CSP** — the WebViews run under `default-src 'self'`; scripts and connections are limited to the app itself and the Tauri IPC endpoint (dev mode additionally allows the Vite dev server).
- **Per-window capabilities, deny-by-default** — four capability files, one per window group: `main` (management, broadest command set), `popup` (list/start projects only), `term-*` (PTY plus docked panel), `panel-*` (panel/archive channels only — no PTY, no management). A backend command is callable only from windows whose capability lists it.
- **Pools separate configuration, not access** — keychain entries are deliberately readable without a prompt; any process running as your user can read any pool key. No isolation promise is made or implied.
## Project deletion
Deleting a project is scoped in three stages, each preceded by a preview of the affected artifacts (integration files, archive permission, todo hook, panel files, archive documents, working directories):
1. **Integration only** — removes ai-control's traces: `.ai-control/`, registry entry, panel/session files, archive permission, todo hook, desktop file. The project itself stays untouched.
2. **+ Archive** — additionally deletes the archive home with its documents.
3. **Full** — additionally deletes the project directory (working directories only with an explicit extra flag).
## Project layout
@@ -73,17 +96,23 @@ Follows soon.
├── panel.html detached text panel window
├── popup.html tray popup
├── src/ frontend: Vue 3 + TypeScript
│ (incl. wiki-view, search-view, archive-form,
│ commands-view + vitest tests)
├── src-tauri/
│ ├── src/lib.rs entry point, process roles
│ ├── src/app.rs Tauri wiring: tray, main/popup windows, watcher
│ ├── src/mcp.rs MCP stdio server (write_panel / archive_panel)
│ ├── src/mcp.rs MCP stdio server (6 tools, see above)
│ ├── src/terminal.rs PTY sessions (portable-pty), terminal windows
│ ├── src/domain/ registry, project config, settings, watcher,
│ │ deletion scopes
│ ├── src/platform/ macOS / Linux / Windows specifics
│ ├── capabilities/ per-window ACL (main/popup/terminal/panel)
│ └── icons/ app and tray icons
├── gnome-shell-extension/ tray/popup integration for GNOME
├── kwin-script/ popup placement for KDE Wayland
├── dev.sh development mode (tauri dev)
── build.sh macOS release build (.app bundle + DMG)
── build.sh release build for the current OS (see below)
└── deploy-linux.sh install the freshest local bundle (rpm/deb)
```
Process roles from one binary:
@@ -99,7 +128,7 @@ Running projects are detected through their terminal processes (`pgrep` for `--t
| Area | Stack |
|-----------|-------|
| Shell | Tauri 2 (Rust) |
| Frontend | Vue 3, TypeScript, Vite |
| Frontend | Vue 3, TypeScript, Vite; vitest (happy-dom) for the panel views |
| Terminal | xterm.js, portable-pty |
| macOS | objc2 / objc2-app-kit (Dock icon, window focus, tray) |
| Linux | GTK 3 / WebKitGTK, ksni (StatusNotifierItem), zbus (D-Bus) |
@@ -109,12 +138,12 @@ Running projects are detected through their terminal processes (`pgrep` for `--t
```sh
./dev.sh # tauri dev with hot reload
./build.sh # macOS release build; bundle lands in src-tauri/target/release/bundle/macos.noindex/
./build.sh # release build for the current OS
```
On Linux, build with `npm run tauri build`; artifacts land under `src-tauri/target/release/bundle/` (`deb/`, `appimage/`). Build dependencies: `webkit2gtk-4.1`, `libgtk-3`, `libayatana-appindicator3`, `librsvg2`, `patchelf`.
`build.sh` picks the bundles by platform: macOS `.app` + DMG (the bundle lands in `src-tauri/target/release/bundle/macos.noindex/`, unregistered from Launch Services so Spotlight only finds the installed copy), Linux deb + rpm, Windows NSIS. `deploy-linux.sh` installs the freshest locally built bundle via `rpm`/`dpkg`.
`build.sh` moves the macOS 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`.
Build dependencies on Linux: `webkit2gtk-4.1`, `libgtk-3`, `libayatana-appindicator3`, `librsvg2`, `patchelf`.
Prerequisites: Rust (stable), Node.js/npm. `dev.sh`/`build.sh` expect `CARGO_HOME`/`RUSTUP_HOME` under `~/tools/` — adjust the two exports in the scripts for a standard installation.
@@ -123,7 +152,7 @@ Prerequisites: Rust (stable), Node.js/npm. `dev.sh`/`build.sh` expect `CARGO_HOM
```
~/.config/ai-control/
├── settings.json app settings (see below)
├── projects.json project registry: project id → directory
├── projects.json registry: project UUID → directory
│ + pool assignment (machine-local)
└── pools/<pool>/ one Claude config directory per pool
└── pool.json name + credential type
@@ -131,9 +160,9 @@ Prerequisites: Rust (stable), Node.js/npm. `dev.sh`/`build.sh` expect `CARGO_HOM
<project directory>/ any path, mapped via the registry
├── .claude/ Claude Code project configuration
└── .ai-control/ syncs with the project
├── config.json project id (UUID) + display name,
│ terminal settings, panel archive
directory (archiveHome)
├── config.json project id (UUID), display name,
│ terminal settings (theme, icon, title),
archive home (archiveHome)
└── icon.png project icon
```
@@ -145,11 +174,11 @@ Prerequisites: Rust (stable), Node.js/npm. `dev.sh`/`build.sh` expect `CARGO_HOM
| `syncOnSessionEnd` | `false` | After a session ends, commit and push the Git repository containing the project. |
| `poolSyncDir` | unset | Directory to sync pool runtime data into (session transcripts, todos, prompt history — what `/resume` needs). When set, a pool's runtime files are replaced by symlinks into `<poolSyncDir>/<pool>`, so sessions travel with however that directory is synced (git, Syncthing, …). Unset: everything stays local in the pool directory. |
| `terminalFontSize` | `13` | Font size of the built-in terminal (also adjustable from the terminal window). |
| `spellcheckLang` | unset | Default spell-check language of the text panel (per-text override in the panel). |
| `spellcheckLang` | `de` | Spell-check language of the text panel (per-text override in the panel). |
## Claude and Anthropic licensing
aICentral is pool management only — it does not change, extend, or circumvent Anthropic's licensing in any way. Using Claude Code through aICentral is subject to the same Anthropic terms as running it directly.
aiCentral is pool management only — it does not change, extend, or circumvent Anthropic's licensing in any way. Using Claude Code through aiCentral 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 or the freedesktop Secret Service, one entry per pool.