npm package: @native-stack/nano
Description: Zero-dependency persistent state machine for AI agents — powered by Node.js 24 native APIs.
Author: Native Stack
Latest version: 1.0.0

# @native-stack/nano

**Zero-dependency persistent state machine for AI agents.**

> Built on Node.js 24+ native APIs — no ORMs, no bundlers, no polyfills.

[![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](./package.json)
[![Node.js 24+](https://img.shields.io/badge/node-%3E%3D24-5FA04E?logo=node.js&logoColor=white)](https://nodejs.org)
[![MIT License](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)

---

## Why Nano?

Modern AI agents need **memory that survives restarts** — conversation state, tool call history, workflow progress. Most solutions pull in ORMs, key-value stores, or cloud SDKs.

Nano takes a different path: **Native-First**.

| Feature | Nano | Typical Alternative |
|---|---|---|
| Dependencies | **0** | 10–200+ |
| Database | Node.js built-in `node:sqlite` | External install required |
| Test runner | Node.js built-in `node:test` | Jest / Vitest / Mocha |
| Module system | Native ESM | Bundler/transpiler needed |
| Persistence | Atomic, WAL-mode SQLite | In-memory / ephemeral |

One import. One file. Zero setup.

---

## Install

```bash
npm install @native-stack/nano
```

> **Requires Node.js 24 or higher.** The `node:sqlite` module is a built-in available from Node.js 24+.

---

## Quick Start

```js
import { Nano } from '@native-stack/nano';

// Create a named state machine (persisted to nano.db by default)
const agent = new Nano({ name: 'support-agent' });

// Record state transitions
agent.transition('greeting', { user: 'alice', channel: 'web' });
agent.transition('collecting_info', { issue: 'billing' });
agent.transition('resolved', { resolution: 'refund issued' });

// Read the current state
console.log(agent.current);
// {
//   id: 3,
//   machine: 'support-agent',
//   state: 'resolved',
//   data: { resolution: 'refund issued' },
//   createdAt: '2026-02-16T00:00:00.000Z'
// }

// Get the full history (most recent first)
console.log(agent.history());

// Get only the last 2 transitions
console.log(agent.history(2));

// Clean up
agent.close();
```

---

## API Reference

### `new Nano(options)`

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `name` | `string` | *required* | Unique identifier for this state machine |
| `dbPath` | `string` | `"nano.db"` | Path to the SQLite database file |

### Instance Members

| Member | Type | Description |
|--------|------|-------------|
| `.name` | `string` | The machine name (read-only) |
| `.current` | `Snapshot \| null` | Latest transition snapshot, or `null` if none |
| `.transition(state, data?)` | `Snapshot` | Records a transition and returns the new snapshot |
| `.history(limit?)` | `Snapshot[]` | Returns transitions in reverse chronological order |
| `.close()` | `void` | Closes the database connection (idempotent) |

### `Snapshot`

```ts
{
  id: number;        // Auto-incremented transition ID
  machine: string;   // State machine name
  state: string;     // State name
  data: any;         // Deserialized payload
  createdAt: string; // ISO 8601 timestamp
}
```

---

## Multiple Machines, One Database

Multiple agents can share a single database file — each machine's state is fully isolated.

```js
const planner = new Nano({ name: 'planner', dbPath: 'agents.db' });
const executor = new Nano({ name: 'executor', dbPath: 'agents.db' });

planner.transition('planning', { tasks: ['a', 'b'] });
executor.transition('idle', {});

// Each sees only its own state
console.log(planner.current.state); // 'planning'
console.log(executor.current.state); // 'idle'
```

---

## Requirements

- **Node.js ≥ 24.0.0** — uses the native `node:sqlite` module
- **Zero runtime dependencies** — nothing to install, audit, or update

---

## License

[MIT](./LICENSE) — © 2026 Native Stack