Building an adapter
The SDK v2 declarative manifest spec.
atrium uses SDK v2 adapters, which are largely declarative. Most integration (binary discovery, session discovery, launch composition, launcher UI) lives in adapter.json. Shell scripts are only needed for the one method that stays dynamic — hooks.
SDK v1 (fully script-based: detect_running.sh, extract_session_id.sh, list_recent_sessions.sh, build_resume_command.sh) is deprecated and no longer supported.
Manifest schema
Canonical schema: atrium-adapters/schemas/adapter.schema.json.
{
"sdkVersion": 2,
"name": "my-tool",
"displayName": "My Tool",
"description": "My AI coding assistant",
"accent": "#4CAF50",
"binary": "my-tool",
"version": "1.0.0",
"author": "me",
"skillInstallPath": "~/.my-tool/skills/atrium/SKILL.md",
"binaryDiscovery": {
"commands": ["my-tool"],
"wellKnownPaths": [
"~/.npm/bin/my-tool",
"/usr/local/bin/my-tool",
"/opt/homebrew/bin/my-tool",
"~/.local/bin/my-tool"
]
},
"sessions": {
"pattern": "~/.my-tool/history/*.json",
"titleField": "title",
"idField": "id"
},
"launch": {
"base": ["my-tool"],
"resumeFlag": ["--resume", "{session_id}"],
"flagMap": {
"thinking": ["--thinking"],
"model": ["--model", "{value}"]
}
},
"launcherOptions": [
{
"id": "thinking",
"kind": "toggle",
"label": "Thinking mode",
"default": false
},
{
"id": "model",
"kind": "select",
"label": "Model",
"options": [
{ "label": "Fast", "value": "fast" },
{ "label": "Smart", "value": "smart" }
],
"default": "smart"
}
],
"hooks": {
"session-start": "atrium://hooks/my-tool/session-start",
"session-end": "atrium://hooks/my-tool/session-end"
},
"methods": {
"hooks": { "script": "hooks.sh" }
}
}
Required fields
| Field | Type | Notes |
sdkVersion | integer | Must be 2. |
name | kebab-case string | Machine ID. Must match the directory name. |
displayName | string | Shown in the launcher and Settings → Tools. |
description | string | One-liner. |
accent | #RRGGBB | UI accent color for this adapter's panes. |
binary | string | Name of the wrapped CLI tool. |
version | semver | Adapter version, independent of the tool's version. |
methods | object | Maps method names to their implementation. In SDK v2 only hooks is typically needed. |
Optional fields
| Field | Type | Notes |
skillInstallPath | path string | Where to copy the canonical atrium skill. Tilde-expanded. |
author | string | |
binaryDiscovery | object | How atrium resolves the binary. See below. |
sessions | object | How atrium lists recent sessions for the resume picker. |
launch | object | How atrium composes the launch command. |
launcherOptions | array | Per-launch UI inputs shown in the launcher. |
hooks | object | Event-name → atrium://hooks/<adapter>/<event> URI map. |
binaryDiscovery
Atrium resolves the binary at launch by trying, in order:
- Each entry in
commandsas a command on the user's$PATH. - Each entry in
wellKnownPaths(tilde-expanded, checked for existence and executability).
Include well-known paths for common Node version managers (nvm, fnm, volta) if your tool is installed via npm, and the Homebrew ARM path (/opt/homebrew/bin) for Apple Silicon.
sessions
Describes where the tool stores its session history so atrium can populate the resume picker.
pattern— glob relative to the user's home directory.titleField— JSON field inside each session file to use as the human label.idField— JSON field to use as the session ID (passed toresumeFlag).
sessions. The launcher will simply not show a recent-sessions picker.
launch
Composes the command atrium runs in the pane.
base— argv prefix, for example["my-tool"]. atrium substitutes the resolved binary path as argv[0].resumeFlag— template applied when resuming.{session_id}is substituted with the stored session ID.flagMap— maps launcher option IDs to argv fragments.{value}substitutes a select/text option's value.
launcherOptions
Inline UI controls shown in the launcher bar when this adapter is selected. Supported kinds:
toggle— boolean switch. Present in argv only when true (viaflagMap).select— single-select dropdown withoptions[]of{label, value}.text— free-form text input.
id (referenced by flagMap), label, and optional default.
Prior to SDK v2, launcher options were a separate launcher_options.json file. That form is still supported (reference it via methods.launcher_options = { "static": "launcher_options.json" }), but inline is preferred.
hooks and hooks.sh
The hooks object lists which events your adapter emits. For each event, atrium registers an atrium://hooks/<adapter>/<event> endpoint.
hooks.sh is invoked once by atrium at install and uninstall time to let the adapter wire its hooks into the tool's own hook system. Contract:
#!/usr/bin/env bash
set -e
case "$1" in
install)
# Register this adapter's hooks with the tool.
# Output JSON to stdout: { "subcommand": "install", "installed": true }
;;
uninstall)
# Remove the registrations.
;;
status)
# Report current state.
;;
esac
Timeout: 5 seconds for install/uninstall; hooks that exceed the timeout fail the operation but do not crash atrium.
Testing locally
- Clone
atrium-adaptersnext to youratriumsource tree. - Drop your adapter directory into
atrium-adapters/adapters/. - Launch atrium's dev build (
pnpm tauri dev). atrium checks the sibling path first in debug builds and will pick up your adapter immediately. - Install it from Settings → Tools.
atrium-adapters repository adding your adapter directory and an entry in registry.json.
Migration from SDK v1
If you have an SDK v1 adapter (four shell scripts + a minimal adapter.json), move each script's logic into the equivalent declarative block:
| SDK v1 script | SDK v2 equivalent |
detect_running.sh | Handled automatically via process-tree introspection. |
extract_session_id.sh | sessions.idField + adapter emits the session ID as part of session-start. |
list_recent_sessions.sh | sessions.pattern + titleField + idField. |
build_resume_command.sh | launch.resumeFlag. |
hooks.sh is still needed for install/uninstall wiring. Everything else becomes JSON.