Skip to content

Architecture

Masterplanner25 edited this page Jun 6, 2026 · 1 revision

Architecture

aindy-runtime is structured in layers. Each layer has a clear responsibility and strict import boundaries — app code (plugins) may not import from the kernel; the kernel does not import from routes; and so on.

Layer Model

AINDY/
├── kernel/           # Core primitives
│   ├── SyscallDispatcher      — single entry point for all capability calls
│   ├── SyscallRegistry        — registered handlers + schema + capabilities
│   ├── EventBus               — Redis pub/sub for cross-instance WAIT/RESUME
│   ├── SchedulerEngine        — priority queue (high/normal/low lanes)
│   ├── CircuitBreaker         — per-provider failure tracking
│   ├── ResourceManager        — tenant quota enforcement
│   └── TenantContext          — tenant isolation
│
├── platform_layer/   # Runtime services
│   ├── LLM clients            — OpenAI / DeepSeek with circuit breaker
│   ├── metrics                — Prometheus counters and histograms
│   ├── OTel                   — distributed tracing
│   ├── rate_limiter           — per-tenant rate limiting
│   ├── cache_backend          — Redis or in-memory cache
│   ├── sandbox_runner         — extension sandbox (OCI/subprocess/VM)
│   ├── scheduler_service      — APScheduler maintenance jobs
│   └── deployment_contract    — runtime state, conditions, profiles
│
├── core/             # Execution pipeline
│   ├── ExecutionPipeline      — middleware wrapper around every route handler
│   ├── DistributedQueue       — Redis-backed job queue with in-memory fallback
│   ├── SystemEventService     — event emission to system_events table
│   ├── RetryPolicy            — per-syscall retry contract
│   └── ResumeWatchdog         — stuck-run recovery
│
├── runtime/          # Flow and Nodus execution
│   ├── FlowEngine             — DAG executor
│   ├── nodus_worker           — Nodus script execution
│   └── memory_loop            — memory signal capture
│
├── agents/           # Agent runtime
│   ├── agent_runtime          — execute_run, approval, capability tokens
│   ├── AgentCoordinator       — multi-agent delegation
│   ├── AutonomousController   — trigger evaluation for scheduled agents
│   └── tool_registry          — tool resolution for agent plans
│
├── memory/           # Memory persistence
│   ├── memory_ingest_service  — write + background embedding queue
│   ├── MemoryAddressSpace     — MAS path queries
│   └── memory_scoring_service — impact score + usage + causal depth ranking
│
├── db/               # Database
│   ├── models/                — SQLAlchemy ORM models
│   ├── alembic/               — migrations (alembic_version_runtime table)
│   └── schema_contract        — blank-bootstrap + schema enforcement
│
└── routes/           # FastAPI routers
    ├── health_router          — /health, /health/deep, /ready
    ├── auth_router            — /auth/register, /auth/login, JWT issuance
    ├── flow_router            — /apps/flows (runtime-owned flows)
    ├── platform_router        — /platform/* operator surfaces
    └── observability_router   — /platform/observability/*

Request → Execution Pipeline

Every route handler runs inside ExecutionPipeline — a middleware-like wrapper that:

  1. Sets ContextVars (trace_id, pipeline_active)
  2. Claims an ExecutionUnit row in the database
  3. All capability calls go to SyscallDispatcher.dispatch()
  4. Records Prometheus metrics and OTel spans
  5. Captures memory signals from the response
  6. Emits a SystemEvent record
  7. Releases the ExecutionUnit (marks completed or failed)

SyscallDispatcher

The single entry point for all capability calls. For every dispatch:

  1. Validates the syscall exists in SYSCALL_REGISTRY
  2. Enforces the caller's SyscallContext.capabilities
  3. Checks tenant isolation and resource quota
  4. Validates input/output schemas (Pydantic)
  5. Runs the idempotency gate for EXACTLY_ONCE handlers (EffectRecord in DB)
  6. Wraps the handler in an OTel span
  7. Returns a uniform {status, data, trace_id, duration_ms, error} envelope

Flow State Machine

pending → executing → completed
                   ↘ failed
                   ↘ waiting → (event fires) → executing → ...

When a flow node calls sys.v1.event.wait, the flow suspends:

  • FlowRun.status → waiting
  • A callback is registered in the in-memory _waiting dict
  • EventBus.publish() broadcasts the wait via Redis to all instances

When publish_event(event_type) fires later, the engine re-enqueues the flow. On restart, rehydration re-registers all waiting rows so no flow is lost.

Agent State Machine

pending_approval → approved → executing → completed
                                        ↘ failed
                                        ↘ delegated → (sub-agent) → ...

Agents require an explicit approval step before execution. The approve_run() function uses an atomic compare-and-set on the database row — concurrent approval requests are safe.

Key Design Principles

  • No direct capability calls — handlers never call services directly; they dispatch through the syscall system. This enforces schema validation, capability checking, and idempotency uniformly.
  • Crash-safe by default — FlowRun and AgentRun states are persisted to PostgreSQL. The rehydration system re-registers all interrupted runs on restart.
  • Single-process OR distributed — the same codebase runs in single-instance mode (thread scheduling, optional Redis) or distributed mode (Redis queue, cross-instance event bus, separate worker process). See Deployment Profiles.
  • Plugin boundary is enforced — no from apps.* import is allowed in AINDY/. App logic lives in plugins; the runtime owns the execution substrate.

Clone this wiki locally