> Complete page index for agents: https://haystack.sh/llms.txt

# Set up Haystack

You are a coding agent, and your user asked you to set up Haystack in this repository. Follow these steps in order. When you are done, `haystack verify` works here: after a code change it runs the app with and without the change, explores both side by side, and reports where the change shows up and what broke.

There is no configuration file to keep in the repository. Haystack works out how to run the app from what the repository already keeps working: lockfiles, Dockerfiles, compose files, package scripts. What you already know about running it saves most of that work, so step 3 has you write it down as notes.

## Rules

- Ask your user only for what you cannot do yourself. Setup needs them for two things: entering a sign-in code on GitHub, and installing the Haystack GitHub App if it is not installed yet. Telemetry (step 7) needs their answers and a few actions only they take.
- Never print, log or commit a secret. Setup needs none from you. Never run `haystack telemetry token` or touch the token it writes: that is your user's.
- Keep changes inside this repository. Ask before changing anything global, such as installing the CLI globally (step 2).
- Show your user what `haystack init` will change before you let it change anything.
- Check each step with the command given, and report only what the commands printed.
- If a step fails in a way you cannot fix, or the instructions are wrong, tell the Haystack team in a sentence: `haystack feedback "<what happened>"`. They see it at once.

## 1. Check the repository

```bash
git remote get-url origin
```

It must name a repository on github.com. If it does not, stop and tell your user that Haystack verifies GitHub repositories.

## 2. Get the CLI

```bash
haystack feedback --help >/dev/null 2>&1 && echo "use: haystack" || npx -y -p @haystackeditor/cli@latest haystack --version
```

If it printed `use: haystack`, the installed CLI is new enough: use `haystack` below. Otherwise it printed the version npx fetched: use `npx -y -p @haystackeditor/cli@latest haystack` in place of `haystack` in every command below (the `-p` and `haystack` are needed: the package has two commands, and npx cannot pick one without them). Do not install anything globally on your own.

A global install only matters with Claude Code: without one, `haystack init` leaves out Claude Code's Stop hook and says so in its `notices`. When that notice appears, offer `npm install -g @haystackeditor/cli@latest` in the same message as the changes from step 3. If your user agrees to both, install it before step 5, and step 5 adds the hook as well.

It needs Node.js 22.18 or newer. The package is `@haystackeditor/cli`; the unscoped `haystack` package on npm is unrelated. If `haystack` rejects a command below as unknown, it is too old: use the npx form.

## 3. Preview the setup

First write what you know about running this app as notes, in a file outside the repository. Onboarding plans from them instead of guessing (a wrong guess at the start command costs it up to half an hour):

```bash
cat > "${TMPDIR:-/tmp}/haystack-notes.json" <<'EOF'
{
  "run": "...",
  "signIn": "...",
  "workflow": "..."
}
EOF
```

- `run`: how production installs, builds and starts the app: the commands and the directory each runs in, the port, the databases and services it needs and their versions, migrations and seed data, and the environment variables it reads (their names and what they are for, never secret values).
- `signIn`: how a person gets an account and signs in (a sign-up page, a first-start admin, an invitation), and the kinds of users the app has.
- `workflow`: what a signed-in user mainly does, step by step through the screens.

Write only what the repository or your own work in it shows you, in plain sentences, and leave out a note you do not know. Onboarding still proves everything it takes from them.

```bash
haystack init --json --notes "${TMPDIR:-/tmp}/haystack-notes.json"
```

Without `--yes` it changes nothing. Act on its exit code (the JSON `status` says the same):

| Exit | `status` | What to do |
|---|---|---|
| 4 | `login-required` | Sign in (step 4). The output already lists the `changes`: show them in the same message as the sign-in code and ask your user to approve them too, so they answer once. |
| 2 | `planned` | Show your user each entry of `changes` (its `path`, `reason` and `diff`) and ask whether to apply them. If they agree, step 5. |
| 5 | `app-required` | Ask your user to install the Haystack GitHub App on the repository's owner (it needs an owner admin) at https://github.com/apps/haystack-code-reviewer-pr-hook/installations/new, then run this step again. |
| 0 or 3 | `done` | Nothing needed changing, and onboarding has started (3: it is blocked). Go to step 6. |
| 6 | `done` | Onboarding stopped before finishing. Run this step again. |
| 1 | (the error envelope) | Show your user `error`. |

Show your user any `notices` as well: things init left alone, and why.

## 4. Sign in (only when step 3 said `login-required`)

Skip this step otherwise: you are already signed in.

```bash
haystack login --no-wait --json
```

Tell your user: "Open `verificationUri` and enter the code `userCode`" (the values it printed), together with the changes from step 3 if they have not approved them yet. Then run:

```bash
haystack login
```

It returns once they have entered the code. If your shell times out first, run it again: it keeps waiting on the same code until GitHub expires it, about 15 minutes after step 4 began.

## 5. Apply the setup

```bash
haystack init --yes --json --notes "${TMPDIR:-/tmp}/haystack-notes.json"
```

It makes the changes it showed, gives Haystack your notes (`notes` in its output says `written`, or `unchanged` when it already had them) and starts onboarding the app on Haystack. At most it changes:

- `.claude/settings.local.json`: a Claude Code Stop hook, `haystack verify precompute --hook`, that prepares each change for `haystack verify` when a session stops. Only when Claude Code is in use; the file is per developer, and init keeps it out of commits.
- `AGENTS.md` (and `CLAUDE.md` when the repository has one): a short marked note telling coding agents to run `haystack verify` after a change.

Its exit codes are those of step 3. Do not commit or push unless your user asks.

## 6. Check onboarding

```bash
haystack verify onboarding --json
```

Onboarding reads the repository, builds the app, starts it with its databases and services, prepares its data and test accounts, and proves one workflow works. The app runs on Haystack's isolated machines with no internet access; nothing touches your user's production systems. The first onboarding can take half an hour. You do not need to wait for it.

- `onboarding.state` is `onboarding` or `ready`: setup is done.
- `blocked`, and `block.ask.question` is present: show your user `block.ask.message` and the `choices`, file their pick with `haystack verify answer <question id> "<choice>"`, then run `haystack init --json` to continue.
- `blocked` otherwise: show your user `block.reason`, and `block.ask.message` when there is one. When the reason is something you know better (how the app starts, a service it needs, how people sign in), correct your notes and run step 5 again: new notes start a new onboarding.
- `incomplete`, `cancelled` or `not-started`: run `haystack init --json` to start it again.

`dataAbsences` and `versionChoices` are notes for your user, for example that the app ran with an empty database, or which version of a service was picked because the repository does not pin one.

## 7. Set up telemetry

Telemetry shows Haystack how real people use the app: their journeys through its pages (a tag in the browser, once visitors consent), the shapes and settings of the data its server handles, and how often a value is missing. Haystack then explores what real users do.

Every `haystack init` also plans telemetry. Until it has your user's answers, only telemetry waits: in the output, `telemetry` parts that are `manual` list in their `steps` what to ask. Ask your user, in one message, for what they list (never guess an answer):

- which app serves production, when the repository has several;
- the app's production origins, for example `https://app.example.com`;
- whether the site asks visitors for consent, and with which consent platform, or that they have decided consent is not required.

Preview it with their answers (repeat `--origin` for each origin; `--app` only when the repository has several apps):

```bash
haystack init --json --app <dir> --origin <origin> --consent <platform, or not-required>
```

Show your user the new `changes` and any `notices`, as in step 3. If they agree, apply them:

```bash
haystack init --yes --json --app <dir> --origin <origin> --consent <platform, or not-required>
```

Then go through `telemetry` and `telemetrySteps` in its output with your user:

- `.haystack/telemetry-settings.proposed.json` is a proposal of the settings whose values telemetry would record; nothing is recorded until your user approves it. Show it to them. They approve it themselves with `haystack telemetry settings --approve`, which shows the diff and writes `.haystack/telemetry-settings.json`; then commit that file. Never approve it yourself.
- A part that is `manual` lists the exact `steps` to take; `unsupported` says why.
- Ask your user to run `haystack telemetry token --repo <owner/name>` themselves, in their own terminal, and to set the three variables it prints in production's server environment. Never run it yourself, and never ask for the token.
- When `dbProfileCommand` is set, ask your user to run it themselves with read access to production's database, then the `show` and `upload` commands `telemetrySteps` lists.
- Tell your user the off switches: `HAYSTACK_TELEMETRY=0` turns server telemetry off, and removing the tag turns the browser tag off.

Once your user has deployed, run the same `haystack init --json` command again. `telemetry.capture.received` and `telemetry.server.received` show the newest telemetry Haystack holds; null means nothing has arrived yet, and `stale` means nothing in the last day.

## 8. Report

Tell your user, using only what the commands printed: which files `haystack init` changed, the onboarding state (and why, if it is blocked), any notes from step 6, which telemetry parts are set up and what is left for them to do, and that from now on you will run `haystack verify` after changing the app's code.

## After setup: the loop

After you change the app's code, or when your user asks you to check a change, two steps:

```bash
haystack verify  # the handshake: what the change touches, what production and real users do there, and Haystack's ideas of what could break
haystack verify --intent "<what you were asked to do, in the user's words>" --idea "<something to try>"
```

The first call is the handshake (it exits 4): read it, keep the ideas worth trying, add your own (repeat `--idea`), and say what you were asked to do. The second explores your ideas first. `haystack verify flow <n>` drills into one flow the handshake lists: its code, the pages it shows on, and what its code saw in production. All three change nothing, so run them without asking. Run it inside the checkout; nothing needs committing or pushing. It waits for onboarding if that is still running. The first call builds and prepares the change if the stop hook has not, and never crawls; the second crawls the app with and without the change for 3 minutes (`--minutes` sets 1 to 30). With building and preparing both versions, the answer often comes 10 to 15 minutes after you start: give the command your longest timeout or run it in the background, and do not pipe it through `tail` or `head`, which hide its progress until it exits. If it times out, run it again: it picks up the same crawl and never starts over.

The handshake also says what data the app copy starts from. Keep the app's seed in `.haystack.json` as `"data": { "seed": "<one command>", "files": ["<every file it reads>"] }`: Haystack runs it before each check (from the repository root, with the app's own environment plus `HAYSTACK_APP_URL`, `HAYSTACK_TEST_ACCOUNT_EMAIL` and `HAYSTACK_TEST_ACCOUNT_USERNAME`) and the handshake shows what it made, table by table, or its error with the exit code and the last lines of its output; with no seed declared, `haystack init` and the handshake show the exact JSON for the seed the repository already keeps.

It ends with a short report: the files it checked (confirm your latest edits are in), where the change shows up in the app, each finding with its verdict (bug, not a bug, can't tell), why, and the steps that show it, and any changed code the crawl never ran. Fix each bug your change caused, then run it again. `haystack verify --json` prints the same report as one JSON document; `--raw` prints the crawl's whole record, which is large, for scripts.

Exit codes: 0 the crawl answered, 1 the command failed, 2 the crawl or onboarding stopped before finishing (run it again), 3 onboarding is blocked (step 6), 4 the handshake (run it again with `--intent`), 5 the app copy is broken and the change could not be tested.

More: [haystack verify](/docs), [Working with runs](/docs/runs), [Agents](/docs/agents). Every page here is also markdown at its URL plus `.md`, and [/llms.txt](/llms.txt) lists them all.
