# Getting started

A guided, end-to-end path to a running Agent Protocol server, then to production. Pick the path that
matches what you have right now:

- **Nothing yet** → [Path A](#path-a--starting-from-scratch): one command scaffolds a working project.
- **A `langgraph.json`** → [Path B](#path-b--i-have-a-langgraphjson-drop-in): a one-line drop-in.
- **A compiled graph in code** → [Path C](#path-c--i-have-a-graph-in-code-embed): wrap it in `deps`.

All three expose the same Agent Protocol API. For a terse reference instead of a walkthrough, see
[using-skein.md](./using-skein.md).

Deployment is a separate choice: keep the default memory drivers while developing, use
[Postgres/Redis](./deploy.md) for a shared server, or choose
[SQLite for a local app or one Node process](./local-deployment.md). The graphs and Agent Protocol
remain the same.

## Prerequisites

- **New projects (Path A):** Node 24 is recommended. Generated engines support `^22.12.0 || ^24.0.0 || ^26.0.0`.
- **Existing graphs (Paths B and C):** Node ≥ 20 and a package manager (`pnpm`/`npm`).
- **Node 22, 24 or 26** when selecting SQLite; desktop examples build with Node 24.
- For Paths B and C, a
  **[LangGraph.js graph](https://docs.langchain.com/oss/javascript/langgraph/graph-api)** — a
  `CompiledStateGraph` from `@langchain/langgraph`. Path A writes one for you.

<span id="path-a--starting-from-scratch"></span>

## Path A — Starting from scratch

No graph, no config, no LangGraph experience. One command:

```bash
npm create skein-js@latest my-agent
cd my-agent
npm run dev            # → http://localhost:2024, console at /console
```

You get a `langgraph.json`, a keyless echo graph you can edit, a test, and the whole
`dev` → `build` → `start` lifecycle wired up. ESLint and Prettier are enabled by default;
`--no-linting` opts out. The default memory development server needs no API key or database.

[**Your first agent**](./your-first-agent.md) walks through it end to end — what each generated file
does, the four LangGraph concepts you need, adding a model and a tool, then deploying.
[scaffolding.md](./scaffolding.md) is the flag-by-flag reference, and covers doing it by hand if you
would rather not run a scaffolder.

<span id="path-b--i-have-a-langgraphjson-drop-in"></span>

## Path B — I have a `langgraph.json` (drop-in)

If you already run `langgraph dev`, this is a one-line change. Keep your `langgraph.json` exactly as
it is:

```jsonc
// langgraph.json
{ "graphs": { "agent": "./src/agent.ts:graph" } }
```

Swap the CLI:

```diff
- "dev": "langgraph dev",
+ "dev": "skein dev",
```

```bash
pnpm add -D skein-js
pnpm dev            # skein dev — in-process, hot-reload, on http://localhost:2024
```

`skein dev` loads your TypeScript graphs, hot-reloads on save, and restores development state across
restarts. Saving a model key in `.env` also reloads the graphs. See the
[CLI reference](./langgraph-cli-compat.md) for supported commands, fields, and limitations.

Prefer to mount it inside your own Express/Fastify/Nest/Next app instead of the CLI? Point an adapter
at the same config — `{ config: "./langgraph.json" }` — using the snippets in
[Mount it on your framework](./using-skein.md#mount-it-on-your-framework).

<span id="path-c--i-have-a-graph-in-code-embed"></span>

## Path C — I have a graph in code (embed)

No `langgraph.json`, no CLI — bring the compiled graph you already hold and wrap it into a
`ProtocolDeps` with `embedInMemoryGraphs`, then hand `{ deps }` to any adapter:

```ts
// server.ts
import { createExpressServer } from "@skein-js/express";
import { embedInMemoryGraphs } from "@skein-js/server-kit";
import { graph } from "./agent.js"; // your CompiledStateGraph

const server = await createExpressServer({ deps: embedInMemoryGraphs({ agent: graph }) });
await server.listen(2024);
console.log("Agent Protocol on http://localhost:2024");
```

```bash
pnpm add @skein-js/express @skein-js/server-kit @langchain/langgraph
npx tsx server.ts              # or your usual TS runner
```

This exposes the same Agent Protocol API. Your host owns development reload and process lifetime;
see [embedding](./embedding.md) for graph factories and production drivers.

## Verify your project

For CLI paths A and B, open the printed **Console** URL. Select your graph's Assistant in Playground,
send a known input, and compare the response with its expected result. A scaffolded **echo** graph
returns `echo: hello` when you send `hello`. For structured graphs, choose JSON and follow the input
schema. See [Test your graph in the console](./console.md#test-your-graph).

Path C does not mount the console automatically. Use the SDK below, or follow the
[manual mounting reference](./console-reference.md#mounting-it-yourself).

If you scaffolded a project, run `npm test` from its directory: the generated echo tests need neither
credentials nor a server. See [Testing your project](./testing-your-project.md) for repeatable graph
assertions and an SDK smoke test against your own server.

## Talk to your server

With the server running on `:2024`, call it with the standard SDK. Install the client in the calling
project if it is not already declared:

```bash
pnpm add @langchain/langgraph-sdk
```

The examples below use the scaffold's `echo` Assistant and its `messages` input. For Paths B and C,
set `assistantId` to your configured graph key (such as `agent`) and adapt the input to its schema.

```ts
import { Client } from "@langchain/langgraph-sdk";

const client = new Client({ apiUrl: "http://localhost:2024" });
const assistantId = "echo";
const thread = await client.threads.create();
const reply = await client.runs.wait(thread.thread_id, assistantId, {
  input: { messages: [{ role: "user", content: "hello" }] },
});
console.log(reply);
```

Stream tokens as they arrive instead of waiting:

```ts
for await (const event of client.runs.stream(thread.thread_id, assistantId, {
  input: { messages: [{ role: "user", content: "hello" }] },
})) {
  console.log(event.event, event.data);
}
```

Each registered graph has a default Assistant whose `assistant_id` equals its graph key. The full endpoint surface is in
[agent-protocol.md](./agent-protocol.md); the stream wire format is in [streaming.md](./streaming.md).

## Add a web UI

Follow [the frontend SDK guide](./react-sdk.md#usestream-against-skein-js) to install the React
binding and build a UI that displays messages, errors, and cancellation controls. Test it against the
same Assistant you used above.

A browser on a different origin needs CORS enabled — see the
[CORS recipe](./recipes/serving.md#cors-for-a-browser-client). For a same-origin full-stack app (no CORS), the
[`nextjs-app`](https://github.com/skein-js/skein-js/tree/main/examples/nextjs-app) example serves the protocol and the UI from one Next.js app.

## Go to production

The default dev server uses in-memory drivers. For a durable shared server, choose Postgres for
state and checkpoints, and add Redis when workers or streaming clients span instances.

For an embedded backend (Path C), install `@skein-js/runtime` before using the durable helper:

```bash
pnpm add @skein-js/runtime
```

```ts
// embed path → durable, reading POSTGRES_URI / REDIS_URI from the environment
import { embedPostgresGraphs } from "@skein-js/runtime";
import { createExpressServer } from "@skein-js/express";
import { graph } from "./agent.js";

const { deps, dispose } = await embedPostgresGraphs({ agent: graph });
const server = await createExpressServer({ deps });
await server.listen(2024);
process.on("SIGTERM", async () => {
  await server.close();
  await dispose(); // release the pools it opened
  process.exit(0);
});
```

From a `langgraph.json`, either call `buildRuntime({ store: "postgres", queue: "redis" })` and pass its
`deps` **and** `channels` to the adapter, or skip code entirely: `skein dev --store postgres --queue
redis`, and `skein build` / `skein up` to containerize. Redis is optional for a single instance but
required to run more than one. Details:
[embedding.md](./embedding.md#going-to-production), [storage.md](./storage.md),
[runs-and-redis.md](./runs-and-redis.md), [deploy.md](./deploy.md).

### Or choose SQLite for a local application

Scaffold with `npm create skein-js@latest my-app -- --storage sqlite` for SQLite dev/start scripts,
or install `@skein-js/local` and the upstream SQLite saver in an existing project:

```bash
pnpm add @skein-js/local @langchain/langgraph-checkpoint-sqlite@~1.0.4
pnpm skein dev --store sqlite --queue sqlite
```

The CLI defaults to `.skein/state.sqlite`. For an Electron utility process, a Tauri Node backend,
or a CLI using graphs in code, use `embedSqliteGraphs` and let the host own startup and shutdown.
See [local deployment](./local-deployment.md) for embedding, examples, and failure accounting.

## Where to next

- [Your first agent](./your-first-agent.md) — the from-zero walkthrough, if you took Path A.
- [Recipes](./recipes/) — auth, human-in-the-loop, long-term memory, CORS, background runs, deploy.
- [Using skein-js](./using-skein.md) — the terse consumer/agent cheat-sheet.
- [Examples](https://github.com/skein-js/skein-js/tree/main/examples) — a runnable project per framework and pattern.
- [Overview & architecture](./index.md) · [Agent Protocol surface](./agent-protocol.md)
