Executar um servidor headless
Execute o cc_server numa máquina que fique ligada e depois ligue-se a ele a
partir do seu computador, de um navegador ou do seu telemóvel. O servidor é um
binário nativo em Dart puro — sem motor do Flutter — por isso é executado em modo
headless no macOS, Linux ou Windows. É ele que detém a base de dados, executa os
agentes e faz todas as chamadas a APIs externas; os clientes apenas renderizam.
Executar no Docker (imagens pré-compiladas)
Secção intitulada “Executar no Docker (imagens pré-compiladas)”Cada versão publica um stack autoalojado de quatro imagens GHCR — o backend, os
dois clientes finos estáticos e o relay de emparelhamento opcional — mais uma
imagem cc-server-demo separada para o anfitrião de demonstração público. Uma
instalação autoalojada não precisa de nenhuma cópia do código-fonte. Fixe uma
etiqueta de versão (ghcr.io/samuelalev/<image>:v0.0.1-rc.1) ou acompanhe a
latest.
| Imagem | O que é | Publica |
|---|---|---|
ghcr.io/samuelalev/cc-server |
O backend: base de dados, agentes, MCP, webhooks | -p 9030:9030 |
ghcr.io/samuelalev/cc-webapp |
O cliente web (nginx estático) | -p 8080:8080 |
ghcr.io/samuelalev/cc-remote |
A PWA complementar para telemóvel (nginx estático) | -p 8081:8080 |
ghcr.io/samuelalev/cc-signaling-server |
O relay de emparelhamento WebRTC (opcional) | -p 8788:8788 |
O stack completo como ficheiro 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:Aspetos que vale a pena saber antes de expor isto para além do loopback:
-
A imagem
cc-serverincluiCC_SERVER_INSECURE=1(tem de se ligar a0.0.0.0para receber o tráfego da porta publicada), o que só é seguro atrás de um reverse proxy que termina o TLS — Caddy, Traefik, nginx ou um Cloudflare Tunnel — numa rede de confiança. Para terminar o TLS no próprio processo, monte um certificado e definaCC_SERVER_TLS_CERT/CC_SERVER_TLS_KEY(e depois removaCC_SERVER_INSECURE). Tudo pode ser substituído comdocker run -e …ou com o blocoenvironment:do compose. -
/dataé o único estado. As bases de dados SQLite, os segredos dos dispositivos emparelhados, os modelos descarregados e o áudio das reuniões residem todos no volume — faça uma cópia de segurança dele e o contentor torna-se descartável. -
Emparelhe um cliente a partir do interior da imagem antes da primeira ligação, o equivalente em contentor do passo 3:
Janela do terminal docker run --rm -it -v cc_data:/data \--entrypoint /app/bin/cc_server ghcr.io/samuelalev/cc-server:latest pair -
As duas imagens de cliente são anfitriões nginx estáticos — nada para configurar em tempo de execução; o formulário de ligação de cada cliente recebe o URL do servidor, o id do dispositivo e a chave de emparelhamento. O relay de sinalização, do mesmo modo, só precisa da sua porta (
SIGNALING_HOST/SIGNALING_PORTsubstituíveis); não tem estado, não guarda segredos e é um fallback — um telemóvel usa loopback, LAN, tailnet ou um caminhowss://direto quando algum está acessível, e só recorre ao relay quando nenhum está. Ignore-o se os seus clientes chegarem sempre diretamente ao servidor.
O resto deste guia compila o servidor a partir do código-fonte; as flags e o comportamento que aborda são os mesmos que as variáveis de ambiente da imagem alimentam.
Pré-requisitos
Secção intitulada “Pré-requisitos”- O Dart SDK. Este repositório fixa o seu SDK com fvm, por isso prefixe todos os comandos com
fvm. - Este repositório clonado.
- A cadeia de ferramentas nativa de que o script de preparação precisa — Rust/
cargo, além demeson,ninja,pkg-config,gite um compilador de C++. Cada script de compilação indica o que não conseguiu encontrar e como o instalar. - Um anfitrião acessível: loopback para uso local, ou um endereço de LAN/público com TLS para clientes remotos.
Passo 1: Preparar as bibliotecas nativas
Secção intitulada “Passo 1: Preparar as bibliotecas nativas”As bibliotecas nativas são obrigatórias — não existe modo degradado. Compile-as a partir da raiz do repositório antes de qualquer outra coisa:
scripts/natives/build_natives.shIsto compila rift, fff, o tree-sitter e as suas gramáticas, aec, lame,
ccpty, cc_watcher, cc_inference e a biblioteca nativa do SAML em
build/natives/. O hook de compilação do cc_server
reemite para o pacote tudo o que estiver preparado ali, por isso saltar este passo
ou faz a compilação falhar de imediato ou — com a válvula de escape abaixo —
produz um binário cuja verificação de arranque se recusa a iniciar e indica a
biblioteca em falta.
Passo 2: Compilar o binário
Secção intitulada “Passo 2: Compilar o binário”cd apps/cc_serverfvm dart build cliO pacote inclui libsqlite3 e as bibliotecas nativas preparadas ao lado do
binário — não é preciso o SQLite do sistema nem um motor do Flutter. O executável
fica em ./build/cli/<os_arch>/bundle/bin/cc_server.
Passo 3: Emparelhar um cliente antes do primeiro arranque
Secção intitulada “Passo 3: Emparelhar um cliente antes do primeiro arranque”Um diretório de dados novo não tem nenhum dispositivo emparelhado nem chave
pré-partilhada, por isso o pedido de chave de emparelhamento de um cliente ainda
não pode ser satisfeito. Gere uma com o subcomando pair.
Escreve global.db e secrets.json diretamente; um servidor que já esteja a
servir esse diretório de dados reconhece o novo dispositivo sem reiniciar:
./build/cli/<os_arch>/bundle/bin/cc_server pair --data-dir ./data --port 9030Imprime três valores para colar no formulário de ligação de um cliente:
Connect a thin client (paste into its connect form): Server ws://localhost:9030/rpc Device id web-client Pairing key <a freshly generated key>Flags úteis: --device (predefinição web-client; o id também escolhe o nível do
dispositivo — desktop, ios, android, e qualquer outra coisa é um cliente
web), --label (a predefinição é o nome da plataforma mais o hostname desta
máquina), --host (o anfitrião a imprimir no URL, uma vez que o loopback não é
acessível a partir de outra máquina) e --client-url. Voltar a executar pair
roda a chave desse dispositivo e termina as suas sessões ativas. O emparelhamento
nunca cria um espaço de trabalho: o onboarding do cliente que se liga dá-lhe nome
e cria o primeiro.
Com --client-url imprime também um QR que pode ser lido pelo terminal e que abre
o cliente web já preenchido:
./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.devUma credencial gerada por cc_server pair não tem validade; uma gerada na
aplicação expira sempre ao fim de 30 dias. Revogue um dispositivo gerado pela CLI
em Definições → Você → Seus dispositivos quando já não precisar dele.
Passo 4: Iniciar o servidor
Secção intitulada “Passo 4: Iniciar o servidor”Em loopback — a predefinição e tudo o que precisa para um cliente na mesma máquina:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030Para o alcançar a partir de outra máquina, vincule todas as interfaces. Um bind
que não seja de loopback sem TLS é recusado no arranque (Refusing to bind non-loopback address … without TLS), por isso forneça um certificado:
./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/rpcOu termine o TLS num reverse proxy numa rede privada de confiança e opte por um bind em texto simples atrás dele:
./build/cli/<os_arch>/bundle/bin/cc_server --data-dir ./data --port 9030 \ --bind any --insecure --public-url wss://server.example/rpcO --insecure é ignorado quando --tls-cert e --tls-key estão ambos definidos —
o TLS ganha sempre. O servidor anuncia o estado de texto simples como
insecure: true em GET /healthz e os clientes marcam essa ligação como
insegura.
O servidor é executado até receber SIGINT/SIGTERM e depois encerra de forma
limpa.
Passo 5: Ligar um cliente
Secção intitulada “Passo 5: Ligar um cliente”Aponte um cliente ao URL do servidor e à chave de emparelhamento do passo 3:
- Aplicação para computador: no ecrã de primeira execução (Como o Control Center deve ser executado?) preencha os campos de ligação em vez de Executar nesta aplicação, ou adicione o servidor mais tarde em Definições → Servidor → Ligação e status. Consulte Ligar a um servidor remoto.
- Cliente web: abra app.usectrl.dev (ou a sua própria cópia da versão web) e introduza o URL do servidor, o id do dispositivo e a chave de emparelhamento.
- Telemóvel: emparelhe a aplicação Remote a partir de um cliente em execução — consulte Emparelhar um dispositivo.
Passo 6: Ligar um Google Calendar (opcional)
Secção intitulada “Passo 6: Ligar um Google Calendar (opcional)”Para sincronizar o calendário de um espaço de trabalho sem nenhuma interface gráfica ligada, use o fluxo de código de dispositivo:
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>Imprime um código e um URL para aprovar noutro dispositivo, guarda o refresh token
do lado do servidor e termina. Uma compilação a partir do código-fonte não inclui
nenhum cliente Google, por isso as variáveis de ambiente do id e do segredo são
obrigatórias — não existe nenhuma flag --google-client-id. Consulte
Ligar um Google Calendar.
Configuração
Secção intitulada “Configuração”As flags usadas acima são as de que uma primeira configuração precisa. A superfície
completa — 23 pares de flag e variável de ambiente, os quatro subcomandos e a
estrutura do diretório de dados — está na
referência da CLI do cc_server.
As quatro de que mais provavelmente vai precisar:
| Flag | Predefinição | Significado |
|---|---|---|
--data-dir |
o diretório de dados de aplicação por utilizador do SO | Bases de dados, segredos, modelos e multimédia em cache |
--port |
9030 |
Porta TCP (0 = efémera) |
--bind |
loopback |
loopback, ou any para todas as interfaces (precisa de TLS ou --insecure) |
--public-url |
derivado do bind | O URL de RPC anunciado aos clientes emparelhados. Defina-o explicitamente atrás de um proxy, NAT ou túnel |
O diretório de dados predefinido é ~/Library/Application Support/control-center
no macOS, %APPDATA%\control-center no Windows e $XDG_DATA_HOME/control-center
(ou, caso contrário, ~/.local/share/control-center) em qualquer outro sistema.
Um .cc_server relativo ao diretório de trabalho atual só é usado quando não é
possível resolver nenhum diretório pessoal ou de dados de aplicação.
O que o servidor serve
Secção intitulada “O que o servidor serve”O cc_server é toda a superfície do produto, não um subconjunto: o caminho de
dados e as subscrições de repo-RPC, o endpoint de ferramentas MCP em POST /mcp
e GET /sse na mesma porta, os webhooks de entrada, os proxies de multimédia e de
tipos de letra, os callbacks de início de sessão único, o protocolo de lease da
frota, a recolha de RSS do lado do servidor segundo um agendamento de 30 minutos
e a pesquisa vetorial (a extensão sqlite_vector é registada como auto-extension
global do processo, degradando para pesquisa de texto integral apenas onde a
extensão não está disponível).
O dispatcher é sem estado: não existe qualquer vínculo de espaço de trabalho
por sessão. Cada chamada com âmbito de espaço de trabalho transporta o seu próprio
workspace_id e o acesso é decidido pela pertença e pela função do autor da
chamada no espaço de trabalho — não por deter uma chave de emparelhamento.
Duas coisas a saber antes de expor a porta para além do loopback:
- O MCP falha em modo fechado fora do anfitrião. Uma superfície MCP sem token responde apenas a loopback. Vincular
anynão a amplia — um pedido de fora do anfitrião é recusado com “MCP requires a bearer token to answer non-loopback clients” até configurar um token (mcp.setToken, ou Definições → Servidor → Servidores MCP). GET /healthznão tem autenticação por conceção, tem CORS com wildcard e publica o id, o nome, a impressão digital de identidade e a versão de compilação do servidor. Os clientes precisam da impressão digital para fixar o servidor, por isso isto é deliberado — mas significa que qualquercc_serveracessível divulga tudo isso a quem o pedir.
Guias relacionados
Secção intitulada “Guias relacionados”- Ligar a um servidor remoto
- Emparelhar um dispositivo
- Executar um worker da frota
- Ligar um Google Calendar