Skip to content

How it fits together

The SDK mirrors the game’s own structure. Once you can see that structure, most of the API follows from it.

Most reads start from a player and walk down:

Wallet ──▶ Profile ──▶ Character ──▶ Fleet

A wallet may own a profile; a profile has one SAGE character; a character owns many fleets. A wallet cannot be turned into a profile by derivation — profiles are created by the player, so that step needs discovery or a known address.

Fleet ──┬──▶ cargo (what it is carrying)
├──▶ mining (what it is extracting, and how fast)
├──▶ scanning (what it has surveyed)
├──▶ combat (its combat status)
└──▶ state (docked, in transit, mining, …)

A fleet’s location lives inside its state, not as a standalone field, because where a fleet is depends on what it is doing.

Profile ──┬──▶ factions (allegiance, standing)
├──▶ loyalty (epoch contributions, accumulated ATLAS)
├──▶ rewards (treasuries, commitments)
└──▶ starbases (this player's state at each starbase)
World ──┬──▶ star systems ──▶ starbases ──┬──▶ markets
│ └──▶ crafting
└──▶ planets & asteroids ──▶ claim stakes

Shared starbase data belongs to the world. A player’s own state at a starbase is separate, which is why starbases appear in both places.

client ── context, cache, provenance, subscriptions
registry ── the Game account's definitions: ships, cargo, recipes, XP
bindings ── the raw generated client (escape hatch)

The client owns the machinery every read shares. The registry holds the game’s static definitions — read once, reused everywhere. The bindings entry is the escape hatch for anything not yet adapted.

Each arrow is a method, and each cluster is roughly an entry point:

const character = await sage.characters.forProfile(profileAddress);
const fleets = await character.fleets.all();
const inventory = await fleets[0].inventory.get();

Where a name appears in the map, there is usually an entry point of the same name — @aephia/sage/fleets, @aephia/sage/world, and so on. See the reference for the full list.