Запустить headless-сервер
Запустите cc_server на машине, которая остаётся включённой, и подключайтесь к
нему с компьютера, из браузера или с телефона. Сервер — это нативный бинарник на
чистом Dart, без движка Flutter, поэтому он работает без графического интерфейса
на macOS, Linux и Windows. Ему принадлежит база данных, он выполняет агентов и
делает все обращения к внешним API; клиенты только отрисовывают интерфейс.
Запуск в Docker (готовые образы)
Заголовок раздела «Запуск в Docker (готовые образы)»Каждый выпуск публикует стек для самостоятельного размещения из четырёх образов
GHCR — бэкенд, два статических тонких клиента и необязательное реле сопряжения, —
а также отдельный образ cc-server-demo для публичного демонстрационного хоста.
Установка на своём оборудовании не требует копии исходного кода. Закрепите тег
версии (ghcr.io/samuelalev/<image>:v0.0.1-rc.1) или используйте latest.
| Образ | Что это | Публикует |
|---|---|---|
ghcr.io/samuelalev/cc-server |
Бэкенд: база данных, агенты, MCP, вебхуки | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
Веб-клиент (статический nginx) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
Приложение-компаньон для телефона PWA (статический nginx) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
Реле сопряжения WebRTC (необязательно) | -p 8788:8788 |
Весь стек в виде файла Compose:
services: server: image: ghcr.io/samuelalev/cc-server:latest ports: ["9030:9030"] volumes: ["cc_data:/data"] restart: unless-stopped web: image: ghcr.io/samuelalev/cc-webapp:latest ports: ["8080:8080"] restart: unless-stopped remote: image: ghcr.io/samuelalev/cc-remote:latest ports: ["8081:8080"] restart: unless-stopped signaling: image: ghcr.io/samuelalev/cc-signaling-server:latest ports: ["8788:8788"] restart: unless-stopped
volumes: cc_data:Что стоит знать, прежде чем открывать что-либо из этого за пределы loopback:
-
Образ
cc-serverпоставляется сCC_SERVER_INSECURE=1(он должен привязываться к0.0.0.0, чтобы принимать трафик опубликованных портов), а это безопасно только за обратным прокси, терминирующим TLS — Caddy, Traefik, nginx или туннелем Cloudflare, — в доверенной сети. Чтобы вместо этого терминировать TLS внутри процесса, смонтируйте сертификат и задайтеCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(затем снимитеCC_SERVER_INSECURE). Всё это можно переопределить с помощьюdocker run -e …или блокаenvironment:в Compose. -
/data— единственное состояние. Базы данных SQLite, секреты сопряжённых устройств, скачанные модели и аудио встреч — всё живёт в томе: сделайте его резервную копию, и контейнер станет расходуемым. -
Сопрягите клиент изнутри образа до первого подключения — контейнерный эквивалент шага 3:
Окно терминала docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
Оба клиентских образа — статические хосты nginx: настраивать во время работы нечего; форма подключения каждого клиента принимает URL сервера, идентификатор устройства и ключ сопряжения. Сигнальному реле, так же, нужен только его порт (
SIGNALING_HOST/SIGNALING_PORTможно переопределить); оно не хранит состояния, не содержит секретов и служит запасным путём: телефон использует loopback, локальную сеть, tailnet или прямой путьwss://, когда хоть один из них доступен, и переключается на реле, только когда недоступны все. Пропустите его, если ваши клиенты всегда достигают сервера напрямую.
Остальная часть этого руководства собирает сервер из исходного кода; флаги и поведение, о которых здесь идёт речь, — те же, что задают переменные окружения образа.
Предварительные требования
Заголовок раздела «Предварительные требования»- Dart SDK. Этот репозиторий закрепляет свою версию SDK с помощью fvm, поэтому предваряйте каждую команду
fvm. - Этот репозиторий, склонированный на вашу машину.
- Нативный набор инструментов, необходимый скрипту подготовки, — Rust/
cargo, а такжеmeson,ninja,pkg-config,gitи компилятор C++. Каждый скрипт сборки называет то, что не смог найти, и способ это установить. - Доступный хост: loopback для локального использования либо адрес в локальной сети или публичный адрес с TLS для удалённых клиентов.
Шаг 1: Подготовьте нативные библиотеки
Заголовок раздела «Шаг 1: Подготовьте нативные библиотеки»Нативные библиотеки обязательны — режима с ограниченной функциональностью не существует. Соберите их из корня репозитория прежде всего остального:
scripts/natives/build_natives.shЭта команда собирает rift, fff, tree-sitter с его грамматиками, aec, lame,
ccpty, cc_watcher, cc_inference и нативную библиотеку SAML в
build/natives/. Хук сборки cc_server
переносит в бандл всё, что там подготовлено, поэтому пропуск этого шага либо
приводит к явному провалу сборки, либо — с обходным путём ниже — даёт бинарник,
чья предстартовая проверка при загрузке отказывается запускаться и называет
недостающую библиотеку.
Шаг 2: Соберите бинарник
Заголовок раздела «Шаг 2: Соберите бинарник»cd apps/cc_serverfvm dart build cliВ бандле рядом с бинарником поставляются libsqlite3 и подготовленные нативные
библиотеки — системный SQLite и движок Flutter не нужны. Исполняемый файл
оказывается по пути ./build/cli/<os_arch>/bundle/bin/cc_server.
Шаг 3: Сопрягите клиент до первого запуска
Заголовок раздела «Шаг 3: Сопрягите клиент до первого запуска»В новом каталоге данных нет сопряжённых устройств и предварительно
распределённого ключа, поэтому запрос ключа сопряжения у клиента пока нечем
удовлетворить. Создайте его подкомандой pair.
Она напрямую записывает global.db и secrets.json; сервер, который уже
обслуживает этот каталог данных, подхватывает новое устройство без перезапуска:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Она выводит три значения для вставки в форму подключения клиента:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Полезные флаги: --device (по умолчанию web-client; идентификатор также задаёт
уровень устройства — desktop, ios, android, всё остальное считается
веб-клиентом), --label (по умолчанию — название платформы плюс имя хоста этой
машины), --host (хост, который выводится в URL, поскольку loopback недоступен с
другой машины) и --client-url. Повторный запуск pair меняет ключ этого
устройства и завершает его активные сеансы. Сопряжение никогда не создаёт рабочее
пространство: первое создаёт и называет онбординг подключающегося клиента.
С --client-url она также выводит QR-код, считываемый из терминала, который
открывает уже заполненный веб-клиент:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030 \ --bind any --host 192.168.1.42 --client-url https://app.usectrl.devУчётные данные, созданные cc_server pair, не имеют срока действия;
созданные в приложении всегда истекают через 30 дней. Отзывайте устройство,
созданное через CLI, в Настройки → Вы → Ваши устройства, когда оно больше не
нужно.
Шаг 4: Запустите сервер
Заголовок раздела «Шаг 4: Запустите сервер»На loopback — это значение по умолчанию, и его достаточно для клиента на той же машине:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Чтобы добраться до него с другой машины, привяжитесь ко всем интерфейсам.
Привязка не к loopback без TLS отклоняется при запуске
(Refusing to bind non-loopback address … without TLS), поэтому предоставьте
сертификат:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --tls-cert /path/fullchain.pem --tls-key /path/privkey.pem \ --public-url wss://server.example:9030/rpcЛибо терминируйте TLS в обратном прокси в доверенной частной сети и включите привязку в открытом виде за ним:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpc--insecure игнорируется, если заданы и --tls-cert, и --tls-key, — TLS
всегда побеждает. Сервер сообщает о состоянии без шифрования как
insecure: true в GET /healthz, и клиенты помечают такое соединение как
небезопасное.
Сервер работает до SIGINT/SIGTERM, после чего корректно завершает работу.
Шаг 5: Подключите клиент
Заголовок раздела «Шаг 5: Подключите клиент»Направьте клиент на URL сервера и ключ сопряжения из шага 3:
- Приложение для компьютера: на экране первого запуска (Как запускать Control Center?) заполните поля подключения вместо Запустить в этом приложении или добавьте сервер позже в Настройки → Сервер → Подключение и состояние. См. Подключиться к удалённому серверу.
- Веб-клиент: откройте app.usectrl.dev (или собственную копию веб-сборки) и введите URL сервера, идентификатор устройства и ключ сопряжения.
- Телефон: сопрягите приложение Remote из запущенного клиента — см. Привязать устройство.
Шаг 6: Подключите Google Calendar (необязательно)
Заголовок раздела «Шаг 6: Подключите Google Calendar (необязательно)»Чтобы синхронизировать календарь рабочего пространства без графического интерфейса, используйте поток с кодом устройства:
GOOGLE_OAUTH_CLIENT_ID=<id> GOOGLE_OAUTH_CLIENT_SECRET=<secret> \ ./build/cli/<os_arch>/bundle/bin/cc_server calendar connect \ --data-dir ./data --workspace <workspace-id>Она выводит код и URL для подтверждения на другом устройстве, сохраняет токен
обновления на стороне сервера и завершает работу. Сборка из исходного кода не
содержит клиента Google, поэтому переменные окружения с идентификатором и
секретом обязательны — флага --google-client-id не существует. См.
Подключить Google Calendar.
Конфигурация
Заголовок раздела «Конфигурация»Флаги, использованные выше, — те, что нужны при первой настройке. Полный набор —
23 пары «флаг и переменная окружения», четыре подкоманды и структура каталога
данных — приведён в
справочнике по CLI cc_server.
Четыре, которые, скорее всего, понадобятся:
| Флаг | Значение по умолчанию | Значение |
|---|---|---|
--data-dir |
каталог данных приложений текущего пользователя ОС | Базы данных, секреты, модели и кэшированные медиа |
--port |
9030 |
Порт TCP (0 — эфемерный) |
--bind |
loopback |
loopback либо any для всех интерфейсов (требуется TLS или --insecure) |
--public-url |
выводится из привязки | URL RPC, объявляемый сопряжённым клиентам. Задайте его явно за прокси, NAT или туннелем |
Каталог данных по умолчанию — ~/Library/Application Support/control-center в macOS,
%APPDATA%\control-center в Windows и $XDG_DATA_HOME/control-center (иначе
~/.local/share/control-center) в остальных системах. Относительный к текущему
рабочему каталогу .cc_server используется, только когда не удаётся определить ни
домашний каталог, ни каталог данных приложений.
Что обслуживает сервер
Заголовок раздела «Что обслуживает сервер»cc_server — это вся поверхность продукта, а не её подмножество: путь данных и
подписки repo-RPC, эндпоинт инструментов MCP по POST /mcp и GET /sse на том же
порту, входящие вебхуки, прокси медиа и шрифтов, обратные вызовы единого входа,
протокол аренды флота, получение RSS на стороне сервера по расписанию раз в
30 минут и векторный поиск (расширение sqlite_vector регистрируется как
авто-расширение, глобальное для процесса, и переходит к полнотекстовому поиску
только там, где расширение недоступно).
Диспетчер не хранит состояния: привязки рабочего пространства к сеансу нет.
Каждый вызов в рамках рабочего пространства несёт собственный workspace_id, а
доступ определяется членством и ролью вызывающего в рабочем пространстве — а не
обладанием ключом сопряжения.
Две вещи, которые стоит знать, прежде чем открывать порт за пределы loopback:
- MCP отказывает закрыто за пределами хоста. Поверхность MCP без токена отвечает только на loopback. Привязка
anyэтого не расширяет — запрос извне хоста отклоняется с сообщением «MCP requires a bearer token to answer non-loopback clients», пока вы не настроите токен (mcp.setTokenили Настройки → Сервер → MCP-серверы). GET /healthzнамеренно не требует аутентификации: у него wildcard-CORS, и он публикует идентификатор, имя, отпечаток идентичности и версию сборки сервера. Клиентам нужен отпечаток, чтобы закрепить сервер, поэтому это сделано намеренно — но это значит, что любой доступныйcc_serverраскрывает эти сведения всякому, кто спросит.
Связанные руководства
Заголовок раздела «Связанные руководства»- Подключиться к удалённому серверу
- Привязать устройство
- Запустить воркер флота
- Подключить Google Calendar