Architecture Overview
Peri uses a layered architecture: Frontend (TUI/ACP) → Agent Core (ReAct loop) → Middleware Layer (feature implementations) → External Systems.
Layered Structure
┌─────────────────────────────────────┐
│ peri-tui / peri-acp (Frontend) │ TUI full-screen / ACP stdin/stdout
├─────────────────────────────────────┤
│ peri-agent (Agent Framework Core) │ ReAct loop, middleware chain, LLM interface
├─────────────────────────────────────┤
│ peri-middlewares (Features) │ 18 built-in middleware
├─────────────────────────────────────┤
│ External Systems │ Filesystem, terminal, web, MCP, LSP
└─────────────────────────────────────┘The frontend communicates with the Agent core via mpsc channel (TUI) or stdio (ACP), sharing the same Agent backend.
Crate Responsibilities
| Crate | Responsibility |
|---|---|
peri-agent | ReAct loop, middleware chain, LLM interface, Thread persistence, message system, Compact compression |
peri-middlewares | 18 built-in middleware: filesystem, terminal, web, sub-agent, Tool Search, HITL, Hooks, Plugins, Cron, Skills |
peri-tui | Ratatui terminal UI, CLI entry point (clap), event handling, Markdown rendering |
peri-acp | ACP service layer: SessionManager, Transport abstraction, system prompt construction, Langfuse tracing |
peri-widgets | TUI reusable component library |
peri-lsp | LSP client integration |
langfuse-client | Langfuse LLM observability client |
Data Flow
User Input
↓
TUI (Ratatui) / ACP (stdio JSON-RPC)
↓ mpsc / StdioTransport
AcpServer → SessionManager
↓
ReActAgent (peri-agent)
↓
MiddlewareChain
├── before_agent → Inject CLAUDE.md, Skills
├── before_model → Compact check
├── LLM Call → OpenAI / Anthropic API
├── after_model → Token tracking
├── before_tool → HITL permission check
├── Tool Execution → File read/write, command execution
└── after_tool → Logging
↓
AgentOutput → UserReAct Agent Execution Flow
1. Add human message to state
2. Collect tools from all middleware (collect_tools)
3. chain.run_before_agent(state)
4. Prepend system_prompt
5. for step in 0..max_iterations:
a. chain.run_before_model(state) ← Compact checkpoint
b. call_llm(messages, tools) → Reasoning
c. chain.run_after_model(state)
d. if needs_tool_call:
- chain.run_before_tool() ← Permission check
- Tool execution
- chain.run_after_tool()
e. else:
- Return AgentOutput
6. chain.run_after_agent(state)Key Design Decisions
| Decision | Rationale |
|---|---|
| Rust implementation | Memory safety + high performance, ~50MB memory footprint, single binary distribution |
| Middleware-driven | All features injected via Middleware trait, pluggable and testable |
| Context optimization | System prompt cache boundary + Tool Search lazy loading + Compact auto-compression |
| .claude/ compatible | Directly reuse Claude Code's directory structure, zero migration cost |
| Multi-frontend | TUI (mpsc) and IDE (stdio/ACP) share the same Agent backend |
| ThreadStore abstraction | Pluggable storage backends (SQLite/Redis/filesystem), supports session recovery |
See Also
- Middleware Protocol Reference — Full Middleware trait API
- ThreadStore API Reference — Thread storage interface