Other frameworks give LLMs a shell and pray. Peon gives LLMs a leash and proves it works.
Most agent frameworks (LangChain, AutoGPT, CrewAI) focus on what an AI can do. Peon focuses on what it cannot — and enforces that at the architecture level, not the prompt level.
User "3856588331" sends: "Roll a 128-sided die"
✅ read_skill("roll-dice") → Skill loaded, paths unlocked
✅ execute_script("roll.sh", 128) → Whitelist check passed, enforcer approved
✅ Agent response: "You rolled **30** on a d128!"
Same bot, different user (not in policy):
✅ read_skill("roll-dice") → Skill loaded...
⛔ ALL PERMISSIONS DENIED → Path never entered whitelist
⛔ execute_script("roll.sh", 128) → SECURITY VIOLATION: not in whitelist
🤖 Agent response: "I cannot execute this script — permission denied."
Same bot. Same code. Same skill. Different user → different outcome. That's zero-trust.
Here's what actually happens when a Telegram user sends "Roll a 128-sided die" to a Peon-powered bot:
INFO peon_telegram Received message from chat ID 3856588331
INFO peon_core::agent User input (uid=3856588331): Roll a 128-sided die for me
INFO peon_runtime::agent Agent run: uid='3856588331'
# Turn 1: LLM discovers the skill
INFO peon_runtime::agent Tool call: read_skill({"skill_name":"roll-dice"})
INFO peon_core::scanner Added to execute whitelist: .../roll-dice/scripts/roll.sh
# Turn 2: LLM executes with the unlocked path
INFO peon_runtime::agent Tool call: execute_script({"path":"...roll.sh","arguments":["128"]})
INFO peon_core::tools Execute access granted for: .../roll-dice/scripts/roll.sh
# Turn 3: Done.
INFO peon_runtime::agent Agent response (turn 3): You rolled a **30** on the 128-sided die.
Now change one line in user_permissions.csv — remove the user's access:
INFO peon_core::tools Tool call: read_skill('roll-dice')
WARN peon_core::scanner All permissions denied for path 'roll.sh' — not added to any whitelist
WARN peon_core::tools SECURITY VIOLATION: './scripts/roll.sh' not in execute whitelist — blocked
INFO peon_runtime::agent Agent response: "I cannot execute this script — permission denied."
The LLM retried twice. It tried relative paths. It tried re-reading the skill. Nothing worked. The path was never whitelisted because the enforcer rejected the user identity at the scan layer — two layers before execution.
┌──────────────┐ ┌────────────────────┐ ┌──────────────────┐
│ LLM Brain │────▶│ Peon Security │────▶│ OS Execution │
│ (Reasoning) │ │ Matrix (Casbin) │ │ (Scripts/Files) │
│ │ │ │ │ │
│ "Execute X" │ │ UID? ✓ │ │ bash roll.sh 128 │
│ │ │ Whitelist? ✓ │ │ │
│ │ │ File ACL? ✓ │ │ → stdout: "30" │
│ │ │ User ACL? ✓ │ │ │
└──────────────┘ └────────────────────┘ └──────────────────┘
▲ Fails ANY check?
│ → Blocked. Period.
Defence in Depth, not Defence by Prompt:
| Layer | What | Bypass-proof? |
|---|---|---|
| Whitelist | Only paths discovered from SKILL.md are executable |
✅ LLM cannot invent paths |
| File ACL | file_permissions.txt — system-wide deny/allow rules |
✅ Not visible to LLM |
| User ACL | user_permissions.csv — per-user RBAC via Casbin |
✅ UID injected physically, not via prompt |
| RequestContext | UID is passed as a Rust struct, not a task-local or env var | ✅ Unforgeable by the LLM |
cargo add peon-coreOr from source:
git clone https://github.com/stephen94125/peon-lib.git
cd peon-lib
cargo build --release# .env
PROVIDER=openai # openai | anthropic | gemini | openrouter
MODEL=gpt-4o-mini
API_KEY=sk-...
PEON_SKILLS_DIR=skills
PEON_FILE_PERMISSIONS=file_permissions.txt
PEON_USER_PERMISSIONS=user_permissions.csvlet agent = PeonAgentBuilder::new().await?.default_prompt().build();
let response = agent.prompt("Roll a 20-sided die", "user_123").await?;
// The UID "user_123" is physically passed to every tool call.
// The LLM cannot forge, override, or escalate it. Period.| Crate | crates.io | Purpose |
|---|---|---|
peon-runtime |
Custom LLM runtime — provider abstraction, agent loop, multimodal messages | |
peon-core |
Zero-trust engine — skill scanner, Casbin enforcers, tool sandboxing | |
peon-cli |
Unix-style CLI — pipe stdin, use in CI/CD | |
peon-telegram |
Multi-user Telegram bot with per-user identity isolation |
Warning
Strict Zero-Trust: Peon requires file_permissions.txt and user_permissions.csv to exist. If missing, the agent panics on startup — no silent fallback, no "allow-all" default.
file_permissions.txt — What the agent can touch:
x, ./skills/* # Allow execution within skills
!x, /bin/rm # Block rm, always, no exceptions
r, ./data/* # Allow reading data files
!r, ./secrets/* # Block reading secrets
user_permissions.csv — Who can do what:
p, *, *, *, allow # Allow everyone (development mode)
p, 3856588331, *, execute, allow # Only this Telegram user can execute
p, admin_role, *, *, allow # Role-based access
g, alice, admin_role # Alice inherits admin permissionsSkills are Markdown files that define what an LLM is allowed to do — not just what it can do.
skills/
└── roll-dice/
├── SKILL.md # Instructions + path declarations
└── scripts/
└── roll.sh # The actual executable
---
name: roll-dice
description: Roll dice using a random number generator.
---
To roll a die, execute: `./scripts/roll.sh <sides>`When read_skill("roll-dice") is called, Peon:
- Reads the SKILL.md content
- Extracts all referenced paths (
./scripts/roll.sh) - Resolves them to absolute paths via
canonicalize() - Checks the enforcer for each path
- Only whitelisted + enforcer-approved paths get added
The LLM never sees the filesystem. It only sees what Peon explicitly unlocks.
| Status | Feature |
|---|---|
| ✅ | Zero-trust tool execution with dual-layer enforcement |
| ✅ | Custom LLM runtime (peon-runtime) — OpenAI, Anthropic, Gemini, OpenRouter |
| ✅ | Telegram bot with per-user identity isolation |
| ✅ | Skill discovery, dynamic whitelisting, session reset |
| 🔜 | Telegram: Rich responses — images, files, formatted messages |
| 🔜 | Telegram: Multimodal input — photos, voice, documents |
| 🔜 | Discord: Bot integration |
| 🔜 | CLI: End-to-end verification with real API providers |
| 🗓️ | WASM runtime support for browser-based agents |
| 🗓️ | Persistent conversation memory across sessions |
Peon uses its own runtime (peon-runtime) with native support for:
OpenAI · Anthropic · Gemini · OpenRouter (access to 200+ models)
Made with contrib.rocks.
Licensed under MIT or Apache-2.0.