ARIA — Agent Runtime for Intelligent Automation
Local-first. Secure by default. Fully auditable.
Build smallest possible correct system. Fail loudly, never silently.
What This Is
ARIA is a production-grade, single-agent AI execution runtime. It is not a framework, not a platform, and not a library. It is a complete, runnable system with explicit contracts between every component.
Design philosophy:
- Fail loudly, never silently
- Explicit state transitions only (typed FSM)
- Every side effect logged before and after
- All boundaries validate input/output against schemas
- Synchronous core — no async race conditions
- Security by default, least privilege
- No vendor lock-in (abstraction layers)
Quick Start
# Set your API key
export ANTHROPIC_API_KEY=sk-ant-...
# Run a task
python -m aria.cli.main run --task "What are the first 5 prime numbers?"
# See registered tools
python -m aria.cli.main tools list
# View audit log
python -m aria.cli.main audit list
python -m aria.cli.main audit export --session-id <id>
python -m aria.cli.main audit verify --session-id <id>
Architecture
CLI Layer (thin boundary, zero business logic)
│
▼
AgentKernel (orchestrator — sequences, delegates, enforces limits)
│
├── SessionFSM (IDLE→RUNNING→WAITING→DONE|FAILED|CANCELLED)
├── ModelRouter (retry + circuit breaker per provider)
├── ToolRegistry (manifest validation, permission enforcement)
├── SandboxRunner (subprocess isolation, path traversal prevention)
└── SQLiteStorage (memory + audit, WAL mode, chain hashing)
State Machine
IDLE ──► RUNNING ──► WAITING ──► RUNNING
│ │ │
│ ▼ ▼
└────► CANCELLED FAILED
▲
RUNNING ──► DONE
Every transition is validated. Invalid transitions raise InvalidStateTransitionError immediately.
Security Architecture
| Threat | Mitigation |
|---|---|
| Malicious model output | Schema validation before any tool execution |
| Path traversal | Path.resolve() + allowlist check before subprocess |
| Prompt injection | Syntactic scanner + structural separation + schema validation |
| Command injection | shell=False always; args as list[str], never concatenated |
| API key leaks | Secrets scrubber in every log record — cannot be bypassed |
| Malicious plugins | Subprocess isolation + permission boundaries enforced at load |
| Audit tampering | SHA-256 chain hash across all audit records |
Security invariants that must never be broken:
shell=Falseeverywhere. No exceptions.- Paths resolved and validated before subprocess spawns.
- Tool input/output validated against manifest schemas.
- Audit writes preceded by chain hash computation.
AuditWriteFailureErroralways halts the process.
Directory Structure
aria/
├── aria/
│ ├── kernel/
│ │ ├── fsm.py # Session finite state machine
│ │ ├── context.py # Immutable per-step execution context
│ │ └── kernel.py # Agent kernel (orchestrator)
│ ├── models/
│ │ ├── types.py # All shared data contracts (dataclasses)
│ │ ├── errors.py # Typed exception hierarchy
│ │ ├── router.py # Model router: retry + circuit breaker
│ │ └── providers/
│ │ ├── base.py # ModelProviderInterface ABC
│ │ ├── circuit_breaker.py # Per-provider circuit breaker
│ │ ├── anthropic_provider.py # Anthropic Claude adapter
│ │ └── ollama_provider.py # Local Ollama adapter (tinyllama)
│ ├── tools/
│ │ ├── registry.py # Tool registry: load, validate, enforce permissions
│ │ ├── sandbox.py # Subprocess sandbox + path/schema validation
│ │ └── builtin/
│ │ ├── read_file.py
│ │ └── write_file.py
│ ├── memory/
│ │ └── sqlite.py # SQLite memory + audit (WAL, chain hashing)
│ ├── security/
│ │ ├── secrets.py # Env-based secrets loader
│ │ └── scrubber.py # Log scrubber + injection scanner
│ ├── cli/
│ │ ├── main.py # CLI entry point
│ │ ├── bootstrap.py # Dependency wiring
│ │ ├── run_cmd.py
│ │ ├── audit_cmd.py
│ │ ├── tools_cmd.py
│ │ └── config_cmd.py
│ └── logging_setup.py # Structured JSON logging (stdlib)
└── tests/
├── unit/ # FSM, scrubber, CB, memory, manifest validation
├── integration/ # Full kernel with mock provider + real SQLite
└── security/ # Path traversal, injection, tampering, permissions
Error Taxonomy
| Error | Retryable | Action |
|---|---|---|
ToolInputValidationError |
No | FAILED + log |
ToolTimeoutError |
No | FAILED + log |
ModelProviderError (5xx) |
Yes (3x) | Retry with backoff |
ModelRateLimitError (429) |
Yes (3x) | Retry with backoff |
CircuitBreakerOpenError |
No | Try fallback or FAILED |
StepLimitExceededError |
No | FAILED + log |
InvalidStateTransitionError |
No | CRITICAL + halt |
AuditWriteFailureError |
No | CRITICAL + halt |
UnknownToolError |
No | FAILED + log |
PathTraversalError |
No | FAILED + log |
No silent failures. No bare except Exception: pass. Every error has a name.
Configuration
All configuration via environment variables:
ANTHROPIC_API_KEY=sk-ant-... # Required for Anthropic provider
ARIA_PRIMARY_PROVIDER=ollama # Default: ollama
ARIA_PRIMARY_MODEL=tinyllama # Default: tinyllama
ARIA_MAX_STEPS=20 # Default: 20
ARIA_MAX_COST_USD=1.0 # Default: 1.00
ARIA_DB_PATH=~/.aria/aria.db
ARIA_LOG_PATH=~/.aria/logs/aria.jsonl
ARIA_LOG_LEVEL=INFO
Writing a Plugin Tool
# my_tool.py — place in a plugin_dirs directory
from aria.models.types import ToolManifest, ToolPermission
class ToolPlugin:
manifest = ToolManifest(
name="word_count",
version="1.0.0",
description="Count words in a text string. Returns integer count.",
permissions=frozenset({ToolPermission.NONE}), # No FS/network access
timeout_seconds=5,
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
"additionalProperties": False,
},
output_schema={
"type": "object",
"properties": {"count": {"type": "integer"}},
"required": ["count"],
"additionalProperties": False,
},
)
@staticmethod
def execute(input_data: dict) -> dict:
return {"count": len(input_data["text"].split())}
Plugin rules:
- Must define
ToolPluginclass withmanifest: ToolManifestandexecute(dict) -> dict executeruns in a subprocess — it cannot import ARIA internals- Schema validation happens before and after execution
- Path access validated against
allowed_pathsbefore subprocess spawns shell=Falsealways — never usesubprocess.callwith string args
Audit & Observability
Every session produces a complete, append-only audit trail:
# List recent sessions
aria audit list --last 20
# Export full audit trail (JSON or human-readable text)
aria audit export --session-id <id> --format json
aria audit export --session-id <id> --format text
# Verify audit chain integrity (detect tampering)
aria audit verify --session-id <id>
The audit chain uses SHA-256 linking: each record's hash is computed from the previous record's hash and the current record's content. Any modification breaks the chain.
Roadmap
Month 1 (Foundation — ONLY phase that matters):
✅ Agent kernel + FSM
✅ ToolManifest validation
✅ Subprocess sandbox
✅ Anthropic + Ollama provider adapters
✅ SQLite memory + audit with chain hashing
✅ Structured JSON logging with secrets scrubber
✅ CLI: run, audit, tools
✅ Unit + integration + security tests
Month 3 (Stability): OpenAI adapter, full circuit breaker, schema migration, cost dashboard, fuzzing tests.
Month 6 (Hardening): Prometheus metrics, 4 built-in tools, plugin SDK, chaos testing, session resumption.
Month 12 (Enterprise): Postgres backend, multi-session concurrency, read-only web UI, RBAC, OpenTelemetry.
Known Limitations (v1)
- Subprocess ≠ container: Same-user processes can observe each other. For untrusted plugins, upgrade to namespace isolation (Month 6).
- No session resumption: FAILED sessions are terminal. Replay from beginning.
- Context truncation: Conversation history truncated when approaching token limits. Crude but deterministic.
- SQLite only: Concurrent write throughput bottleneck. Acceptable for single-process v1.
MemoryInterfaceabstraction enables Postgres migration. - Prompt injection: Syntactic + structural defenses implemented. Schema validation is the last hard boundary, not the only one.
ARIA Philosophy
"Stable > Feature-rich. Predictable > Smart. Auditable > Autonomous."
Metadata
Release files for aria-runtime 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| aria_runtime-0.1.0.tar.gz | 50.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aria_runtime-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 91.7 kB
Release files / aria_runtime-0.1.0.tar.gz
| Download URL | aria_runtime-0.1.0.tar.gz |
|---|---|
| Size | 50.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
710ef36b8f1319d024955a321002efc4f4162f78d6d6ead69a4b9b554d64e542
|
|
BLAKE2b-256 checksum How to use checksums |
0c1ae40daab6ab159b4a8ecd512103158561a87d71f7144022d6b78e40166157
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|
Release files / aria_runtime-0.1.0-py3-none-any.whl
| Download URL | aria_runtime-0.1.0-py3-none-any.whl |
|---|---|
| Size | 40.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ff161997d799e71df6397d90cf30eb6902b3f6a06ce6fe2dea8424f067498023
|
|
BLAKE2b-256 checksum How to use checksums |
2c1683659792f7cace6ac8dc3db33464c7e7fc76fa2aaf867467946483da98fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.6
|
Security for aria-runtime 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.