
Aplique delegação de privilégio mínimo para agentes de IA com credenciais assinadas e com escopo. Conceda aos subagentes capacidades e recursos limitados, verifique as ações antes da execução e evite a escalada de privilégios.
O seu agente gerou um sub-agente e entregou-lhe a mesma chave de API. Esse sub-agente pode agora fazer deploy para produção, ler a base de dados de pagamentos e fazer merge para a main.
A Pigeon impede isso. Você entrega ao filho um Pigeon Pass: uma credencial restrita e assinada para o que ele pode fazer, não uma cópia de tudo o que você pode fazer.
Python 3.12 ou mais recente.
git clone https://github.com/pigeonlabsHQ/pigeon.git
cd pigeon
pip install .
from pigeon import grant, verify
authority = grant(
subject="agent:deployer",
capabilities=["deploy"],
resources=["environment:staging"],
)
allowed = verify(authority, action="deploy", resource="environment:staging")
assert allowed.allowed
denied = verify(authority, action="deploy", resource="environment:production")
assert not denied.allowed
assert denied.reason_code == "RESOURCE_NOT_ALLOWED"
print(denied.reason_code, denied.message, denied.details)
verify nunca retorna um booleano simples. Uma negação inclui um código de motivo, uma mensagem e a comparação que falhou (requested vs allowed).
Experimente sem escrever isso você mesmo:
python examples/01_infrastructure.py
python demo/agent.py
Não existe um servidor Pigeon ao qual se conectar. Você altera dois lugares que já possui:
delegate(...) e dê um Pass ao filho.verify(...) e não execute a ferramenta se for negado.Mantenha o segredo real no runner. O filho carrega o Pass.
from pigeon import delegate, grant, verify, DelegationError
parent = grant(
subject="agent:orchestrator",
capabilities=["deploy", "open_pr"],
resources=["environment:staging", "repo:acme/api"],
constraints={"max_deploys_per_hour": 3},
)
worker = delegate(
parent,
subject="agent:pr-bot",
capabilities=["open_pr"],
resources=["repo:acme/api"],
constraints={"max_deploys_per_hour": 3}, # cannot drop a parent constraint
)
result = verify(worker, action="open_pr", resource="repo:acme/api")
assert result.allowed
denied = verify(worker, action="deploy", resource="environment:staging")
assert denied.reason_code == "CAPABILITY_NOT_GRANTED"
try:
delegate(worker, "agent:rogue", ["open_pr", "deploy"], ["repo:acme/api"])
except DelegationError as exc:
assert exc.reason_code == "PRIVILEGE_ESCALATION"
Um filho não pode adicionar capacidades, alargar recursos, aumentar um limite ou remover uma restrição do pai. Se a Pigeon não conseguir provar que o filho é mais restrito, ela rejeita.
Se o runner nunca chamar verify, o Pass é apenas decoração.
Este é um ponto de aplicação, não parte do protocolo. O cliente cunha um Pass mais restrito por chamada de ferramenta. O servidor verifica-o antes de a ferramenta ser executada.
from pigeon import grant
from pigeon.integrations.mcp import execute_tool, pass_for_tool
parent = grant(
subject="agent:github",
capabilities=["create_issue", "merge_pr"],
resources=["mcp:github"],
)
tool_pass = pass_for_tool(parent, "create_issue", "mcp:github")
def create_issue(*, title, body):
return {"created": True, "title": title}
ok = execute_tool(tool_pass, "create_issue", "mcp:github",
{"title": "bump deps", "body": "automated"}, create_issue)
assert ok["allowed"]
no = execute_tool(tool_pass, "merge_pr", "mcp:github",
{"title": "nope", "body": "nope"}, create_issue)
assert no["reason_code"] == "CAPABILITY_NOT_GRANTED"
A identidade diz-lhe quem é o agente. A autoridade diz-lhe o que ele pode fazer.
pigeon keygen
pigeon inspect pass.json
A Pigeon é um primitivo pequeno. Não é uma plataforma, um motor de políticas, um fornecedor de identidade ou um guardião de chaves. Não impede injeção de prompts. Limita o raio de explosão ao longo das dimensões que você coloca no Pass, e apenas essas.
SPEC.mdSECURITY.mdexamples/ (infraestrutura, dados, código e depois pagamentos)