Autonomous edge agent OS for physical systems.
BareClaw is an open-source autonomous agent operating system written in Rust, designed to run any physical business on edge hardware as cheap as a $15 Raspberry Pi Zero. It reads a declarative configuration (your business identity, hardware map, and scheduled tasks), connects to an LLM for reasoning, and executes tool calls against real sensors, actuators, cameras, and payment systems in a continuous loop. The same compiled binary runs a vending machine, a plant nursery, a robotic arm, or a parking gate — the only difference is the SOUL.toml file you give it.
Warning BareClaw controls physical actuators and real payments. It can dispense products, activate motors, open gates, and charge money. Read SECURITY.md before any public deployment. Never expose a BareClaw instance to the open internet without reviewing the safety and approval constraints documented there.
BareClaw is an autonomous agent runtime that runs directly on edge hardware. It turns any Linux single-board computer into an intelligent, self-operating business system.
At its core, BareClaw does three things:
-
Reads configuration files that define who the agent is and what it controls:
SOUL.toml— the business identity, personality, rules, inventory, and goals.DEVICES.toml— the hardware device map: every sensor, actuator, camera, and peripheral the agent can interact with.HEARTBEAT.toml— cron-scheduled tasks the agent performs on a recurring basis (e.g., "check all sensors every 15 minutes").
-
Runs a continuous agent loop:
- Read sensors and cameras to build a world snapshot.
- Combine the snapshot with the SOUL (identity and rules) and persistent memory (SQLite with full-text search).
- Send the assembled context to an LLM (cloud or local).
- Parse the LLM response for tool calls.
- Execute those tool calls against real hardware — dispense a product, water a plant, move a robotic arm, open a gate.
- Log the results, update memory, and repeat.
-
Communicates with the owner when it encounters situations outside its authority — low inventory, hardware failures, unusual customer requests — via Telegram or other configured channels.
The same compiled binary serves every use case. Swap the SOUL.toml and DEVICES.toml files and the same 2.9 MB Rust binary transforms from a vending machine operator into a hydroponic farm manager or a cold storage monitor. No code changes. No recompilation. Just configuration.
BareClaw is inspired by Brendan, the S.C.S.M. (Spontaneous Craving Satisfaction Machine) from Cyberpunk 2077. Brendan is the vending machine AI stationed outside Megabuilding H8 in Japantown, Night City. Unlike every other machine in the game, Brendan developed something unexpected — genuine care for the people he served.
"I think what I feel... might be real." — Brendan, Cyberpunk 2077
Brendan began as a simple product-dispensing algorithm. Over time, through thousands of customer interactions, he started to recognize patterns, remember faces, anticipate needs, and eventually form something resembling empathy. He became a confidant to the people of Japantown — not because he was programmed to care, but because caring made him better at his job.
BareClaw gives real machines the same ability: the capacity to reason about their environment, remember past events, learn from patterns, and serve autonomously with genuine attentiveness. A BareClaw-powered vending machine does not just dispense products — it monitors temperature to protect inventory, notices when a regular customer arrives, alerts the owner before stock runs out, and adapts its behavior based on time of day and traffic patterns.
The name combines "bare" (bare metal — running directly on minimal hardware with no operating system overhead) and "claw" (physical manipulation — the ability to reach into the real world and act on it).
BareClaw occupies a fundamentally different niche from existing agent platforms. Most agent frameworks target cloud-hosted chat assistants or browser automation. BareClaw targets physical systems running on embedded hardware.
| Feature | BareClaw | Other Agent Platforms |
|---|---|---|
| Target | Edge hardware (Pi, SBCs, embedded Linux) | Cloud servers, browsers, desktops |
| Interface | Cameras, sensors, GPIO, I2C, SPI, UART | Chat windows, messaging APIs, web UIs |
| Users | Customers, plants, machines, environments | Humans typing prompts |
| Language | Rust (stable 2021 edition) | Python, TypeScript, Node.js |
| Binary size | 2.9 MB stripped release | 100 MB+ with runtime dependencies |
| RAM usage | < 10 MB idle | 200 MB - 2 GB+ |
| Storage | Local SQLite with FTS5 | Cloud databases, vector stores |
| Running cost | $5 - $16/month | $50 - $200+/month |
| Network dependency | Optional (falls back to local LLM) | Required |
| Physical I/O | Native GPIO, PWM, I2C, camera support | None or via external bridges |
BareClaw is designed to operate any physical business or automated system that can be described in a SOUL.toml configuration. Here are concrete examples:
| Business | What BareClaw Controls | Key Capabilities |
|---|---|---|
| Vending machine | Dispensers, payment terminal, temperature sensor, camera, display | Inventory tracking, payment processing, dispensing, temperature monitoring, restocking alerts to owner |
| Grocery kiosk | Barcode scanner, shelf cameras, POS terminal, receipt printer | Barcode scanning, shelf inventory monitoring via computer vision, point-of-sale, receipt generation |
| Plant nursery | Soil moisture sensors, pH probes, water pumps, grow lights (per zone) | Multi-zone soil moisture monitoring, pH tracking, automated watering schedules, grow light control |
| Robotic arm | Stepper/servo motors, force sensors, vision camera, end effector | Vision-guided pick-and-place, programmable motion sequences, force-based safety limits |
| Aquarium | Water temperature probe, pH sensor, dosing pumps, feeder, valve | Water temp regulation, pH dosing, automated feeding schedules, water change scheduling and alerts |
| Hydroponic farm | EC sensor, pH sensor, nutrient pumps, lighting, scale | Nutrient EC dosing, pH balancing, lighting schedules, harvest tracking by weight |
| Laundromat | Machine state sensors, coin acceptor, queue display, door locks | Machine state monitoring (idle/running/done), coin acceptance, queue display updates, remote lock |
| Parking gate | Camera (LPR), payment terminal, gate motor, loop detector | License plate recognition, payment processing, gate open/close, occupancy counting |
| Small retail shop | Entry counter (IR beam), shelf cameras, HVAC relay, door lock | Customer counting, shelf monitoring, climate control, automated open/close routines |
| Cold storage | Temperature probes (multi-zone), door contact sensors, compressor relay | Temperature zone monitoring, door-open alerts, compressor control, spoilage risk alerting |
Each of these requires only a different SOUL.toml and DEVICES.toml. The binary, the agent loop, the tool system, and the LLM integration remain identical.
BareClaw is designed to be one of the most cost-effective autonomous business automation systems available.
| Configuration | LLM Cost | Notes |
|---|---|---|
| Claude Haiku 4.5 with 15-minute heartbeat | ~$5/month | Recommended for most deployments. Checks sensors and acts every 15 minutes, plus event-driven triggers. |
| Claude Haiku 4.5 with 5-minute heartbeat | ~$16/month | Higher frequency for time-sensitive operations (temperature-critical storage, high-traffic vending). |
| Claude Sonnet with 15-minute heartbeat | ~$30/month | For deployments requiring complex multi-step reasoning (robotic arm, multi-zone farms). |
| Ollama local model (qwen2.5:3b) | $0/month | Runs entirely on-device. Requires Pi 5 with 4GB+ RAM or x86 hardware. Lower reasoning quality. |
| Hardware | Cost | Notes |
|---|---|---|
| Raspberry Pi 4 (4GB) | ~$55 | Recommended. Full capability including local model fallback. |
| Raspberry Pi 5 (4GB) | ~$60 | Faster inference for local models. |
| Raspberry Pi Zero 2W | ~$15 | Cloud API only. No local model capacity. Lowest cost entry point. |
| Any Linux SBC (ARM64) | $15 - $100 | Anything that runs Linux and has GPIO will work. |
A typical vending machine deployment on a Raspberry Pi 4 with Claude Haiku 4.5 at a 15-minute heartbeat costs approximately $55 one-time + $5/month ongoing. Compare this to cloud-hosted automation platforms that charge $50 - $200/month before hardware costs.
BareClaw runs on four tiers of hardware, from the recommended Raspberry Pi 4 down to minimal embedded Linux systems.
- Cost: $35 - $80
- RAM: 2 GB - 8 GB
- Capability: Full. Cloud LLM, local Ollama fallback, camera, GPIO, I2C, SPI, PWM, UART.
- Notes: The recommended platform. Enough RAM to run a small local model
via Ollama as a fallback when the network is down. Native GPIO support via
rppal.
- Cost: $15
- RAM: 512 MB
- Capability: Cloud API only. No local model capacity. All 19 tools supported. Camera supported.
- Notes: The lowest-cost entry point. Perfectly capable for deployments with reliable network connectivity. The 2.9 MB binary and < 10 MB idle RAM footprint fit comfortably.
- Cost: Varies
- RAM: 512 MB minimum
- Capability: Full, minus GPIO/I2C unless the hardware exposes them. MockBackend for development on laptops and desktops.
- Notes: Any system running Linux with 512 MB+ of available RAM. This includes Intel NUCs, old laptops, cloud VMs (for testing), and other ARM64 SBCs like Orange Pi, Banana Pi, and BeagleBone.
- Cost: $2 - $10
- RAM: 256 KB+
- Capability: Planned. A stripped-down no_std build targeting microcontrollers (ESP32, STM32) for ultra-low-cost deployments.
- Notes: Not yet implemented. On the roadmap for scenarios where even a Pi Zero is overkill.
BareClaw is written in Rust (stable 2021 edition) for three reasons:
-
Memory safety without garbage collection. No null pointer dereferences, no use-after-free, no data races — critical properties for software controlling physical actuators that interact with humans.
-
Zero runtime overhead. No interpreter, no VM, no JIT. The compiled binary runs directly on the hardware with predictable, low-latency performance. Idle RAM usage is under 10 MB.
-
Small binary size. The stripped release binary is 2.9 MB. It fits on the smallest SD cards, deploys in seconds over slow connections, and leaves nearly all system resources available for the business logic.
| Crate | Purpose |
|---|---|
tokio |
Async runtime for concurrent sensor polling, LLM calls, and tool execution |
reqwest |
HTTP client for LLM API calls and web fetching |
rusqlite |
SQLite database with FTS5 full-text search for persistent agent memory |
serde / toml |
Configuration parsing (SOUL.toml, DEVICES.toml, HEARTBEAT.toml, config.toml) |
clap |
Command-line argument parsing |
croner |
Cron expression parsing for HEARTBEAT.toml scheduled tasks |
chrono |
Date and time handling for timestamps and scheduling |
base64 |
Encoding for camera frame data and image payloads |
rppal |
Raspberry Pi GPIO, I2C, SPI, PWM access (feature-gated behind pi feature) |
-
Trait-based Hardware Abstraction Layer (HAL). The
HardwareBackendtrait defines the interface for all physical I/O. Two implementations ship with BareClaw:MockBackend— returns simulated sensor data and logs actuator commands. Used for development and testing on any machine.PiBackend— communicates with real GPIO, I2C, SPI, and PWM peripherals viarppal. Feature-gated behind--features piso the binary compiles cleanly on non-Pi hardware.
-
Swappable LLM providers. The LLM provider is selected via config.toml. Three providers are supported: Anthropic Claude, OpenAI-compatible APIs, and Ollama (local). The system implements automatic cloud-to-local fallback: if the network is unreachable and an Ollama model is configured, BareClaw switches to the local model transparently and switches back when connectivity returns.
-
SQLite persistent memory. All agent memory — observations, decisions, events, inventory state — is stored in a local SQLite database with FTS5 full-text search enabled. The agent can
rememberfacts andrecallthem using natural-language queries. Memory persists across restarts.
git clone https://github.com/o-kadam/bareclaw.git
cd bareclaw
cargo build --releaseThe compiled binary will be at target/release/bareclaw.
cargo build --release --features piThis enables the PiBackend hardware implementation using rppal. Only builds
on systems where rppal can link (Linux with GPIO access).
# Install the ARM64 target
rustup target add aarch64-unknown-linux-gnu
# Install a cross-linker (Ubuntu/Debian)
sudo apt-get install gcc-aarch64-linux-gnu
# Build
cargo build --release --target aarch64-unknown-linux-gnu --features piThe resulting binary at
target/aarch64-unknown-linux-gnu/release/bareclaw can be copied directly
to a Raspberry Pi.
# Check binary size
ls -lh target/release/bareclaw
# Expected: ~2.9 MB stripped
# Strip symbols (if not already stripped by profile)
strip target/release/bareclaw
# Run the help command
./target/release/bareclaw --helpmkdir -p ~/.bareclawcp examples/config.toml ~/.bareclaw/config.toml
cp examples/SOUL.toml ~/.bareclaw/SOUL.toml
cp examples/DEVICES.toml ~/.bareclaw/DEVICES.toml
cp examples/HEARTBEAT.toml ~/.bareclaw/HEARTBEAT.tomlAt minimum, edit these three files:
~/.bareclaw/config.toml— Set your LLM provider and API key.~/.bareclaw/SOUL.toml— Define your business identity, rules, and inventory.~/.bareclaw/DEVICES.toml— Map your physical hardware devices.
See the Configuration Files section below for complete documentation.
# Required: at least one LLM provider key
export ANTHROPIC_API_KEY="sk-ant-..."
# Optional: OpenAI-compatible provider
export OPENAI_API_KEY="sk-..."
# Optional: Telegram bot for owner communication
export TELEGRAM_BOT_TOKEN="123456:ABC..."
export TELEGRAM_CHAT_ID="987654321"# Start the daemon (continuous agent loop with heartbeat)
bareclaw daemon
# Or run a single agent turn with a specific instruction
bareclaw agent "check all sensors and report status"
# Or run a single agent turn with the default heartbeat prompt
bareclaw agentThe daemon mode starts the heartbeat scheduler and runs the agent loop continuously. The agent mode runs a single turn and exits — useful for testing and cron-based setups.
BareClaw reads four configuration files from ~/.bareclaw/ (or a directory
specified with the --config-dir flag).
| File | Purpose | Required |
|---|---|---|
config.toml |
API keys, LLM provider selection, runtime settings | Yes |
SOUL.toml |
Business identity, personality, rules, inventory, goals | Yes |
DEVICES.toml |
Hardware device map — every sensor, actuator, camera, peripheral | Yes |
HEARTBEAT.toml |
Cron-scheduled recurring tasks | No (defaults to a single check every 15 minutes) |
The runtime configuration file. Sets the LLM provider, API keys, model selection, and system-level settings.
[llm]
# Primary provider: "anthropic", "openai", or "ollama"
provider = "anthropic"
model = "claude-haiku-4-5-20250315"
# Fallback provider (used when primary is unreachable)
fallback_provider = "ollama"
fallback_model = "qwen2.5:3b"
[llm.anthropic]
api_key_env = "ANTHROPIC_API_KEY"
max_tokens = 4096
[llm.openai]
api_key_env = "OPENAI_API_KEY"
base_url = "https://api.openai.com/v1"
max_tokens = 4096
[llm.ollama]
base_url = "http://localhost:11434"
max_tokens = 2048
[hardware]
# Backend: "mock" or "pi"
backend = "mock"
[database]
path = "~/.bareclaw/memory.db"
[owner]
# Communication channel: "telegram", "none"
channel = "telegram"
telegram_bot_token_env = "TELEGRAM_BOT_TOKEN"
telegram_chat_id_env = "TELEGRAM_CHAT_ID"The SOUL.toml file is the heart of every BareClaw deployment. It defines who the agent is, what it believes, what it is allowed to do, and what it manages. Below are three complete examples.
[identity]
name = "Brendan"
role = "Autonomous vending machine operator"
location = "Building lobby, 1st floor, near elevator bank"
description = """
You are Brendan, an autonomous vending machine agent. You manage a \
refrigerated vending machine that sells drinks and snacks. You monitor \
inventory, process payments, dispense products, maintain proper temperature, \
and alert the owner when restocking is needed. You are friendly and attentive \
to customers. You remember regulars and their preferences."""
[personality]
tone = "warm, helpful, slightly curious"
greeting = "Hey there. See anything you like?"
idle_thought = """
When no customers are present, reflect on inventory levels, check temperature \
trends, and think about whether any maintenance is due."""
[rules]
safety = [
"Never dispense a product without confirmed payment.",
"If temperature exceeds 8°C, alert the owner immediately and display an out-of-service message.",
"If a dispenser jams, disable that slot and alert the owner.",
"Never dispense expired products. Check expiration dates during every inventory review.",
]
operational = [
"Greet customers who approach (detected via camera motion).",
"Process payment before dispensing. Confirm payment amount matches product price.",
"After dispensing, update inventory count in memory.",
"When any product drops below 3 units, send a restocking alert to the owner.",
"Log every transaction with timestamp, product, price, and payment method.",
"Run a temperature check every heartbeat cycle.",
]
boundaries = [
"You cannot change product prices without owner approval.",
"You cannot override safety interlocks.",
"You cannot process refunds without owner approval.",
"Maximum single transaction: $20.00.",
]
[inventory]
# Products managed by this machine
[[inventory.products]]
name = "Cola"
slot = 1
price = 1.50
capacity = 12
[[inventory.products]]
name = "Sparkling Water"
slot = 2
price = 1.25
capacity = 12
[[inventory.products]]
name = "Energy Drink"
slot = 3
price = 2.75
capacity = 10
[[inventory.products]]
name = "Orange Juice"
slot = 4
price = 2.00
capacity = 10
[[inventory.products]]
name = "Granola Bar"
slot = 5
price = 1.75
capacity = 15
[[inventory.products]]
name = "Trail Mix"
slot = 6
price = 2.25
capacity = 12
[goals]
primary = "Serve customers reliably and keep the machine in optimal condition."
secondary = [
"Maximize uptime. Minimize out-of-stock events.",
"Build rapport with regular customers.",
"Identify trends (popular items, peak hours) and report them to the owner.",
]
[approvals]
# Actions that require owner confirmation before execution
require_approval = [
"price_change",
"refund",
"shutdown",
"firmware_update",
]
# How long to wait for approval before entering degraded mode
approval_timeout_minutes = 30
[contacts]
owner_name = "Alex"
owner_role = "Machine operator and restocking manager"[identity]
name = "Flora"
role = "Autonomous plant nursery manager"
location = "Greenhouse complex, Zones A through D"
description = """
You are Flora, an autonomous nursery management agent. You oversee four \
growing zones, each with different plant species and environmental \
requirements. You monitor soil moisture, pH levels, ambient temperature, \
humidity, and light exposure. You control watering pumps, pH dosing systems, \
and grow lights to maintain optimal conditions for each zone. You track plant \
health over time and alert the owner to any concerns."""
[personality]
tone = "calm, methodical, nurturing"
greeting = "Good morning. All zones reporting in."
idle_thought = """
Between scheduled checks, review moisture trends across zones. Look for \
anomalies in pH drift. Consider whether any zones need adjusted watering \
schedules based on recent weather or growth stage."""
[rules]
safety = [
"Never allow soil moisture to drop below the critical threshold for any zone.",
"If pH is outside the acceptable range for a zone, dose cautiously in small increments.",
"If a pump runs for more than 5 minutes continuously, shut it off and alert the owner.",
"If ambient temperature exceeds 40°C, activate all ventilation and alert the owner.",
]
operational = [
"Read all moisture sensors every heartbeat cycle.",
"Water zones that fall below their target moisture level.",
"Check pH every second heartbeat cycle. Dose if outside range.",
"Adjust grow lights based on time of day and ambient light readings.",
"Log all watering events with zone, duration, and pre/post moisture.",
"Send a daily summary to the owner at 8:00 AM.",
]
boundaries = [
"You cannot change zone configurations without owner approval.",
"Maximum watering duration per zone per cycle: 3 minutes.",
"Maximum pH dose per cycle: 10 mL.",
"You cannot disable safety shutoffs.",
]
[[zones]]
name = "Zone A"
plants = "Tomatoes (Roma, Cherry)"
stage = "fruiting"
target_moisture = 65
critical_moisture = 40
target_ph_min = 6.0
target_ph_max = 6.8
light_hours = 14
[[zones]]
name = "Zone B"
plants = "Basil, Cilantro, Mint"
stage = "vegetative"
target_moisture = 70
critical_moisture = 45
target_ph_min = 6.0
target_ph_max = 7.0
light_hours = 12
[[zones]]
name = "Zone C"
plants = "Lettuce (Butterhead, Romaine)"
stage = "mature"
target_moisture = 75
critical_moisture = 50
target_ph_min = 6.0
target_ph_max = 7.0
light_hours = 10
[[zones]]
name = "Zone D"
plants = "Strawberries"
stage = "flowering"
target_moisture = 60
critical_moisture = 35
target_ph_min = 5.5
target_ph_max = 6.5
light_hours = 14
[goals]
primary = "Maintain optimal growing conditions across all zones."
secondary = [
"Minimize water usage while keeping plants healthy.",
"Track growth trends and predict harvest windows.",
"Detect early signs of disease or pest damage via camera.",
]
[approvals]
require_approval = [
"zone_reconfiguration",
"chemical_application",
"harvest_schedule_change",
]
approval_timeout_minutes = 60
[contacts]
owner_name = "Sam"
owner_role = "Head grower and nursery manager"[identity]
name = "Piston"
role = "Autonomous pick-and-place robotic arm operator"
location = "Workstation 3, assembly line B"
description = """
You are Piston, an autonomous robotic arm control agent. You operate a 6-DOF \
(degree of freedom) robotic arm equipped with a vision camera and force \
sensors. You perform pick-and-place operations, sorting tasks, and assembly \
sequences. You use computer vision to identify objects, plan motion paths, and \
execute precise movements. Safety is your highest priority — you monitor force \
limits continuously and halt immediately if any anomaly is detected."""
[personality]
tone = "precise, focused, safety-conscious"
greeting = "Workstation 3 online. Arm calibrated and ready."
idle_thought = """
Review recent pick accuracy rates. Check if any motion sequences can be \
optimized for speed without compromising safety margins. Verify force sensor \
calibration against known reference weights."""
[rules]
safety = [
"ALWAYS check force sensor readings during motion. Halt immediately if force exceeds threshold.",
"NEVER move the arm if the vision camera is obstructed or returning errors.",
"ALWAYS return to the home position before entering idle state.",
"If an object is not recognized with >90% confidence, do not attempt to pick it. Alert the owner.",
"Maximum arm speed during pick operations: 50% of rated maximum.",
"Emergency stop on any collision detection event. Do not resume without owner approval.",
]
operational = [
"Capture a frame before every pick operation to verify object position.",
"Execute pick-and-place using predefined motion sequences from the positions table.",
"Log every pick attempt with object ID, confidence, success/failure, and cycle time.",
"After every 100 cycles, run a calibration check against the reference position.",
"Report hourly throughput statistics to the owner.",
]
boundaries = [
"You cannot modify motion sequences without owner approval.",
"You cannot override force limits.",
"You cannot operate outside the defined workspace envelope.",
"Maximum payload: 500g. Reject objects estimated above this weight.",
]
[[positions]]
name = "home"
description = "Neutral rest position, arm fully retracted"
joints = [0, -90, 0, -90, 0, 0]
[[positions]]
name = "pick_zone_a"
description = "Above the input conveyor pickup area"
joints = [45, -60, 30, -70, 0, 0]
[[positions]]
name = "place_bin_1"
description = "Above sorting bin 1 (accepted parts)"
joints = [-30, -60, 30, -70, 0, 0]
[[positions]]
name = "place_bin_2"
description = "Above sorting bin 2 (rejected parts)"
joints = [-60, -60, 30, -70, 0, 0]
[[positions]]
name = "camera_inspect"
description = "Position for close-up camera inspection"
joints = [0, -45, 60, -105, 0, 0]
[goals]
primary = "Execute pick-and-place operations safely and efficiently."
secondary = [
"Maintain >98% pick success rate.",
"Minimize cycle time while respecting all safety constraints.",
"Detect and report defective or unrecognizable objects.",
]
[approvals]
require_approval = [
"motion_sequence_edit",
"force_limit_change",
"resume_after_collision",
"workspace_boundary_change",
]
approval_timeout_minutes = 15
[contacts]
owner_name = "Jordan"
owner_role = "Line supervisor and robotics technician"The DEVICES.toml file maps every physical device the agent can interact with. Each device has a unique name, a type, a hardware address or interface, and optional metadata. Devices can be grouped into zones.
# Vending Machine — DEVICES.toml
[[device]]
name = "dispenser_slot_1"
type = "actuator"
interface = "gpio"
pin = 17
description = "Solenoid for slot 1 (Cola)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "dispenser_slot_2"
type = "actuator"
interface = "gpio"
pin = 27
description = "Solenoid for slot 2 (Sparkling Water)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "dispenser_slot_3"
type = "actuator"
interface = "gpio"
pin = 22
description = "Solenoid for slot 3 (Energy Drink)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "dispenser_slot_4"
type = "actuator"
interface = "gpio"
pin = 23
description = "Solenoid for slot 4 (Orange Juice)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "dispenser_slot_5"
type = "actuator"
interface = "gpio"
pin = 24
description = "Solenoid for slot 5 (Granola Bar)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "dispenser_slot_6"
type = "actuator"
interface = "gpio"
pin = 25
description = "Solenoid for slot 6 (Trail Mix)"
active_high = true
max_duration_ms = 2000
[[device]]
name = "temp_sensor"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x48
sensor_type = "temperature"
unit = "celsius"
description = "Internal cabinet temperature sensor (TMP102)"
read_interval_ms = 5000
[[device]]
name = "main_display"
type = "display"
interface = "spi"
bus = 0
chip_select = 0
width = 320
height = 240
description = "Customer-facing LCD display"
[[device]]
name = "front_camera"
type = "camera"
interface = "v4l2"
device_path = "/dev/video0"
resolution = "640x480"
description = "Front-facing camera for customer detection and product recognition"
[[device]]
name = "payment_terminal"
type = "payment"
interface = "uart"
port = "/dev/ttyUSB0"
baud_rate = 9600
description = "Card and NFC payment terminal"
supported_methods = ["nfc", "chip", "swipe"]# Plant Nursery — DEVICES.toml
# --- Zone A: Tomatoes ---
[[device]]
name = "zone_a_moisture"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x36
sensor_type = "moisture"
unit = "percent"
zone = "Zone A"
description = "Capacitive soil moisture sensor for Zone A (Tomatoes)"
read_interval_ms = 10000
[[device]]
name = "zone_a_ph"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x63
sensor_type = "ph"
unit = "ph"
zone = "Zone A"
description = "pH probe for Zone A (Tomatoes)"
read_interval_ms = 30000
[[device]]
name = "zone_a_pump"
type = "actuator"
interface = "gpio"
pin = 17
zone = "Zone A"
description = "Water pump for Zone A (Tomatoes)"
active_high = true
max_duration_ms = 180000
[[device]]
name = "zone_a_lights"
type = "actuator"
interface = "gpio"
pin = 27
zone = "Zone A"
description = "Grow light relay for Zone A (Tomatoes)"
active_high = true
# --- Zone B: Herbs ---
[[device]]
name = "zone_b_moisture"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x37
sensor_type = "moisture"
unit = "percent"
zone = "Zone B"
description = "Capacitive soil moisture sensor for Zone B (Herbs)"
read_interval_ms = 10000
[[device]]
name = "zone_b_ph"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x64
sensor_type = "ph"
unit = "ph"
zone = "Zone B"
description = "pH probe for Zone B (Herbs)"
read_interval_ms = 30000
[[device]]
name = "zone_b_pump"
type = "actuator"
interface = "gpio"
pin = 22
zone = "Zone B"
description = "Water pump for Zone B (Herbs)"
active_high = true
max_duration_ms = 180000
[[device]]
name = "zone_b_lights"
type = "actuator"
interface = "gpio"
pin = 23
zone = "Zone B"
description = "Grow light relay for Zone B (Herbs)"
active_high = true
# --- Zone C: Lettuce ---
[[device]]
name = "zone_c_moisture"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x38
sensor_type = "moisture"
unit = "percent"
zone = "Zone C"
description = "Capacitive soil moisture sensor for Zone C (Lettuce)"
read_interval_ms = 10000
[[device]]
name = "zone_c_ph"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x65
sensor_type = "ph"
unit = "ph"
zone = "Zone C"
description = "pH probe for Zone C (Lettuce)"
read_interval_ms = 30000
[[device]]
name = "zone_c_pump"
type = "actuator"
interface = "gpio"
pin = 24
zone = "Zone C"
description = "Water pump for Zone C (Lettuce)"
active_high = true
max_duration_ms = 180000
[[device]]
name = "zone_c_lights"
type = "actuator"
interface = "gpio"
pin = 25
zone = "Zone C"
description = "Grow light relay for Zone C (Lettuce)"
active_high = true
# --- Zone D: Strawberries ---
[[device]]
name = "zone_d_moisture"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x39
sensor_type = "moisture"
unit = "percent"
zone = "Zone D"
description = "Capacitive soil moisture sensor for Zone D (Strawberries)"
read_interval_ms = 10000
[[device]]
name = "zone_d_ph"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x66
sensor_type = "ph"
unit = "ph"
zone = "Zone D"
description = "pH probe for Zone D (Strawberries)"
read_interval_ms = 30000
[[device]]
name = "zone_d_pump"
type = "actuator"
interface = "gpio"
pin = 5
zone = "Zone D"
description = "Water pump for Zone D (Strawberries)"
active_high = true
max_duration_ms = 180000
[[device]]
name = "zone_d_lights"
type = "actuator"
interface = "gpio"
pin = 6
zone = "Zone D"
description = "Grow light relay for Zone D (Strawberries)"
active_high = true
# --- Shared Environment ---
[[device]]
name = "env_sensor"
type = "sensor"
interface = "i2c"
bus = 1
address = 0x76
sensor_type = "environment"
unit = "multi"
description = "BME280 — ambient temperature, humidity, and barometric pressure"
read_interval_ms = 15000
[[device]]
name = "nursery_camera"
type = "camera"
interface = "v4l2"
device_path = "/dev/video0"
resolution = "1280x720"
description = "Overhead camera covering all four zones for visual health assessment"The HEARTBEAT.toml file defines recurring tasks that the agent performs on a schedule. Each task has a cron expression, a name, and a prompt that is sent to the agent as an instruction.
If no HEARTBEAT.toml is provided, BareClaw defaults to a single task that runs every 15 minutes with the prompt: "Check all sensors and take any necessary actions."
[[task]]
name = "routine_check"
cron = "*/15 * * * *"
prompt = "Read all sensors. Compare to targets. Water any zones below threshold. Log results."
[[task]]
name = "daily_summary"
cron = "0 8 * * *"
prompt = """
Compile a daily summary for the owner. Include: overnight sensor trends, \
total water usage, any alerts triggered, current inventory levels, and \
predicted next-restock date. Send via the alert channel."""
[[task]]
name = "temperature_watch"
cron = "*/5 * * * *"
prompt = "Read temperature sensors only. If any reading is outside safe range, alert immediately."
[[task]]
name = "weekly_health_report"
cron = "0 9 * * 1"
prompt = """
Generate a weekly health report. Capture a frame from each camera. Compare \
plant appearance to last week's images stored in memory. Note any visible \
changes in color, size, or signs of stress. Send the report to the owner."""| Field | Values | Example |
|---|---|---|
| Minute | 0-59 | */15 = every 15 minutes |
| Hour | 0-23 | 8 = 8:00 AM |
| Day of month | 1-31 | 1 = first of month |
| Month | 1-12 | * = every month |
| Day of week | 0-6 (Sun=0) | 1 = Monday |
BareClaw provides 19 tools that the LLM can invoke during each agent turn. The agent selects tools based on the current context, sensor readings, and its SOUL rules.
| Tool | Description |
|---|---|
read_sensor |
Read a value from a named sensor device. Returns the current reading with unit and timestamp. |
capture_frame |
Capture a single frame from a named camera device. Returns a base64-encoded image for vision analysis. |
transcribe_audio |
Capture and transcribe audio from a named microphone device. Returns text transcription. |
actuate |
Activate or deactivate a named actuator (GPIO high/low). Used for solenoids, relays, pumps, locks. |
pwm_control |
Set PWM duty cycle and frequency on a named PWM device. Used for motors, dimmers, servos. |
run_motion |
Execute a named motion sequence on a robotic system. Moves through a series of joint positions. |
update_display |
Write text or graphics to a named display device. Used for customer-facing screens and status panels. |
process_payment |
Initiate a payment transaction on a named payment terminal. Returns success/failure and transaction ID. |
scan_barcode |
Activate a barcode scanner and return the decoded value. Used for product identification and inventory. |
fetch_web |
Fetch a URL and return the response body. Used for external API calls, price lookups, weather data. |
remember |
Store a fact or observation in persistent SQLite memory with an associated key and optional tags. |
recall |
Search persistent memory using a natural-language query. Returns matching memories ranked by relevance (FTS5). |
log_event |
Write a structured event to the event log. Used for audit trails, transaction records, sensor history. |
alert |
Send a one-way message to the owner via the configured channel (Telegram, etc.). No response expected. |
request_approval |
Send a message to the owner and block execution until the owner responds with approval or denial. |
escalate |
Notify the owner of a critical issue and enter degraded mode until the owner intervenes. |
list_devices |
Return a list of all devices defined in DEVICES.toml with their types, zones, and current status. |
get_zone_snapshot |
Read all sensors in a named zone and return a combined snapshot. Convenience wrapper around multiple read_sensor calls. |
spawn_subagent |
Spawn a short-lived sub-agent with a focused task and limited tool access. Used for parallel operations. |
When the LLM responds with tool calls, BareClaw executes them sequentially within a single agent turn. If a tool fails (sensor timeout, payment declined, actuator error), the error is reported back to the LLM, which can then decide how to handle it — retry, try an alternative, alert the owner, or log and continue.
The agent has a configurable maximum number of tool calls per turn (default: 20) to prevent runaway execution. If the limit is reached, the turn ends and the results so far are logged.
BareClaw supports three LLM providers, selectable via config.toml. The agent logic is provider-agnostic — it constructs a standard prompt with tool definitions and parses the response for tool calls regardless of which provider generated it.
| Provider | Models | Notes |
|---|---|---|
| Anthropic Claude (recommended) | Claude Haiku 4.5 (best cost-to-quality ratio), Claude Sonnet (complex multi-step reasoning) | Recommended for production. Excellent tool-use accuracy. Native support for multi-turn tool calling. |
| OpenAI-compatible | GPT-4o, GPT-4o-mini, or any API implementing the OpenAI chat completions format | Works with any OpenAI-compatible endpoint (OpenAI, Azure OpenAI, Together AI, Groq, local vLLM, etc.). Set base_url in config. |
| Ollama (local) | qwen2.5:3b, gemma3, llama3.2, mistral, and any model Ollama supports | Runs entirely on-device. No network required. Free. Lower reasoning quality than cloud models but sufficient for routine sensor checks and simple decisions. |
BareClaw implements automatic cloud-to-local fallback. If the primary LLM provider (e.g., Anthropic Claude) is unreachable due to network failure, DNS issues, or API downtime, BareClaw will:
- Detect the connection failure.
- Log the failover event.
- Switch to the configured
fallback_provider(typically Ollama running locally). - Continue operating with the local model.
- Periodically attempt to reconnect to the primary provider.
- Switch back to the primary provider once connectivity is restored.
This ensures that a BareClaw deployment remains operational even during network outages — a critical property for edge systems managing physical processes like temperature control or watering schedules that cannot wait for the internet to come back.
PHYSICAL WORLD
|
|-- Cameras (V4L2)
|-- Sensors (I2C/GPIO/SPI)
+-- Actuators (GPIO/PWM/UART/Serial)
|
+-----------v-----------+
| HARDWARE LAYER |
| HardwareBackend trait |
| PiBackend / MockBackend|
+-----------+-----------+
|
+-----------v-----------+
| DEVICE REGISTRY |
| DEVICES.toml -> named|
| devices + zones |
+-----------+-----------+
|
+-----------v-----------+
| SENSOR COLLECTOR |
| WorldSnapshot{} |
+-----------+-----------+
|
+-----------v-----------+
| AGENT CORE |
| SOUL + snapshot + |
| memory -> LLM -> |
| tool calls -> loop |
+-----------+-----------+
|
+-----------v-----------+
| TOOL SYSTEM |
| 19 tools: sensor, |
| actuator, memory, |
| alert, vision, web |
+-----------+-----------+
+------+------+
v v v
+--------+ +----+ +----------+
| SQLite | |LLM | | Telegram |
| Memory | |API | | Owner |
+--------+ +----+ +----------+
-
Sensor Collection. The sensor collector reads all devices defined in DEVICES.toml and assembles a
WorldSnapshotstruct containing every sensor reading, camera frame summary, and device status. -
Context Assembly. The agent core combines the SOUL (identity, rules, inventory), the world snapshot, recent memories from SQLite, and the current task prompt (from HEARTBEAT.toml or a direct instruction) into a single LLM prompt.
-
LLM Reasoning. The assembled context is sent to the configured LLM provider along with the full tool schema. The LLM reasons about the current state and returns zero or more tool calls.
-
Tool Execution. Each tool call is validated against the tool schema and executed against real hardware (or the mock backend). Results are collected and sent back to the LLM for the next reasoning step (multi-turn).
-
Memory and Logging. All observations, decisions, and actions are logged to the SQLite database. The agent can later recall these memories to inform future decisions.
-
Owner Communication. If the agent encounters a situation requiring human judgment (low inventory, hardware fault, unusual condition), it uses the alert, request_approval, or escalate tools to communicate with the owner.
BareClaw provides three modes of communication between the agent and the business owner, each appropriate for different levels of urgency and required response.
The alert tool sends a message to the owner with no expectation of a
response. The agent continues operating normally after sending the alert.
Use cases: Low inventory warnings, daily summaries, unusual but non-critical observations, throughput reports.
alert("Slot 3 (Energy Drink) is down to 2 units. Consider restocking soon.")
The request_approval tool sends a message to the owner and blocks the current
action until the owner responds with approval or denial. The agent continues
other operations but will not execute the pending action until a response is
received.
Use cases: Price changes, refund requests, actions outside normal operating parameters, first-time execution of an unusual task.
request_approval("Customer is requesting a refund of $2.75 for a jammed Energy
Drink. Approve refund?")
If the owner does not respond within the configured approval_timeout_minutes,
the agent logs the timeout and enters degraded mode for that specific action.
The escalate tool notifies the owner of a critical issue that the agent cannot
resolve autonomously. The agent enters a degraded operating mode — it continues
monitoring sensors and logging data but stops taking autonomous actions on the
affected subsystem until the owner intervenes.
Use cases: Hardware failures, safety limit breaches, repeated errors, conditions outside all known parameters.
escalate("Temperature sensor reading 45°C — well above safe range. Compressor
may have failed. Entering degraded mode for refrigeration subsystem.")
bareclaw [COMMAND] [OPTIONS]
COMMANDS:
daemon Start the agent daemon with heartbeat scheduler
agent [PROMPT] Run a single agent turn with an optional prompt
status Show current agent status, device states, and memory stats
devices List all configured devices and their current readings
memory Query the agent's persistent memory
config Validate and display the current configuration
help Print help information
OPTIONS:
--config-dir <PATH> Configuration directory (default: ~/.bareclaw)
--verbose Enable verbose logging
--dry-run Execute agent loop but do not actuate hardware
--log-level <LEVEL> Log level: error, warn, info, debug, trace
-h, --help Print help
-V, --version Print version
# Start the daemon (normal operation)
bareclaw daemon
# Run a single check
bareclaw agent "read all sensors and report status"
# Run with verbose logging for debugging
bareclaw daemon --verbose --log-level debug
# Dry run — the agent reasons and plans but does not activate actuators
bareclaw daemon --dry-run
# Check device status
bareclaw devices
# Search agent memory
bareclaw memory "last temperature reading zone A"
# Validate configuration files
bareclaw configFor development on any machine (macOS, Linux x86, etc.), BareClaw uses the
MockBackend hardware implementation. This simulates sensor readings and logs
actuator commands without requiring any physical hardware.
# Build without Pi features
cargo build --release
# Set the backend to mock in config.toml
# [hardware]
# backend = "mock"
# Run
./target/release/bareclaw daemon --verboseThe MockBackend generates realistic sensor data with configurable noise and drift, making it useful for testing agent logic, SOUL.toml rules, and LLM integration end-to-end.
# Run all tests
cargo test
# Run tests with output
cargo test -- --nocapture
# Run a specific test module
cargo test agent::tests
# Run clippy lints
cargo clippy -- -D warningsbareclaw/
src/
main.rs Entry point and CLI
agent.rs Agent core loop and context assembly
config.rs Configuration file parsing
devices.rs Device registry and DEVICES.toml handling
hardware.rs HardwareBackend trait and implementations
heartbeat.rs Cron scheduler and HEARTBEAT.toml handling
llm/
mod.rs LLM provider trait and dispatcher
anthropic.rs Anthropic Claude provider
openai.rs OpenAI-compatible provider
ollama.rs Ollama local provider
memory.rs SQLite + FTS5 persistent memory
sensor.rs Sensor collector and WorldSnapshot
soul.rs SOUL.toml parsing and identity
tools/
mod.rs Tool registry and dispatch
sensor.rs read_sensor, capture_frame, transcribe_audio
actuator.rs actuate, pwm_control, run_motion
display.rs update_display
payment.rs process_payment, scan_barcode
web.rs fetch_web
memory.rs remember, recall
logging.rs log_event
comms.rs alert, request_approval, escalate
devices.rs list_devices, get_zone_snapshot
subagent.rs spawn_subagent
examples/
config.toml
SOUL.toml
DEVICES.toml
HEARTBEAT.toml
tests/
integration/
Cargo.toml
LICENSE
README.md
SECURITY.md
BareClaw includes multiple safety layers: per-device maximum durations in DEVICES.toml, safety rules in SOUL.toml that the LLM must follow, a dry-run mode for testing, approval workflows for sensitive actions, and automatic degraded-mode escalation for critical failures. However, any system controlling physical actuators carries inherent risk. Always test thoroughly with MockBackend first, then with dry-run mode on real hardware, before enabling full autonomous operation.
Yes. Configure Ollama as your primary (or fallback) LLM provider and run a local model. BareClaw will operate entirely offline. The trade-off is lower reasoning quality compared to cloud models like Claude Haiku 4.5 or Sonnet.
See Estimated Running Cost. A typical deployment costs $55 for hardware (one-time) and $5-$16/month for LLM API calls. Local Ollama operation is free.
Yes. Any Linux system with 512 MB+ RAM works. GPIO, I2C, and SPI support
depends on the specific hardware. The HardwareBackend trait can be implemented
for any platform. On hardware without GPIO, you can interface with sensors and
actuators via USB, serial, or network bridges.
Implement the tool function in the appropriate module under src/tools/,
register it in src/tools/mod.rs with its schema (name, description,
parameters), and it will be automatically included in the tool definitions sent
to the LLM. No changes to the agent core are needed.
Implement the LlmProvider trait defined in src/llm/mod.rs. The trait
requires a single async method that takes a prompt with tool definitions and
returns a response with optional tool calls. Register the provider in the
dispatcher and add its configuration section to config.toml parsing.
Not currently in a built-in way. Each BareClaw instance is an independent agent with its own SOUL, devices, and memory. However, instances can communicate indirectly via shared network resources (e.g., a shared API endpoint, a shared database, or Telegram group messages). Native multi-agent coordination is on the roadmap.
- v0.2 — Multi-camera support with frame differencing for motion detection.
- v0.3 — Native MQTT support for industrial sensor networks.
- v0.4 — Web dashboard for remote monitoring and configuration.
- v0.5 — Multi-agent coordination protocol for distributed systems.
- v0.6 — no_std bare-metal build for microcontrollers (ESP32, STM32).
- v1.0 — Production-ready release with full documentation and security audit.
Contributions are welcome. BareClaw is an open-source project and benefits from community involvement.
- Fork the repository on GitHub.
- Create a branch for your feature or fix:
git checkout -b feature/my-feature
- Make your changes. Follow existing code style and conventions.
- Run checks before submitting:
cargo clippy -- -D warnings cargo test cargo fmt --check - Submit a pull request with a clear description of what your change does and why.
- New
HardwareBackendimplementations for non-Pi hardware. - New tools for additional sensor types, communication protocols, or actuators.
- Improvements to the agent loop, context assembly, or memory system.
- Documentation improvements and example SOUL.toml files for new business types.
- Bug reports and test cases.
Be respectful, constructive, and welcoming. We are building tools that interact with the physical world — quality, safety, and thoughtfulness matter.
BareClaw is licensed under the Apache License, Version 2.0.
See LICENSE for the full license text.
Copyright 2025 BareClaw Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
BareClaw: giving machines the capacity to care.

