---
summary: "How the ScaiGrid wrapper sits over the ScaiCore language runtime \u2014\
  \ what the wrapper owns, what the language owns, where the seam is."
title: Architecture
path: modules/scaicore/concepts/architecture
status: published
---

The ScaiCore *language* and its standalone runtime are documented separately at [/docs/scaicore](https://www.scailabs.ai/docs/scaicore). They are not part of this module. This page is about the ScaiGrid wrapper that hosts a compiled ScaiCore program inside ScaiGrid — what it adds and where the seam is.

## Two ScaiCores, one diagram

```mermaid
flowchart LR
    subgraph Machine[Your machine]
        Compiler[scaicore<br/>compiler]
    end

    subgraph ScaiGrid["ScaiGrid /v1/modules/scaicore/"]
        Row[Core row DB<br/>checkpoints<br/>delegations<br/>plugins<br/>FrontendModel]
        AdminAPI[Admin UI + API]
    end

    subgraph Library["ScaiCore (library)"]
        Engine[CoreEngine<br/>.ainvoke&#40;&#41;<br/>.aresume&#40;&#41;]
        Host[HostEnvironment<br/>memory, models,<br/>events, plugins,<br/>placement]
    end

    Compiler -- "IR bundle" --> Row
    Row -- "invoke / resume" --> Engine
    Engine --- Host
```

ScaiCore-the-library is invoked, not deployed. The wrapper holds the IR bundle, manages the row, calls `CoreEngine.ainvoke()` / `aresume()` on behalf of API or event callers, and threads ScaiGrid services into the `HostEnvironment` so the program can use real Redis, real MariaDB, real model inference, real S3, and real event bus instead of in-process stubs.

## What the wrapper owns

- **Persistence.** The `mod_scaicore_cores` table holds the IR source, the runtime config, the identity mode, the plugins list, the (encrypted) environment, the avatar URL, and the lifecycle status.
- **Lifecycle state machine.** `created → starting → running → stopping → stopped`; `running → paused → running`; `running → error`; `crashed → restarting → running`. The wrapper enforces the legal transitions.
- **HostEnvironment backends.** Production backends for memory (Redis), checkpoints (S3 + MariaDB), models (`InferenceService`), events (`EventBus`), plugins (HTTP bridge), entity placement (Redis Grain Directory).
- **Checkpoints.** Captured into `mod_scaicore_checkpoints`, routed by assignee, expired or escalated by a 5-minute cron, resolved via the API or the admin UI's checkpoint queue.
- **Identity.** Service-account by default. Delegation lets a Core run as a specific human user, with explicit scopes and an optional expiry; the delegated user is resolved on `start()` exactly like JWT auth.
- **Plugins.** Plugin definitions live on the Core row as a JSON list; the HTTP bridge in the HostEnvironment calls the registered endpoints when the program asks for them.
- **Publishing.** A Core can be published as a `FrontendModel` (slug `scaicore/{tenant_slug}/{core_slug}`); after publication the Core is callable through any model-aware ScaiGrid API.
- **Admin UI pages.** Dashboard, editor, console, logs, debugger, identity, checkpoint queue, checkpoint history, plugin marketplace, event monitor (mounted by the module registry).

## What the language owns

- The DSL, the compiler, the IR format, semantic versioning of IR schema.
- `CoreEngine.ainvoke()` / `aresume()` — interpreting the IR, calling models, materialising checkpoints, scheduling resume.
- The `HostEnvironment` protocol — what the wrapper has to implement to host a Core.
- Standalone-runtime concerns (CLI tooling, local dev, package layout).

If something feels like "how does the program execute?", that's the language. If something feels like "how do I run the program in ScaiGrid and let humans interact with it?", that's this module.

## Request flow for one event

1. **Caller** posts `POST /v1/modules/scaicore/cores/{id}/events` with `{event_name, data}`.
2. **Auth.** Standard ScaiGrid bearer-token auth; tenant scoping enforced on every row read.
3. **Routing.** The wrapper resolves the Core, validates it is `running`, and dispatches to `CoreEngine.ainvoke()` with `trigger_type=EVENT`. (Eventing currently records the dispatch as `accepted` — runtime invocation is wired through the HostEnvironment.)
4. **Execution.** The CoreEngine interprets the relevant flow; tool calls / inference go out through the InferenceService and back; events fire over the EventBus.
5. **Checkpoint (if any).** Execution suspends; a row is written to `mod_scaicore_checkpoints`; a notifier emails the resolved assignee.
6. **Resolution.** A human posts `POST /checkpoints/{id}/resolve`; the row is updated; the runtime resumes from the captured state.

## State

- **Cores, checkpoints, delegations, plugin configs** — MariaDB tables under the `mod_scaicore_*` prefix.
- **Encrypted env vars** — `environment_encrypted` blob on the Core row, with a wrapped DEK + IV.
- **Avatars** — Garage S3 under `scaicore/{tenant_id}/{core_id}/avatar`, served back through an internal proxy path.
- **Checkpoint state blob** — S3, keyed by `state_s3_key` on the row.
- **Engine instances** — in-process `EngineRegistry` keyed by `core_id`; cleaned up on `stop` / `delete`.

## How it differs from the standalone runtime

The standalone runtime (documented at [/docs/scaicore](https://www.scailabs.ai/docs/scaicore)) runs a Core in-process with stub backends. The wrapper differs in five places:

| Concern | Standalone | ScaiGrid wrapper |
|---|---|---|
| Storage | In-memory / local files | MariaDB + S3, tenant-scoped |
| Identity | Whatever you pass in | Service-account or delegated human |
| Checkpoints | Block until resolved in-process | Persisted, routed to assignees, surfaced in admin UI |
| Models | You wire them | Resolved through ScaiGrid's inference router (accounted) |
| Multi-tenancy | None | Every row tenant-scoped, RBAC-gated, audit-logged |

For everything else — the IR, the compiler, semantic versioning, language reference — see [/docs/scaicore](https://www.scailabs.ai/docs/scaicore).
