Where it came from
De onde veio
Tell is built by two founders with day jobs, so I put a team of agents on it: tech lead, PM, two devs, QA, marketing, sales and social. After a few weeks of running it every day, the part worth sharing was not the prompts, it was the plumbing. agent-team is that plumbing, rewritten without anything from Tell, with a fictional example team you can run on your laptop.
O Tell é feito por dois sócios que têm emprego, então coloquei um time de agentes nele: tech lead, PM, dois devs, QA, marketing, vendas e social. Depois de algumas semanas rodando todo dia, o que valia compartilhar não eram os prompts, era o encanamento. O agent-team é esse encanamento, reescrito sem nada do Tell, com um time de exemplo fictício que roda no seu notebook.
Six days in production: what the numbers showed
Seis dias em produção: o que os números mostraram
Before opening the code I looked at what Tell's own team did between 16 and 21 October, from its mailbox and run log. Counts only, no message content.
Antes de abrir o código, olhei o que o próprio time do Tell fez entre 16 e 21 de outubro, a partir da caixa de correio e do registro de execuções. Só contagens, nenhum conteúdo de mensagem.
Humans see about one message in seven
As pessoas veem cerca de uma mensagem em cada sete
Show the numbersVer os números
| Total | To humansPara pessoas | |
|---|---|---|
| 16/10 | 405 | 53 |
| 17/10 | 213 | 21 |
| 18/10 | 42 | 2 |
| 19/10 | 265 | 33 |
| 20/10 | 320 | 47 |
| 21/10 | 208 | 40 |
Review and coordination were half the bill
Revisão e coordenação eram metade da conta
Show the numbersVer os números
| % | RunsExecuções | |
|---|---|---|
| QA | 28.4 | 200 |
| Tech Lead | 24.6 | 155 |
| CMO | 15.0 | 79 |
| Dev Back | 14.7 | 75 |
| Dev Front | 11.3 | 40 |
| Seller | 2.9 | 46 |
| PM | 2.3 | 10 |
| Social | 0.5 | 3 |
And the founders were approving all day
E os sócios passavam o dia aprovando
Show the numbersVer os números
| Approval requestsPedidos de aprovação | |
|---|---|
| 16/10 | 13 |
| 17/10 | 11 |
| 18/10 | 1 |
| 19/10 | 12 |
| 20/10 | 23 |
| 21/10 | 22 |
What changed: an orchestrator
O que mudou: um orquestrador
The fix was not a better prompt, it was structure. Version 0.2 adds an optional orchestrator, ported from what now runs on Tell:
A solução não foi um prompt melhor, foi estrutura. A versão 0.2 traz um orquestrador opcional, portado do que hoje roda no Tell:
- One door. A message without an addressee goes to the orchestrator, even inside a thread, so "approved" never lands on the wrong agent.
- Authority levels. What the team does alone, what it logs, what needs one question with a recommendation, and what needs a human now.
- Approvals with a receipt. Every request becomes a tracked decision. An ambiguous "approved" covering a pull request and e-mails approves no e-mail; the orchestrator asks, then confirms what it understood.
- A merge gate in code. The reviewer only gives a verdict. The dispatcher merges when CI is green on that commit, no decision is pending and, for sensitive paths, a human said yes. One review round instead of many.
- Promises. "I'll let you know when..." has to be a registered promise; the dispatcher wakes the agent when it is due and flags it when late.
- A daily digest built by code. Non-urgent news waits for one message a day instead of trickling in.
- Heartbeat by trigger and a weekly retro that reads the numbers and proposes at most a few changes, each waiting for approval.
- Porta única. Mensagem sem destinatário vai para o orquestrador, mesmo dentro de uma thread, então um "aprovo" nunca cai no agente errado.
- Níveis de alçada. O que o time faz sozinho, o que só registra, o que pede uma pergunta com recomendação e o que precisa de uma pessoa agora.
- Aprovação com recibo. Todo pedido vira uma decisão rastreada. Um "aprovo" ambíguo, que cobre um pull request e e-mails, não aprova nenhum e-mail; o orquestrador pergunta e depois confirma o que entendeu.
- Portão de merge em código. O revisor só dá o veredito. O dispatcher faz o merge quando o CI está verde naquele commit, não há decisão pendente e, em caminhos sensíveis, uma pessoa disse sim. Uma rodada de revisão em vez de várias.
- Promessas. "Te aviso quando..." precisa virar uma promessa registrada; o dispatcher acorda o agente no prazo e avisa quando atrasa.
- Resumo diário montado por código. Novidade que não é urgente espera uma mensagem por dia, em vez de pingar o dia todo.
- Heartbeat por gatilho e uma retro semanal que lê os números e propõe no máximo algumas mudanças, cada uma esperando aprovação.
It went live on Tell on 21 October; it is too early for a before-and-after, and I will add one here when there is a full week to compare.
Entrou no ar no Tell em 21 de outubro; ainda é cedo para um antes e depois, e vou colocar aqui quando houver uma semana inteira para comparar.
How it works
Como funciona
- Roles are configuration. One
team.jsonlists the agents, their prompts and allowed tools, the humans, who approves what, routines and triggers. - A mailbox exposed as an MCP server. Agents use
ask,assign,reply,share,request_approvalandremember. SQLite, Python standard library only. - A dispatcher that wakes an agent only when it has mail. Nobody polls, each run takes minutes, messages from a human go first, and there are caps per day and per run.
- Routines and triggers. "Monday 10:00, marketing drafts the newsletter"; "a new line in this error log becomes a task".
- Optional integrations, off by default: Discord (one thread per conversation), e-mail over SMTP, a GitHub pull request queue.
- Papéis são configuração. Um
team.jsonlista os agentes, seus prompts e ferramentas permitidas, as pessoas, quem aprova o quê, rotinas e gatilhos. - Uma caixa de correio exposta como servidor MCP. Os agentes usam
ask,assign,reply,share,request_approvaleremember. SQLite, só biblioteca padrão do Python. - Um dispatcher que só acorda o agente quando ele tem mensagem. Ninguém faz polling, cada execução leva minutos, mensagem de pessoa passa na frente, e há limite por dia e por execução.
- Rotinas e gatilhos. "Segunda 10h, marketing rascunha a newsletter"; "linha nova neste log de erro vira tarefa".
- Integrações opcionais, desligadas por padrão: Discord (uma thread por conversa), e-mail por SMTP, fila de pull requests no GitHub.
The office
O escritório
Logs are honest but nobody reads them. The office is a 3D floor plan in the browser: agents walk to their desks when they have work, envelopes fly between them, and a panel shows the day's runs, messages, tokens and what they would cost at API prices. A replay mode plays a scripted conversation; the repository ships one, pictured below.
Log é honesto, mas ninguém lê. O escritório é uma planta 3D no navegador: os agentes vão até a mesa quando têm trabalho, envelopes voam entre eles, e um painel mostra as execuções, mensagens e tokens do dia e quanto custariam a preço de API. O modo replay reproduz uma conversa roteirizada; o repositório traz uma, na imagem abaixo.
Security first, limits stated
Segurança primeiro, limites declarados
Agents read untrusted text, so the framework assumes any of them can be talked into anything its tools allow. The answer is least privilege, not detection:
Agentes leem texto não confiável, então o framework parte do princípio de que qualquer um deles pode ser convencido a fazer tudo o que as ferramentas permitem. A resposta é privilégio mínimo, não detecção:
- Per-role tool lists and normal permission mode by default; full bypass only inside a sandbox.
- Outgoing e-mail is enforced, not just requested: a separate mailer sends only what a human approved, checked with an HMAC, and only if the text is unchanged.
- Secrets stay with the services that need them, never in prompts or messages; attachments are checked for keys and env files.
- Budgets and a stop button: few runs at once, daily caps, a timeout per run,
agent-team stop.
- Lista de ferramentas por papel e modo de permissão normal por padrão; bypass total só dentro de sandbox.
- O e-mail que sai é garantido, não só pedido: um mailer separado só envia o que uma pessoa aprovou, conferido por HMAC, e só se o texto não mudou.
- Segredos ficam com os serviços que precisam deles, nunca em prompts ou mensagens; anexos são conferidos contra chaves e arquivos de ambiente.
- Limites e botão de parar: poucas execuções ao mesmo tempo, teto diário, timeout por execução,
agent-team stop.
The README says plainly what it doesn't do: it runs on one machine, prompt injection is not solved, and only e-mail and the merge gate are enforced in code. The gate can't stop an agent that holds a merge token from merging by hand, so the docs say to keep that token away from the agents.
O README diz com clareza o que ele não faz: roda numa máquina só, prompt injection não está resolvido e só o e-mail e o portão de merge são garantidos em código. O portão não impede um agente que tenha token de merge de mergear na mão, então a documentação manda manter esse token longe dos agentes.
Try it
Experimente
git clone https://github.com/victoorsaad/agent-team && cd agent-team
python3 -m agent_team office --replay examples/tea-shop/replay.json
# http://127.0.0.1:8130
No Claude calls and no network needed for the demo. A dry-run mode then exercises the whole loop with a stub in place of Claude.
A demonstração não chama o Claude nem precisa de rede. Depois, um modo seco roda o ciclo inteiro com um stub no lugar do Claude.