Your supplier spawned a sub-agent and handed it the aforesaid API key. That sub-agent tin now deploy to production, publication the payments database, and merge to main.
Pigeon stops that. You manus the kid a Pigeon Pass: a narrowed, signed credential for what it whitethorn do, not a transcript of everything you tin do.
Python 3.12 aliases newer.
git clone https://github.com/pigeonlabsHQ/pigeon.git cd pigeon
pip instal .
The full idea, successful 20 lines
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 ne'er returns a bare boolean. A denial includes a logic code, a message, and the comparison that grounded (requested vs allowed).
Try it without penning that yourself:
python examples/01_infrastructure.py
python demo/agent.py
Where it goes successful an agent
There is nary Pigeon server to link to. You alteration 2 places you already have:
- Spawn. Where you would person copied an API cardinal into a sub-agent, telephone delegate(...) and springiness the kid a Pass.
- Tool. Where the broadside effect happens (deploy, query, MCP tool), telephone verify(...) and do not tally the instrumentality if it is denied.
Keep the existent concealed connected the runner. The kid carries the 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 driblet a genitor 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"
A kid cannot adhd capabilities, widen resources, raise a bound, aliases driblet a genitor constraint. If Pigeon cannot beryllium the kid is narrower, it rejects.
If the runner ne'er calls verify, the Pass is decoration.
This is an enforcement point, not portion of the protocol. The customer mints a narrower Pass per instrumentality call. The server verifies it earlier the instrumentality runs.
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"
Identity tells you who the supplier is. Authority tells you what it whitethorn do.
pigeon keygen
pigeon inspect pass.json
Pigeon is simply a mini primitive. It is not a platform, a argumentation engine, an personality provider, aliases a cardinal custodian. It does not extremity punctual injection. It bounds blast radius on the dimensions you put connected the Pass, and only those.
- Protocol: SPEC.md
- Limits: SECURITY.md
- More scripts: examples/ (infrastructure, data, code, past payments)