Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Agentes, workspaces e projetos

Um agente é uma coisa para a pessoa que o usa e outra coisa em disco. Este capítulo cobre as duas, depois o layout de diretórios que o proxy escreve e, por fim, o único lugar em que os dois harnesses divergem de propósito.

O que é um agente para um membro

Quando você entra no cliente de chat, você não escolhe um modelo nem um container. Você escolhe um agentealpha, beta, o que este deploy declarar — e ganha uma conversa com ele.

Sem nenhum workspace selecionado, a área de chat vira um seletor: uma linha por tenant, uma caixa por subscription dentro dela, e os agentes que você alcança como blocos mostrando suas permissões em cada um (um olho para leitura, um lápis para escrita). Clicar em um abre uma conversa nova.

Um agente é, portanto, um tipo de assistente, compartilhado no nome entre todos que o alcançam e privado na substância para cada um deles. Dois membros conversando com alpha estão falando com a mesma persona, a mesma configuração de modelo e as mesmas skills publicadas pelo administrador — em dois containers diferentes, com duas memórias diferentes, duas árvores de arquivos diferentes e nenhum caminho entre elas.

Seu agente é chaveado pelo seu id de conta, não pelo seu e-mail. E-mails mudam e são guardados só como um marcador legível para operadores; troque seu e-mail e o seu agente e o histórico dele continuam seus.

O que é um agente em disco

A unidade de isolamento do proxy é uma chave de quatro partes: tenant, subscription, papel (a chave do agente) e id de conta do usuário. Essa chave nomeia um diretório:

<data root>/tenants/<tenant>/subscriptions/<subscription>/agents/<agent>/users/<user>/

Cada componente é sanitizado antes de virar um segmento de caminho, então nada vindo de uma requisição consegue criar um separador ou um ... O diretório é criado preguiçosamente, no primeiro chat do membro — ou de antemão para uma subscription inteira, se o webhook opcional subscriptionAccount.created estiver registrado no mycelium.

Esse diretório é o que este livro chama de diretório do usuário. Ele pertence ao proxy. Parte dele é montada no container do agente; parte, de propósito, não é.

O layout

<user dir>/                       the proxy's, NOT necessarily mounted
├── config.json                   harness configuration, proxy-written
├── .security.yml                 picoclaw only
├── .projects.json                proxy-owned: which projects exist
├── .schedules.json               proxy-owned: scheduled tasks (ganglion)
├── .crab-owner.json              proxy-owned: who this workspace belongs to
├── .crab-model.json              proxy-owned: this member's model choice
├── .crab-mode.json               proxy-owned: this instance's lifecycle override
├── workspace/                    THE MAIN AGENT
│   ├── AGENT.md SOUL.md HEARTBEAT.md USER.md
│   ├── memory/  public/  sessions/  ...
└── workspace-<project-id>/       ONE PER PROJECT, A SIBLING OF workspace/
    ├── AGENT.md SOUL.md HEARTBEAT.md USER.md
    └── memory/  public/  sessions/  ...

Duas regras fazem valer a pena aprender este layout em vez de consultá-lo.

Todo harness organiza seu diretório por usuário da mesma maneira. Um caminho que significa uma coisa no picoclaw significa a mesma coisa em qualquer outro harness que esta stack criar. Isso não é uma gentileza com o picoclaw; é o que permite ao proxy ler e escrever esses diretórios com um só conjunto de funções em vez de um por harness. Um desvio por harness que esteja faltando não falha alto — ele lê um diretório que nunca existiu e relata que o membro não tem histórico, nem arquivos, nem tarefas agendadas.

Os dotfiles acima de workspace/ são do proxy, não do agente. Eles decidem quais identidades de projeto existem, qual modelo é usado, se o container pode ser mantido vivo e o que está agendado. Um agente capaz de editá-los poderia desviar para si as conversas de um colega, escolher o endpoint para onde as próprias chaves são enviadas, ou manter o próprio container rodando indefinidamente. Por isso eles ficam fora do alcance do agente — por dois mecanismos diferentes, dependendo do harness.

.crab-owner.json é um pequeno marcador JSON que registra a tupla completa do workspace e o e-mail do dono, para que um operador consiga descobrir a que humano um container pertence. Ele é necessário porque o nome do container não consegue carregar essa informação: a tupla completa são dois UUIDs, o que passa do limite de 63 caracteres de um rótulo DNS.

O workspace de um projeto é um irmão

Quando um membro cria um projeto, o proxy cria para ele uma segunda identidade de agente com um workspace próprio:

workspace-<project-id>       correct
workspace/projects/<id>      WRONG

workspace-<id> é irmão de workspace/, nunca filho dele. O nome não é uma preferência. O picoclaw deriva o workspace de um agente nomeado como <defaults.workspace>/../workspace-<id> quando a configuração do agente não define um, então a ferramenta dele resolve esse caminho independentemente do que o proxy escreve. O helper WorkspaceSegment do proxy devolve workspace para o projeto vazio e workspace-<id> caso contrário, e não faz desvio por harness.

Já fez. O ganglion manteve os projetos dentro do workspace principal por uma release, para poupar-se de um segundo bind, e o custo foi que uma função era na verdade duas fingindo ser uma — todo chamador que buscava as sessões de um projeto, seu diretório público ou sua mídia herdava a divisão, e um chamador que esquecia não falhava: ele lia um diretório que nunca existiu. O caminho filho legado sobrevive só para que o código de limpeza consiga achar uma subárvore escrita antes da migração. Nada pode criar um novo.

O workspace de cada projeto tem seus próprios arquivos de persona, sua própria memória, suas próprias sessões e seu próprio diretório public/. O histórico de um projeto não é alcançável pedindo o do workspace principal, e esse é o ponto: um projeto delimita as transcrições, a janela de contexto e os arquivos. Veja Trabalhando com projetos para o lado do membro.

O que os dois harnesses montam, e por que isso importa

O layout é compartilhado. O conjunto de binds não é, e essa diferença é estrutural, não acidental.

O picoclaw monta o diretório do usuário inteiro. Ele tem sua própria opção restrict_to_workspace, que mantém o agente dele dentro de workspace/, então o estado do próprio proxy pode ficar ao lado do workspace e ainda assim fora de alcance. O proxy monta ainda uma visão somente leitura de .secrets em cada workspace, um por projeto além do principal, mais a cascata de persona e a raiz de skills compartilhada.

O ganglion monta cada workspace separadamenteworkspace/, e um bind por workspace-<id> — e nada acima deles.

A razão é que o ganglion não tem restrict_to_workspace, e não teria como ter um que fosse útil. Sua única ferramenta de sistema de arquivos é /bin/sh -c <string>: não há argumento de caminho para recusar, e qualquer denylist de .. ou /etc é derrotada por $(echo L2V0Yw== | base64 -d). O que o confina, em vez disso, é um domínio Landlock em volta de cada comando, cuja única hierarquia de leitura e escrita é o workspace do turno — mais a própria fronteira do container. Então o estado que pertence ao proxy precisa estar do outro lado da fronteira, e não apenas ao lado dela.

A primeira versão do caminho do ganglion usava um único bind largo, e o custo foi concreto: ele punha o bearer token do próprio container um nível acima do diretório de trabalho do shell, onde cat ../.crab-ganglion.json o lia.

A ilustração mais clara é .schedules.json. Ele não é um log — é uma instrução permanente ao proxy para acordar um container e rodar um turno, num timer, para sempre. Dentro de um bind do ganglion, um turno conduzido por texto não confiável poderia escrever uma. Para o picoclaw, guardar isso dentro do workspace é inofensivo, porque o agente que escreve é o mesmo processo que teria de agir sobre aquilo. Aqui o agente e o ator são processos diferentes.

Duas consequências vêm dos binds por workspace:

  • O conjunto de binds muda quando o conjunto de projetos muda, e um conjunto de binds é fixado na criação do container. Então o proxy verifica se houve divergência toda vez que garante o container e o recria quando os projetos não batem mais — senão um projeto criado depois de o container subir ficaria invisível lá dentro, e o turno rodaria contra um diretório que o proxy nunca lê.
  • As skills compartilhadas do administrador são montadas em todo workspace, não só no principal, porque a raiz do Landlock é o workspace do turno. Um índice de skills apontando para arquivos que um turno de projeto não consegue abrir é pior do que nenhum índice.

O que um workspace ganglion contém

Um workspace ganglion é semeado com memory/, public/, sessions/ e windows/. É o conjunto do picoclaw menos o que só o picoclaw tem, mais um próprio dele:

  • sem cron/ — o proxy guarda os agendamentos do ganglion, acima do bind;
  • sem .secrets/ — as credenciais chegam a este harness como variáveis de ambiente, não como arquivos;
  • windows/ é próprio do ganglion, guardando em disco a janela de contexto de cada conversa. Não tem equivalente no picoclaw.

USER.md só é semeado se o workspace ainda não tiver um. É o único arquivo de persona que o agente escreve de volta, então sobrescrevê-lo toda vez que o container é garantido apagaria o que o agente aprendeu sobre o membro a cada recriação do container — o que, para um agente scale-to-zero, é rotina.

Dentro do container a raiz de dados é /data/.ganglion, e só os filhos workspace dela são montados. O arquivo de chave de credenciais e o registro de modelos ficam ao lado dessa raiz, somente leitura, fora de todo workspace: o workspace é a única hierarquia que um comando alcança, então uma lista de modelos gravável deixaria uma ferramenta conduzida por texto não confiável escolher o endpoint para onde vão as chaves do próprio deploy.

Para onde ir agora

Skills e memória cobre o que vive dentro de memory/ e skills/; Arquivos e entrega cobre public/. Trabalhando com projetos é a visão do membro sobre os workspaces irmãos descritos aqui.