Continual Platform

Introduction

Continual Platform serves MGPT — Masking Generative Pretrained Transformer — through one API: Entities. An entity is a persistent being. Its conversation lives with the model that formed it, so you send only the new message, never the history, and you are never billed for the history again.

Base URL: https://platform.continualmi.com/v1

  • POST /v1/entities — create an entity.
  • POST /v1/entities/{id}/messages — talk to it, streamed.
  • GET /v1/entities/{id}/window — see exactly what it remembers.

Current backbone: a routed open 27B. Native MGPT weights are in training; entities carry over by replay.

Authentication

Every request carries a bearer token created on the Keys page. The secret half of a key is shown once, at creation, and stored only as a hash — if you lose it, create another key.

Authorization: Bearer cmi_live_<public>.<secret>
Content-Type: application/json

Quickstart

Create an entity once. Then every message is one line.

export CONTINUAL_API_KEY="cmi_live_..."
BASE=https://platform.continualmi.com/v1

# 1. Create an entity. Keep the id; it is the whole memory.
ENTITY=$(curl -s $BASE/entities \
  -H "Authorization: Bearer $CONTINUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "mgpt-1-27b", "name": "Ada", "instructions": "You are Ada, a careful research assistant." }' \
  | jq -r .entity_id)

# 2. Talk to it. The reply streams; the entity remembers.
curl -N $BASE/entities/$ENTITY/messages \
  -H "Authorization: Bearer $CONTINUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "content": "I am working on a 4B model that should beat a 27B on code." }'

# 3. Tomorrow, from anywhere, with no history in the request.
curl -N $BASE/entities/$ENTITY/messages \
  -H "Authorization: Bearer $CONTINUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "content": "Where did we leave off?" }'

Replies stream as server-sent events in the standard chunk shape, so any streaming chat parser reads an entity unchanged. Pass "stream": false for a buffered chat.completion object.

Entities

A stateless chat API makes the caller own the conversation and resend it — and pay for it — on every turn. With an entity the conversation lives server-side with the model. The client sends the new message; the platform composes what the model sees.

Three things are stored per entity:

ContentsGrows
headinstructions, name, modelno
windowwhat the model sees: summary blocks plus the still-alive messagesbounded by budget
transcriptevery message ever, append-onlyforever

model is fixed at creation. Changing it is a new entity, not a field update.

Memory

The window has a token budget. When a new message pushes it over, the platform takes the oldest span of the window, has the entity write a summary of it, and replaces that span with one summary block. The transcript keeps the originals forever; rotation changes what the model sees, never what you own.

Each summary block records exactly which transcript range it stands for (covers), so memory is auditable: you can always see what was folded into what. This is summarize-and-rotate at the platform layer today. When native MGPT weights serve, the same rotation happens inside the model over its own KV state — storage changes, the wire does not, and your entity carries over by replay.

Streaming

POST /v1/entities/{id}/messages streams by default: SSE data: lines carrying chat.completion.chunk objects, a usage chunk, then [DONE]. Set "stream": false for a single buffered response with an added entity_id field.

data: {"choices":[{"delta":{"content":"We were "}}]}
data: {"choices":[{"delta":{"content":"comparing..."}}]}
data: {"usage":{"prompt_tokens":812,"completion_tokens":61,"total_tokens":873}}
data: [DONE]

Writes and retries

This API is stateful, so two messages in flight to one entity would interleave rotation and corrupt its memory. Writes to an entity are serialized: a message sent while another is being answered gets 409. Wait for the stream to finish and retry.

Send an Idempotency-Key header (or idempotency_key in the body) with every message. A client retrying after a dropped connection would otherwise append the same message twice — in a stateful API that is a permanent corruption of memory, not a duplicate response you can discard. With a key, a retry returns the reply the entity already gave.

curl -N $BASE/entities/$ENTITY/messages \
  -H "Authorization: Bearer $CONTINUAL_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1f0a2e-msg-0412" \
  -d '{ "content": "Summarize the plan so far." }'

Inspecting the window

An entity that silently rewrites its own memory would not be debuggable, so the live window is readable. If a reply surprises you, look at what the model was actually shown.

curl $BASE/entities/$ENTITY/window -H "Authorization: Bearer $CONTINUAL_API_KEY"

{
  "entity_id": "…",
  "object": "entity.window",
  "budget_tokens": 32000,
  "tokens": 1418,
  "blocks": [
    { "kind": "summary", "role": "system", "tokens": 210, "covers": [1, 38], "content": "- Project: 4B model to beat a 27B on code…" },
    { "kind": "message", "role": "user",      "tokens": 12,  "covers": [39, 39], "content": "Where did we leave off?" },
    { "kind": "message", "role": "assistant", "tokens": 61,  "covers": [40, 40], "content": "We were comparing…" }
  ]
}

GET /v1/entities/{id}/messages?after=&limit= pages through the full transcript, rotated or not.

Export and delete

GET /v1/entities/{id}/export returns the transcript as JSON, or with Accept: application/x-continual-entity a tar archive of manifest.json, transcript.json and window.json. The archive is the container the entity's model state joins when native weights serve; the format does not change then.

DELETE /v1/entities/{id} is a hard delete of transcript, window and state, not a flag. It returns 202 and completes within 24 hours across backups. It is irreversible; export first if you might want it back.

Limits

  • Window budget: 32,000 tokens, well inside the model's context, so a turn never fails for length.
  • Transcript cap: 1,000,000 tokens. At the cap the entity becomes read-only (409 on new messages) rather than silently dropping its oldest memories. Export it, or start a new entity.
  • Token counts on blocks and messages are estimates until the native engine reports exact ones.

Continual CLI

continual is a coding agent in your terminal, talking to this platform. No provider flag, no model flag, no config file: type it and get an agent whose memory is an entity.

The CLI is in preparation. The commands below are its contract; the installer goes live with the first release.

Install

curl -fsSL https://continualmi.com/install | sh

Linux and macOS, x64 and arm64. The installer detects your platform, verifies the checksum, installs to ~/.continual/bin and adds it to your PATH. There is no package manager, no npm, no Homebrew — one binary.

Sign in

continual login

Opens the Keys page, takes the key you paste, validates it against the platform, and stores it in ~/.continual/auth.json (mode 0600). The first run without a key walks you through this. A CONTINUAL_API_KEY environment variable takes precedence when set.

Use

cd your-project
continual

The agent reads and edits files, runs commands, and talks to mgpt-1-27b through your key. Usage is billed to your balance like any other request.

Update and remove

continual update      # fetch the latest release in place
continual licenses    # MIT notices for the agent and its dependencies
rm -rf ~/.continual   # uninstall: binary, auth, everything

Models

  • mgpt-1-27b — the model. One id, priced at cost, on the Models page.

Model ids are platform ids and stay stable. Which weights or hardware serve a given id is ours to change; your entities and your code keep the same name.

Billing

Usage is charged against a prepaid dollar balance on your Continual account. There is no subscription and nothing recurring — add funds when you want them, pay for what you use.

For an entity, you are billed for:

  • input — the new message you send;
  • output — the reply;
  • storage — per entity. Not charged during the preview.

Never billed: the history. The window the platform resends to the model on each turn, and the summaries rotation writes, are our cost. You sent a message once; you pay for it once.

When the balance reaches zero, requests are refused with 402 rather than queued or degraded; add funds and the same key resumes immediately.

Errors

Errors return JSON with an error field and a matching HTTP status.

{ "error": "Entity is busy: writes to an entity are serialized. Retry after the current message completes." }
  • 400 — malformed request, missing content, or an unsupported model id.
  • 401 — missing, malformed, or revoked key.
  • 402 — insufficient balance; the body also reports balanceUsd, billedUsd, and missingUsd.
  • 404 — no entity with that id on this account.
  • 409 — the entity is answering another message, or its transcript is at the cap and read-only.
  • 5xx — upstream or platform failure. A failed turn leaves no trace in the entity; retry with the same idempotency key.

Logs

Every request is recorded with its status, duration, model, token counts, and cost. Usage shows your own traffic, which is the fastest way to see what a request cost and why one failed.