GET /v1/recall/identity.
200 application/json
What it is
Start with the four ideas, in the order they build. Dimension, one axis along which this person’s thinking varies (in practice, a named spectrum with two poles, like whole-system framing against single-component focus). Position, where they sit on those axes at a moment in time (in practice, one number per dimension). Basin, a stable mode of thinking the subject keeps returning to (in practice, the cluster their positions fall into, with a name and a member count). Trajectory, how the position has moved over time (in practice, an ordered series of past positions and the basin each one fell in). The metaphor is a landscape. Dimensions are the directions you can walk. Basins are the valleys you tend to end up in. A trajectory is the path someone actually took across it.The axes are discovered, not chosen
Exo does not start from a personality inventory. It takes the subject’s identity signals, finds the directions in which those signals differ most, and names each direction from the content that loads at either end of it. So the axes are specific to the person: an infrastructure engineer and a novelist get different dimensions, because different things vary in their writing. Two consequences that matter when you consume this:dimensionsis not a fixed list. Its length, its names and its order are all discovered. Do not index into it by position and assume you know what index 0 means.- Names can change between passes. A dimension’s label is regenerated when the axis it describes has genuinely moved.
refresh_counttells you how many passes have run.
Field reference
This object is snake_case, unlike the rest of the API. Those are the stored discovery keys, passed through as written, and the object is deliberately open: a pass records diagnostic keys beyond the ones named here and every one is passed through unchanged. Read what you need and ignore the rest.Reading the two numbers that tell you whether to trust it
variance_ratios says how much of the person the axes actually capture. If the first ratio is 0.31, that axis explains about a third of the variation in their signals. If cumulative_variance is 0.7, the kept axes explain about seventy percent and the rest is noise or structure too fine to name. Low cumulative variance means the axes are real but partial.
silhouette_score says how separated the basins are. Near 1 means tight, well-separated clusters. Near 0 means the basins overlap enough that the boundary between them is not meaningful, and you should present the basin name as a tendency rather than a label. Negative means the clustering did not find structure.
Neither number is a pass or fail. They are how you decide how strongly to phrase what you show a user.
What a basin shift means for you
basinHistory is the recorded series of positions, oldest first. Each snapshot names the basin the subject was in at that moment:
basin.shifted is one of the event types on GET /v1/events and on webhooks, so you can react to the move rather than diffing snapshots yourself. See Reacting to change.
The most direct use is not reading the manifold at all: POST /v1/condition/session already folds the current basin into a system prompt for you. Read the raw state when you are building your own UI over it, and use the ConditioningPack when you want the behaviour.
Why is manifoldState null?
Why is manifoldState null?
Because no discovery pass has run for this subject yet. Two ordinary causes: the background cognition cycle has not reached them since their content landed, or there are too few identity signals to decompose. A handful of signals has no stable axes to find, and reporting invented ones would be worse than reporting nothing.Null is the honest answer, not an error. Everything else in the identity view fills in independently, so
voiceProfile or recentPatterns can be populated while manifoldState is still null.Why do the dimension names read like they were written by a model?
Why do the dimension names read like they were written by a model?
Because they were. The axes are found numerically and then named from the content that loads most strongly at each pole. The numbers are the discovery; the names are a readable gloss on them. If a name looks wrong,
description and the two pole labels give you enough to judge it, and variance_ratios tells you how much weight that axis deserves in the first place.Why did the axes change between two reads?
Why did the axes change between two reads?
A refresh re-runs discovery over the accumulated signals. Exo aligns each new pass to the previous one so an axis keeps its identity where it can, and nudges basin centres rather than replacing them, so the surface evolves instead of resetting. But when a subject’s content genuinely shifts, axes are relabelled and basins can be born or retired. Treat
dimensions as a snapshot with a discovered_at, not as a stable schema.Is basinHistory the same as trajectory?
Is basinHistory the same as trajectory?
They describe the same movement.
trajectory is the field named on the ManifoldState object itself; basinHistory is the recorded series returned alongside it on the identity view. Both are ordered oldest first and both give you position plus basin per snapshot. If you only need “which mode are they in now”, read the last entry, or read basins and take the dominant one.Limits
manifoldStateis null until the first discovery pass. There is no route that triggers one on demand.- The object is snake_case while the rest of the API is camelCase. This is deliberate, since the field names are the stored discovery keys.
- Extra diagnostic keys appear beyond those documented here. Treat unknown keys as forward-compatible rather than an error.
- Dimension count, names and order are all discovered. None of them is a contract.
- There is no route that returns a position for an arbitrary piece of text. The manifold describes a subject, not a message.
Next
ConditioningPack and VoiceProfile
The basin turned into a prompt your own model can use.
Recall cognitive state
The endpoint behind all four views, including
identity.