Reyn Feature Map¶
Full feature inventory of the Reyn Agent OS, extracted from implementation. Each entry links to its reference or concept documentation.
Per-group Differentiation vs general agents callouts position each capability against self-hosted general agents (OpenClaw / Hermes) — Skill is one feature among many, not the headline. Maturity marks: entries are production unless tagged ⚗ experimental / MVP or noted as an optional dependency.
Visual overview¶
mindmap
root((Reyn<br/>Agent OS))
🧩 OS Core
🌀 Phase Engine
Act/Decide loop
Context build
Candidate gate
Phase rollback
✅ LLM Validation
JSON contract
Type-decision check
Next-phase allowlist
Artifact schema
Normalization retry
🗂️ Workspace P5
Artifact storage
Permission-gated IO
♻️ Crash Recovery
WAL state log
Forward-replay resume
CommittedStep memo
⏱️ Time-Travel
/rewind picker
Consistent-cut rewind
Branch registry
checkout-seq primitive
Multi-fork UX
Live-fork gate
📜 Event System P6
171 event types
Append-only JSONL
Replay
🗜️ Chat Compaction
Head+tail+body budget
Overflow retry loop
Adaptive token estimation
Multimodal token estimation
⚙️ Control IR Ops
file
ask_user
shell
sandboxed_exec
web_search
web_fetch
mcp
mcp_install
index_query
recall
index_drop
compact
judge_output
🔧 Tool-Use Schemes
Pluggable per-layer
universal-category default
enumerate-all
retrieval
CodeAct
Per-call gate unchanged
⌨️ CLI
reyn chat
reyn agent
reyn topology
reyn memory
reyn permissions
reyn events
reyn mcp
reyn secret
reyn source
reyn config
reyn auth
reyn cron
reyn web
reyn init
🔧 Config
3-layer cascade
safety
cost
sandbox
web
eval
plan
chat
embedding
voice
events
models
auth
mcp
multimodal
python
cron
action_retrieval
hooks
🔒 Permissions
Tier 0-3 model
4-layer resolution
CLI gates
🛡️ Safety
Force-close wrap-up
limit_denied event
On-limit modes
🔄 LLM Provider Resilience
litellm.Router delegation
Cross-model fallback chain
Retry-After aware retry
Per-deployment cooldown
Default OFF byte-identical
Credential rotation
🧪 Content-layer defense
Threat-pattern library
Content fence
Tool-result guard
Memory-write block
Exec command scan
Inbound peer fence
Compaction secret redact
💰 Budget and Cost
Per-agent caps
Per-chain caps
Rate limits
Daily/monthly quotas
High-cost model warn
🧠 Memory and RAG
Embedding
SQLite index
Recall
Chat compaction
🔌 MCP
Transports
mcp serve
mcp install
📘 Skills
SKILL.md registry
Three-layer exposure
Hot-reload
Session visibility toggle
install_local
install_source
🌐 Web and Protocol
FastAPI gateway
WebSocket chat
A2A sync message/send
A2A async tasks
Webhook push
MCP-over-SSE
REST API
🙋 Intervention
ask_user routing
InterventionBus family
InterventionRegistry
🧬 Sessions and identity
Three-level model
Multiple Sessions per Agent
Per-session persistence
Global-cut rewind
Transport routing-key
🤝 Multi-Agent
Agent registry
Topology system
MessageBus
delegate_to_agent
📋 Task system
11 dynamic task ops
Requester/assignee CAS
Dependency DAG
Cross-session WAKES
Content-fenced task text
/tasks view
🖥️ TUI
Conversation view
Right Panel tabs
tool-result viewers
Viewer registry seam
Content-type shorthand
LLM template fallback
Email viewer
Diff viewer
Input + command palette
🐳 Environment
EnvironmentBackend
HostBackend
Container backend
🏖️ Sandbox
SeatbeltBackend
LandlockBackend
NoopBackend
SandboxPolicy
Feature index¶
OS Core¶
Phase Engine¶
| Feature | Description | Documentation |
|---|---|---|
| Act/Decide loop | LLM↔op volleys until the LLM emits a transition/finish/abort decision | LLM Output Contract |
| Context build | Constructs LLM input from phase instructions, current artifact, candidates, and available ops | Context Frame |
| Candidate gate | LLM picks next phase only from OS-provided candidates (P4) | LLM as Decision Engine |
| Phase rollback | Revert to predecessor phase when downstream output is rejected | LLM Output Contract |
LLM Validation¶
| Feature | Description | Documentation |
|---|---|---|
| JSON contract | Enforce control / artifact / control_ir envelope structure |
LLM Output Contract |
| Type-decision consistency | finish type requires decision=finish, next_phase=null, etc. |
LLM Output Contract |
| Next-phase allowlist | Transition target must appear in the skill graph candidates | LLM Output Contract · Graph |
| Artifact schema validation | data validated against the target phase's input_schema |
Artifact YAML |
| Normalization retry | Minor JSON errors healed before rejecting, up to llm_max_retries |
LLM Output Contract |
Workspace (P5)¶
| Feature | Description | Documentation |
|---|---|---|
| Artifact storage | Phase artifacts persisted to .reyn/artifacts/ |
Concepts: Workspace |
| Permission-gated IO | Paths outside CWD require file.read / file.write declaration |
Concepts: Workspace · Permissions |
Crash Recovery¶
| Feature | Description | Documentation |
|---|---|---|
.reyn/ layout + recovery-core classification |
Which .reyn/ subtrees are recovery-core (state/ + config/) vs persist / audit / cache / outside; the recovery-core write-gate (mutate config via dedicated ops, never raw file.write) |
.reyn/ directory layout |
| Config recovery (config-as-snapshot) | Config registries (.reyn/config/: mcp/cron/hooks/index) reconstruct from truncation-surviving config generations (full-state snapshots written by the durability worker, seq-keyed) — replacing the former config_changed-WAL-event replay, which a WAL truncation below the floor could silently drop (#2259 PR-1). The .yaml IS the durable snapshot, not a derived projection |
.reyn/ directory layout |
| WAL state log | step_started / step_completed / step_failed written to .reyn/state/wal.jsonl (StateLog); fsync'd off the event loop via the shared DurabilityWorker. #2259: durable-RECORD writes (snapshots / config / identity) are async fire-and-forget — the task loop never blocks on durability; step_started BLOCKS by design (durable-before-side-effect, so a crash-mid-op is detected as ambiguous for non-idempotent ops — #2275). Truncatable after snapshot. Not the audit trail — see Event System (P6). |
Skill Resume |
| Async-decoupled durability (recover-to-last-durable) | In-memory state mutates immediately on the task loop; the seq-keyed durable record is submitted fire-and-forget to the serial DurabilityWorker (the seq is assigned IN the worker). Recovery restores to the last durable record — a consistent prefix; the un-durable tail at crash is lost (relaxed durability). A persistent (§4-exhausted) durable-write failure latches durability_failed → the session fail-stops (DurabilityHaltError on new ops + run-loop halt) so in-memory cannot race a dead disk (#2259) |
.reyn/ directory layout |
| Forward-replay resume | SkillResumeAnalyzer reconstructs run state from state log |
Skill Resume |
CommittedStep memo |
Replay recorded op results on resume without re-invoking | Skill Resume |
| World-op bypass | Transient ops (web_search, web_fetch) re-execute fresh on resume | Skill Resume |
Time-Travel / Rewind (Resume)¶
User-facing point-in-time rewind with branching. Phase 1 and Phase 2 (2a/2b/2c/2d) are production. Concurrent-live-fork (parallel live branches) is owner-rejected out-of-scope. Full design: ADR-0038.
| Feature | Description | Documentation |
|---|---|---|
/rewind picker |
Interactive checkpoint timeline (seq / timestamp / kind columns); Esc-Esc double-tap shortcut | How-to: rewind |
| Per-checkpoint anchor preview | Each picker row shows a rendered scroll-hint anchor | How-to: rewind |
| PITR reconstruct | Point-in-time snapshot + WAL-diff reconstruction to target seq | Time-Travel concepts · Crash Recovery |
| Consistent-cut rewind | Both substrates (runtime state + workspace shadow-git as-of-N) rewound atomically |
Time-Travel concepts |
| Append-only reset-record | Undo appends a reset-record at seq R; history before R is preserved on the current branch (no destructive rewrite) | Time-Travel concepts |
| Retention window + GC | Configurable checkpoint retention window; stale snapshots GC'd automatically | How-to: rewind |
| Branch registry | Abandoned-interval lineage: each fork receives a registry entry with origin seq | Time-Travel concepts |
checkout(seq) unified primitive |
Active-branch seq → undo; inactive-branch seq → fork-switch. One primitive for both directions | Time-Travel concepts |
| Multi-fork tree UX | Always-tree picker with per-branch anchor labels | How-to: rewind |
| Act-turn runtime-only rewind | Ghost-Replay memo truncate for rewind within an in-flight turn (no substrate round-trip) | Time-Travel concepts |
| Container-mode shadow-git | Shadow-git as-of-N rewind supported inside the container environment backend |
How-to: rewind |
| Deterministic CI rewind gate | test_live_rewind_gate.py — Phase-1 rewind deterministic gate |
— |
| Deterministic CI live-fork gate | test_live_fork_gate.py — Phase-2 fork / checkout deterministic gate |
— |
| tmux live e2e | P1 undo + P2 fork-switch verified on real terminal | — |
| Phase 2c: fork-then-edit | New branch on edit via ctrl+t |
How-to: rewind |
| Phase 2d: web surface | /rewind picker over WebSocket / A2A; web edit via AskUserMessage UX (original message presented for edit + submit) |
How-to: rewind |
Agent archive-delete (reyn agent rm) |
Archive by default (soft-delete): data preserved — PITR generations + topology membership kept (agent dormant, not destroyed). --purge permanently hard-deletes (topology cascade fires immediately; no rewind possible). WAL-window GC auto-purges archived agents once archival seq leaves the retention window. |
CLI: reyn agent |
Event System (P6)¶
| Feature | Description | Documentation |
|---|---|---|
| 171 event types | Complete taxonomy: workflow / phase / LLM / tool / budget / permission / etc. | Events reference · Concepts: Events |
| Append-only JSONL | .reyn/events/<run_id>.jsonl per-run (EventStore); audit trail — append-only, rotation-based (not per-append fsync). Separate log and lifecycle from the recovery WAL (.reyn/state/wal.jsonl). |
Events reference |
| Replay | reyn events <path> streams events for audit and debug |
reyn events CLI |
Differentiation vs general agents: the agent loop is an OS-enforced contract — the LLM decides only from OS-provided candidates (P3/P4), every output is schema-validated, every inter-phase value lives in the workspace (P5), and every state change emits an append-only, replayable event (P6). Constrained and auditable by construction, not by developer discipline.
Chat Engine¶
Chat Compaction¶
| Feature | Description | Documentation |
|---|---|---|
| Head+tail+body budget | Keeps the most-recent turns (tail) and earliest context (head) within per-component token budgets; turns between them are replaced by an LLM-generated summary | Chat Compaction |
| Overflow retry loop | When the compacted context still exceeds the model limit, budgets for head / tail / summary shrink monotonically per iteration until the prompt fits; fails fast with a structured error when no further reduction is possible | Chat Compaction |
| Adaptive token estimation | Learns a per-model token-count multiplier over time, reducing estimation drift across sessions | Chat Compaction |
| Multimodal token estimation | Estimates tokens for text and image content; image parts use a fixed per-part cost | Chat Compaction |
| Compaction lock | Async mutex prevents concurrent turn appends from racing with an in-flight compaction call | Chat Compaction |
Differentiation vs general agents: instead of naive truncation or an unbounded growing memory, Reyn budgets context as head + tail + LLM summary with a monotonic overflow-shrink retry, adaptive per-model token estimation, and multimodal estimation — predictable context management under a hard model limit.
Router system prompt¶
| Feature | Description | Documentation |
|---|---|---|
| Static / dynamic SP split | The router system prompt separates a stable, cache-prefix-friendly head from per-turn dynamic sections | LLM invocation surfaces |
| Task-completion guidance | Anti-fabrication guidance steering the model to finish and verify rather than claim completion prematurely | SP-improvements study |
| Model-family-gated steering | A coarse model-family classifier gates non-Claude operational-steering hygiene — added only when the router model is non-Claude, kept off the Claude path | SP-improvements study |
| Memory-quality guidance (gated) | Guidance on what makes a good memory entry, rendered only when memory is in scope | SP-improvements study |
Differentiation vs general agents: these SP improvements are adopted by design-judgment (sound + low-cost + non-harmful), not gated on a limited-environment A/B — a measured null on one environment cannot prove a universal negative, so structurally-sound guidance is adopted while genuinely measurable wins are verified separately.
LLM router resilience¶
Config-gated litellm.Router slot-in for provider-resilience. Default OFF (llm.router.use: false) — the direct litellm.acompletion path is byte-identical. When enabled the Router owns infra retry, Retry-After handling, cooldown, and cross-model fallback; Reyn does not re-implement any of these.
| Feature | Description | Documentation |
|---|---|---|
| litellm.Router delegation | When llm.router.use: true, LLM calls route through a litellm.Router; Reyn delegates infra-exception retry / Retry-After / cooldown / fallback entirely to the Router |
Config: llm block · Reliability |
| Default OFF — byte-identical | use: false (default) keeps the direct litellm.acompletion path with no routing overhead; the on/off switch is the only code-path change |
Config: llm block |
| Cross-model fallback chain | llm.router.fallbacks maps primary deployments to an ordered fallback list; on primary failure the Router tries each fallback model in order |
Config: llm block |
| Retry-After aware retry | llm.router.num_retries caps infra retries; the Router natively honours provider Retry-After headers (fold of retry-engineering gap) |
Reliability |
| Per-deployment cooldown | llm.router.cooldown_time + allowed_fails cools a deployment after repeated failures; subsequent calls route to the fallback chain until recovery |
Config: llm block |
| Accurate cost on fallback | On fallback the actual responding model is recorded from response.model so cost attribution reflects which deployment served the call |
Budget config |
| Config-fingerprint Router cache | Router is cached per event-loop with a (model, config-fingerprint) key; a changed llm.router.* rebuilds the Router rather than silently reusing a stale instance |
Config: llm block |
llm.router.credentials rotation |
Per-model list of API-key env-var names; the Router cycles through active keys; a declared model with zero resolvable keys fails loudly — never a silent keyless deployment | Config: llm block |
Differentiation vs general agents: provider-resilience is delegated entirely to litellm.Router (Retry-After, jitter, cooldown, cross-model fallback chain, credential rotation) rather than re-implemented — the on/off gate keeps the direct path byte-identical, so replay and cost-recording work unchanged whether or not the Router is active.
Control IR Ops¶
All ops are documented in the single reference page: Control IR
The op kinds below mirror OP_KIND_MODEL_MAP in op_runtime/registry.py.
| Op | Description |
|---|---|
file |
read / write / edit / delete / glob / grep / regenerate_index (six fine-grained registry kinds) |
ask_user |
Pause phase, collect user answer, re-run same phase |
sandboxed_exec |
argv under SandboxPolicy via platform-selected backend |
shell |
Raw shell exec — deprecated; prefer sandboxed_exec |
web_search |
DuckDuckGo search — Tier 1, default-allow |
web_fetch |
URL fetch + text extract — Tier 1, default-allow |
mcp |
Call a configured MCP server tool by name |
mcp_install |
Install / register an MCP server (registry / package / local source) |
index_query |
Vector similarity search over one indexed source |
recall |
Macro: embed query → index_query per source → merge top-K |
index_drop |
Destructive source removal — requires approval |
compact |
Summarise / compact context within budget (chat + phase results) |
judge_output |
LLM scorer with rubric + threshold + on_fail policy |
The
embedandindex_writeops were removed — embedding and index-writing now run provider-direct insidereyn.api.safe.embed_indexand therecallop, not as standalone ops. See Control IR.
Tool-Use Schemes¶
How tools are presented to the LLM and how its calls are dispatched is a pluggable scheme, selectable per layer (tool_use: {chat, step, phase} in reyn.yaml). The chat layer defaults to enumerate-all; step / phase default to universal-category. Non-default schemes are opt-in per layer. All schemes route every tool call through the same OS gate (exclude → permission → dispatch), so the security and validation pipeline is unchanged whichever scheme is active.
| Feature | Description | Documentation |
|---|---|---|
| Pluggable scheme protocol | ToolUseScheme seam — tool presentation + interpretation + dispatch + feedback behind one interface; schemes are swapped by config, no OS change |
Tool-Use Schemes |
| Per-layer selection | Independent scheme per layer — chat / plan-step / OS-phase — via tool_use config |
Tool-Use Schemes · reyn.yaml § tool_use |
universal-category (step/phase default) |
The universal action catalog — 4 wrappers over every category, qualified-name discover + dispatch | Tool-Use Schemes · Universal catalog |
enumerate-all (chat default) |
Flat-native-JSON baseline — every usable tool presented flatly, dispatched by name. Best for small tool sets where determinism matters | Tool-Use Schemes |
retrieval |
RAG-over-tools — present a search tool, the LLM searches, the OS re-presents matched tools as callable. Supported opt-in for very large tool sets where full-catalog token cost is prohibitive; requires a configured embedding provider (action_retrieval.embedding_class) |
Tool-Use Schemes |
CodeAct |
Code-as-tools — the LLM writes a Python snippet whose in-code tool() calls run in a sandboxed subprocess under the same permission gate as a JSON call. Strongest for weak models |
Tool-Use Schemes |
Differentiation vs general agents: the tool-use strategy is a swappable scheme —
enumerate-all/retrieval/CodeAct/ the default catalog — chosen per layer by config, without changing the OS. Because every scheme dispatches through the same exclude → permission →dispatch_toolgate (P4/P5), swapping the LLM-facing tool surface never weakens the security or validation pipeline. The presentation is data; the gate is constant.
CLI¶
| Command | Description | Documentation |
|---|---|---|
reyn chat |
Interactive multi-turn chat with a named agent | Reference |
reyn agent |
Create and manage named persistent agents | Reference |
reyn topology |
Create and manage communication topologies | Reference |
reyn memory |
CRUD + search + export/import for agent memories | Reference |
reyn permissions |
Inspect and revoke saved approval entries | Reference |
reyn events |
Replay event JSONL files or purge old files by date | Reference |
reyn mcp |
Serve, search, install, and manage MCP servers | Reference |
reyn secret |
Set / list / clear secrets in ~/.reyn/secrets.env |
Reference |
reyn source |
List, describe, and remove indexed RAG sources | Reference |
reyn embeddings |
status / rebuild / clear for the action embedding index (search_actions) |
Reference |
reyn config |
Show, query, and set effective configuration | Reference |
reyn auth |
Manage OAuth credentials — login (RFC 8628 device grant against auth.providers) / list / revoke |
reyn.yaml § auth |
reyn cron |
Manage and run cron-scheduled skill jobs — foreground scheduler / list jobs + next-run / status | reyn.yaml § cron |
reyn web |
Start FastAPI + WebSocket gateway server | Reference |
reyn init |
Scaffold reyn.yaml and .reyn/ in current directory |
Reference |
Config¶
Main reference: reyn.yaml
| Block | Description | Documentation |
|---|---|---|
| 3-layer cascade | user-global / project / project-local + CLI flags | reyn-yaml |
${VAR} interpolation |
Env var expansion in all string fields via secrets.env |
reyn-yaml § interpolation |
safety |
Loop caps / timeout caps / on-limit policy | reyn-yaml § safety |
cost |
Per-agent / per-chain / daily / monthly token+USD caps | Budget config |
sandbox |
Backend selection (auto/seatbelt/landlock/noop) + on_unsupported |
reyn-yaml § sandbox |
web |
web.fetch SSL verify_ssl and ca_bundle override |
reyn-yaml § web |
eval |
Trace exporters: file / langfuse / otlp (optional dep opentelemetry-exporter-otlp-proto-http) / ietf_audit |
reyn-yaml § eval |
chat |
Compaction trigger / head+tail retention / section token caps | Chat Compaction |
embedding |
Model classes / batch_size / cost_warn_threshold | RAG concepts |
voice |
Whisper model / language / device — optional reyn[voice] |
Voice concepts |
events |
Rotation size/age + cleanup_period_days | Events reference |
models |
Class → LiteLLM model string with extends chain |
reyn-yaml § models |
permissions |
Project-wide default capability policy | Permissions config |
multi-agent |
Agent and topology defaults | Multi-agent config |
state_dir |
Runtime state directory (default .reyn/) |
State dir |
auth |
OAuth provider definitions for reyn auth login (RFC 8628 device grant) |
reyn-yaml |
mcp |
Configured external MCP server connections (transport + env) | Concepts: MCP |
multimodal |
Media handling caps (max_bytes, per-part token cost) |
reyn-yaml |
python |
python-step execution policy (safe / unsafe subprocess) |
Preprocessor |
cron |
Cron-scheduled skill job definitions | reyn-yaml |
action_retrieval |
Action-catalog search_actions retrieval tuning |
Universal catalog |
hooks |
Agent-lifecycle push/shell hooks at 8 points (turn_start/end, session_start/end, skill_start/end, task_start/end). push mode: wake:false passive context ride-along, or wake:true self-continuation bounded by safety.loop.max_hook_driven_turns. shell: sandbox-gated side-effect, output ignored. Shell-hook consent routes through the intervention bus → TUI Pending-tab modal ([A]lways / [y]es / [n]o; Always persists to ~/.reyn/shell-hooks-allowlist.json); falls back to stdin on non-TUI. All shell runs emit hook_shell_executed P6 event (Events-tab "tool" group; prefix shell_exec: or shell_push:). Hooks emit attributed [hook:name] messages — history is never silently mutated. |
reyn-yaml § hooks · Concepts: hooks |
| Config hot-reload | Runtime re-read of the IN-set (.reyn/mcp.yaml / cron.yaml / hooks.yaml) at the turn boundary without a process restart. OUT-set (reyn.yaml: security / budget / loop valve) is restart-only — the file-split is the structural write-gate. Two triggers: operator /reload and agent hooks_add LLM-op. Validate-before-apply + per-layer boot resilience + sandbox/loop-valve = safe-by-construction. |
Concepts: Config hot-reload |
Permissions¶
| Feature | Description | Documentation |
|---|---|---|
| Tier 0 — always allowed | ask_user — no gate |
Permission model |
| Tier 1 — default-allow | web_search / web_fetch — deny-only gate |
Permission model · Permissions config |
| Tier 2/3 — declaration + 4-layer approval | shell / mcp / file (out-of-zone) / python |
Permission model |
| Layer 1: config pre-approval | reyn.yaml hard allow / deny |
Permissions config |
| Layer 2: saved approvals | .reyn/approvals.yaml — persisted per path/server |
reyn permissions CLI |
| Layer 3: session approvals | In-memory for current invocation only | Permission model |
| Layer 4: interactive prompt | Ask user with persist choices (yes / always / just-this-path) | Permission model |
| CLI gates | --allow-unsafe-python required at invocation |
Common flags |
| Capability profile | Per-agent MCP / tool / category capability restriction (ProfileLayer in the ∩ model); agent can self-edit .reyn/agents/<name>/profile.yaml within the default write zone |
Concepts: Capability profile · Reference: profile.yaml |
| Delegation policy | Config-selectable default-deny for delegated agents: delegation.capability_default=deny narrows any unbound delegate with the restrictive _delegate floor (same deny taxonomy as _untrusted). Binding replaces the floor (= the re-grant). Recursive: no laundering via re-granted coordinators. reyn audit (gateway:delegation-unsafe) flags re-grants with OPT-A reachability precision (HIGH exit on re-delegation/exec). |
Concepts: Delegation policy · Concepts: Capability profile |
Differentiation vs general agents: autonomous agents typically execute tools with minimal gating. Reyn requires per-capability declaration + 4-layer just-in-time approval (config → saved → session → interactive), a
.reyn/write zone, and per-skill credential scoping (Confused Deputy mitigation).
Safety / limit-handling¶
Bounded-operation checkpoints that stop the agent gracefully rather than hard-failing. See Safety framework.
| Feature | Description | Documentation |
|---|---|---|
handle_limit_exceeded unified checkpoint |
Single shared function runtime/limits/limit_handler.py that all seven loop / timeout / budget checkpoints call; owns the 3-mode dispatch, bus interaction, extension bookkeeping, and audit event — callers only decide what limit fired |
Safety framework |
On-limit modes (OnLimitConfig) |
interactive (ask) / auto_extend (budgeted N times) / unattended (abort) via safety.on_limit.mode; applies uniformly to loop caps, timeout caps, and budget exceed paths |
Safety framework · reyn.yaml § safety |
| Force-close wrap-up | On a denied limit the LLM gets one final tool-less turn to summarise what was accomplished; delivered as a kind="agent" message with meta.limit_stopped |
Safety framework |
limit_denied event |
P6 audit event on every deny path (max_iterations / router_cap) |
Events reference |
| Decision-enabling fallback | When the wrap-up fails or is empty, a structured error states the limit hit, the config key to change, and partial-data availability | Safety framework |
Differentiation vs general agents: where free-running agents hard-stop or run away at a limit, Reyn's force-close turns a denied limit into a graceful LLM wrap-up plus an operator decision — it reports what it accomplished instead of vanishing or looping unbounded.
Content-layer defense¶
Scanning untrusted content (memory, tool results, context files, inbound peer messages) for prompt-injection / exfiltration / role-hijack patterns at the seams where it enters the prompt — a security transform at a content boundary, not OS decision logic. Design: content-threat scan proposal.
| Feature | Description | Documentation |
|---|---|---|
| Threat-pattern library ✅ | Security-domain regexes (injection / exfiltration / role-hijack / exec) applied to untrusted content across all scopes — security/threat_patterns.py |
Design |
| Content fence ✅ | Wraps untrusted content in explicit delimiters so model-visible boundaries are unambiguous — security/content_fence.py |
Design |
| Unified tool-result guard ✅ | One seam scans + fences tool-result content before it reaches the prompt — security/content_guard.py |
Design |
| Memory-write BLOCK ✅ | Memory writes that match threat patterns are blocked before reaching the agent's memory store — runtime/router_loop.py |
Design |
| Pre-exec command scan ✅ | sandboxed_exec scans the full joined argv against exec-scope threat patterns before any shell is launched; blocked commands emit exec_threat_blocked — core/op_runtime/sandboxed_exec.py |
Design |
| Context-file + A2A-inbound fence ✅ | Operator-editable context files (REYN.md/AGENTS.md) and untrusted inbound A2A peer messages are fenced + scanned on arrival — router_host_adapter.py (EP3) / inter_agent_messaging.py (S4b) |
Design |
| Compaction secret redaction ✅ | Secret-looking content is stripped from compaction input before summaries are persisted — security/secret_redaction.py |
Design |
Differentiation vs general agents: Reyn places content-layer scanning at the OS seams — the same content boundaries where secret interpolation already sits — as a security-domain transform that keeps OS decision logic free of skill strings (P7). Structural redundancy means checks already enforced by the sandbox / permission layer (e.g. absolute-path or pipe-to-shell writes) are not re-implemented as ad-hoc per-call scans.
Budget & Cost¶
| Feature | Description | Documentation |
|---|---|---|
| Per-agent caps | Token + USD hard limits with warn_ratio |
Budget config |
| Per-chain caps | Skill spawn count + token total per chain | Budget config |
| Rate limits | Per-model calls-per-minute sliding window | Budget config |
| Daily quotas | Persistent JSONL ledger, resets at local midnight | Budget config |
| Monthly quotas | Persistent JSONL ledger, resets at month boundary | Budget config |
| Crash-durable cap counters | Every cap counter (daily / monthly / per-agent token+USD / per-chain spawn count) is reconstructed on startup from the fsync-per-append ledger — a crash inside the throttled budget_state.json save window cannot under-count a cap and re-allow over-budget calls or spawns. The state file is a best-effort cache; the ledger wins on recovery |
Budget config · state-dir |
extension_calls (+ safety.on_limit.mode) |
Budget-extension flow on hard cap hit; extension_calls > 0 opts the dimension into the unified safety.on_limit policy (ask / auto-extend / deny). The per-dimension ask_on_exceed bool was removed. |
Budget config |
High-cost model warn (cost_warn) |
cost_warn.enabled (default true) emits a model_cost_warn event + inline conv-pane marker when the resolved model's input cost per 1M tokens exceeds model_threshold_per_1m_input_usd (default 5.0); fires at /model switch and session startup, de-duped once per model per session |
reyn.yaml § cost_warn |
Differentiation vs general agents: token + USD caps per agent / chain / model with refuse-on-exceed and a
safety.on_limit-driven extension flow, plus a pre-selection high-cost model warning — runaway spend is structurally bounded, not merely observed after the fact.
Memory & RAG¶
| Feature | Description | Documentation |
|---|---|---|
| LiteLLM embedding backend | Any provider via named model class config | RAG concepts |
| Local embedding backend | sentence-transformers via pip install 'reyn[local-embed]' — local-mini / local-e5 classes, credential-free, GPU-optional via REYN_EMBED_DEVICE |
RAG concepts § Local embedding backend · Guide |
| Provider-prefix routing | sentence-transformers/ → local backend; anything else → LiteLLM |
RAG concepts § Embedding configuration |
| Batch embed | Configurable batch_size with concurrency semaphore |
RAG concepts |
| Dimension table | Static lookup for OpenAI / Voyage / Cohere | RAG concepts |
| SQLite index per source | .reyn/index/<source>/index.db with WAL mode |
RAG concepts |
| Chunk dedup | content_hash upsert prevents re-indexing |
RAG concepts |
recall op |
embed → index_query per source → merge top-K globally |
Control IR |
| Action embedding index | ActionEmbeddingIndex (SQLite-WAL, class-swap detection, cross-process build lock) — backs the search_actions tool the chat LLM uses |
Universal catalog § search_actions · reyn embeddings |
| Memory CRUD | list / read / remember_shared / remember_agent / forget |
Memory concepts · reyn memory CLI |
Differentiation vs general agents: beyond chat memory, Reyn ships a RAG framework — a safe-mode Python step calls
embed_and_index()directly (you own the chunking logic) over a pluggableIndexBackend, with a credential-free local-embedding option. A foundation to build on, not a fixed memory feature.
MCP¶
| Feature | Description | Documentation |
|---|---|---|
| stdio transport | Subprocess StdioServerParameters — implemented |
Concepts: MCP |
| HTTP transport | Streamable HTTP with request headers — implemented | Concepts: MCP |
| SSE transport | Reserved — raises NotImplementedError |
Concepts: MCP |
mcp serve |
Expose Reyn agents as an MCP server over stdio JSON-RPC 2.0 | reyn mcp CLI |
mcp install |
Fetch from registry, gate permissions, write config, store secrets. Three chat verbs: mcp__install_registry (official registry), mcp__install_package (npm/pypi/docker/github URL), mcp__install_local (direct command). CLI: reyn mcp install <SERVER_ID> or --source <SPEC>. |
Concepts: MCP · reyn mcp CLI |
| Secret management | Per-server env vars in ~/.reyn/secrets.env |
reyn secret CLI |
| Tool dispatch | Lazy-load and cache MCPClient per server connection |
Concepts: MCP |
Differentiation vs general agents: Reyn is both an MCP client (consumes external servers) and an MCP server (exposes its own agents) — standard-protocol interop in both directions, with stdio MCP servers subprocess-sandboxed under Seatbelt.
Skills¶
| Feature | Description | Documentation |
|---|---|---|
SKILL.md registry |
Explicit skills.entries declarations (no directory scan) — same registration model as mcp.servers |
Concepts: Skills |
| Three-layer exposure | L1 system-prompt ## Skills menu (name — description [path]) → L2 on-demand SKILL.md read → L3 bundled-asset file-read, all via the ordinary file-read op |
Concepts: Skills |
| Config cascade | ~/.reyn/config.yaml ⊕ reyn.yaml ⊕ reyn.local.yaml ⊕ dynamic .reyn/config/skills.yaml, later tier wins on name collision |
Reference: reyn.yaml |
| Hot-reload | .reyn/config/skills.yaml edits apply at the next turn boundary via the "skills" reload seam |
Concepts: Config hot-reload |
| Session visibility toggle | set_capability_visible("skill", name, visible) — restrict-only, cannot re-grant beyond the registered set |
Concepts: Skills |
skill_management__install_local |
Register a local skill directory into .reyn/config/skills.yaml; threat-scanned, permission-gated, config-generation recorded for crash-recovery |
Concepts: Skills |
skill_management__install_source |
Fetch + shallow-clone a skill from a git/GitHub URL into .reyn/skills/<name>/; same threat-scan/gate/recovery pipeline, plus path-traversal-hardened name sanitization and containment checks |
Concepts: Skills |
Differentiation vs general agents: skills are instructions the model chooses to read, not programs the OS executes — the same layered-disclosure shape (menu → on-demand load) as MCP tool discovery, applied to task-specific technique instead of external APIs.
Web & Protocol¶
| Feature | Description | Documentation |
|---|---|---|
| FastAPI gateway | REST + WebSocket server on localhost:8080 |
reyn web CLI |
| WebSocket chat | /ws/chat for interactive browser sessions |
reyn web CLI |
| A2A Agent Card | Per-agent /.well-known/agent-card.json capability declaration |
reyn web CLI |
A2A message/send |
Synchronous JSON-RPC 2.0 single-turn endpoint per agent | reyn web CLI |
| A2A agent discovery | GET /a2a/agents server-level listing |
reyn web CLI |
| A2A async tasks | async_mode → Task envelope; GET /a2a/tasks/{run_id} poll, …/events SSE stream, …/cancel; mid-run ask_user surfaces as input-required |
A2A concepts |
| Webhook push | Status-transition POSTs to params.webhook_url for async tasks (reyn.web.notifications) |
A2A concepts |
| MCP-over-SSE | /mcp/sse + /mcp/messages for MCP client connections |
reyn web CLI · reyn mcp CLI |
| REST API | /api/* for agents / skills / runs / topologies / budget / permissions |
reyn web CLI |
Differentiation vs general agents: competitors specialise in broad, deep connectivity to the messaging apps you already use. Reyn keeps connectivity to standard protocols — MCP (client + server), A2A (sync + async tasks with webhook push), and a REST / WebSocket gateway — rather than per-app integrations.
TUI¶
The Textual terminal interface for reyn chat (src/reyn/interfaces/tui/).
| Feature | Description | Documentation |
|---|---|---|
| Conversation view | Streaming conversation with inline thinking rows and tool-call rendering | — |
| Right Panel tabs | Live side panels: Agents / Cost / Docs / Events / Keys / Memory / Pending | — |
| Tool-result viewer registry ✅ | register_viewer seam replaces inline content-type dispatch; register_content_type_viewer(content_types, viewer, *, match="exact"\|"prefix"\|"substring") provides the ergonomic MIME shorthand — delegates to register_viewer so name/position behave identically |
Tool-result viewers reference |
| LLM-generated template fallback ✅ | On registry miss, _generate_template async-generates a TemplateSchema (label/value rows + caption) via LLM call; _apply_template renders it with label escape and row/caption caps (_MAX_TEMPLATE_ROWS=8, _MAX_CAPTION_CHARS=40) |
Tool-result viewers reference · FP-0051 proposal |
| Email-diff viewer ✅ | Concrete viewers for message/rfc822 (email from/subject card) and text/x-diff / text/x-patch (syntax-highlighted patch); registered before the generic JSON viewer so declared content-type takes priority |
Tool-result viewers reference |
| Input + command palette | Input bar with slash commands (/plan, /compact, /find, /help, /clear) via a command palette |
— |
| Intervention widget | In-TUI ask_user prompt rendering |
— |
| Chainlit web chat (⚗ PoC) | Alternative browser chat UI sharing the same agent — reyn chainlit + chainlit_app/ (agent picker, settings, uploads, slash routing); coexists with the TUI |
— |
Differentiation vs general agents: Reyn's chat surface is a local, inspectable TUI with live audit panels (events / cost / permissions) beside the conversation — the operator sees what the agent is doing and spending in real time.
Intervention¶
Cross-surface ask_user and permission routing — the same prompt reaches the operator over whichever surface is active (chat/services/intervention_registry.py).
| Feature | Description | Documentation |
|---|---|---|
| InterventionBus family | ChatInterventionBus (TUI) / StdinInterventionBus (CLI) / A2AInterventionBus (web) / _MCPInterventionBus (MCP) |
Permission model |
| InterventionRegistry | Tracks pending interventions and pairs each answer back to the waiting run | — |
ask_user lifecycle |
Pause run → surface prompt → resume on answer; async wait works across surfaces | Control IR — ask_user |
Differentiation vs general agents: human-in-the-loop is a first-class, surface-agnostic primitive — a permission ask or
ask_userroutes to the operator identically whether the agent runs in the TUI, CLI, web / A2A, or MCP.
Sessions and identity¶
| Feature | Description | Documentation |
|---|---|---|
| Two-level model | Agent (identity) → Session (conversation) |
Concepts: Sessions |
| Multiple Sessions per Agent | One identity, many parallel conversations; AgentRegistry maps name → {sid → Session} with a shared Agent identity |
Concepts: Sessions |
| Identity vs conversation scope | Memory / permissions / workspace / peer-addressing live on the Agent; history / inbox-outbox / current task stay per-Session | Concepts: Sessions |
| Per-session persistence | Each Session is snapshotted and restored independently (WAL-backed; snapshot re-keyed per Session) | Concepts: Sessions |
| Global-cut time-travel | /rewind moves every Session and Agent to the target checkpoint atomically (one global single-seq WAL) — per-Session granularity is in persistence, not the rewind |
Concepts: time-travel |
| Multi-session crash recovery | On restart the full name → {sid → Session} structure is reconstructed from event log + snapshots, not just one conversation | Concepts: time-travel |
| Transport routing-key | Default: native conversation-id → Session (namespaced, auto-spawn/resume). Explicit: join an existing Session by id (non-existent = error). Scoped within one Agent | Concepts: Sessions |
Differentiation vs general agents: the Agent / Session / runtime split is the mainstream agent-platform shape (cf. Assistant / Thread / Run); Reyn's distinction is what sits beneath it — every Session is event-sourced, permission-gated, and independently persisted, so one identity can hold many isolated conversations, with a single global consistent-cut rewind across them all.
Multi-Agent¶
| Feature | Description | Documentation |
|---|---|---|
| Agent registry | Named agents with role profiles + history.jsonl |
reyn agent CLI |
network topology |
Full mesh — any member to any member | reyn topology CLI |
team topology |
Star around leader — member-to-member forbidden | — |
pipeline topology |
Ordered — each member sends only to next | — |
_default topology |
Auto-synthesized full mesh for unassigned agents | Multi-agent config |
| MessageBus | Quiescence-based coordination with reply_to correlation |
Multi-agent config |
delegate_to_agent |
Async-dispatch to peer with topology permission gate | Multi-agent concepts |
| Agent hops cap | Max delegation depth via safety.loop.max_agent_hops |
reyn-yaml § safety |
chain_id propagation |
Trace multi-hop chains in P6 events | Events reference |
Differentiation vs general agents: delegation is topology-gated (network / team / pipeline) with a hop-depth cap and
chain_idaudit propagation — multi-agent reach is bounded and traceable, not free-form.
LLM org-design (runtime spawn primitives)¶
Three router-only tools the LLM uses to build a live organisation at runtime — distinct from the operator CLI / Topology YAML surface (which defines structure up front in configuration).
| Feature | Description | Documentation |
|---|---|---|
agent_spawn |
Create a new agent (name + role) under the calling agent's authority; capabilities capped at ⊆ the spawner's by construction; spawn lineage is OS-set / identity-keyed (forge-guarded) | Concepts: LLM org-design tools |
session_spawn |
Start a fresh-context sub-session under the calling agent to run a task in isolation; mode=ephemeral auto-vanishes after the task, mode=persistent stays; optional narrowing (restrict-only) at spawn time |
Concepts: LLM org-design tools |
topology_create |
Wire agents in the caller's spawn subtree into a named topology (network / team / pipeline) and optionally bind members to capability profiles (narrowing within the ⊆-parent envelope); subtree-restriction gate enforced by OS |
Concepts: LLM org-design tools |
| ⊆-parent capability model | Spawned agent effective capability = parent's live effective ∩ assigned profile; recursive no-escalation-via-spawn; closed across four stale-lineage axes (live, rewind-drop, absent-parent, name-reuse) | Concepts: permission model § LLM spawn |
| Operator spawn-tree bounds | safety.spawn.max_depth (chain depth) + safety.spawn.max_children (fan-out + topology member count) — DoS guard; exceeding either fires the safety.on_limit checkpoint (interactive=operator-prompt / unattended=reject / auto_extend); depth and children carry separate per-spawner extension keys; LLM cannot self-raise the base limit |
reyn-yaml § safety.spawn |
Differentiation vs general agents: the LLM designs the org structure at runtime — not free-form (every spawned agent is capability-capped at ⊆ the spawner, recursively), not pre-wired (the org emerges from the task), and fully rewind-safe (lineage is WAL-tracked; spawn and topology events survive crash recovery).
Task system¶
The dynamic work-unit model: small composable ops the LLM reaches for as structure emerges, instead of an upfront plan.
| Feature | Description | Documentation |
|---|---|---|
| Dynamic task ops | 11 composable work-unit ops (task__create / update_status / get / list / add_dependency / remove_dependency / repoint_dependency / abort / heartbeat / register_unblock_predicate / comment) the LLM reaches for when structure emerges |
Concepts: Tasks · Control IR — Task ops |
| Requester / assignee model | Requester (creator, notify-target) vs a single immutable assignee (worker); a non-self assignee delegates cross-session; a task created while executing a task is automatically owned (requester) by it — OS-derived, no parent_id op field (§16) |
Concepts: Tasks |
| Single-writer CAS gate | Only the assignee session may write a task's status — fixed-equality assignee == caller session_id in the backend; topology writes (deps / abort) are owned by the requester |
Concepts: Tasks |
| Dual-path, no bypass | The same assignee CAS is enforced whether ops arrive from a phase's control-IR or the chat router (invoke_action); the bridge refuses a session-less context rather than mask the gate |
Concepts: Tasks |
| Dependency DAG | deps are depends-on edges; a task with unmet deps is OS-derived blocked, readiness recomputed (never written); edges are existence- + cycle-checked; repoint swaps a dep to a substitute |
Concepts: Tasks |
| Cross-session WAKES | A born-startable delegated task — and a dependent promoted to ready — wakes its assignee session to execute it, with the OS execute-framing as the trusted instruction | Concepts: Tasks |
| Content-fenced task text | The free-text description / name / result fields are structurally fenced as untrusted data on the query path (task.get / list) and in the execution-path wake message; OS-generated structural fields stay unfenced |
Security: what gets structurally fenced |
/tasks view |
List running tasks + per-task status + kill, spanning skill runs and dynamic tasks | chat CLI |
| Single-source ToolDefinitions | The LLM-facing tool schemas are derived from the IROp models (model_json_schema() minus the kind discriminator), so the catalog never drifts from the runtime contract |
Control IR — Task ops |
Differentiation vs general agents: rather than a forced upfront plan, the task model is small composable ops the LLM reaches for as structure emerges — with a single-writer compare-and-set on the immutable assignee session (no hand-off, no bypass across the phase / chat paths), a cycle-checked dependency DAG, and cross-session WAKES that let one agent hand a durable, crash-recoverable work-unit to a peer.
Sandbox¶
| Feature | Description | Documentation |
|---|---|---|
SeatbeltBackend |
macOS sandbox-exec SBPL profile generation |
Concepts: Sandbox |
LandlockBackend |
Linux 5.13+ Landlock LSM + seccomp-BPF stacking | Concepts: Sandbox |
NoopBackend |
Fallback audit-only with one-time WARN log | Concepts: Sandbox |
SandboxPolicy |
network / read_paths / write_paths / subprocess / env_passthrough / timeout |
Control IR — sandboxed_exec |
| Auto-selection | Platform detection + on_unsupported: warn\|error\|ignore |
reyn-yaml § sandbox · Concepts: Sandbox |
Differentiation vs general agents: tool / code execution runs under an OS-level sandbox (Seatbelt / Landlock + seccomp-BPF) with an explicit
SandboxPolicy, rather than unsandboxed tool calls. Stdio MCP servers are also subprocess-wrapped under Seatbelt.
Environment — ⚗ Stage 2 (experimental MVP)¶
Repo-filesystem mechanism abstraction decoupling the workspace from where the repo FS lives. The host backend is production; the container backend is an exec-per-op MVP. See src/reyn/environment/.
| Feature | Description | Documentation |
|---|---|---|
EnvironmentBackend protocol |
Abstracts repo-FS read / write / exec away from the OS + permission layer | — |
HostBackend |
Default — identity over the local filesystem (production) | — |
DockerEnvironmentBackend |
⚗ Stage 2 MVP — repo FS + exec inside a Docker container (--container attach); exec-per-op |
— |
| Mount-mode launcher | ⚗ container launch with the repo mounted + devcontainer.json awareness / build-on-demand |
— |
Differentiation vs general agents: Reyn adopts the container-exec pattern those agents popularised (e.g. Hermes docker-exec), but keeps the OS + permission + audit layer on the host while only the repo FS lives in the container — sandboxed execution without surrendering governance. (⚗ Stage 2 / experimental.)