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.1.tar.gz (5.6 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.1-py3-none-any.whl (5.6 MB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: arachnite-0.11.1.tar.gz
  • Upload date:
  • Size: 5.6 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.1.tar.gz
Algorithm Hash digest
SHA256 6abacbd454bd77fa8c30494fb359e432ff4f8f43c3575ce922541156e907ba0b
MD5 5015be17ae9b95969b688eb19a430ed9
BLAKE2b-256 48251e580f7bc2a69a34920fdaa316d43415f915394fbf3287724423e2cce711

See more details on using hashes here.

Provenance

The following attestation bundles were made for arachnite-0.11.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: arachnite-0.11.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4d7e64598518800f22927cef18ba06c0a47ded27eb7eb2df9d224a68c2f86357
MD5 7c4a4b3b507c610e86cf1227980c629c
BLAKE2b-256 f0a1df46879f629037a8fd6497c8481b7fb678ad110f398c57735e03e118be36

See more details on using hashes here.

Provenance

The following attestation bundles were made for arachnite-0.11.1-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