> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pult.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> From an empty project to a working inbox, with a record your team can act on.

This takes about ten minutes. You'll end up with an inbox your app sends crashes into, linked to your users, with an action to reset a user's two-factor login.

## 1. Create a project

Sign in at [app.pult.sh](https://app.pult.sh) and add a project. Pult creates its first environment and shows you its key once. Put it in your app's environment as `PULT_KEY`.

```bash theme={null}
PULT_KEY=pult_...
```

## 2. Install

```bash theme={null}
bun add pult@npm:@lantharos/pult
```

npm, pnpm and yarn work the same way. The package is published as `@lantharos/pult` for now, and installing it under the name `pult` keeps your imports as `"pult"`. It's both the library your app imports and the `pult` command.

## 3. Add a config

`pult.config.ts` sits at the root of your app. It names the project and tells Pult where your definitions live.

```ts theme={null}
// pult.config.ts
import { defineConfig } from "pult"

export default defineConfig({
  project: "acme",
  include: ["src/**/*.pult.ts", "pult/**/*.ts"],
  environments: ["dev", "prod"],
})
```

Definitions can live anywhere `include` matches. A common layout keeps resources next to the code they wrap (`src/users/user.pult.ts`) and inboxes, roles and views together in `pult/`.

## 4. Describe a resource

```ts theme={null}
// src/users/user.pult.ts
import { b, resource } from "pult"
import { db } from "../db"

export const user = resource("user", {
  get: (id) => db.users.find(id),
  find: (query) => db.users.search(query),
  title: (u) => u.username,
  render: (u) => [
    b.fields({ email: u.email, plan: u.plan, joined: u.createdAt }),
  ],
  actions: (action) => ({
    resetTwoFactor: action({
      label: "Reset 2FA",
      danger: "confirm",
      when: (u) => u.twoFactor,
      run: ({ record }) => db.users.resetTwoFactor(record.id),
    }),
  }),
})
```

## 5. Add an inbox

```ts theme={null}
// pult/crashes.ts
import { b, inbox } from "pult"
import { z } from "zod"
import { user } from "../src/users/user.pult"

export const crashes = inbox("crashes", {
  icon: "bug",
  resource: user,
  states: ["open", "resolved"],
  reopenOn: "new-occurrence",
  data: z.object({ stack: z.string().max(20_000), version: z.string() }),
  render: (item) => [
    b.chart("occurrences"),
    b.code(item.data.stack, { lang: "trace" }),
  ],
})
```

Schemas can come from zod, valibot, arktype or any library that implements Standard Schema.

## 6. Build

```bash theme={null}
bunx pult build
```

This writes `.pult/manifest.json` and `.pult/index.ts`. Commit both: manifest changes then show up in code review like any other change.

## 7. Connect and send

```ts theme={null}
// src/pult.ts
import { createPult } from "pult"
import project from "../.pult"

export const pult = createPult({ project })
pult.listen()
```

`listen()` opens a WebSocket from your app to Pult. Pult sends action requests down it, so your app needs no public endpoint. Now send something:

```ts theme={null}
import { crashes } from "../pult/crashes"
import { pult } from "./pult"

await pult.send(crashes, {
  fingerprint: topFrame,
  title: `panic in ${topFrame}`,
  record: currentUser.id,
  data: { stack, version: APP_VERSION },
})
```

Open the console. The crash is in the Crashes inbox, linked to the user, with Reset 2FA on it for users who have two-factor turned on. Send the same fingerprint again and the count goes up instead of a new item appearing.

The first environment in your config follows your code: whenever your app connects or sends something with definitions Pult hasn't seen, it deploys them there. See [Connecting your app](/start/connecting) for the rest.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.