Solução de problemas
Cada entrada abaixo é um sintoma que você consegue observar de fato, a causa por trás dele, e o que fazer. Todas são falhas para as quais esta stack tem evidência real, registrada nos arquivos compose, nos arquivos de configuração ou no código do próprio proxy. Se o seu problema não está aqui, o log de boot do crab-shell-proxy é quase sempre o primeiro lugar certo para olhar — ele nomeia variáveis faltando de propósito.
Um agente ganglion para de responder, e o proxy loga uma falha no pull da imagem
Sintoma. Conversar com um agente que roda o harness ganglion falha. O log do proxy carrega um erro de pull nomeando a imagem, tipicamente zombie-crab/crab-ganglion:dev. Os outros agentes não são afetados. Isso costuma começar logo depois de um docker system prune, ou em um servidor cujo deploy foi feito baixando imagens em vez de construindo-as.
Causa. O EnsureImage em crab/crab-shell-proxy/internal/docker/client.go tem um caminho rápido: ele pergunta ao daemon pela imagem localmente e, se ela estiver lá, retorna sem contatar registry nenhum. É isso que permite que uma tag construída localmente funcione. Ele não para por aí quando a imagem está faltando — ele cai para POST /images/create, um pull de registry de verdade, que dá 404 em uma tag que nenhum registry tem.
O CRAB_GANGLION_IMAGE padrão é zombie-crab/crab-ganglion:dev, um nome que só existe na máquina que o construiu. Um prune remove imagens não usadas, essa vai junto, e o agente fica morto até a tag voltar.
Correção. Reconstrua a tag. O serviço ganglion-image em docker-compose.yaml existe exatamente para isso: é um serviço que só constrói, que produz a imagem, roda /bin/true e sai, e o crab-shell-proxy espera a conclusão dele. O picoclaw-image faz o mesmo para o outro harness, então os dois são recuperados pelo mesmo comando:
docker compose up -d --build
Em um servidor, prefira a correção duradoura: defina CRAB_GANGLION_IMAGE no seu .env com uma referência imutável publicada — o workflow de release do crab/crab-ganglion-harness publica ghcr.io/lepistabioinformatics/crab-ganglion:sha-<short-sha> — e baixe-a. Veja Deploy para entender por que essa referência precisa ser imutável e não uma tag móvel.
Nada sobe: o gateway nunca fica saudável
Sintoma. O docker compose up -d retorna, mas o mycelium-gateway fica esperando e o chat-webapp nunca inicia. Nada está acessível.
Causa. O mycelium-gateway declara depends_on: crab-shell-proxy: condition: service_healthy, e o chat-webapp por sua vez depende de o gateway estar saudável, então um proxy que sai no boot leva a stack inteira junto.
O proxy sai fatalmente por um conjunto pequeno e específico de razões. O validate() dele rejeita uma configuração sem hostDataRoot, sem network, com um agente sem serviceName ou sem template, ou com um agente nomeando um harness que ele não orquestra. Separadamente, um agente picoclaw cujo bearer token não pode ser resolvido do ambiente é fatal — deliberadamente, porque descartar um em silêncio deixaria um membro trancado do lado de fora sem nenhum sinal no boot.
Correção.
docker compose logs crab-shell-proxy
A falha nomeia o que está faltando. Defina isso no .env e suba a stack de novo.
As rotas de um agente respondem 404 e todo o resto funciona
Sintoma. Um único agente se comporta como se não existisse — suas rotas respondem 404 — enquanto os outros agentes estão bem e o proxy está saudável.
Causa. Um agente ganglion se remove na carga em vez de derrubar o proxy, e esse é o comportamento projetado, não um defeito. Um mesmo arquivo de configuração pode descrever vários deploys, e um agente que chega a um host sem chave para ele degrada para “esse agente não existe” em vez de “o proxy não vai subir”, o que derrubaria junto todos os outros agentes. Há três motivos para isso acontecer: CRAB_GANGLION_IMAGE não está definida, a variável apiKeyEnv do modelo do agente não está definida, ou o bearer token dele não pode ser resolvido.
Nada é rebaixado em silêncio. O proxy imprime uma linha por agente desabilitado no boot: agent "<key>" disabled: <reason> — its routes will answer 404, em que o motivo nomeia a configuração, por exemplo que ganglionImage (ou CRAB_GANGLION_IMAGE) não está definida e não tem valor padrão de propósito.
Correção. Procure disabled no log de boot, defina a variável que ele nomeia e reinicie o proxy.
Um agente que não declara a chave
harness:é hoje um agente ganglion (DefaultHarnessemcrab/crab-shell-proxy/internal/config/config.go), então está sujeito às três verificações. Declare o harness explicitamente em todo agente — uma atualização de configuração não deveria trocar um runtime por omissão.
Criar uma tarefa agendada responde 501
Sintoma. O painel de Tarefas, ou uma chamada direta à API, recusa criar, alterar, desabilitar ou apagar uma tarefa agendada com um 501 Not Implemented e uma mensagem como:
creating scheduled tasks over this API is not available on the picoclaw
harness (agent beta): its agent creates them itself
Causa. crab/crab-shell-proxy/internal/httpapi/cron_write.go recusa toda rota de escrita de cron para um agente cujo harness não é o ganglion. No picoclaw o harness é dono do armazenamento de jobs e mantém a agenda viva em memória, então um botão no painel poderia discordar dos timers que estão de fato rodando. No ganglion o proxy é dono da agenda, acima do container, então ele consegue atender às escritas honestamente. As rotas de leitura são atendidas nos dois harnesses, e é por isso que você ainda vê as tarefas de um agente picoclaw e o histórico de execução delas.
Correção. Em um agente picoclaw, peça ao próprio agente no chat para criar, alterar ou remover a tarefa; ele é dono delas. Se você quer os controles de escrita do painel, use um agente no harness ganglion. Veja Tarefas agendadas.
O mecanismo geral é
requireHarnessFeatureeminternal/httpapi/harness_gate.go: um recurso que o harness não consegue atender responde 501 nomeando o harness, em vez de fingir sucesso. Essa regra existe porque um harness já retirado deixou, certa vez, projetos serem criados, guardados, listados e reportados como ativos sem mudar nada no agente que respondia. Como as tabelas desse arquivo estão hoje, ele não reserva nada de nenhum dos dois harnesses distribuídos, então a escrita de cron acima é o 501 que você vai realmente encontrar.
O gateway responde 400 "Request path does not match any service"
Sintoma. Uma requisição através do mycelium-gateway é rejeitada antes mesmo de chegar ao proxy, com exatamente esse texto.
Causa. O Mycelium roteia pelo primeiro segmento do caminho, comparado com uma chave de serviço na configuração TOML dele, e depois compara o resto do caminho com os blocos [[<agent>.path]] desse serviço. Um caminho sem bloco correspondente é recusado aqui. É o que acontece quando existe uma rota no proxy mas a configuração do gateway não foi estendida para permiti-la — as rotas de leitura /v1/cron/* são o exemplo de sempre, e todos os perfis em deploy/ já trazem um bloco por agente para elas.
Correção. Adicione o bloco [[<agent>.path]] correspondente à configuração de gateway que o seu modo monta (deploy/standalone/config.standalone.toml ou deploy/prod/config.base.toml) e recrie o gateway.
O mesmo texto de erro aparece por um motivo sem relação: a própria rota
/healthdo Mycelium só trataGETe rejeitaHEADcom essa mensagem. Se você a está sondando com algo que enviaHEAD—wget --spider, por exemplo — o 400 é sobre o método, não sobre roteamento. Os dois healthchecks emdocker-compose.yamlusam umGETsimples por isso.
O Grafana está vazio e todos os containers estão saudáveis
Sintoma. Os dashboards carregam, os painéis desenham, e não há dado nenhum. Nenhum container está com problema, nenhum log mostra erro, e o log do próprio harness-sphere parece movimentado.
Causa. A cadeia de -f foi omitida em algum comando. O Compose aplica um overlay só quando você o nomeia, então docker compose up -d, restart, ou mesmo up -d harness-sphere sem os dois arquivos devolve cada serviço que o overlay sobrescreve para o docker-compose.yaml. Para o harness-sphere isso significa que o exportador volta para stdout e o bind-mount da configuração dele some, então ele imprime as métricas nos próprios logs em vez de enviá-las. Nada, em lugar nenhum, avisa disso.
Correção. Suba nomeando os dois arquivos e depois elimine a armadilha colocando isto no .env da raiz do repositório; feito isso, um docker compose up -d puro passa a estar correto:
COMPOSE_FILE=docker-compose.yaml:docker-compose.observability.yaml
Veja Observabilidade.
O agente diz que salvou um arquivo, e o painel de Arquivos não o lista
Sintoma. O agente relata ter escrito um documento, e nada aparece no painel de Arquivos do membro. O arquivo foi mesmo escrito — ele está apenas em um lugar onde a interface não procura.
Causa. public/ dentro de um workspace é o único diretório que a interface do membro lista, e public/attachments/ é onde o agente é instruído a escrever as entregas. Um arquivo de memória gerenciado (FILE_DELIVERY.md) leva essa regra para dentro de todo workspace e é lido a cada turno, justamente porque um arquivo escrito fora de public/ é invisível para o membro, não importa como o deploy esteja configurado.
Correção. Peça ao agente para mover ou salvar de novo o arquivo em public/attachments/, dizendo o caminho. Não escreva em uploads/: esse é o nome antigo do diretório, mantido no código só para que uma migração única reconheça um workspace anterior à renomeação.
Uma surpresa relacionada: o aviso de clipe que o proxy acrescenta quando um arquivo é entregue existe só no stream e nunca é persistido. Depois de recarregar a página, o único registro de um arquivo entregue é o que o próprio modelo escreveu na resposta, e é por isso que a regra gerenciada também manda ele dizer o caminho em voz alta.
As abas Mapa e Entidades continuam vazias
Sintoma. O grafo de conhecimento nunca registra nada. Nenhum erro é mostrado e nada é registrado em log sobre isso.
Causa. CRAB_MCP_TOKEN_SECRET está vazia. Esse valor assina o bearer token que um agente criado apresenta de volta ao endpoint MCP do próprio proxy. Não definir é um estado suportado e deliberado: /v1/mcp não é registrado, nenhum bloco de servidor MCP é escrito em nenhum workspace, e todo o resto se comporta normalmente. Um deploy que esqueceu o segredo tem que ficar sem memória, e não com um endpoint sem autenticação alcançável por todo container da rede.
Correção. Gere um com openssl rand -hex 32, defina-o no .env e recrie o proxy. Os dois arquivos .env.example explicam isso.
O harness-sphere não consegue atribuir instâncias, ou /v1/instances responde 404
Sintoma. O observador reporta o host, a si mesmo e as três sondas de serviço, mas nada por tenant. Uma requisição direta a GET /v1/instances no proxy retorna 404.
Causa. CRAB_TELEMETRY_TOKEN está vazia, então a rota não é registrada de jeito nenhum — ausente, não 401. Esse endpoint revela toda a topologia de tenants, subscriptions e usuários do deploy, então um deploy que não optou por isso não ganha superfície nova.
Correção. Gere um segredo novo com openssl rand -hex 32 e defina-o. Não reaproveite o bearer token de um agente para isso: um token de agente dá acesso a conversar como qualquer membro de qualquer tenant, e o raciocínio está em Observabilidade.
rm -rf data/... falha com Permission denied
Sintoma. Apagar o estado em disco durante um reset falha.
Causa. O crab-shell-proxy cria a árvore do tenant como root, 0700, então os diretórios não são seus.
Correção. Use sudo nesse único comando, como faz a sequência de reset em Deploy. É também por isso que o harness-sphere roda como root com um bind somente leitura: nada mais conseguiria percorrer a árvore.
Nenhum e-mail de login chega no standalone
Sintoma. Você pede um magic link, ou o código de bootstrap do Staff, e nenhum e-mail chega.
Causa. O standalone não tem SMTP de verdade. Ele traz um transporte simulado que escreve a mensagem no log em vez de enviá-la — uma propriedade deliberada do modo.
Correção. Leia no log do gateway. Os links de login caem no mesmo lugar.
docker compose logs mycelium-gateway | grep -i bootstrap
Ninguém consegue entrar em um deploy de prod recém-criado
Sintoma. A stack de prod está no ar, o gateway está rodando, e a autenticação não funciona.
Causa. O adaptador Postgres do Mycelium não tem migrações embutidas, ao contrário do de SQLite, então um banco recém-criado não tem schema.
Correção. Rode a aplicação de schema única, em dois passos, descrita em Banco de dados e migrações. Os dois passos são necessários na versão que este repositório fixa; o segundo não é opcional.
Para onde ir agora
Se a falha é sobre como um deploy é montado, Deploy é o relato mais completo. Se é sobre o que o observador mostra ou deixa de mostrar, Observabilidade cobre essa superfície. Para o comportamento dos dois harnesses em si, veja Harnesses.