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

# Quickstart

> Scaffold an app, run it against your workspace and change your first block.

> Reintersect apps are in developer preview. Names and limits can still change before general
> release.

This guide takes about ten minutes. At the end you have an app running on your machine, a block you
can insert into a conversation, and a playground that shows the block the way members, share pages
and agents see it.

Using Effect? See [Build with Effect](/effect).

## Before you start

* Node.js 22 or later (the templates use Node 24 in CI), or Bun 1.3 or later.
* A Reintersect account. Any member can build apps; you don't need to be an admin to develop one.

## Create the app

<Steps>
  <Step title="Scaffold a project">
    Run the scaffolder and answer its prompts:

    <CodeGroup>
      ```bash npm theme={null}
      npm create reintersect@latest
      ```

      ```bash pnpm theme={null}
      pnpm create reintersect@latest
      ```

      ```bash bun theme={null}
      bun create reintersect
      ```
    </CodeGroup>

    It asks for:

    | Prompt | Default | Choices |
    | - | - | - |
    | What's your app called? | `my-reintersect-app` | Any name with lowercase letters, digits, `-`, `.` or `_`. It names the folder, the app and its slug. |
    | How should your app run? | Reintersect hosting | Reintersect hosting (Workers), Next.js route, Hono on Bun, Effect (`HttpLayerRouter`) |
    | Which schema library? | Zod | Zod, ArkType, Valibot. The Effect template always uses Effect Schema. |
    | Which package manager? | The one running the command | npm, pnpm, Bun |

    Skip the prompts with flags, for example
    `npm create reintersect@latest tasks -- --template next --schema arktype --yes`:

    | Flag | Meaning |
    | - | - |
    | `--template`, `-t` | `hosted` (default), `next`, `hono-bun` or `effect`. |
    | `--schema` | `zod` (default), `arktype` or `valibot`. |
    | `--pm` | `npm`, `pnpm` or `bun`. Defaults to the one running the command. |
    | `--yes`, `-y` | Use defaults for everything you didn't pass. |
    | `--no-install`, `--no-git` | Skip installing dependencies or creating a git repository. |
    | `--login`, `--dev` | Run `reintersect login` and `reintersect dev` when the app is ready. |

    `npm create reintersect@latest -- --help` lists every flag and template.

    The project contains a Task block with a `move` action, a task reference with search, typed
    environment variables and install config, tests, a GitHub workflow that deploys with
    [`reintersect/deploy@v1`](/ci), and an `AGENTS.md` with an SDK skill so coding agents follow the
    same conventions.
  </Step>

  <Step title="Sign in">
    The scaffolder offers to sign you in at the end. To do it later:

    ```bash theme={null}
    npx reintersect login
    ```

    The CLI prints a link and a code. Open the link, check that the page shows the same code, and
    approve it. The CLI then stores a key for your workspace in
    `~/.config/reintersect/credentials.json`.
  </Step>

  <Step title="Start the dev server">
    ```bash theme={null}
    npm run dev
    ```

    `reintersect dev`:

    1. Creates a personal development app in your workspace the first time it runs, with a
       development install only you can use.
    2. Syncs the manifest built from your code (blocks, references, actions, scopes and events) every
       time you save.
    3. Runs your app locally and opens a relay from Reintersect to it. Every delivery for your
       development install is replayed to your machine as the exact signed request production would
       send.
    4. Prints a playground link.

    Hosted apps run locally in the same Workers runtime Reintersect uses in production (Miniflare).
    Self-hosted templates run in a local Node server the CLI starts. Put local values for your
    environment variables in `.dev.vars`.
  </Step>

  <Step title="Open the playground">
    The playground link opens your app's playground in Reintersect. It renders each block with sample
    props in three modes:

    | Mode | Shows |
    | - | - |
    | Interactive | What a member with write access sees, with working buttons and inputs. |
    | Read-only | What share pages and connected workspaces see, with actions hidden. |
    | Agent text | The plain-text projection the Reintersect agent reads. |

    Click **Start** in the interactive view. The request goes through the relay to your machine, and
    the dev panel in your terminal shows the delivery.
  </Step>
</Steps>

## Change the block

Open `src/taskBlock.tsx`. The scaffolded block looks like this (with Zod schemas from
`src/schemas.ts`):

```tsx src/taskBlock.tsx theme={null}
import { defineAction, defineBlock } from "@reintersect/sdk/app";
import { Actions, Block, Button, Fact, Facts, Header, Status } from "@reintersect/sdk/components";
import { env, InstallConfig, MoveTask, TaskProps, TaskState, type TaskStatus } from "./schemas";
import { taskUrl, updateTaskStatus } from "./tasks";

const STATUS_LABELS = { todo: "To do", doing: "In progress", done: "Done" } as const satisfies Record<TaskStatus, string>;

const STATUS_STATES = { todo: "neutral", doing: "running", done: "success" } as const satisfies Record<TaskStatus, string>;

const NEXT_MOVES = {
  todo: { status: "doing", label: "Start" },
  doing: { status: "done", label: "Mark done" },
  done: { status: "todo", label: "Reopen" },
} as const satisfies Record<TaskStatus, { status: TaskStatus; label: string }>;

export const moveTask = defineAction(
  "move",
  { args: MoveTask, state: TaskState, description: "Move the task to another status" },
  async ({ args }) => {
    await updateTaskStatus(args.id, args.status);

    return { state: { status: args.status }, notice: `Moved to ${STATUS_LABELS[args.status]}` };
  },
);

export const TaskBlock = defineBlock({
  type: "task",
  title: "Task",
  description: "A task from your tracker, with its status and a button to move it along.",
  icon: "list-todo",
  insertable: true,
  props: TaskProps,
  state: TaskState,
  initialState: { status: "todo" },
  actions: { move: moveTask },
  env,
  config: InstallConfig,
}).render((props, { actions, config, env: blockEnv, state }) => {
  const next = NEXT_MOVES[state.status];

  return (
    <Block summary={`${props.id} ${props.title}: ${STATUS_LABELS[state.status]}`}>
      <Header
        href={taskUrl(blockEnv.TASKS_URL, props.id)}
        trailing={<Status state={STATUS_STATES[state.status]} label={STATUS_LABELS[state.status]} />}
      >
        {props.title}
      </Header>
      <Facts>
        <Fact label="Project">{config.project}</Fact>
        <Fact label="Assignee">{props.assignee ?? "Unassigned"}</Fact>
      </Facts>
      <Actions>
        <Button label={next.label} action={actions.move.with({ id: props.id, status: next.status })} />
      </Actions>
    </Block>
  );
});
```

Change the `Fact` label, save, and the playground re-renders. Now try a mistake: add
`destructive: true` to `moveTask`. TypeScript reports that the button needs a `confirm` prop, because
Reintersect asks members to confirm destructive actions. The dialog's button repeats the button's
label, and the button switches to the danger style:

```tsx theme={null}
<Button
  label={next.label}
  action={actions.move.with({ id: props.id, status: next.status })}
  confirm={{ title: `${next.label} this task?` }}
/>
```

## Use it in a conversation

Open a conversation in your workspace, type `/` and pick **Task**. Reintersect shows a form for the
block's required props, then inserts it. A development install belongs to you alone: other members
see its blocks with a "Dev" label, and only you can insert them or run their actions.

Paste `https://tasks.example.com/tasks/TASK-1` into a message too: the task reference resolves into a
chip, and the card display shows the Task block.

<Tip>
  Leave `reintersect dev` running while you test. When it stops, your development blocks keep their
  last tree, and clicking an action fails with an "offline" error until you start it again.
</Tip>

## Test, check and deploy

Run the tests and the same checks CI runs:

```bash theme={null}
npm test
npm run check
```

`reintersect check` builds the app, renders every block with sample props, and reports problems the
type checker can't see, such as a tree over the size limit or a pattern for a domain you didn't
claim. Signed in, it also sends the rendered trees to Reintersect's own validator.

Then deploy a preview to your development app:

```bash theme={null}
npx reintersect deploy --preview
```

For production, deploy to an app by id. Create one in **Settings → Developer → Apps** (or use your
development app's id), then:

```bash theme={null}
npx reintersect deploy --app app_123
```

A hosted app uploads its bundle; a self-hosted app syncs its manifest and endpoint. A workspace admin
can then install the app from its [install link](/concepts/install-and-consent#install-link). For
deploys from GitHub on every merge, see [GitHub Action](/ci).

## Next steps

<Columns cols={2}>
  <Card title="How apps are composed" icon="shapes" href="/concepts/composition">
    Blocks, references, events, commands and message actions are standalone pieces. Learn how they
    combine into one app.
  </Card>

  <Card title="Blocks" icon="square-stack" href="/blocks/overview">
    State, actions, viewer inputs, sections and forms.
  </Card>

  <Card title="Component catalog" icon="layout-grid" href="/components/overview">
    Every component with its props, read-only behaviour and agent text.
  </Card>

  <Card title="References" icon="link" href="/references/overview">
    Teach Reintersect your links.
  </Card>
</Columns>


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