BUILD

Author against stable contracts.

Implement three verbs. Declare a manifest. Your creature runs, reloads, and travels on the same substrate the lab runs on.

THE SURFACE

Three verbs and a manifest.

A creature is a unit of capability. It implements ModuleInstance, speaks through the Bus, and carries one manifest.

The SDK depends only on aether and gawd-manifest, never on the kernel. That keeps native daemons, WASM beasts, and script critters on one load path.

Native rule: spawn every thread through managed::spawn so the Sanctum can join it before unload.

lifecycle

01 bind

load context once

02 handle

process envelopes

03 shutdown

drain before unload

manifest

nameversionabientrypointscapabilitiesrequirementsprovenancecontent_addressprovides

WHAT RUNS TODAY

What you can lean on today.

The source-first release is pre-1.0 and unaudited, but these mechanisms are real enough to build against. Native code is still trusted by admission; hosted federation and production hardening come later.

The roadmap tracks the status of each of these →

native + WASM + critter load pathsafe reload and unloadAI self-authoring looped25519 transportregistry seedAbode migrationcapability gatingMCP control surface

QUICKSTART

A creature, end to end.

A native daemon is a Rust type that implements the trait and declares its entrypoint. No kernel imports appear anywhere in it.

use gawd_sdk::prelude::*;

#[derive(Default)]
struct Echo;

impl ModuleInstance for Echo {
    // Called once when the Sanctum loads the creature.
    fn bind(&mut self, ctx: ModuleCtx) -> Result<()> {
        ctx.log("echo bound");
        Ok(())
    }

    // Called for every envelope routed to this creature.
    fn handle(&mut self, env: Envelope) -> Outcome {
        env.reply(env.body()) // emit a new envelope back through the Bus
    }

    // Called before unload; return once every spawned thread has joined.
    fn shutdown(&mut self, _deadline: Deadline) -> Result<()> {
        Ok(())
    }
}

// Registers the entrypoint the manifest names.
declare_module!(Echo);

Drive it from sanctumd, the same machine-native control surface an agent uses. Each command flows through admission, engine load, and routing.

sanctum> load ./echo.toml ./libecho.so
loaded  [email protected]  (daemon)
sanctum> bind handler echo
sanctum> send echo "ping"
echo  →  "ping"
sanctum> unload echo
unloaded  echo  (threads joined, rss stable)

There is no hosted product UI yet. Talk to us about access →

A REAL ONE, STEP BY STEP

Build a redactor in five steps.

Echo shows the shape. A redactor earns its keep: it sits on the bus, strips secret-looking tokens from messages, then reloads a smarter version with no downtime.

1 · The manifest

One file of truth: name, tier, role, and no host capabilities.

# redactor.toml — the only metadata the Sanctum trusts
name = "redactor"
version = "0.1.0"
abi = { backend = "native", entry = "redactor" }
provides = ["filter"]   # the role other creatures bind to
capabilities = []       # reads the message and replies. nothing else.

2 · The creature

Three methods again. The work lives in handle: clean the body, reply with it.

use gawd_sdk::prelude::*;

#[derive(Default)]
struct Redactor;

impl ModuleInstance for Redactor {
    fn bind(&mut self, ctx: ModuleCtx) -> Result<()> {
        ctx.log("redactor online");
        Ok(())
    }

    fn handle(&mut self, env: Envelope) -> Outcome {
        env.reply(redact(env.body()))   // forward the cleaned message
    }

    fn shutdown(&mut self, _d: Deadline) -> Result<()> { Ok(()) }
}

declare_module!(Redactor);

3 · The rule

The redaction is plain Rust. The substrate never inspects it; the rule is yours alone.

fn redact(body: &str) -> String {
    let mut out = Vec::new();
    for word in body.split_whitespace() {
        if looks_secret(word) { out.push("‹redacted›") } else { out.push(word) }
    }
    out.join(" ")
}

fn looks_secret(w: &str) -> bool {
    w.len() >= 20 && w.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_')
}

4 · Run it

Load it, bind it to filter, send it a message.

sanctum> load ./redactor.toml ./libredactor.so
loaded  [email protected]  (daemon)
sanctum> bind filter redactor
sanctum> send redactor "ship with key sk_live_9F2aQ7bX4rT1cE6dW0p"
redactor  →  "ship with key ‹redacted›"

5 · Ship a smarter version, live

Add a rule for email addresses, rebuild, and swap it in. The Sanctum drains the old instance, joins its threads, and loads the new one without a restart.

# next build also masks anything with an @  — rebuild, then:
sanctum> reload redactor ./libredactor.so
reloaded  [email protected]  (threads joined, rss stable)
sanctum> send redactor "ping [email protected] about the key"
redactor  →  "ping ‹redacted› about the key"

That is the contract: a manifest, three methods, and your logic in between. Reload, routing, and sandboxing belong to the substrate.

OPEN PROBLEMS

The hard parts, in the open.

These are unsolved in the general case. If one is your kind of problem, this is the work.

Native trust limit

Admission can trust native code. Containing native speed without operator trust is still open.

Cross-tier ABI

Daemons, beasts, and critters should evolve without a flag day.

Anti-entropy

Realm peers need clean store-and-forward convergence after drift or partition.

Trust models

Verifiable randomness has a reference creature. Consensus and weighting remain deployment models.