Quickstart
Start Mango locally and complete a Session in your preferred language.
Run a text-only Session with the built-in offline model. You will create an Environment and an Agent, send a message, and read its persisted reply. No model-provider account or credentials are required.
Requirements
- Git, Docker with Compose, and
make. curlfor the readiness check;jqif you choose the HTTP example.- One SDK runtime if needed: Node.js 22+, Python 3.11+, or Go 1.24+.
Get the code
git clone https://github.com/yanpgwang/mango.git
cd mangoRun the following commands from this directory.
Run the server
export MANGO_API_KEY=sk-mango-local-development
MANGO_MODEL_BASE_URL= MANGO_MODEL_API_KEY= MANGO_MODEL_ID= \
docker compose -f deployments/local/compose.yaml up -d --build
make local-healthWait for every service to report healthy. The API listens on
http://localhost:8080; Temporal's workflow explorer is at
http://localhost:8233.
curl -i http://localhost:8080/readyzExpect HTTP/1.1 200 OK. The stack initializes the schema with a one-shot
migrate container, then starts Mango's API and orchestration worker,
PostgreSQL, Temporal, NATS, and SeaweedFS. The model variables above explicitly
select offline mode. Later, use Model configuration
to connect a real endpoint.
Local development
The example key and Compose configuration are for local use. Docker shares the host kernel; this stack is not a hardened boundary for untrusted tenants. Use Deployment to review its operating limits.
Run your first Session
Choose a language below. Each command runs a complete application that creates
its own resources and removes them when finished. Keep MANGO_API_KEY set in
this terminal; in a new terminal, export the same value again.
Install the SDK from this checkout
These examples use the current resource-based SDKs, which are not yet published. The commands below install them from source. For use in your own application, see SDK installation.
npm --prefix sdk/typescript ci
npm --prefix sdk/typescript run build
node --experimental-strip-types sdk/typescript/examples/quickstart.tsThe program prints the offline response and persisted history, then finishes with:
Quickstart completedThe offline model exercises the Session lifecycle; it does not generate open-ended answers or choose tools. A successful run confirms that your local stack can accept input, complete a turn, and retrieve its recorded response.
Understand the example
The following snippets come from the complete programs above. They share the
same client and resource variables; run the complete file to execute them
rather than pasting each excerpt as a separate program. Go excerpts belong
inside a function returning error.
Configure the client
MANGO_BASE_URL defaults to http://localhost:8080. Do not append /v1.
The Workspace key authenticates to Mango, not to the model provider.
import { Mango } from 'mango-sdk';
const client = new Mango({
baseURL: process.env.MANGO_BASE_URL ?? 'http://localhost:8080',
apiKey: process.env.MANGO_API_KEY!,
});Create an environment
An Environment groups Sessions by their execution configuration. Omitting
config selects self_hosted. This example has no shell or file tools, so it
completes without a separate Environment worker.
const environment = await client.environments.create({ name: 'Quickstart' });Create an agent
The offline stack uses offline-fake. Agents are versioned; each Session keeps
the resolved definition captured at creation.
const agent = await client.agents.create({ name: 'Assistant', model: 'offline-fake', system: 'Be concise.' });Create a session
Creating the Session without initial events does not start a model turn.
const session = await client.sessions.create({ agent: agent.id, environment_id: environment.id, title: 'First session' });Send a message and observe the turn
Sending an event admits durable work; the response contains accepted input,
not the eventual agent reply. The SDK variants subscribe before sending,
then wait for session.status_idle with stop_reason.type = end_turn.
The HTTP-only variant polls persisted history for this fresh Session's first turn.
// Subscribe before sending: the stream does not replay earlier events.
const stream = await client.sessions.events.stream(session.id, {}, { signal: AbortSignal.timeout(60_000) });
let completed = false;
try {
await client.sessions.events.send(session.id, { events: [{ type: 'user.message', content: [{ type: 'text', text: 'Hello, Mango!' }] }] });
for await (const event of stream) {
if (event.type === 'agent.message') console.log(event.content);
if (event.type === 'session.status_idle') {
if (event.stop_reason.type !== 'end_turn') throw new Error('The turn requires attention');
completed = true;
break;
}
}
if (!completed) throw new Error('Stream ended before completion; reconcile persisted history');
} finally {
await stream.close();
}The examples fail if the stream ends early or the turn needs attention. They do not blindly retry a message after an ambiguous network failure. For an existing or reconnected Session, open a stream and reconcile history before deciding whether to send again. Preview deltas are ephemeral, not durable output.
Read persisted history
SDK iterators follow pagination. With raw HTTP, follow next_page until it is
null; the first-turn example is small enough for one page.
const history = [];
for await (const event of client.sessions.events.listItems(session.id, { order: 'asc', limit: 100 })) history.push(event);
console.log(`Persisted events: ${history.length}`);Clean up
The example deletes its Session and Environment and archives its Agent. Stop the local services when you are done:
make local-downThis keeps the PostgreSQL and SeaweedFS volumes for your next run. Use
make local-down VOLUMES=1 only when you intend to delete the stack's stored data.
Next steps
- Connect a model for open-ended agent work.
- Run a Docker worker to enable shell and file tools.
- Learn the core concepts before adding resources or multi-agent work.
- Explore the examples for approval gates and specialist teams.