Skip to main content

A biologically-inspired reactive agent framework for Python

Project description

Arachnite

A biologically-inspired reactive agent framework for Python.

The architecture models the nervous system of arachnids — sense → context → reflex → instinct → decide → act. Developers extend abstract base classes to build agents that run on edge devices (Raspberry Pi, Jetson Nano), laptops, or cloud servers, all connected by a pluggable transport layer.

  • Async-first: every node interface is asyncio-native
  • Typed: strict type annotations throughout (mypy strict)
  • Pluggable transports: in-process, MQTT, NATS, Redis
  • Distributed by manifest: declarative multi-device deployment
  • Reflex co-location: safety-critical reflexes are validated at deploy time
  • Python 3.10+

Install

pip install arachnite

With optional extras:

pip install "arachnite[all]"            # every optional dependency
pip install "arachnite[mqtt]"           # MQTT transport
pip install "arachnite[nats]"           # NATS transport
pip install "arachnite[redis]"          # Redis transport
pip install "arachnite[web]"            # bundled signal dashboard
pip install "arachnite[llm]"            # Anthropic LLM provider
pip install "arachnite[benchmarks]"     # psutil for RSS measurement

Development install from source:

git clone https://github.com/memrecolak/arachnite-oss.git arachnite
cd arachnite
pip install -e ".[all,dev]"

Quick start

A minimal agent: a sensor that reads temperature, an instinct that fires when it gets hot, and an action that cools things down.

import asyncio
import time

from arachnite import (
    BaseActionNode,
    BaseInstinctNode,
    BaseSenseNode,
    Proposal,
    Result,
    RuntimeBuilder,
    Signal,
)


class TempSense(BaseSenseNode):
    node_id = "TempSense"
    signal_kind = "temperature"

    async def read(self) -> Signal:
        return Signal(
            source=self.node_id,
            kind=self.signal_kind,
            value=42.0,
            confidence=1.0,
            timestamp=time.monotonic(),
        )


class HotInstinct(BaseInstinctNode):
    node_id = "HotInstinct"
    priority = 80

    async def evaluate(self, ctx) -> Proposal | None:
        hot = [s for s in ctx.signals if s.kind == "temperature" and s.value > 40.0]
        if hot:
            return Proposal(
                instinct_id=self.node_id,
                action_id="CoolDown",
                priority=self.priority,
                urgency=0.9,
            )
        return None


class CoolDown(BaseActionNode):
    node_id = "CoolDown"

    async def execute(self, proposal) -> Result:
        print(f"Cooling down! params={proposal.parameters}")
        return Result(action_id=self.node_id, success=True)


async def main() -> None:
    rt = (
        RuntimeBuilder()
        .sense(TempSense)
        .instinct(HotInstinct)
        .action(CoolDown)
        .tick_rate(5.0)
        .build()
    )
    await rt.start()
    await asyncio.sleep(5.0)
    await rt.stop()


asyncio.run(main())

See the examples/ directory for more complete programs: reflex nodes, multi-step actions, supervisor restart policies, and a web dashboard.

Documentation

  • tutorials/ — step-by-step lessons starting at tutorials/01_welcome.md. Advanced topics (multi-step actions, supervisors, distributed deployment, LLM instincts, active inference, safety monitors) live under tutorials/advanced/.
  • spec/ — the formal framework specification, eight numbered sections covering architecture, nodes, runtime, distributed deployment, infrastructure, and the benchmark suite.

Core concepts

Nodes

Five node families, each with an abstract base and a master that owns the registered instances:

Node Returns When to use
BaseSenseNode Signal Read hardware/state, emit one signal per tick
BaseInstinctNode Proposal or None Evaluate context, propose an action
BaseReflexInstinctNode Proposal or None Same as instinct, but bypasses the decision layer (priority ≥ 200, co-located with target action)
BaseDecisionNode Decision Pick which proposal to execute (Greedy / Weighted / Random / ActiveInference built-ins, or your own)
BaseActionNode Result Carry out the work — must always return, never raise
MultiStepActionNode Result Long-running actions with interrupt/rollback policies

Priority convention

  • 200+ — reflex instincts only
  • 100–199 — safety / survival
  • 50–99 — goal-directed
  • 1–49 — exploratory / maintenance
  • 0 — reserved (inactive)

Architectural rules

  1. Nodes never hold references to each other; communication goes through SignalBus.
  2. ReflexInstinctNode and its target ActionNode must be on the same AgentNode.
  3. MultiStepActionNode mandatory blocks cannot be interrupted (except emergency_stop).
  4. execute() on any ActionNode must always return a Result — never raise.
  5. evaluate() on any InstinctNode must return None when not applicable — never raise.
  6. All node I/O must be async — wrap blocking hardware calls in asyncio.to_thread().

Distributed deployments

A DeploymentManifest declares which nodes run on which AgentNode. The manifest validator enforces co-location rules and fails loudly on missing environment variables.

agents:
  vision:
    transport: nats
    transport_url: ${NATS_URL}
    nodes:
      - ProximitySense
      - ObjectDetectionSense
  control:
    transport: nats
    transport_url: ${NATS_URL}
    nodes:
      - JointPositionSense
      - CollisionReflex     # priority 250, reflex
      - EmergencyRetract    # co-located target
      - GraspInstinct
      - PickAndPlace

See examples/robot_arm/ for a runnable two-agent case study.

Benchmarks

A reproducible benchmark suite ships under benchmarks/:

# Full suite (30 runs, JSON output)
python benchmarks/suite.py

# Quick run (5 runs)
python benchmarks/suite.py --runs 5

# Individual benchmarks
python benchmarks/tick_latency.py
python benchmarks/reflex_latency.py
python benchmarks/scalability_sweep.py
python benchmarks/transport_latency.py

Benchmarks include tick latency, per-stage breakdown, reflex arc timing, memory footprint, scalability sweeps, multi-step action interrupt latency, long-horizon stability soak, and transport publish-to-deliver latency. All emit JSON with bootstrap CIs for median / P95 / P99.

Cross-framework comparison (optional)

baselines/ holds comparison harnesses against py_trees, ROS 2, and the Jason AgentSpeak BDI engine. These are not part of the framework — they are not installed by pip install arachnite and are excluded from the wheel. They require external toolchains (JVM, ROS 2) to run. See baselines/README.md for setup.

Development

# Run all tests
pytest

# With coverage
pytest --cov=arachnite --cov-report=term-missing

# Type check
mypy arachnite

# Lint
ruff check arachnite tests benchmarks

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arachnite-0.11.4.tar.gz (6.7 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arachnite-0.11.4-py3-none-any.whl (5.6 MB view details)

Uploaded Python 3

File details

Details for the file arachnite-0.11.4.tar.gz.

File metadata

  • Download URL: arachnite-0.11.4.tar.gz
  • Upload date:
  • Size: 6.7 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arachnite-0.11.4.tar.gz
Algorithm Hash digest
SHA256 f792bac5c155048d3a6c89a98d40934f6f0ed86e4beec67b0e647a5b35914005
MD5 978620c430774a85fefabc01b37d9a31
BLAKE2b-256 5b161c7d7001c53e2874e0eb3c4d07f38855f3549001db56272367c8646f01f9

See more details on using hashes here.

Provenance

The following attestation bundles were made for arachnite-0.11.4.tar.gz:

Publisher: publish.yml on memrecolak/arachnite-oss

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file arachnite-0.11.4-py3-none-any.whl.

File metadata

  • Download URL: arachnite-0.11.4-py3-none-any.whl
  • Upload date:
  • Size: 5.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arachnite-0.11.4-py3-none-any.whl
Algorithm Hash digest
SHA256 7b2683be11a4661fe746ca3abea088f4615a7f08b9239b9eae3896bec2ab8b5e
MD5 7cbcec1d681e673fd0f50d4970f1488b
BLAKE2b-256 f74c9b5664f52d60c812b1494751a0b25e6c9ec5492d69608b97a8ddac11cf09

See more details on using hashes here.

Provenance

The following attestation bundles were made for arachnite-0.11.4-py3-none-any.whl:

Publisher: publish.yml on memrecolak/arachnite-oss

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page