IoT devices do not need more data. They need to reason about that data — and act on it.
Ori is an open-source agentic IoT runtime that gives physical devices tiered autonomous reasoning — from deterministic safety rules to local SLMs. This reasoning is governed by a Physical Actuation Trust framework that defines exactly what an AI agent is permitted to do in the physical world, at what consequence level, and with what human oversight. Offline-first with an offline-capable safety core; gateway escalation is optional. Runs on a $55 Raspberry Pi.
Built for the world's majority condition — unreliable power, intermittent connectivity, constrained hardware. Systems designed for constraint work everywhere.
Current channel: Stable (1.0.x)
- Runtime core is v1-stable for PoC, demo API, and controlled field deployment.
- Safety invariants (tier guards, strict skill validation, sandbox boundaries) are CI-enforced on every PR.
- Public runtime contracts used by companion repos are the MQTT gateway/export contracts and the typed
ori.integrationrule-evaluation boundary. - Recommended use today: pilots, PoCs, controlled deployments, and the
ori-energydemo/API integration. - Release notes:
docs/releases/v1.0.0.md
Related repos in the org:
- Runtime:
ori-platform/ori-runtime(this repo) - Skills registry:
ori-platform/ori-skills - CLI:
ori-platform/ori-cli - Gateway:
ori-platform/ori-gateway - SDK (Python):
ori-platform/ori-sdk-python - Dashboard:
ori-platform/ori-dashboard - Specs/RFCs:
ori-platform/ori-specs
Every existing IoT platform does the same thing: collect data, apply a threshold, fire an alert, wait for a human. Sensors report numbers. Ori reasons about them — and acts.
❌ Traditional IoT: "Current draw: 8.2A"
❌ Traditional IoT: "ALERT: threshold exceeded. Please investigate."
✅ Ori (Tier A): "Your AC unit has drawn 40% above baseline for three afternoons.
Pattern: refrigerant depletion, not usage change.
Estimated failure: 2 weeks.
I've sent a service reminder to your WhatsApp."
— sent autonomously from a $55 Pi, without requiring cloud inference for safety decisions
✅ Ori (Tier B): "Grid voltage dropped to 174V. I have switched to
inverter power automatically." ← Acted. Then told you.
✅ Ori (Tier C): "Critical fault detected on main circuit. I am
proposing to open the protected-load safety circuit. Reply YES-AB12CD34
to approve or NO-AB12CD34 to cancel. Auto-cancel in 5 minutes."
← Reasoned. Proposed. Awaiting you.
✅ Ori (Tier D): [Installer-wired relay/contactor opens immediately]
"Dangerous overcurrent (52A on 10A circuit). Emergency
cutoff executed at 14:32." ← Safety. No waiting.
Ori is not a monitoring system with a language model attached. It is an agent that reasons and acts — and trust is won by proving that human correction permanently alters the machine's future behaviour.
- Not a monitoring dashboard like Grafana — Ori acts, not just displays
- Not a cloud IoT platform like AWS IoT Core — Ori keeps an offline-capable safety core (Tier 1 + local Tier 2), with optional gateway escalation when connected
- Not a notification system — alerts are Tier A, the least of what Ori does
- Not just a rules engine — Ori pairs deterministic safety rules with LLM reasoning
┌──────────────────────────────────────────────────────────────┐
│ Layer 6 Business ori-cloud · dashboard · fleet │
├──────────────────────────────────────────────────────────────┤
│ Layer 5 Application Skills · Skills Hub · SDK │
├──────────────────────────────────────────────────────────────┤
│ Layer 4 Reasoning+Action Intelligence Elevator │
│ + Action Tier Framework │
├──────────────────────────────────────────────────────────────┤
│ Layer 3 Middleware Runtime · Event Loop · Dispatcher │
├──────────────────────────────────────────────────────────────┤
│ Layer 2 Network EventBus · Protocol Normaliser │
├──────────────────────────────────────────────────────────────┤
│ Layer 1 Perception HAL · GPIO · I2C · RS485 · psutil │
└──────────────────────────────────────────────────────────────┘
Layers 1–4 run on the device. Layers 3 and 4 are inseparable — the runtime always pairs a reasoning decision with an action decision. Layer 5 is the community. Layer 6 is the business.
For the full architectural specification, read CLAUDE.md. For the design philosophy, read PRINCIPLES.md.
| Protocol | Status | Coverage |
|---|---|---|
| GPIO (Raspberry Pi) | ✅ | Wired sensors and relay control |
| I2C / SPI | ✅ | Precision sensors: BME280, ADS1115, SCD40 |
| Modbus RTU (RS485) | ✅ | Industrial energy meters, PLCs, motor drives |
| psutil | ✅ | PC and server health monitoring (any laptop) |
| MQTT | ✅ | WiFi-connected sensors/devices via an MQTT broker (commonly Mosquitto) |
| CoAP (actuation) | ✅ | Constrained-device command path for low-overhead control endpoints |
| OPC-UA | ✅ | Industrial PLCs (IEC 62541) |
| SolarmanV5 (Growatt) | ✅ | Smart inverter integration |
| Zigbee | ✅ | Smart-home sensors via MQTT bridge (for example zigbee2mqtt) |
| LoRaWAN | ✅ | Rural long-range uplink sensors via MQTT brokers (TTN/ChirpStack) |
✅ = Implemented
All adapters include a hardware circuit breaker that auto-isolates failing buses to protect the rest of the system.
| Configuration | Hardware | RAM | Notes |
|---|---|---|---|
| Rule engine only (Tier 1) | Raspberry Pi 3B+ or equivalent | 1GB | No local SLM. Full safety framework active. |
| Full stack with local SLM | Raspberry Pi 4 4GB | 4GB | Validated reference hardware. 3–8s inference. |
| Development / laptop | Any modern machine | 4GB+ | psutil adapter. No Pi required. |
The model file (Qwen2.5-0.5B Q4) is 500MB. The SQLite state store stays bounded under 80MB via the compaction pyramid regardless of deployment duration. Production/staging deployments must place the SQLite state path on an encrypted filesystem or mount and declare that posture under state.encryption; the runtime uses standard sqlite3, not SQLCipher.
Ori runs a paired decision system on every sensor event:
Tier 1 RULE ENGINE microseconds · always available · safety triggers
Tier 2 LOCAL SLM 3-8 seconds · offline-capable · everyday reasoning
Tier 3 GATEWAY LLM 1-3 seconds · LAN only · cross-device or cloud-backed reasoning
- Tier 1 (Rule Engine) and Tier 2 (Local SLM) are fully implemented and available offline.
- Tier 3 (Gateway LLM) is implemented over MQTT request/response and remains optional.
- Cloud reasoning, when used, is a gateway backend, not a runtime dependency.
- Production runtime-gateway MQTT deployments should follow
docs/MQTT_SECURITY.mdfor broker ACLs, network isolation, and HMAC envelope configuration. - Public SMS webhook deployments should follow
docs/SMS_WEBHOOK_SECURITY.md. Runtime sender allowlisting is necessary, but carrier-level sender spoofing requires deployment controls such as a signing bridge, source CIDR allowlisting, or a trusted reverse proxy. - The runtime is correctly described as an offline-capable safety runtime. Tier 1 and Tier D safety paths are available with zero network dependency.
Tier A INFORMATIONAL Always autonomous
Alerts, logs, reports — the agent acts without asking
Tier B SOFT PHYSICAL Explicit approval or post-action policy
Power source switching, thermostat adjustments, irrigation valves
The agent either asks first or acts first and explains after
Tier C HARD PHYSICAL Approval workflow — always
Relay/contactor-controlled shutdown, high-consequence control
The agent reasons, proposes, and waits for your YES or NO
Tier D SAFETY-CRITICAL Always autonomous, cannot be overridden
Dangerous overcurrent, thermal runaway, hazardous gas
The agent acts first, notifies you immediately
The runtime picks the cheapest reasoning tier that can answer. The action tier determines whether it acts, asks, or moves immediately.
Ori is designed for physical actuation trust. The safety architecture enforces invariants at every layer:
- Tier D rules fire before any LLM — deterministic, microsecond-latency cutoffs that cannot be disabled or overridden
- AST whitelist validation — skill condition expressions are parsed into abstract syntax trees and only safe constructs are permitted (comparisons, arithmetic,
history.method()calls). No string-pattern blacklist that can be bypassed - Sandboxed skill hooks — community skills cannot import arbitrary modules. The sandbox enforces an explicit allowlist at import time
- Hardware circuit breakers — failing sensor buses are auto-isolated using a three-state (CLOSED → OPEN → HALF_OPEN) circuit breaker so one bad sensor doesn't crash the runtime
- Approval workflows for hard physical actions — Tier C actions always require operator approval via WhatsApp/SMS. No config flag to skip it
- Alert transport failover — approval requests use the configured primary channel first, then fail over to the secondary channel if delivery fails
For constrained deployments, a common pattern is MQTT for continuous telemetry plus CoAP for low-overhead command delivery.
For the full set of security invariants, see AGENTS.md.
Everything Ori does is a skill. A skill is a packaged agent behaviour with explicit action authority declarations written in YAML.
# skills/energy-anomaly-detector/skill.yaml
triggers:
- name: anomalous_draw
condition: "load_current > (history.avg_24h('load_current') * 1.4)"
action_tier: A # → autonomous WhatsApp with reasoning
- name: grid_instability
condition: "grid_voltage < 180 and inverter_battery > 0.4"
action_tier: B
reasoning_policy: post_action # → switches source, explains after
- name: critical_fault
condition: "load_current > rated_capacity * 3.0"
action_tier: C # → "Open protected load safety circuit? Reply YES-<proposal_id>/NO-<proposal_id>"
- name: dangerous_overcurrent
condition: "load_current > rated_capacity * 5.0"
bypass_llm: true
action_tier: D # → cuts power. no waiting.Bundled skills: pc-system-health (runs on any laptop), energy-anomaly-detector, retail-occupancy-optimizer, solar-performance-monitor, battery-lifecycle-observer, hvac-refrigerant-monitor, and site-safety-ppe.
Community skills live at ori-platform/ori-skills. The runtime enforces strict skill validation and sandboxed hook loading for community-installed skills.
When Ori proposes a hard physical action, this is what the operator receives:
ORI ALERT — Action Required
Device: energy-monitor-ikeja-office-01
Proposal ID: AB12CD34
Time: Wednesday 14:32
OBSERVATION:
Load current has reached 38.4A — 3.8x the rated 10A capacity.
Sustained for 45 seconds and climbing.
REASONING:
Pattern consistent with a short circuit, not a temporary surge.
Active fault propagation detected.
PROPOSED ACTION:
Open the installer-wired safety circuit to cut power to the protected load.
CONFIDENCE: 94%
Reply YES-AB12CD34 to approve | Reply NO-AB12CD34 to cancel
Auto-cancel in 5 minutes if no response.
The message is delivered over SMS (primary for Nigeria deployments) with automatic failover to WhatsApp when SMS is unavailable, or WhatsApp-first when configured. The same message format is used on both channels.
The agent does the diagnosis. The operator approves or rejects a specific, fully-reasoned proposal.
Ori's pc-system-health skill runs on any laptop using psutil. No Raspberry Pi, no sensors, no wiring.
Linux users: See docs/linux-setup.md for a step-by-step Linux setup guide, including a minimal validated config (
ori.linux.yaml.example), Linux model paths, and troubleshooting for common Linux-specific issues.
# Clone and install
git clone https://github.com/ori-platform/ori-runtime.git
cd ori-runtime
python3 -m venv .venv
source .venv/bin/activate
# One-command dev bootstrap (deps + hooks + formatting baseline)
bash scripts/bootstrap.sh
# Verify everything works
pytest tests/ -v
# Validate a skill loads cleanly
python -c "
import asyncio
from ori.skills.loader import SkillLoader
skill = asyncio.run(SkillLoader().load_one('skills/pc-system-health'))
print(f'Loaded: {skill.name} v{skill.version}')
for t in skill.triggers:
print(f' Trigger: {t.name} tier={t.action_tier}')
"ori-runtime has two intentionally different install shapes:
# Product/demo consumers: typed rule-evaluation boundary only.
# This is what ori-energy FastAPI should use for /demo proof evaluation.
python -m pip install "ori-runtime[eval] @ git+https://github.com/ori-platform/ori-runtime.git@<commit-or-tag>"
# Runtime/device development: full transport, security, provider, and HAL deps.
python -m pip install -e ".[runtime,dev]"
# Edge deployment still uses the signed wheelhouse / hash-locked requirements path.
bash scripts/build-wheelhouse.shThe base package deliberately installs only the dependency needed by
ori.integration (PyYAML) plus the packaged bundled skills. MQTT, SMS,
WhatsApp, OPC-UA, HTTP adapters, crypto transports, and hardware/provider
libraries live behind extras or the deployment wheelhouse. This keeps
ori-energy and other product/demo consumers from inheriting the full device
runtime dependency surface while still using the real rule engine.
# 1) Activate your venv
source .venv/bin/activate
# 2) Install llama-cpp-python (CPU path; stable across laptops)
pip install --no-cache-dir llama-cpp-python
# 3) Download a local GGUF model
mkdir -p ~/models
curl -L https://huggingface.co/Qwen/Qwen2.5-0.5B-Instruct-GGUF/resolve/main/qwen2.5-0.5b-instruct-q4_k_m.gguf \
-o ~/models/qwen2.5-0.5b-instruct-q4_k_m.gguf
# 4) Point your config to the local model
# reasoning:
# default_tier: local
# local_model: qwen2.5-0.5b-instruct-q4_k_m
# model_path: /Users/<you>/models # macOS
# # model_path: /home/<you>/models # Linux
# offline_fallback: local_slm
# 5) Optional dev convenience: auto-load .env before config parse
export ORI_AUTOLOAD_DOTENV=true
# 6) Start runtime
python -m ori.runtime --config ori.local.yaml
# 7) Optional: hot-reload skills without restart (Unix only)
# Reload applies to new events only; in-flight actions keep previous skill config.
kill -HUP "$(pgrep -f 'python -m ori.runtime' | head -n 1)"# Full runtime smoke test (auto-selects config by platform if arg #1 is omitted)
bash scripts/smoke-runtime-local.sh
# Linux explicit config (recommended)
bash scripts/smoke-runtime-local.sh ori.yaml
# Force pretty console output
ORI_PRETTY_LOGS=true bash scripts/smoke-runtime-local.sh
# Disable ANSI colors (CI/plain terminals)
ORI_PRETTY_LOGS=false bash scripts/smoke-runtime-local.sh
# Live host-health report (real psutil readings + skill trigger evaluation)
ORI_PRETTY_LOGS=true .venv/bin/python scripts/pc_health_report.py
# Release wheel smoke test
# Builds the wheel, installs it into a clean venv, verifies PEP 561 typing,
# bundled skill packaging, and a real Tier D rule evaluation through
# ori.integration.
bash scripts/smoke-release-wheel.sh
# Local SLM quality smoke test (without starting full runtime)
python - <<'PY'
import asyncio
from ori.reasoning.local_llm import LocalLLM
async def main():
llm = LocalLLM(
model_path="/Users/<you>/models/qwen2.5-0.5b-instruct-q4_k_m.gguf", # macOS
# model_path="/home/<you>/models/qwen2.5-0.5b-instruct-q4_k_m.gguf", # Linux
context_window=2048,
)
result = await llm.reason("CPU at 96% for 10 minutes. Give 2 short operator actions.")
print(result.tier, result.model)
print(result.text)
asyncio.run(main())
PYTroubleshooting:
ori-runtime: command not found:- install entrypoint into the active venv:
python -m pip install -e . - or run directly:
python -m ori.runtime --config ori.local.yaml
- install entrypoint into the active venv:
- Config fails with
Environment variable not set: ${...}:- export required vars into shell or set
ORI_AUTOLOAD_DOTENV=truewith a valid.envfile
- export required vars into shell or set
Failed to create llama_contexton macOS:- reinstall
llama-cpp-pythonwithout Metal (CPU path), then retry
- reinstall
- VS Code uses wrong interpreter:
- select
${workspaceFolder}/.venv/bin/pythonviaPython: Select Interpreter
- select
pytest tests/ -v # Full suite
pytest tests/test_rule_engine.py -v # Specific module
pytest tests/ --cov=ori --cov-report=term-missing # With coverage
bash scripts/typecheck-boundaries.sh # Scoped mypy gate for public/runtime contracts
bash scripts/smoke-release-wheel.sh # Installed-wheel release readiness smokeThe test suite covers all layers — HAL adapters, event bus, rule engine (with AST safety validation), action dispatcher (all four tiers), skill loader, state store, and runtime.
Run scripts/smoke-release-wheel.sh before tagging a runtime release. It is
deliberately stricter than an editable install: it builds the wheel, verifies
the wheel metadata keeps the base install slim for ori-energy/demo consumers,
installs runtime dependencies from hash-locked requirements, installs the wheel
with --no-deps, then verifies the public ori.integration rule-evaluation
boundary is typed (ori/py.typed) and can resolve bundled skill data from the
installed artifact. This protects the ori-energy demo/API path from
type-checker ignores, accidental dependency bloat, and source-checkout-only
packaging mistakes.
See SECURITY.md for vulnerability reporting, supported versions, and disclosure policy.
| Phase | Status | Milestone |
|---|---|---|
| Core | ✅ Stable v1 | Core runtime with 6-layer architecture and 4-tier action framework |
| PoC | 🔨 In Progress | Energy skill deployed in Lagos. HVAC refrigerant monitor. Demo video. |
| Launch | 🔨 In Progress | Skills Hub. CLI tooling. Phone-as-gateway (Termux path live). |
| Growth | 🗓️ Planned | Rust HAL rewrite. 500+ skills. ori-cloud. Enterprise pilots. |
We welcome contributions! Start here:
- Read the design philosophy:
PRINCIPLES.md - Read the contributor guide:
CONTRIBUTING.md - Understand the extension points:
AGENTS.md
pip install -e ".[runtime,dev]"
pytest tests/ -vFirst PR suggestions: new psutil sensor types — testable on any laptop, no hardware required.
Apache 2.0. Forever free.
ori-cloud — the managed service — is how the project sustains itself.
Contributing · Architecture · Design Principles · Issues
Ori Nexus Systems LTD · Lagos, Nigeria · 2026
