WorkspaceGuard

Servidor MCP que encapsula a CLI do WorkspaceGuard para verificações de uso do workspace.

Documentação

WorkspaceGuard

CI npm version PyPI version License: MIT

Instalação • Início rápido • Referência da CLI • Comparação • Perguntas frequentes

Medição de uso por workspace e limites de cota com falha fechada para uma única implantação compartilhada de assistente de IA auto-hospedado (Odysseus ou um backend compatível).

Installing workspaceguard-cli from npm and running init, add-workspace, set-cap, and usage for the first time in a terminal

Execute o Odysseus (ou um assistente auto-hospedado compatível) para sua casa ou pequena equipe e não há como ver quem enviou quantas mensagens neste mês, nem impedir que o uso de uma pessoa consuma o orçamento de API de todos. O WorkspaceGuard é um sidecar que adiciona essa camada: contagens de mensagens por workspace, um limite mensal opcional que falha fechado e um relatório via CLI (ou JSON) que um administrador ou outro agente pode ler.

npx workspaceguard-cli usage
-> alex   [alex@example.com]: 812 messages this period, cap 1000 (81%)
-> jordan [jordan@example.com]: 203 messages this period, cap unlimited

Instalação

npm install -g workspaceguard-cli

Ou execute sem instalar:

npx workspaceguard-cli usage

O pacote é workspaceguard-cli; o comando que ele instala é workspaceguard. Um port genuíno e independente em Python, com a mesma superfície de CLI e as mesmas formas de --json, é publicado separadamente como workspaceguard-cli no PyPI (pip install workspaceguard-cli, veja python/).

Início rápido

# Register the workspaces sharing one deployment (identity = the header value
# your reverse proxy sets after authenticating, e.g. Cloudflare Access).
workspaceguard add-workspace alex --identity alex@example.com
workspaceguard add-workspace jordan --identity jordan@example.com

# Optional: cap alex at 1000 messages/month. Omit for unlimited (the default).
workspaceguard set-cap alex 1000

# See usage for every workspace.
workspaceguard usage

Saída real de uma instalação nova:

-> alex [alex@example.com]: 0 messages this period, cap 1000 (0%)
-> jordan [jordan@example.com]: 0 messages this period, cap unlimited

Running workspaceguard status --json, rotate-key, and usage --json to show structured output and vault key rotation

Recursos

  • Contagem de mensagens por workspace. Cada requisição através do ponto de entrada chat() do sidecar incrementa um contador por workspace e por mês (src/core/usage.ts), isolado para que o uso de um workspace nunca vaze para o de outro.
  • Imposição de cota com falha fechada. Um workspace no limite recebe um QuotaExceededError antes que o backend seja chamado. Se o armazenamento de uso estiver corrompido ou ilegível, o WorkspaceGuard bloqueia requisições em vez de silenciosamente zerar a contagem de todos (veja CHANGELOG.md).
  • --json nativo para agentes em todos os comandos. workspaceguard usage --json retorna saída estruturada que um orquestrador pode analisar diretamente, sem raspar a tela.
  • Cofre AES-256-GCM com rotação real de chaves. workspaceguard rotate-key <id> re-criptografa os segredos de um workspace sob uma nova chave e invalida o texto cifrado antigo.
  • Disjuntor auto-recuperável. Chamadas ao backend abrem o circuito após 3 falhas consecutivas, depois tentam novamente por meio de uma sonda meio-aberta e fecham novamente em caso de sucesso, em vez de permanecerem desarmados para sempre.
  • Um único ponto de estrangulamento, não verificações dispersas. chat() em src/core/isolation-guard.ts é o único lugar por onde toda requisição passa: resolver workspace, verificar cota, chamar backend, registrar uso.
  • Duas distribuições independentes e testadas. O pacote TypeScript (npm) e o port Python (PyPI) implementam o mesmo design com suítes de teste separadas: 41/41 testes TypeScript e 50/50 testes Python passando no momento em que este texto foi escrito.

Referência da CLI

Todo comando aceita --json para uma saída estruturada, nativa para agentes, em vez do texto legível por humanos mostrado abaixo.

ComandoO que faz
workspaceguard initInicializa o diretório de dados e o cofre para esta implantação.
workspaceguard add-workspace <id> --identity <value>Registra um workspace, idempotente em chamadas repetidas para o mesmo id. --identity é analisado posicionalmente e deve vir imediatamente após <id>; não é uma flag independente.
workspaceguard status [--json]Lista os workspaces configurados.
workspaceguard usage [--json]Contagem de mensagens por workspace, limite e percentual usado no mês atual.
workspaceguard set-cap <id> <count|none>Define ou limpa o limite mensal de mensagens de um workspace.
workspaceguard rotate-key <id>Rotaciona a chave de criptografia do cofre de um workspace (invalida o texto cifrado antigo).
workspaceguard scan [--json]Varredura de configuração de isolamento (stub de andaime, herdado da construção original; sempre retorna uma lista vazia de achados hoje).
workspaceguard -h, --helpImprime a lista de comandos acima e sai com 0.
workspaceguard -V, --versionImprime a versão do pacote instalado e sai com 0.

Running workspaceguard scan --json, the isolation config scan scaffold stub

Opções globais

OpçãoO que faz
--data-dir <path>Diretório de dados para configuração, cofre e dados de uso. Tem precedência sobre WORKSPACEGUARD_DATA_DIR.
--forceSomente init: regenera a chave mestra mesmo se um arquivo de chave existente no diretório de dados resolvido parecer corrompido ou truncado.
--jsonSaída estruturada, nativa para agentes, em vez de texto legível por humanos.

[!WARNING] --force invalida permanentemente qualquer coisa já criptografada sob a chave mestra antiga. Use apenas quando o arquivo de chave existente for confirmadamente irrecuperável.

Resolução do diretório de dados, em ordem: flag --data-dir, depois variável de ambiente WORKSPACEGUARD_DATA_DIR, depois ~/.workspaceguard. Isso costumava ter como padrão o diretório de trabalho atual sem substituição — executar init a partir do shell errado podia silenciosamente gravar uma chave de criptografia ativa em um diretório não relacionado. init em uma chave existente e válida é idempotente (carrega e reutiliza essa chave); init em um arquivo de chave que existe mas não decodifica para uma chave válida se recusa a sobrescrevê-lo sem --force.

$ workspaceguard usage --json
{"ok":true,"usage":[{"workspaceId":"alex","identity":"alex@example.com","monthlyMessageCap":1000,"percentUsed":81,"period":"2026-07","messageCount":812,"estimatedBytes":48213}]}

O modo --json é o que torna isso nativo para agentes, e não apenas conveniente para humanos: um orquestrador ou agente de monitoramento pode chamar workspaceguard usage --json e analisar o resultado diretamente, em vez de raspar a saída do terminal.

API da biblioteca

import { createWorkspaceGuard, MockAdapter, QuotaExceededError } from "workspaceguard-cli";

const guard = await createWorkspaceGuard({ dataDir: "./data", backend: new MockAdapter() });
await guard.addWorkspace("alex", "alex@example.com");
await guard.setCap("alex", 1000);

try {
  await guard.chat("alex@example.com", "hello");
} catch (err) {
  if (err instanceof QuotaExceededError) {
    // alex is over their monthly cap
  }
}

const report = await guard.usageReport();

O port Python expõe a mesma forma: from workspaceguard import create_workspace_guard, MockAdapter, QuotaExceededError.

Servidor MCP

A distribuição Python do WorkspaceGuard inclui um servidor Model Context Protocol, para que um agente compatível com MCP (Claude Desktop, Claude Code, um orquestrador) possa chamar o WorkspaceGuard diretamente como ferramenta, em vez de invocar a CLI e analisar texto.

pip install "workspaceguard-cli[mcp]"

Ele expõe uma ferramenta, run, um wrapper genérico de subprocesso: passe a mesma lista de argumentos que você passaria na linha de comando, e ele invoca o binário workspaceguard instalado, analisa o JSON resultante e o retorna. Todo modo de falha (binário ausente, erro de lançamento, tempo limite, saída não zero, saída não analisável) retorna como um dict {"error": ...} simples, em vez de lançar exceção, para que uma chamada ruim não derrube o servidor.

run(args=["usage", "--json"])
# -> {"ok": true, "usage": [{"workspaceId": "alex", "identity": "alex@example.com", "monthlyMessageCap": 1000, "percentUsed": 0, "period": "2026-08", "messageCount": 0, "estimatedBytes": 0}]}

Para registrá-lo com um cliente compatível com MCP, como o Claude Desktop, adicione-o à configuração de servidores do cliente:

{
  "mcpServers": {
    "workspaceguard": {
      "command": "workspaceguard-mcp"
    }
  }
}

Isso pressupõe que workspaceguard-mcp já esteja em PATH (instalado via o extra mcp acima). Se você o instalou em outro lugar, substitua "command" pelo caminho completo para o script de console.

Comparação

O WorkspaceGuard é um sidecar, não um produto concorrente. Ele fica na frente de uma implantação do Odysseus (ou de um backend compatível) e adiciona a única camada que esse backend não fornece.

CapacidadeWorkspaceGuardOdysseus (nativo)
Isolamento por usuário (histórico de chat, memória, chaves de API)Não reimplementado; tratado como já resolvidoSim, embutido por padrão
Contagem de mensagens por workspaceSimNão
Limites de cota mensal, com falha fechadaSimNão
Relatório de uso via CLI / --jsonSimNão
LicençaMITAGPL-3.0

O que é o WorkspaceGuard e por que ele existe

Este projeto originalmente pretendia adicionar isolamento de workspace por usuário (histórico de chat separado, memória, chaves de API) a uma plataforma de chat de IA auto-hospedada. Um estudo de viabilidade descobriu que o Odysseus já impõe propriedade por usuário em histórico de chat, memória e tokens de API por padrão, então construir uma camada de isolamento concorrente teria duplicado trabalho que o Odysseus já faz corretamente.

O WorkspaceGuard, em vez disso, mantém seu motor de isolamento testado (separação de namespaces, um cofre AES-256-GCM com rotação real de chaves, resolução de identidade com falha fechada, um disjuntor auto-recuperável) como substrato de resolução de identidade, e constrói a camada que o Odysseus não fornece: medição de uso e imposição de cota por workspace.

Camada gratuita (este repositório, MIT): contagem de mensagens por workspace, imposição de limite mensal, relatório de uso via CLI/JSON. Não está neste repositório: um painel de cobrança multi-tenant hospedado é um produto separado, de código fechado, mencionado aqui apenas como item de roadmap e nunca mesclado neste código MIT.

Arquitetura

  • src/core/isolation-guard.ts — o único ponto de estrangulamento (chat()) por onde toda requisição passa: resolver workspace, verificar cota, chamar backend, registrar uso.
  • src/core/usage.ts — o motor de medição de uso que este projeto adiciona: contadores por workspace e por mês com rolagem automática de período, e imposição de QuotaExceededError.
  • src/core/vault.ts, src/core/namespace.ts, src/core/circuit-breaker.ts — o código do motor de isolamento original, mantido como substrato de identidade e fronteira de workspace do qual a camada de medição lê.
  • src/adapters/ — a interface BackendAdapter. MockAdapter é a única implementação hoje; um adaptador HTTP real para Odysseus ainda não foi construído.

O comportamento específico do backend nunca entra diretamente em src/core/. Tudo passa por BackendAdapter.

Limite de confiança

O WorkspaceGuard confia em um cabeçalho de identidade upstream (padrão: Cf-Access-Authenticated-User-Email) para resolver o workspace.

[!WARNING] Este serviço nunca deve ser diretamente alcançável pela rede. Execute-o apenas atrás de um proxy confiável que defina esse cabeçalho (Cloudflare Access, Tailscale, etc.). Esse limite é documentado, não imposto por código.

O que é real vs. ainda não construído

  • Real e testado: medição de uso, imposição de cota, o motor de isolamento original (cofre, separação de namespaces, disjuntor) e a CLI com modo --json, verificado por 41/41 testes TypeScript passando e 50/50 testes Python passando.
  • Ainda não construído: um adaptador HTTP real para Odysseus (apenas MockAdapter existe hoje) e um painel de cobrança multi-tenant hospedado (deliberadamente fora do escopo deste repositório MIT).

Documentação

Perguntas frequentes

P: O que o WorkspaceGuard realmente faz? R: Ele adiciona medição de uso por workspace e imposição de cota na frente de uma única implantação compartilhada de assistente de IA auto-hospedado. Conta mensagens por workspace por mês, permite definir um limite opcional que falha fechado quando atingido, e fornece a você (ou a um agente) um relatório workspaceguard usage. Ele não adiciona histórico de chat, memória ou isolamento de chaves de API por conta própria; isso já existe por padrão na plataforma alvo (veja "O que é o WorkspaceGuard" acima), e o código de isolamento do próprio WorkspaceGuard (src/core/vault.ts, src/core/namespace.ts) é mantido apenas como substrato de resolução de identidade do qual a camada de medição lê.

P: Qual é o diferencial real do WorkspaceGuard? R: Escopo estreito bem feito: não é uma plataforma completa de cobrança, e não é uma reimplementação de isolamento que o backend já tem. Toda requisição passa por um único ponto de estrangulamento (chat() em src/core/isolation-guard.ts), a imposição de cota falha fechada em um armazenamento de uso corrompido em vez de silenciosamente zerar o uso de todos (veja CHANGELOG.md), e todo comando suporta --json para saída nativa para agentes.

P: Como o WorkspaceGuard se compara ao Odysseus? R: Não é um produto concorrente. O WorkspaceGuard é um sidecar que fica na frente de uma implantação do Odysseus (ou de um backend compatível); ele não substitui nada que o Odysseus já faz. Veja a tabela de comparação acima para a divisão específica de capacidades.

P: Em quais plataformas o WorkspaceGuard roda? R: O pacote npm (workspaceguard-cli) requer Node.js 20 ou mais novo (engines.node em package.json). O port Python em python/ requer Python 3.9 a 3.13 (veja os classificadores em python/pyproject.toml). Nenhuma das distribuições inclui binário específico de plataforma, então ambos rodam onde quer que seus respectivos runtimes rodem (Linux, macOS, Windows). P: O WorkspaceGuard é uma CLI, uma biblioteca ou ambos?
R: Ambos, em ambas as distribuições. A CLI (workspaceguard <command>) cobre init, add-workspace, status, usage, set-cap, rotate-key e scan. A mesma funcionalidade pode ser importada diretamente (createWorkspaceGuard do pacote TypeScript, create_workspace_guard do pacote Python) para qualquer coisa que queira chamá-la a partir do código em vez de invocar via shell.

P: Qual é uma limitação real atual que devo conhecer antes de confiar nisso?
R: O único adaptador de backend implementado hoje é o MockAdapter, um adaptador em memória usado para testes e experimentação local. Um adaptador HTTP real do Odysseus ainda não foi construído (veja docs/integrations/backends.md), então o WorkspaceGuard ainda não encaminha tráfego de chat ao vivo para uma implantação real do Odysseus. A lógica de medição e cota é real e testada; a ponte de rede para um backend ao vivo é a parte que ainda falta.

P: O WorkspaceGuard precisa de suas próprias chaves de API ou armazena alguma das minhas credenciais de provedor de IA?
R: Não. O único adaptador de backend que existe atualmente (MockAdapter) é em memória e não chama nenhuma API externa. Todo o comportamento específico do backend é isolado atrás da interface BackendAdapter (src/adapters/), então o código do próprio WorkspaceGuard nunca precisa ver credenciais de provedor diretamente.

P: O WorkspaceGuard é gratuito para uso comercial?
R: Sim. Este repositório é totalmente licenciado sob MIT, sem licenciamento duplo e sem bloqueio de recursos. O painel de cobrança hospedado e multi-tenant mencionado acima é um produto separado, de código fechado, descrito apenas como um item de roadmap; nenhum código de painel de cobrança vive neste código MIT, nem é retido dele.

Contribuição e segurança

Veja CONTRIBUTING.md e SECURITY.md. Mudanças notáveis são rastreadas em CHANGELOG.md.

Licença

MIT.