Skip to main content

aindy-sdk

Universal interface SDK for the A.I.N.D.Y. runtime API.

aindy-sdk is the local+cloud bridge: the same client code works against a locally-installed runtime (where the operator owns the infrastructure) and a cloud-hosted runtime (where the provider owns the infrastructure). Switching deployment context requires only a base_url change — no application code changes.

Part of the Masterplan Infinite Weave ecosystem by Shawn Knight. Runtime infrastructure: https://github.com/Masterplanner25/aindy-runtime

Install

pip install aindy-sdk

Requirements

  • Python 3.11+
  • No external dependencies (stdlib only) for the API client
  • Watcher subpackage optional dependencies: psutil (fallback window detection), pyobjc-framework-AppKit + pyobjc-framework-Quartz (macOS window titles), xdotool system package (Linux window detection)

Getting started

1. Start the runtime

Install and start aindy-runtime (full instructions):

git clone https://github.com/Masterplanner25/aindy-runtime.git
cd aindy-runtime
cp AINDY/.env.example AINDY/.env   # set SECRET_KEY and OPENAI_API_KEY at minimum
docker compose up -d

Wait until the server is ready:

curl http://localhost:8000/ready    # → {"status": "ok", ...}

2. Register and log in

# Register
curl -s -X POST http://localhost:8000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "yourpassword", "display_name": "You"}' \
  | python -m json.tool

# Log in — copy the access_token from the response
curl -s -X POST http://localhost:8000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "yourpassword"}' \
  | python -m json.tool

To promote your account to admin (required to create API keys via the CLI):

# Using the CLI (no server restart needed)
aindy-runtime auth promote-admin you@example.com

# Or via env var (requires server restart)
# Add AINDY_BOOTSTRAP_ADMIN_EMAIL=you@example.com to AINDY/.env, then docker compose restart api

3. Create a Platform API key

Platform API keys start with aindy_ and are shown only once — save the key field.

JWT="<your-access_token>"

curl -s -X POST http://localhost:8000/platform/keys \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-app",
    "scopes": ["memory.read", "memory.write", "flow.execute", "event.emit"]
  }' \
  | python -m json.tool

Available scopes:

Scope Grants access to
memory.read Read and search memory nodes (client.memory.read/search/list/tree/trace)
memory.write Write and delete memory nodes (implies read)
flow.execute Run registered flows (client.flow.run)
event.emit Emit events to the event bus (client.events.emit)
execution.read Read execution unit status (client.execution.get)
platform.admin Full platform admin — bypasses all scope checks

4. First call

from aindy_sdk import AINDYClient

client = AINDYClient(
    base_url="http://localhost:8000",
    api_key="aindy_your_platform_key",
)

result = client.memory.read("/memory/you/notes/**", limit=5)
print(result["data"]["nodes"])

Run the full example:

AINDY_API_KEY=aindy_... python examples/quickstart.py

Usage

from aindy_sdk import AINDYClient

# Local runtime (operator owns infrastructure)
client = AINDYClient(
    base_url="http://localhost:8000",
    api_key="aindy_your_platform_key",
)

# Cloud-hosted — same code, different base_url
# client = AINDYClient(base_url="https://runtime.aindy.ai", api_key="...")

# Read memory
result = client.memory.read("/memory/shawn/entities/**", limit=5)
nodes = result["data"]["nodes"]

# Run a flow
analysis = client.flow.run("analyze_entities", {"data": nodes})

# Write memory
client.memory.write(
    "/memory/shawn/insights/outcome",
    analysis["data"].get("summary", ""),
    tags=["sdk-demo"],
)

# Emit an event
client.events.emit("analysis.completed", {"node_count": len(nodes)})

API reference

All capabilities are accessed through namespaces on AINDYClient:

Namespace Description
client.memory Read, write, and search memory nodes by MAS path or vector similarity
client.flow Trigger flow runs and poll their status
client.events Emit events to the runtime event bus
client.nodus Compile and execute Nodus scripts
client.syscalls List and inspect the syscall registry
client.execution Introspect in-flight or completed execution units
client.sandbox Query sandbox assurance posture

Every method returns a syscall envelope:

{
    "status":      "success",        # "success" or "error"
    "data":        { ... },          # payload — varies by call
    "trace_id":    "abc123...",      # for log correlation
    "duration_ms": 12,               # server-side execution time in ms
    "error":       None,             # error description when status == "error"
}

Memory (client.memory)

# Read nodes at a MAS path (glob patterns supported)
result = client.memory.read("/memory/shawn/entities/**", limit=10)
nodes = result["data"]["nodes"]

# Write a node
result = client.memory.write(
    "/memory/shawn/insights/daily-summary",
    "Worked on SDK documentation today.",
    tags=["insight", "daily"],
    node_type="insight",
)
node_id = result["data"]["node"]["id"]

# Semantic similarity search
result = client.memory.search("recent project decisions", limit=5)

Flow (client.flow)

# Run a registered flow and get its result (synchronous)
result = client.flow.run("analyze_entities", {"data": nodes})
output = result["data"]

Events (client.events)

# Emit an event (can trigger waiting flows)
result = client.events.emit(
    "user.action.completed",
    {"user_id": "u-123", "action": "document_saved"},
)

Nodus (client.nodus)

# Execute a Nodus script
result = client.nodus.run_script(
    script="""
let greeting = "Hello from Nodus"
set_state("message", greeting)
emit("script.hello", {text: greeting})
""",
    input={},
)
print(result["nodus_status"])      # "complete" | "wait" | "error"
print(result["output_state"])      # dict of set_state() calls
print(result["events_emitted"])    # count of emit() calls

Execution (client.execution)

run = client.execution.get("run-abc123")
status = run["data"]["status"]          # "running" | "success" | "failed" | "waiting"
syscall_count = run["data"]["syscall_count"]
wall_time_ms = run["data"]["wall_time_ms"]  # accumulated wall-clock time (includes I/O wait)

Syscalls (client.syscalls)

registry = client.syscalls.list(version="v1")
print(registry["total_count"])
for action, spec in registry["syscalls"]["v1"].items():
    deprecated = " [DEPRECATED]" if spec.get("deprecated") else ""
    print(f"sys.v1.{action}{deprecated}")

Error handling

The SDK maps HTTP status codes to typed exceptions so you can handle failure cases explicitly rather than inspecting status codes:

from aindy_sdk import AINDYClient
from aindy_sdk.exceptions import (
    AuthenticationError,    # 401 — key missing, invalid, or expired
    PermissionDeniedError,  # 403 — key scope doesn't include this capability
    NotFoundError,          # 404 — resource doesn't exist
    ValidationError,        # 422 — bad request shape or schema violation
    ResourceLimitError,     # 429 — syscall count or wall_time_ms exceeded
    ServerError,            # 5xx — unexpected runtime error
    NetworkError,           # connection refused, timeout, or DNS failure
    AINDYError,             # base class — catches all of the above
)

client = AINDYClient(base_url="http://localhost:8000", api_key="aindy_...")

try:
    result = client.memory.read("/memory/shawn/entities/**", limit=5)
except AuthenticationError:
    print("Invalid API key — check AINDY_API_KEY")
except PermissionDeniedError as exc:
    print(f"Key scope missing: {exc.message}")
    # exc.response contains the full server error payload
except ValidationError as exc:
    print(f"Bad request: {exc.message}")
except NetworkError as exc:
    print(f"Server unreachable: {exc.cause}")
except AINDYError as exc:
    print(f"Runtime error [{exc.status_code}]: {exc.message}")

All typed errors carry:

  • .message — human-readable description
  • .status_code — HTTP status code (None for NetworkError)
  • .response — raw server JSON dict

Watcher

The SDK ships the A.I.N.D.Y. Watcher client process. The watcher runs on your machine, observes the active OS window, classifies your activity, and emits structured signals to the runtime for flow triggering and session tracking.

# Start the watcher (requires AINDY_API_KEY and AINDY_WATCHER_API_URL)
python -m aindy_sdk.watcher.watcher

# Dry run — logs signals, no HTTP requests
python -m aindy_sdk.watcher.watcher --dry-run

# Custom poll interval and verbose logging
python -m aindy_sdk.watcher.watcher --poll-interval 10 --log-level DEBUG

Environment variables:

Variable Default Description
AINDY_WATCHER_API_URL http://localhost:8000 Runtime base URL
AINDY_API_KEY (required) Service API key (X-API-Key header)
AINDY_WATCHER_DRY_RUN false Log signals only, no HTTP POST
AINDY_WATCHER_POLL_INTERVAL 5 Seconds between window samples
AINDY_WATCHER_FLUSH_INTERVAL 10 Seconds between signal batch flushes
AINDY_WATCHER_BATCH_SIZE 20 Signals per POST batch
AINDY_WATCHER_CONFIRMATION_DELAY 30 Seconds of focus before session_started fires
AINDY_WATCHER_DISTRACTION_TIMEOUT 60 Seconds of off-task time before distraction state
AINDY_WATCHER_RECOVERY_DELAY 30 Seconds of focus to recover from distraction
AINDY_WATCHER_HEARTBEAT_INTERVAL 300 Seconds between heartbeat signals
AINDY_WATCHER_LOG_LEVEL INFO DEBUG | INFO | WARNING | ERROR

See examples/watcher_demo.py for a dry-run demonstration.


Status

Beta. Part of the aindy-runtime 1.x ecosystem (verified against aindy-runtime 1.5.3).

Metadata

Release files for aindy-sdk 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aindy-sdk 1.0.1
File Size Uploaded
aindy_sdk-1.0.1.tar.gz 36.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aindy-sdk 1.0.1
File Interpreter ABI Platform
aindy_sdk-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 70.6 kB

Release files / aindy_sdk-1.0.1.tar.gz

Download URL aindy_sdk-1.0.1.tar.gz
Size 36.9 kB
Tags Source
SHA-256 checksum
How to use checksums
5176a41d25ab62b8d8d54653a59cbcb9cfa178c04fc1690ae87210016d58b856
BLAKE2b-256 checksum
How to use checksums
0272c08eddaf1202077a4dcab5e02ab80f00e9727b7c15b40e47d5cc98c2f4e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release files / aindy_sdk-1.0.1-py3-none-any.whl

Download URL aindy_sdk-1.0.1-py3-none-any.whl
Size 33.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
538915227c1645ea4912aa1ab619bfeb72395ee1cedb45c66eab7d3f9d59960c
BLAKE2b-256 checksum
How to use checksums
d2ffb4744f136fdee465c43ce8ae5fafebd56a5e101a9411c3c2bfc13fbdeea1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page