Documentation: 0.5.0 (source: v0.5.0).
# How the SDK thinks

> The five design decisions that explain the shape of every read in this SDK.

Markdown source of https://docs-v0-5-0.atlas-kit-docs.pages.dev/start-here/how-it-thinks/ — see https://docs-v0-5-0.atlas-kit-docs.pages.dev/ai/ for the full machine-readable surface.

Five decisions explain almost every API in this SDK. Knowing them means you can
usually guess how something works instead of looking it up.

## 1. Everything hangs off a context

A context holds the cache, the RPC binding, and the cluster's known addresses.
Creating one is synchronous and does no network work.

```ts
const sage = createSageClient({ cluster: 'zink-ptr', rpc });
```

There is no global `init()`. Two contexts are genuinely independent — separate
caches, separate endpoints — which is what makes it safe to run several in one
process.

If you prefer functions to objects, `createSageContext` gives you the context
alone, and every domain function takes it as its first argument. The convenience
client is a thin wrapper over exactly those functions.

## 2. Reads return loaded data

There are no two-phase handles. When a read resolves, the data is there.

```ts
const character = await sage.characters.forProfile(profileAddress);
character.address; // already loaded
```

The tradeoff is deliberate: anything that costs a network round trip is a
**method you call**, not a property you read. `character.fleets.all()` is a
separate read, so it is a separate `await`. If it looks like a property, it is
already in memory.

## 3. Nothing is trusted until it is validated

Every account read is checked before decoding: program owner, discriminator,
data shape, minimum length. Data that fails produces a typed error and never
enters the cache.

This matters more than it sounds. An RPC can return anything — a wrong account,
a truncated response, an account from a different program. Without validation
those become silently wrong values deep in your application. Here they become
an error at the read.

## 4. The cache is keyed by identity, not by call

Two reads of the same account through the same context return the same
immutable snapshot until it expires. Not an equal copy — the same object.

The key is cluster, program, account type, and address. Reading a fleet through
`character.fleets.all()` and reading it directly hit the same cache entry.

Every snapshot carries provenance: where it came from and when. So "is this
fresh?" is always answerable, and the [interactive
examples](/start-here/first-read/) will later let you watch caching happen.

## 5. You pay for what you import

The package has one entry point per capability:

```ts
import { getFleet } from '@aephia/atlas-kit/fleets';
import { getStarSystem } from '@aephia/atlas-kit/world';
```

Importing `fleets` does not pull in `markets` or `crafting`. Bundle budgets for
every entry are enforced in CI, so this stays true.

The root entry (`@aephia/atlas-kit`) is the convenience client, which composes the
common capabilities. It is the largest import and the easiest to start with.
Reach for capability entries when bundle size matters.

## What this adds up to

Reads are explicit, results are trustworthy, and staleness is visible. The cost
is a little more ceremony than an SDK that hides its I/O — an extra `await`
where another library might give you a magic property.

That is a deliberate trade. The alternative hides network calls behind property
access, which is exactly how a dashboard ends up making four hundred RPC
requests a second without anyone noticing.

## Where to go next

- [The game map](/game-map/) — the gameplay concepts and what connects them
- [The API map](/map/) — the same universe from the SDK's side
- [Reference](/reference/) — every public entry, generated from source
- [For AI assistants](/ai/) — machine-readable docs, and the legacy-package trap
