---
title: "The Archive Map — a 2-D projection of the corpus"
method: GET
path: "/v2/workspaces/{id}/projection"
tags: ["Memories"]
---

# The Archive Map — a 2-D projection of the corpus

`GET /v2/workspaces/{id}/projection`

## Request

- Base URL: `https://api.infolang.ai`
- URL: `https://api.infolang.ai/v2/workspaces/{id}/projection`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - HTTP bearer

One point per LOGICAL memory (a chunked memory is one place, at the centroid of its chunks), in the unit square. Omit `ns` for every namespace in the workspace; pass it for one — a cold basis costs a PCA FIT per bank, which takes seconds on a large namespace.

THE MAP DOES NOT RESHUFFLE. The basis is fitted once and reused, so a memory written after the fit is placed by the existing basis and moves nothing. `basis_version` is the `corpus_version` the basis was fitted at; `basis_stale` means memories have landed since. Treat that as an OFFER to re-fit (`POST …/projection/refit`), never as a trigger — the point of the feature is that the map stays put.

CACHED per (workspace, namespace, `include_properties`, credential namespace ceiling) with a 5-minute TTL — longer than property-stats because the payload is stable by construction: only a re-fit or a Kairos restart moves a point. `cache.hit` is true when the answer cost no upstream call and therefore no billing.

READ BEFORE DRAWING: do not label an axis flagged in `degenerate_axes` — its points all sit at the constant 0.5, and drawing that as a spatial dimension presents a constant as a finding. Publish `variance_explained`: `[0.21, 0.13]` means the map explains 34% of what the embeddings encode. `skipped` counts memories with no vector at all (pre-ML rows), which are excluded from `points` rather than placed somewhere invented. A point's `properties` value may be an explicit `null` — 'no value', which a color scale must distinguish from a low one. Set `include_properties=false` only if you are not coloring.

Requires the `memories:read` scope. Accepts all three lanes: a session JWT (bounded by the caller's role on this workspace) or an `il_*` machine credential whose own scope set, workspace set and validity window cover it — both ceilings apply and neither can raise the other, so a credential carrying `memories:read` is still refused where the role does not permit it.

A credential with no scope record resolves to `LEGACY_DEFAULT`, which INCLUDES `memories:read` — every key minted before scoping keeps working here.

## Path parameters

- `id` string, required

## Query parameters

- `ns` string
- `include_properties` 'true' | 'false'

## Response `200`

Projected points per namespace

- object
  - `namespaces` object[], required
    - `namespace` string, required
    - `count` integer, required
    - `skipped` integer, required
    - `corpus_version` number, required
    - `basis_version` number, required
    - `basis_stale` boolean, required
    - `basis_memories` integer, required
    - `variance_explained` number[], required
    - `degenerate_axes` boolean[], required
    - `out_of_extent` integer, required
    - `points` object[], required
      - `id` string, required
      - `x` number, required
      - `y` number, required
      - `properties` object
  - `cache` object, required
    - `hit` boolean, required
    - `age_ms` integer, required
    - `ttl_ms` integer, required
    - `corpus_versions` object, required
    - `basis_versions` object, required

## Other responses

- `401`: Missing/invalid credential
- `403`: The credential holds no grant on this workspace. Or `lane_not_supported` — the credential is well-formed but this route does not accept its lane
- `502`: Upstream Kairos failure

---

[API](https://skmtc.dev/infolang/apis/infolang-api.md) · [All operations](https://skmtc.dev/infolang/apis/infolang-api/llms.txt) · [OpenAPI document](https://skmtc.dev/infolang/apis/infolang-api/revisions/d04bf6de72c8?raw)
