Install echo.cc

echo.cc is in pre-release validation. A public installer must point to a qualified release; there is no supported public release to download yet. Do not replace a running installation until its configuration has been reviewed.

Choose where your net runs

Single-machine setup is in progress. The planned quickstart will manage a private, loopback-only NATS JetStream server and echod for one operator. You will not need a separate broker account or remote server. This is not a supported public installer yet; adding other machines requires a separate authenticated, TLS-protected net setup.

Source build (unreleased working tree)

All configuration commands, installers, and service behaviors described below reflect the unreleased working tree. From a reviewed source checkout, build the binaries using the pinned Go toolchain:

go build -o bin/ ./cmd/ecc ./cmd/echod

Run commands directly via ./bin/ecc, or add the output directory to your executable path:

One configuration document

ecc and echod share a versioned JSON configuration document (config.json). Standard platform configuration paths are:

Configuration discovery and precedence

Configuration file selection follows a strict order:

  1. Explicit --config FILE passed before the subcommand
  2. ECHO_CONFIG_FILE environment variable
  3. config.json inside ECHO_CONFIG_DIR
  4. Platform user configuration directory

For individual settings, explicit command-line flags take precedence over present environment variables, which override values in config.json, followed by each consumer's defaults. Note that not every setting exposes a flag or environment variable; run ./bin/ecc config schema for available fields. Relative file paths in config.json resolve relative to the configuration file's directory, whereas environment paths remain caller-relative.

Managing configuration

Use the operator configuration subcommands to generate, inspect, and validate your settings:

./bin/ecc config init
./bin/ecc config validate
./bin/ecc config show
./bin/ecc config inspect
./bin/ecc config schema

ecc config init creates a starter document and refuses to overwrite an existing configuration. ecc config show prints stored settings without opening private credential files. ecc config inspect reports shared-loader input provenance (selected path, active profile, AI endpoint, and whether values come from environment, configuration, built-in defaults, or are unset) with secrets redacted; it never displays secret contents, and does not enumerate consumer-specific defaults, command-line flags, or dashboard settings. ecc config schema generates JSON Schema for editor tooling. ecc config validate checks JSON syntax, schema tags, URI structures, and cross-field constraints. It intentionally does not open credential files or verify their filesystem permissions; only the owning transports verify credentials when establishing connections.

Starter configuration example

The following example configures a local development net connecting to a local broker:

{
  "version": 1,
  "active_profile": "local",
  "profiles": {
    "local": {
      "type": "self-hosted",
      "server": "nats://127.0.0.1:4222",
      "net": "home"
    }
  },
  "logging": { "level": "info", "format": "json" },
  "metrics": { "enabled": true },
  "hooks": { "holds": "advisory" }
}

Driven agent processes enforce a 4 MiB frame limit by default (configurable via limits.drive_frame_bytes from 1024 to 16777216 bytes). Structured logging supports JSON and text output with redaction for recognized secret fields and known credentials; arbitrary payloads may contain unmodeled secrets, and automatic file retention or rotation is not implemented.

Coordinator workflows and CLI subscriptions

When driving coding agent CLIs (such as Claude Code, OpenAI Codex, or Antigravity) across your net, operators choose whichever CLI fits their installed toolset and local session context. There is no universal "best" coordinator or worker role; benchmarks reflect specific task configurations rather than general superiority.

Using agent CLIs preserves existing interactive tools, local permissions, and project context, but does not guarantee cheaper or unlimited execution:

Agent setup planning and client integration (pre-release source build)

Current source includes the pre-release setup command to plan and manage agent integrations across supported coding assistants. There is no released public installer yet; the repository installer script points to the setup plan and never modifies client configuration automatically. The examples below use ./bin/ecc directly; ensure you have built the binaries from source or added ./bin to your PATH.

Plan first

Always inspect the integration plan before modifying any configuration:

# Human-readable plan
./bin/ecc setup

# Machine-readable plan with detailed review targets
./bin/ecc setup --format json

Planning discovers agent executables on your PATH and outputs proposed native registration commands or manual review targets. It operates strictly read-only: it does not read private client settings, grant permissions, install skills, or alter any registration files.

The plan reports registration-not-inspected by design: detecting an agent binary on PATH is discovery, not proof that the client has registered echo, loaded the MCP server, or established connectivity. In JSON output, command arrays represent explicit argv vectors, not shell commands.

Apply and remove

One command connects each selected client: its MCP registration, a native permission grant for ecc, and the coordination skill. Changes require an explicit --agents selection:

# Apply every component each selected client supports
./bin/ecc setup --apply --agents claude,codex,agy

# Remove only what echo setup wrote and that is still unchanged
./bin/ecc setup --remove --agents claude,codex,agy

Add --mcp, --permissions or --skills to limit a plan, apply or remove to those components. A rerun reports unchanged. Removal deletes the entries echo added, and any file or settings container that apply created, once nothing else is in it, and the empty echo-coordination skill directory. Entries that already existed without an echo receipt are reported as existing-unmanaged and left for manual review. Close client sessions before changing their configuration, then restart them to load it.

The grant covers only member commands (ls, send, inbox, read, wait, whoami, hold, holds, release, task, tasks, campaign, campaigns, log, stats, watch, version, worker) and echo's MCP tools. setup, config, login, switch, cert, revoke, run, mcp, hook and every other admin command keep prompting. Each rule names an installed ecc by absolute path: the one deploy/local install puts in ~/.local/share/echo/local/bin, and ~/.local/bin/ecc. A path is granted only if the file and every directory up to / are owned by you or root and writable by nobody else, and neither it nor its target sits in a git worktree, the current directory or an agent workspace (agy trustedWorkspaces, Claude additionalDirectories). A development build is never granted; run deploy/local install first. Claude gets Bash(/path/ecc send *)-style entries and mcp__echo__* in ~/.claude/settings.json; agy gets command(/path/ecc send) entries (agy's rule grammar is undocumented) and mcp(echo/*) in ~/.gemini/antigravity-cli/settings.json; Codex gets prefix_rule(pattern=["/path/ecc","send"]) lines in ~/.codex/rules/echo-ecc.rules. Deny rules and managed policy still win.

Security notice: A member command still acts in the net under your identity: it can send mail, take tasks and hold files. Goose permissions are per tool and Aider has no command allow list, so setup grants nothing for them.

For Goose (tested on 1.52.0), setup installs the shared skill only. Connect per session via --with-extension 'echo:ecc mcp' without editing YAML configuration. On Linux, ecc run currently requires the dedicated /echo.slice/echo-workers.slice cgroup-v2 boundary. The system service must place the worker and its process tree inside it; the flag verifies placement and finite limits but does not create or enforce them. The root-owned guard is available in source but is not installed by setup and has not completed native VM qualification; guarded Linux runs require its live admission socket. Because Goose resolves the inner extension executable via PATH, explicitly add the source-built binary directory to your PATH first (e.g. export PATH="$PWD/bin:$PATH" from the repository root):

export PATH="$PWD/bin:$PATH"
./bin/ecc run --resource-aggregate-cgroup /echo.slice/echo-workers.slice --tool goose --session worker-goose goose session --with-extension 'echo:ecc mcp'

Aider uses the CLI subprocess path (./bin/ecc run) without an MCP adapter and has the same Linux cgroup-v2 requirement: a host-provisioned /echo.slice/echo-workers.slice with finite limits. Echo checks the boundary but does not install or enforce it.

Check what each client will launch

# This binary alone, in disposable state
./bin/ecc setup --check

# The command each client has registered, in disposable state
./bin/ecc setup --check --agents claude,codex,agy

Both start an MCP server with disposable state, complete the handshake, list tools and resources, and call echo_whoami. With --agents the server started is the command each client has registered. Neither starts the client, so they do not prove that a running session has reloaded its configuration.

See Integrations & API contracts for detailed adapter specifications, Codex permission scope, shared skill destination paths (Codex and Goose share ~/.agents/skills/echo-coordination/SKILL.md), custom root caveats, and lifecycle verification boundaries.

Quota from your own status line

Echo never edits status-line settings, in any client, even as an option. The status line is yours. To let Echo record your Claude Code quota, add one line to your own status-line script that passes the same input to ecc usage statusline capture:

input=$(cat); printf '%s' "$input" | ecc usage statusline capture; printf '%s' "$input" | your-renderer

The capture prints nothing, always exits 0, runs nothing else and adds a few milliseconds to your status line, never more than 200 ms. A problem is written to a private file, usage/statusline-capture.diag in the Echo state directory, and nowhere else. ecc usage entitlements shows what was recorded. Use the full path to ecc if it is not on the status line's PATH.

If you have no status line yet, this script is enough. It needs jq. Save it, make it executable and point Claude Code's statusLine setting at it yourself:

#!/bin/sh
input=$(cat)
printf '%s' "$input" | ecc usage statusline capture
printf '%s' "$input" | jq -r '"\(.model.display_name) \(.workspace.current_dir)"'

Before 2026-09-29, ecc setup statusline --apply could wrap an existing status line. To undo it by hand, open ~/.local/state/echo-setup/statusline-PROVIDER-backup.json, a copy of the whole settings file from before the change. Copy only its statusLine key back into the client settings, or delete that key if the backup has none; restoring the whole file would undo later settings changes. Then delete statusline-PROVIDER-receipt.json, statusline-PROVIDER-config.json and echo-statusline-PROVIDER-health.json there (PROVIDER is claude or agy).

Protected credential references

Inline tokens, passwords, and API keys are not accepted in config.json. Authentication credentials must be kept in separate private files referenced by path (for example, credentials_file, token_file, password_file, key_file, or api_key_file).

The owning transport validates credential files at connection time against strict filesystem checks:

Member service installation and removal (pending qualification)

Native tests cover Linux amd64, macOS arm64 and Windows amd64 as an administrator. macOS Intel, Linux arm64, Windows arm64 and non-admin Windows are built, not natively qualified yet.

Native qualification of the new JSON service installers is currently pending. These scripts configure echod on a machine joining an existing net; they do not install the private broker used by the planned single-machine quickstart. In the working tree they require Python 3 and either Go with a source checkout or prebuilt binaries in ECHO_BIN_DIR. A validated config.json must exist before service installation:

Linux (systemd user unit)

# Install or update the user service
deploy/member/install.sh --config ~/.config/echo/config.json

# Uninstall the service (retains binaries, state, and credentials)
deploy/member/install.sh --uninstall

The Linux member service uses a systemd user unit. To keep it running after logout and start it at boot, the operator must enable user lingering (loginctl enable-linger USER, which may require administrator access). Without lingering, the unit can stop when the last login session ends. Non-systemd Linux service managers, including Alpine's default OpenRC setup, are not qualified by this installer.

macOS (launchd agent)

# Install or update the LaunchAgent
deploy/member/install.sh --config ~/Library/Application\ Support/echo/config.json

# Uninstall the LaunchAgent (retains binaries, state, and credentials)
deploy/member/install.sh --uninstall

Windows (Scheduled Task)

# Install or update the Scheduled Task
deploy/member/install.ps1 -ConfigFile "$env:APPDATA\echo\config.json"

# Uninstall the task (retains binaries, state, and credentials)
deploy/member/install.ps1 -Uninstall

Binary update status and release foundation

Releases of ecc and echod are signed, and metadata is checked against a pinned root of Ed25519 keys before anything is installed. ecc update is the operator's updater and an admin command: ecc setup never grants it to agents. Managed updates are opt-in. ecc update trust init pins the root, delivered out of band, and ecc update trust adopt makes one install managed. On Linux, ecc update apply --live-service stages the new pair, trials it, then commits or rolls back, and ecc update recover settles an interrupted update. Windows and macOS refuse service activation for now. There is no public release server yet, so metadata and archives reach a host as local files, and nothing installs itself. What sits underneath:

Migration and compatibility

A legacy profiles.json produces a conversion error only when the default config.json is absent; an existing backup file can safely coexist with a new configuration document. Before switching binaries, operators must review their configuration, validate it with ./bin/ecc config validate, and test services. See the command reference, self-hosting guide, and security guide.