Artificial Brains SDK
Build artificial brains, connect them to the synthetic neurons on Prima-Lux or ABi, explore biomimetic intelligence, create applications that let robots and other machines sense, decide, and act as they experience the world.
The SDK provides a common interface for designing an Artificial Brain, preparing it on Prima-Lux, publishing live sensory information, receiving neural outputs, decoding commands, and running a robot's sensor–actuator loop. Your application owns its sensors, actuators, safety limits, and environment.
Quick start
Python 3.10 or later is required. Install the SDK supplied for your environment:
python -m pip install artificialbrains_sdk
ab --help
Import its Python API with from ab import .... You can use the CLI as ab or python -m ab.
A typical project looks like this:
my-robot/
├── .env
├── brain.py # optional Python source for the Brain
├── brain.abdesign.json # saved Brain design used by the application
└── run.py # your sensor and actuator application
The usual workflow is:
- Design or edit an Artificial Brain using Python or Canvas.
- Build it on the synthetic neurons on Prima-Lux or ABi and wait for READY.
- Run your Python application, which sends sensory observations and handles neural outputs.
- Stop the application and wait for Prima-Lux to finish saving neural state.
1. Create your first Artificial Brain
Create brain.py:
from ab import Brain
brain = Brain("First Brain")
# Named external input populations
brain.input("SENSE", 64)
# OPUs: rhythm and, where applicable, TNorm
brain.opu("SENSE_RELAY", "high-gamma")
brain.opu("T1", "theta", 3)
brain.opu("T2", "theta", 2.01)
brain.opu("MOTOR", "beta", 5)
# Named output populations
brain.output("ACTION") # One output neuron by default
brain.output("STATE", 4) # Four output neurons
brain.connect("SENSE", "SENSE_RELAY")
brain.connect("SENSE_RELAY", "T1")
brain.connect("T1", "T2")
brain.connect("T2", "MOTOR")
brain.connect("MOTOR", "ACTION")
brain.connect("MOTOR", "STATE")
brain.save("brain.abdesign.json")
Run it once to save the design:
python brain.py
Brain API
| Python method | What it does |
|---|---|
Brain("Name") |
Creates a named Artificial Brain design. |
brain.input("NAME", n) |
Declares an external input population with n neurons. |
brain.opu("NAME", "theta", 2.01) |
Adds an OPU with a rhythm and TNorm. |
brain.opu("RELAY", "high-gamma") |
Adds an input-adjacent high-gamma relay, without TNorm. |
brain.output("NAME") |
Adds a named, one-neuron output. |
brain.output("NAME", 4) |
Adds a named output with four neurons. |
brain.connect("A", "B") |
Connects A to B (excitatory by default). |
brain.connect("A", "B", "inh") |
Adds an inhibitory connection. |
brain.save("brain.abdesign.json") |
Saves the editable Brain design. |
Brain.load("brain.abdesign.json") |
Opens a saved design from Python. |
brain.validate() |
Returns design warnings you can review. |
brain.render() |
Opens the visual Brain editor. |
OPUs can use high-gamma, gamma, beta, alpha, theta, or delta. Rhythmic OPUs take a TNorm from 0 to 10; decimal values such as 2.01 are valid. High-gamma is a fast relay immediately after an external input and does not take a TNorm. All connections are excitatory unless you explicitly choose inhibition. Output neurons hold their state until the Brain clears them.
Choose input population widths to match the sensory encoding that your application will publish. Choose output widths to match the way your application will decode the result.
Build visually with Canvas or Python
From your project folder:
ab design --brain brain.abdesign.json
The Designer has two views of the same Brain: Canvas for arranging OPUs and connections and Python for editing code. Changes can be made in either view. Save the Brain to retain your work.
Its Build brain, Run brain, and Stop brain controls operate the connected Prima-Lux device. Running the Brain in the Designer starts its neural activity; it does not launch a robot application or automatically connect sensors and motors. Use ab run to launch your application.
2. Connect to Prima-Lux
Complete the initial Prima-Lux or ABi onboarding, obtain your developer API key, and connect your computer to the device. Create a .env file in your project:
AB_DEVICE_URL=http://prima-lux.local:8080/
AB_DEVICE_API_KEY=YOUR_DEVICE_API_KEY
The URL is an example; use your device's actual address. Keep your .env private and out of version control. Prima-Lux also needs Internet access when preparing a new Brain.
To inspect the device:
ab device --env .env status
ab device --env .env events
3. Build the Brain
From the project directory:
ab build brain --brain brain.abdesign.json --env .env
You may also build directly from a Python Artificial Brain design:
ab build brain --brain brain.py --env .env
Building prepares and installs the selected Brain on Prima-Lux. Wait for READY before starting your application. Build does not start the Brain. The compiled Brain is mapped onto the synthetic neurons in Prima-Lux or ABi.
You can provide an Artificial Brain path from a subdirectory with --brain path/to/brain.abdesign.json. For ab run, also keep an appropriate local design as brain.abdesign.json or brain.py in the application directory, or explicitly provide its input/output contract. The application needs the correct input and output names to talk to the installed Brain.
4. How a robot application works
Your sensors → SpikeEncoder → RealtimeSession → Artificial Brain on Prima-Lux or ABi
Your motors ← your motor code ← output decoder ← neural output events
↑
RobotLoop (optional sensor polling and command handling)
| SDK component | Responsibility |
|---|---|
ABClient |
Connects to Prima-Lux and starts an application session. |
RealtimeSession |
Publishes observations, receives output events, registers callbacks, and manages the session lifecycle. |
SpikeEncoder |
Converts application sensor readings into input populations. |
GenericSpikeDecoder |
Converts neuron-identified output events into named command changes. |
ActuationChannelDecoder |
Converts device actuation-channel counts into named command changes. |
RobotLoop |
Polls sensors, publishes inputs and optional rewards, and dispatches decoded commands. |
The SDK does not know your robot's wheel geometry, joint limits, camera calibration, or safe operating range. Your application supplies sensor readers, interprets commands, and enforces motor limits and emergency-stop behavior.
5. Start a session and use live inputs
Create run.py and use a session as the boundary between the robot and the installed Brain:
import os
from ab import ABClient
env_path = os.environ.get("AB_ENV", ".env")
client = ABClient.from_env(env_path=env_path)
session = None
try:
session = client.start_from_env(env_path=env_path)
session.on_output(lambda event: print("Brain output:", event))
# Replace these values with the latest reading from your sensor.
session.publish_input("SENSE", [0.0] * 64, mode="vector_f32")
# In a real application, continue capturing sensors and processing outputs.
finally:
if session is not None:
session.stop()
client.close()
A session starts the installed Brain if necessary. Register handlers before beginning sensor activity. Use finally to stop even if the application encounters an error.
Session methods
| Method | Use |
|---|---|
session.publish_input(sensor, signal, ...) |
Send one current sensor observation immediately. |
session.publish_sensor_frame(readings) |
Send multiple channels captured at the same time as one frame. |
session.publish_reward(input_name, magnitude) |
Send a reward to an existing named reward input. |
session.on_output(callback) |
Observe raw neural output events. |
session.set_decoder(decoder) |
Set the output decoder for the application's command representation. |
session.on_command(callback) |
Receive decoded commands. |
session.on_control(callback) |
Receive session-control events. |
session.stop() |
Stop the session and wait for the device's Stop/save confirmation. |
Keep output callbacks short: they run on the SDK output-stream thread. Avoid slow camera or motor operations directly inside an output callback.
Encoding sensory information
Input names such as SENSE must match your Brain's named input populations. The encoded width must match the selected input's neuron count.
For example:
# A 64-value sensory population
session.publish_input("SENSE", sensor_vector, mode="vector_f32")
# One nonnegative measurement represented across its input population
session.publish_input(
"DISTANCE",
distance_meters,
mode="positive_scalar_population",
vmax=2.0,
radius=1,
)
The following encoding modes are available:
| Mode | Input | Encoding |
|---|---|---|
vector_f32 |
Numeric vector | Values passed through to the named input population. |
binary_spikes |
Numeric vector | Values greater than zero become 1; other values become 0. |
positive_scalar_population |
Nonnegative scalar | A local group of neurons represents a value; requires vmax. |
positive_scalar_cumulative_population |
Nonnegative scalar | A cumulative active range; requires vmax. |
ranged_scalar_population |
Scalar in a range | Maps [vmin, vmax] into a local group. |
signed_scalar_population |
Signed scalar | Maps [-absmax, absmax] into a local group. |
reward_population |
Reward magnitude | Represents a reward between 0 and 1. |
Supply finite, normalized input values compatible with your device and encoding mode. For live Prima-Lux vector inputs, values should be in [0, 1]. Sensor preprocessing (such as image resizing and normalization) is performed by your application.
For a simultaneous capture—for example, three color channels from a single image—use:
session.publish_sensor_frame({
"RETINA_R": red_values,
"RETINA_G": green_values,
"RETINA_B": blue_values,
})
Never pre-schedule sensory observations for future neural steps. publish_input() sends each reading when it arrives. publish_sensor_frame() is for channels captured together, not a queue of samples from different times. Output step numbers are useful for reading events, not for scheduling inputs.
To inspect how a signal is encoded before sending it:
encoded = session.encoder.encode(
"DISTANCE", 0.75,
mode="positive_scalar_population", vmax=2.0,
)
print(encoded.target, encoded.payload, encoded.meta)
session.encoder is the session's configured SpikeEncoder; it already knows the Brain's input map.
6. Decode neural outputs into actions
Outputs are neural signals, not robot motor instructions. You decide how to interpret them and which physical actuator limits to apply. Choose the decoder according to the output event representation.
Actuation-channel outputs
If a device output event includes actuation.channels, use ActuationChannelDecoder:
from ab import ActuationChannelDecoder
decoder = ActuationChannelDecoder({
"ACTION": {
"motor": "drive",
"gain": 0.02,
"limit": [-0.1, 0.1],
}
})
session.set_decoder(decoder)
def apply_motor_command(command):
delta = float(command.get("deltas", {}).get("drive", 0.0))
delta = max(-0.1, min(0.1, delta))
# Send this bounded value to your actual motor driver.
print("Drive change:", delta)
session.on_command(apply_motor_command)
Neuron-identified outputs
If the device supplies neuron identities in output events, use GenericSpikeDecoder:
from ab import GenericSpikeDecoder
decoder = GenericSpikeDecoder([
{
"output_id": "STATE",
"channel": "drive",
"scheme": "bipolarSplit",
"n": 4,
"per_step_max": 0.05,
"gain": 1.0,
"clamp": [-0.1, 0.1],
}
])
session.set_decoder(decoder)
session.on_command(apply_motor_command)
GenericSpikeDecoder supports bipolarSplit, addition, booleanThreshold, and bipolarScalar. The decoder returns a command such as {"t": 123, "deltas": {"drive": 0.05}}; your motor driver decides how to apply it. If you only want to inspect the Brain's raw outputs, register session.on_output() without setting a decoder.
Do not assume actuation-channel counts and neuron-identified spikes are interchangeable. Check the actual events from your Brain. Always apply robot-side speed, force, joint, and emergency-stop limits independently of decoding.
7. Use RobotLoop for continuous robot control
RobotLoop is the convenient option when your robot application polls sensors at a regular rate. It joins sensor reading, input publication, optional rewards, and decoded command handling.
For example, add the following to your application after creating the session and selecting the appropriate decoder:
from ab import RobotLoop
def read_sensor_state():
# Replace the example measurement with your robot's sensor reading.
distance_meters = 0.75
return {
"SENSE": {
"signal": distance_meters,
"mode": "positive_scalar_population",
"vmax": 2.0,
"radius": 1,
}
}
loop = RobotLoop(
session,
state_provider=read_sensor_state,
command_executor=apply_motor_command,
input_mode="realtime",
tick_hz=20.0,
strict=True,
)
try:
loop.run_forever()
finally:
loop.stop()
session.stop()
For this example, change the SENSE input and its encoding as appropriate for your real sensor; the Brain and encoder must agree on its width and meaning.
state_providerreturns current named sensor readings; it can supply raw values or per-sensor encoding options.tick_hzis your robot's sensor polling rate, not the Brain's neural execution rate.input_mode="realtime"sends readings immediately rather than scheduling future neural steps.strict=Truereports unknown sensor names instead of silently ignoring them.command_executorapplies decoded commands through your application's motor driver.
RobotLoop registers its own command callback when command_executor is supplied. Normally, do not also register session.on_command(apply_motor_command) for the same action, or you may process one command twice.
If a camera or another sensor already provides event-driven callbacks, use session.publish_input() directly at capture time instead of forcing it through a polling loop. Outputs are received independently of the sensor polling rate.
Rewards
Rewards are sent to named input populations already defined in the Artificial Brain:
session.publish_reward("REWARD", 0.8)
Or define a reward source for RobotLoop:
def reward_state():
return {"rewards": {"REWARD": 0.8}}
loop = RobotLoop(
session,
state_provider=read_sensor_state,
command_executor=apply_motor_command,
reward_provider=reward_state,
input_mode="realtime",
)
Your robot application decides when and how rewards are measured. The SDK only encodes and publishes them to the corresponding Artificial Brain inputs.
8. Complete run.py example
This example demonstrates an application that reads one sensor, uses a decoder, and handles motor commands. Its sensor and motor functions are demonstrations only—replace them with your real robot drivers and safety controls. It expects an Artificial Brain with a 64-neuron SENSE input and an ACTION output exposed as a device actuation channel.
"""Example robot application for an installed Brain on Prima-Lux."""
import os
from ab import ABClient, ActuationChannelDecoder, RobotLoop
def read_sensor_state():
# Replace this demonstration reading with your robot sensor.
distance = 0.75
return {
"SENSE": {
"signal": distance,
"mode": "positive_scalar_population",
"vmax": 2.0,
"radius": 1,
}
}
def apply_motor_command(command):
change = float(command.get("deltas", {}).get("drive", 0.0))
change = max(-0.1, min(0.1, change))
# Replace with your safe actuator implementation.
print("Drive change:", change)
def main():
env_path = os.environ.get("AB_ENV", ".env")
client = ABClient.from_env(env_path=env_path)
session = None
loop = None
try:
session = client.start_from_env(env_path=env_path)
session.set_decoder(ActuationChannelDecoder({
"ACTION": {
"motor": "drive",
"gain": 0.02,
"limit": [-0.1, 0.1],
}
}))
loop = RobotLoop(
session,
state_provider=read_sensor_state,
command_executor=apply_motor_command,
input_mode="realtime",
tick_hz=20.0,
strict=True,
)
loop.run_forever()
finally:
if loop is not None:
loop.stop()
if session is not None:
session.stop()
client.close()
if __name__ == "__main__":
main()
Build the Artificial Brain first and wait for READY, then launch the application:
ab build brain --brain brain.abdesign.json --env .env
ab run -ab --env .env
The -ab flag is supported for the Prima-Lux and ABi target; ab run --env .env is also valid. The run command starts the installed Artificial Brain and the application's run.py. It does not rebuild or replace the Brain. Stop the application with Ctrl+C to initiate its normal Stop/save sequence.
9. Device commands and lifecycle
ab device --env .env status
ab device --env .env events
ab device --env .env run
ab device --env .env stop
ab device --env .env reset-dynamics
- Build maps an Artificial Brain into the Synthetic Neurons in your chip or device, and leaves it READY.
- Run starts or resumes the installed Artificial Brain.
ab runalso starts your Python application. - Stop waits for Prima-Lux or ABi to confirm that the neural state has finished saving; request acceptance alone is not completion.
- Reset dynamics starts the installed Artificial Brain's neural dynamics from its initial state, discarding accumulated changes, memory and learnings. It does not change your robot's physical state.
An Artificial Brain's saved neural state and your robot's environment are separate. Your application is responsible for camera, joint, world, or other external state when resuming in a changed environment. Avoid disconnecting or powering down the device while Stop is still in progress.
10. Troubleshooting
| Symptom | Check |
|---|---|
ab command not found |
Ensure you installed the SDK in the currently active Python environment. |
| Cannot reach Prima-Lux or ABi | Verify Ethernet, AB_DEVICE_URL, API key, and device power. |
| Build is not READY | Check ab device --env .env status and events; verify Prima-Lux has Internet access for builds. |
| Brain input name not found | Match the sensor name exactly to brain.input(...) and the application's I/O contract. |
| Brain design not found when running | Keep brain.abdesign.json or brain.py in the application directory, or configure AB_DEVICE_CONTRACT. |
| Encoded input rejected | Check input width, finite values, normalization, and mode-specific limits (vmax, vmin, absmax). |
| Output events arrive but the robot does not move | Verify the correct decoder type, output names, command_executor, and actual motor driver. |
| Commands are applied twice | Don't register the same motor callback both through RobotLoop and session.on_command(). |
| The robot moves incorrectly | Verify sensor mapping, sign conventions, actuator limits, and the installed Brain before changing motor gains. |
| Application stops before sensor activity | Check that run.py starts the session and keeps the sensor loop or callbacks alive. |
| Changed Brain design has no effect | ab run uses the Brain already installed on Prima-Lux; rebuild explicitly to install changes. |
Guidance for development agents
When an AI coding agent or another developer helps build your robot application, give it the "Introductory Guide to Building an Artificial Brain" and this README. The important integration rules are:
- Use
from ab import Brainto define inputs, OPUs, connections, and outputs. Keep the design in a savedbrain.abdesign.jsonor Python source file. - Match every sensor and output name in application code to the installed Brain's input/output contract.
- Keep sensor acquisition and actuator safety logic in the application. Use SDK encoding and decoding for the neural interface.
- Publish current observations as they arrive; only group channels that were captured simultaneously. Never assign future neural steps to inputs.
- Use
RobotLoopfor sensor polling, or publish inputs directly from event-driven sensor callbacks. - Test the actuator command handler and its physical limits independently.
- Stop the session and wait for neural-state saving before disconnecting the device.
See AGENTS.md for a shorter agent-facing checklist.
Next steps
Use the "Introductory Guide to Building an Artificial Brain" for understanding how synthetic neurons and artificial brains work, and visit our github repository to find examples, primitives and new documentation. Start with one sensory pathway and one observable output, then extend the Artificial Brain and your robot application as you verify each behavior.
Your Python application is the middleware between the Artificial Brain and the robot: connect cameras, proximity sensors, robot joints, simulators like Webots, Alakazam, or other sensor and actuator drivers through the same live SDK interface.
License
See LICENSE for the terms supplied with your SDK distribution.
Metadata
Release files for artificialbrains-sdk 0.3.8
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 | |
|---|---|---|---|---|
| artificialbrains_sdk-0.3.8.tar.gz | 189.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| artificialbrains_sdk-0.3.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 377.4 kB
Release files / artificialbrains_sdk-0.3.8.tar.gz
| Download URL | artificialbrains_sdk-0.3.8.tar.gz |
|---|---|
| Size | 189.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
42a6301b1164a2d5d735ec3d290d4103f52ddf519e07181cf0aa1dda4f5b7b1b
|
|
BLAKE2b-256 checksum How to use checksums |
8cb689e1e74aad318c76e3b8d45744044bb47add0e4ce1dc3960fb8ece7526b4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / artificialbrains_sdk-0.3.8-py3-none-any.whl
| Download URL | artificialbrains_sdk-0.3.8-py3-none-any.whl |
|---|---|
| Size | 187.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
36966074f59880f72d90d81699d9c4c262d4f6038a8eab7e1075e0cf167afc2b
|
|
BLAKE2b-256 checksum How to use checksums |
cf4a74cd004a773d49e00f5a718b87baece951638832c0d038043452878e2b73
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Security for artificialbrains-sdk 0.3.8
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.