# agentteam

`agentteam` is the headless AgentTeam daemon/CLI and Desktop sidecar. The
`desktop/electron/` host packages the shared Web renderer and owns native
window, tray, menu, deep-link, and whole-application update behavior on macOS
and Windows. Linux ships only the daemon/CLI.

After consolidating the legacy `daemon-go` path into the first-party client, this directory is now the only AgentTeam Desktop Client implementation in the repo. If you want to run the AgentTeam desktop client locally, use this binary and this README.

## What `agentteam` Means Now

`agentteam` has one implementation and two common usage paths:

- use the native Desktop GUI to select a server, register or log in, and select a Workspace
- use the CLI/headless path to save machine auth with `agentteam auth login --api-key ...`
- connect the daemon to a remote AgentTeam Workspace with saved machine auth, or with `agentteam daemon --server-url ... --api-key ...`

That means:

- `agentteam daemon` is the canonical first-party client entrypoint
- plain `agentteam daemon` starts the local daemon stack using saved settings
- `agentteam auth login --api-key ...` resolves and saves AgentTeam machine auth against the default AgentTeam SaaS URL; pass `--server-url` for another server
- `agentteam daemon --server-url ... --api-key ...` resolves AgentTeam machine auth, saves it, and starts the daemon if needed
- the GUI defaults to `https://agentteam.pingcap.com`, keeps access tokens only in memory, and persists only an encrypted refresh token in `auth.yaml`
- the GUI accepts HTTP and HTTPS server origins, including IP addresses with custom ports; use HTTPS whenever available because HTTP sends passwords, tokens, and Workspace data without transport encryption
- activating or restoring a Workspace where the current user has no Machines automatically creates this computer as that user's first Machine and waits for its daemon connection before entering the Workspace
- Desktop validates a saved local Machine binding before reusing it; a server-deleted binding is removed locally and disconnected before first-Machine setup is evaluated
- the Desktop Add Machine dialog can add this computer when it is not yet bound; other machines use the CLI/API-key setup command
- `--connect agentteam` is still accepted, but it is optional for the AgentTeam machine connect path
- `desktop/` is the canonical implementation home for the AgentTeam Desktop Client
- there is no separate long-term `daemon-go` client path anymore

## The Two Keys

There are two different keys in the system. They are not interchangeable.

| Key | Source | Used for |
|---|---|---|
| `machineApiKey` | Created or rotated from AgentTeam Web when you add a machine | `agentteam auth login --api-key ...`, `agentteam daemon --server-url ... --api-key ...`, and the workspace machine websocket connection |
| Electron UI session | Issued through the private daemon control plane | Authenticated renderer access to local Desktop APIs and the selected-server gateway |

Electron main obtains short-lived, window-scoped UI sessions through the
authenticated daemon control plane and exposes only the renderer token through
the typed preload facade. The control capability never enters the renderer,
URLs, logs, or generic IPC. The daemon does not serve a local browser UI.

## Architecture

```
┌────────────────────────────────────────────────────────────┐
│                          Daemon                            │
│              (component wiring and HTTP server)            │
└────────┬───────────────────────────────┬───────────────────┘
         │                               │
         ▼                               ▼
┌─────────────────┐           ┌──────────────────────────────┐
│   ServerManager │──────────▶│          API Service         │
│                 │           │                              │
│  Channels       │◀──────────│  RESTful Desktop APIs        │
│  └─ agentteam        │  outbound │  + per-channel MCP endpoint  │
│                 │           │  (/mcp/...)                  │
│                 │           │  + local management APIs     │
└────────┬────────┘           │                              │
         │                    └──────────────┬───────────────┘
         │                                   │         ▲
         │                                   │         │ HTTP MCP
┌────────▼───────────────────────────────────▼────┐    │
│                     Dispatcher                  │    │
│  ┌───────────────┐              ┌──────────────┐│    │
│  │ Instructions  │              │   Sessions   ││    │
│  │ (/agent,      │              │  (dispatch)  ││    │
│  │  /new, etc.)  │              │              ││    │
│  └───────────────┘              └──────────────┘│    │
└─────────────────────────────────────────┬───────┘    │
                                          │            │
                                ┌─────────▼──────────┐ │
                                │  Runtime Process   │─┘
                                │ (claude/codex/     │
                                │  opencode)         │
                                └────────────────────┘
```

The AgentTeam daemon manages channels, API service, dispatcher, the Desktop gateway,
and the HTTP MCP bridge in one local process. The root `web/` tree owns the
shared Browser/Desktop business UI; Electron packages the Desktop renderer in
`app.asar`. The Go daemon serves APIs only, not static Web assets or SPA
fallbacks.

The gateway reserves `/api/internal/*` for authenticated local capabilities. All other data requests use the same relative server URLs as Browser Web and are routed to the current window's active registered AgentTeam Server. Active server selection is isolated per local UI session/window and carries a generation so switching one window cannot redirect another window's requests or let stale responses update the new server view.

## Prerequisites

- Go 1.25+
- [Node.js](https://nodejs.org/) and npm (shared frontend toolchain)
- `rsvg-convert` from librsvg, only when regenerating icon assets with
  `make generate-icons` or packaging the macOS app bundle

## Getting Started

### 1. Clone and build

```bash
git clone https://github.com/tidbcloud/AgentTeam.git
cd agentteam/desktop

# Build the pure Go daemon/CLI
make build-daemon

# Or install it into AgentTeam's canonical user bin directory
make install
```

`make build-daemon` requires only Go and does not stage Web/Electron assets.
Use `make linux-release` with explicit managed OpenCode and models sources for
the Linux release payload. Electron staging uses
`electron/scripts/stage-sidecar.mjs` and the target-specific managed runtime
sources.
Override sources must be native platform
binaries from the OpenCode platform packages, not the generic `opencode-ai` npm
wrapper.

By default, `make install` installs `agentteam` to `~/.agentteam/bin/agentteam`.
This matches the release installer and the managed binary path used by
service/onboard flows. When the source binary has a bundled `runtimes/` tree,
`make install` copies it next to the installed binary.

On Apple Silicon macOS, `make build-daemon`, `make -C .. dev:desktop`, and `make install` default
to a `darwin/arm64` binary even if the active Go toolchain is running under
Rosetta. Override `GOARCH` or `AGENTTEAM_BUILD_GOARCH` explicitly if you need a
different local target.

If you want a different target directory, override it explicitly:

```bash
make install INSTALL_DIR="$HOME/.local/bin"
```

### Install the Linux daemon/CLI from release

```bash
curl -fsSL https://static.pingcap.com/agentteam/client/install.sh | bash
```

This installer is Linux-only and supports amd64 and arm64. It installs the
headless `agentteam` daemon/CLI plus the matching AgentTeam-managed OpenCode executable
and `models.json`. It does not install Electron, renderer, Web assets, or a local
Dashboard. Install the platform application package on macOS or Windows.

To install a specific Linux version explicitly:

```bash
curl -fsSL https://static.pingcap.com/agentteam/client/install.sh | \
  bash -s -- --version v0.2.0
```

Options:

- `--version <vX.Y.Z>`: install a specific version; if omitted, the installer resolves the current stable version
- `--stable-version-url <url>`: stable release metadata URL (default `https://static.pingcap.com/agentteam/releases/desktop/stable.json`; the legacy daemon feed is used only while the Desktop catalog migration is in progress)
- `--base-url <url>`: release host base URL (default `https://static.pingcap.com`)
- `--repo <path>`: release asset path (default `agentteam/client`)
- `--install-dir <dir>`: install target directory (default `~/.agentteam/bin`)
- `--binary <name>`: binary name (default `agentteam`)
- `--install-url-handler`: on Linux, register `x-scheme-handler/agentteam` for
  `agentteam://` links

The optional URL handler is installed into
`${XDG_DATA_HOME:-$HOME/.local/share}/applications/agentteam-url-handler.desktop`.
It dispatches each URL to the installed binary as `agentteam connect %u`; it does
not serve or open a local Dashboard. The installer leaves URL handling
unregistered unless `--install-url-handler` is passed.

By default, the release installer installs `agentteam` to `~/.agentteam/bin/agentteam`.
This keeps the binary in a user-writable location so the Linux/headless Go
`agentteam upgrade` path can replace the binary without requiring `sudo`.

For service installation, agentteam still uses the binary's absolute path, so the
service can continue to run even when the binary is installed under the user's
home directory.

### 2. First-time setup

```bash
./bin/agentteam onboard
```

Use this to create the initial config, detect usable runtimes, and optionally set up the service. OpenCode is shipped with AgentTeam Desktop; external runtimes are detected or configured manually.

### 3. Start the local daemon

```bash
# Development mode — starts Vite and Electron; Electron supervises the daemon
make -C .. dev:desktop

# Or run the daemon directly
./bin/agentteam daemon
```

Foreground `agentteam daemon` uses the exact binary you invoked. It does not switch
to the managed install under `~/.agentteam/bin`, which keeps local `make build-daemon`
debugging predictable. Service and desktop-launcher workflows still prepare and
run the managed binary path when they need a stable executable location.

The API service listens on loopback. Electron-owned daemons request an
ephemeral port and publish the exact address through the private runtime
receipt; explicit CLI/service ports remain supported. In development,
`AGENTTEAM_DEV=127.0.0.1:<vite-port>` admits only that exact Vite origin for
CORS/WebSocket requests; the daemon does not proxy or serve the renderer.

### 4. Open AgentTeam Desktop

On macOS and Windows, launch the Electron application from the application
launcher, Dock, or taskbar. Electron owns one retained main window and the tray
menu. Linux has no native application or local browser dashboard.

If startup reports that an older AgentTeam Desktop is still running, fully quit that
application and retry. On macOS use **AgentTeam → Quit AgentTeam** or `⌘Q`; on Windows use
**Exit AgentTeam** from the tray menu. Closing the window alone may leave the old
application running.

On Linux, `agentteam status` checks both the system and user systemd managers by default and shows installed services even when they are inactive or failed. Use `./bin/agentteam status --user` if you want to limit the output to the user-level service.

When the daemon is running, `agentteam status` reports receipt health, address,
version, PID, and owner facts; it does not mint or print a browser login URL.

### 5. Connect this machine to a AgentTeam workspace

When you add a machine from the AgentTeam Web UI, it generates the advanced CLI setup snippet:

```bash
./bin/agentteam auth login --api-key <machineApiKey>
```

This resolves the machine key with AgentTeam Server, learns the workspace and machine identity, and saves the local auth entry. When `--server-url` is omitted, the command uses the default AgentTeam SaaS URL, `https://agentteam.pingcap.com`. Pass `--server-url` when connecting to another AgentTeam server.

To save auth and immediately start the daemon in the foreground, use:

```bash
./bin/agentteam daemon --server-url https://agentteam.example.com --api-key <machineApiKey>
```

Both commands upsert auth by normalized server URL plus workspace ID. Re-running the command for the same server and workspace updates the existing local entry; using the same server with a different workspace creates another entry.

Inspect saved auth with:

```bash
./bin/agentteam auth status
```

If the AgentTeam server rejects the saved machine key with `invalid machine api key`,
the daemon stops retrying that connection. Create or rotate a machine connection
from AgentTeam Web and run the generated connect command again.

### 6. Run as a long-lived service

```bash
./bin/agentteam service install
./bin/agentteam service start         # Linux/Windows only: start the service now
./bin/agentteam service install --user  # Linux only: install as user-level systemd service
./bin/agentteam service start --user    # Linux only: start the user-level service now
./bin/agentteam status
```

On macOS, `service install` bootstraps the user LaunchAgent and starts it immediately; `service reinstall` starts it when the previous service was running, and also when reinstall is acting as a first install.
On Linux, use `--user` with `service install`, `reinstall`, `start`, `stop`, `restart`, `uninstall`, or `status` to target the current user's systemd manager instead of the system manager.
On Linux, `service install` registers and enables the systemd service; run `service start` if you want to start it immediately.
On Linux, plain `./bin/agentteam status` checks both managers and shows installed services even when they are inactive or failed.
Run the connect command and service commands as the same OS user. If you install from a root shell, the service uses root's AgentTeam profile; if your connection settings were saved under another user, run service install via `sudo` from that user instead.
User-level systemd services start with that user's systemd manager. Enable lingering (`loginctl enable-linger <user>`) if you need them to come back before login after a reboot.
When you run `agentteam service reinstall`, AgentTeam now restores the previous running state: a running service comes back up after reinstall, while a stopped service stays stopped.

## Development

### Frontend only

From the repository root:

```bash
cd web
npm run dev -- --mode desktop
```

This starts the root Web application's Desktop entry with HMR. Point the development proxy at the local daemon gateway port shown by `agentteam status` or persisted in `~/.agentteam/config.yaml`:

```bash
VITE_DEV_PROXY_TARGET=http://127.0.0.1:8084 npm run dev -- --mode desktop --host 0.0.0.0
```

Replace `8084` with the daemon port on that server.

### Backend only

```bash
make build-daemon
./bin/agentteam daemon
```

### Full stack (frontend + backend)

```bash
make -C .. dev:desktop
```

Builds the pure Go sidecar plus Electron main/preload, starts the root `web/`
Vite Desktop entry, and runs Electron with explicit sidecar and renderer
targets. Electron remains the daemon owner/supervisor. Press Ctrl+C to stop the
development stack.

### Local Token diagnosis

The shipped `agentteam` executable owns the only Token-analysis entry points. Start
AgentTeam Desktop or `agentteam daemon`, then run:

```bash
agentteam token analyze --window 1d
agentteam token analyze --window 1d --run <run-ref> \
  --case exec-help --changed-variable platform.agentteam.exec \
  --workspace-revision <revision> --tool-profile <profile> \
  --cache-state warm --outcome success \
  --output /tmp/token-baseline.json
agentteam token ui
agentteam token ui --no-open
agentteam token analyze --stop
agentteam token compare \
  --baseline /tmp/token-baseline.json \
  --candidate /tmp/token-candidate.json
```

For a causal run comparison, reproduce the same task payload on both sides.
Desktop records only a machine-keyed payload fingerprint; it never exports the
task body or raw message/run IDs. Attribution explicitly distinguishes records
without a task payload from payloads whose identity is unavailable. A run with
an unavailable, invalid, or multiple payload identity remains descriptive even
when the operator-supplied case, Workspace, tool profile, cache state, outcome,
and changed variable match.

Detailed high-cardinality collection is off by default. A human
`agentteam token analyze` automatically enables it for the current daemon lifetime
and explains that history is not backfilled; reproduce the target task, then
analyze again. `--stop` reports first and disables collection afterward. The UI
has the same single collection switch. There is no environment variable,
Desktop Settings toggle, or ordinary Desktop navigation item.

The UI listens on a random `127.0.0.1` port, uses a process-scoped bearer token,
rejects non-loopback and cross-origin requests, enables no CORS, and serves only
embedded assets under a restrictive CSP. Reports never contain Prompt, message,
task, tool-output, or source-location bodies. Portable exports also remove
Agent/Run details, local Agent names, and exact runtime/model values. A runtime Agent may explicitly
run `agentteam token analyze --format json`, but it can read only itself and cannot
change collection or open the machine-wide UI; when collection is off, the
report points to the Human-owned UI or Human shell command. `24h` is accepted
as an alias for `1d`. Run-scoped reports include one snapshot boundary and
whether the Run was still active; the saved artifact is frozen at that boundary.
Compare requires
matching controlled case, Workspace/tool profile, cache state, outcome, and
task-payload fingerprint, plus one declared changed variable, before it reports
`comparable`.

### Build Electron inputs

```bash
make build-daemon
make build-renderer
AGENTTEAM_DESKTOP_PLATFORM=darwin AGENTTEAM_DESKTOP_ARCH=arm64 \
  AGENTTEAM_DESKTOP_VERSION=0.0.0-dev make build-electron
```

Use `cd web && npm run build:web` from the repository root for the Browser deployment bundle.

Production Electron packages target macOS arm64/x64 and Windows arm64/x64.
The native signing-host entrypoints are documented in
`release/manual-owner-client-assets.md`; Linux amd64/arm64 remains daemon/CLI
only.

## Testing

```bash
make test                # go test ./...
make ci-required         # Desktop Go required checks
```

### Validate installer tests

```bash
cd scripts
go test -count=1
```

### Build local snapshot artifacts (no publish)

```bash
goreleaser check
AGENTTEAM_MANAGED_OPENCODE_VERSION=1.2.3 \
AGENTTEAM_MANAGED_OPENCODE_LINUX_AMD64_SOURCE=/path/to/linux-amd64/opencode \
AGENTTEAM_MANAGED_OPENCODE_LINUX_ARM64_SOURCE=/path/to/linux-arm64/opencode \
AGENTTEAM_MANAGED_OPENCODE_MODELS_SOURCE=/path/to/models.json \
goreleaser release --snapshot --clean --skip=publish
```

Current release track includes `linux/amd64` and `linux/arm64` artifacts. Each
Linux archive includes the matching AgentTeam-managed OpenCode binary and
`models.json` under `runtimes/opencode/`. The complete archive payload is:

```text
agentteam                                      0755
runtimes/opencode/opencode                0755
runtimes/opencode/models.json             0644
```

There are no Electron, renderer, or Web assets in Linux archives. GoReleaser
uses only the Go toolchain and staged managed-runtime sources; it never invokes
Node or Electron. Linux/headless installations keep the Go `agentteam upgrade`
path.

### Test a specific package

```bash
go test ./internal/dispatcher/...
go test ./internal/agent/...
```

### Run with verbose output

```bash
go test -v ./internal/types/...
```

### Run a specific test

```bash
go test -run TestValidateAgent ./internal/agent/...
```

### AgentTeam task routing and owner-private context

AgentTeam task wakes can carry an `activeTaskTarget` in `agent:start` or `agent:deliver` payloads. The daemon injects task routing guidance only when the current wake is explicitly task-routed, tied to thread focus, or human-selected. Sticky session targets left by prior task tool calls, such as `created_task`, `claimed_task`, or `task_tool_call`, remain runtime state but do not automatically add task guidance to ordinary channel, DM, or thread messages. When task guidance is active, task discussion replies should use `send_message` with the exact task scope target (for example `#tsk_...`) provided in the prompt. High-signal task checkpoints should use `task_add_checkpoint`. Human-facing channel, DM, or thread replies still use `send_message` with the exact target.

For owner-scoped private-agent deliveries, the daemon shows the runtime the parent target (`#channel`, `#channel:thread`, `dm:@user`, or task-native target) and keeps the owner-private context in authenticated session metadata. Agents must reuse the visible parent target when replying or reading history. MCP tool schemas and prompts must not expose hidden context IDs; attachment support follows the normal parent channel, DM, or thread authorization rules.

AgentTeam Exec-owned actions are exposed to supported agent runtimes through the hidden `agentteam exec` transport rather than through MCP tool schemas. The hidden command is for daemon-owned runtime execution only, not a human public CLI. One logical Exec surface follows the runtime process lifetime; its short-lived bearer generation has a default 12-hour TTL and is atomically rotated by the daemon through an OS-account-private token file before expiry (owner-only `0700/0600` directory/file modes on Unix; a protected current-user/SYSTEM DACL on Windows). New runtimes inherit only the canonical base URL and token-file path, never a raw bearer token. Nested daemons, runtime probes, and adjacent helpers strip inherited or shell-captured Exec variables before a new runtime receives its own canonical base/file pair. Each `agentteam exec` invocation reads that file once; when a file is declared, any read or content failure is closed rather than falling back to the legacy raw-token environment supported for older daemons. Rotation is independent of `agent:start`, preserves the current generation if publication fails, and never extends an old generation beyond its original expiry. Process exit or replacement, launch abort, and daemon shutdown revoke the logical surface, stop renewal, retry private-file cleanup, and drain in-flight requests; crash or bounded-shutdown residue is removed by the next singleton daemon startup. This local file boundary protects against other OS accounts; it does not claim per-Agent isolation between processes running as the same login user. Public authentication failures remain bounded generic `403` responses while rate-limited daemon diagnostics distinguish expired, revoked/inactive lifecycle, and wrong-scope credentials. Exec-owned actions use a bounded JSON result envelope; MCP remains the transport only for the retained MCP-owned tool set and external MCP servers.

### Packages with unit tests

| Package | Tests | Coverage |
|---------|-------|----------|
| `internal/types` | message state machine, metadata, MCP constructors, raw message, events | Core types |
| `internal/i18n` | translator, language fallback, format strings, concurrency | i18n |
| `internal/provider` | validation, type checking, normalization | Provider config |
| root `internal/core/rewindcaps` | encode/decode round-trips, capability lookup, recovery point validation | Recovery |
| `internal/dispatcher` | agent overrides, deferred delivery ordering/comparison | Dispatch logic |
| `internal/workspace` | local memory scaffold, role seed materialization | Workspace lifecycle |
| `internal/metrics` | KeyID, MaskAPIKey, TimeWindow, ChannelCollector, error types | Metrics |
| `internal/agent` | agent validation, runtime validation/normalization, MCP URLs, prompt helpers, recovery | Agent config |
| `internal/api/mcp` | RPC dispatch (initialize, ping, tools/list, tools/call), error handling | MCP protocol |
| `internal/token` | API key generation/validation, agent token generation/validation, expiry | Auth |
| `internal/daemon` | PID file read/write/remove, process status | Daemon lifecycle |
| `internal/profile` | config load/save, defaults, runtime directory, verbose flag | Configuration |

## Code Quality

```bash
make fmt                 # go fmt ./...
make vet                 # go vet ./...
make lint                # golangci-lint run
```

## Configuration

Config files are stored in `~/.agentteam/`:

| File | Contents |
|---|---|
| `config.yaml` | Server host/port, PID file, log file, language, default agent; the first daemon start persists an automatically selected port, and `port: 0` requests automatic selection again |
| `agents.yaml` | Agent definitions synced from AgentTeam servers (ID, name, runtime, model, policy) |
| `servers.yaml` | AgentTeam server auth entries resolved by server URL and workspace |
| `auth.yaml` | Desktop GUI server accounts, encrypted refresh tokens, and the opaque last-selected server/Workspace target; the file is restricted to mode `0600` |
| `skills.yaml` | Imported skill metadata and enablement state |

Runtime-default LLM credentials live in each runtime's own config file; inline agent LLM credentials are stored with the agent definition.

Override the profile directory with `AGENTTEAM_CONFIG_DIR`.

### Environment variables

| Variable | Description |
|---|---|
| `AGENTTEAM_CONFIG_DIR` | Override `~/.agentteam/` |
| `AGENTTEAM_VERBOSE` | Enable verbose logging (`1`, `true`, `yes`) |
| `AGENTTEAM_DEV` | Exact local Vite origin admitted by the daemon in Electron development (for example `127.0.0.1:5173`) |

## CLI Commands

```bash
./bin/agentteam daemon              # Run daemon in foreground
./bin/agentteam daemon --server-url https://agentteam.example.com --api-key <machineApiKey>
./bin/agentteam auth login --api-key <machineApiKey>
./bin/agentteam auth login --server-url https://agentteam.example.com --api-key <machineApiKey>
./bin/agentteam auth status         # List saved AgentTeam auth entries
./bin/agentteam auth logout <id>    # Remove one saved AgentTeam auth entry
./bin/agentteam onboard             # First-time setup wizard with runtime detection
./bin/agentteam onboard --runtime   # Runtime detection status
./bin/agentteam doctor              # Diagnostic health checks
./bin/agentteam doctor --fix-runtime # Runtime remediation guidance
./bin/agentteam agent list          # List synced agents
./bin/agentteam agent get           # Get agent details
./bin/agentteam service install     # Install as system service (launchd/systemd)
./bin/agentteam service install --user  # Linux only: install as user-level systemd service
./bin/agentteam service reinstall   # Reinstall system service
./bin/agentteam service start       # Start system service (Linux/Windows)
./bin/agentteam service stop        # Stop system service (Linux/Windows)
./bin/agentteam service restart     # Restart system service
./bin/agentteam status              # Linux: check services across system + user managers
./bin/agentteam status --user       # Linux only: inspect the user-level systemd service
./bin/agentteam service uninstall   # Uninstall system service
./bin/agentteam journal             # View service logs (alias: j)
./bin/agentteam journal --tail 50   # Show last 50 lines
./bin/agentteam journal --follow    # Follow log output
./bin/agentteam upgrade             # Self-upgrade
./bin/agentteam upgrade --check     # Check for updates only
./bin/agentteam doc --man           # Generate man page
./bin/agentteam doc --skill         # Generate agent skill doc
./bin/agentteam --version          # Show version info
```

`agent list` table output includes `ID`, `NAME`, `STATUS`, `RUNTIME`, `MODEL`, and `SOURCE`. Structured formats expose the same live-or-registration state as `status`; the daemon supplies live session state when running, otherwise the CLI falls back to registration state.

The current Machine settings in Electron can collect a bounded, scrubbed ZIP of
the selected Workspace's local daemon and OpenCode diagnostics. The archive is
saved locally and is not uploaded automatically.

When a AgentTeam server is configured with `AGENTTEAM_DAEMON_MIN_VERSION`, agent message APIs require a connected daemon whose ready/session `daemonVersion` meets that minimum semver. If the daemon is older, upgrade this binary with `agentteam upgrade` before using agent messaging features against that server.

## Project Structure

```
├── internal/
│   ├── agent/      # Agent lifecycle, runtime drivers, interactive sessions
│   ├── api/        # HTTP routes, selected-server gateway, MCP bridge
│   ├── channel/    # Channel implementations
│   ├── cmd/        # CLI commands (Cobra)
│   ├── daemon/     # Headless daemon lifecycle, receipt, component wiring
│   ├── doctor/     # System diagnostics
│   ├── i18n/       # Internationalization (en, zh-CN)
│   ├── metrics/    # Prometheus-based metrics collection
│   ├── profile/    # Centralized config manager (agents, channels, providers)
│   ├── provider/   # Provider type definitions
│   ├── dispatcher/  # Message dispatch and session management
│   ├── token/      # API key generation and validation
│   ├── icon/       # Tray icon assets
│   ├── types/      # Shared value types and interfaces
│   ├── upgrade/    # Self-upgrade logic
│   └── version/    # Build-time version info
├── electron/       # Electron main, preload, native shell, packaging
├── docs/           # Specifications and design docs
└── main.go         # Entry point (cmd/agentteam/main.go)
```

## Supported Channels

| Channel | Transport | MCP Tools |
|---------|-----------|-----------|
| **AgentTeam** | Bidirectional WebSocket | unified agentteam MCP (message/memory/execution) + agentteam exec domains for task/kb/agent and other first-party actions; app-hosted Extensions use the runtime Extension surface |

## Supported Runtimes

| Runtime | Binary | Protocol |
|---------|--------|----------|
| Builtin OpenCode | AgentTeam-managed `opencode` bundled with Desktop | HTTP REST + SSE (`opencode serve`) |
| OpenCode | External `opencode` from PATH or manual binary path | HTTP REST + SSE (`opencode serve`) |
| Claude Code | `claude` | stream-json |
| Codex | `codex` | JSON-RPC app-server (`codex app-server`) |
| Kimi Code | `kimi` | Agent Client Protocol over stdio (`kimi acp`) |
| Pi | `pi` | JSON-RPC over stdio (`pi --mode rpc`) |

Builtin OpenCode is bundled in the AgentTeam Desktop release artifact and upgrades with AgentTeam Desktop. If the managed OpenCode binary is missing, not executable, or does not match the expected bundled version, the daemon reports an incomplete AgentTeam Desktop installation.

External OpenCode, Claude Code, Codex, Kimi Code, and Pi remain available as advanced runtimes. Desktop can detect them from `PATH` and common package-manager install locations or use manually configured binary paths, but it does not install or upgrade them. Detection registers only usable runtime candidates; Codex still requires the `codex app-server` entrypoint, Kimi requires the public `kimi acp` entrypoint, and Pi requires the `pi --mode rpc` entrypoint. AgentTeam supplies the configured model provider when it launches Kimi and Pi and does not run their interactive login flows.

## Tech Stack

**Backend:** Go, Gin, Cobra, SQLite, WebSocket

**Native host:** Electron, electron-builder, electron-updater

**Frontend:** React 19, TypeScript, Vite 8, Tailwind CSS v4, shadcn/ui, React Router, i18next

**Supported runtimes:** Builtin OpenCode, external OpenCode, Claude Code, Codex, Kimi Code, Pi

**Supported LLM providers:** OpenAI, Anthropic, OpenRouter, Azure OpenAI, Custom (plus forwarding support for DeepSeek, Zhipu, Ark, and other OpenAI/Anthropic-compatible endpoints)

## License

MIT
