---
title: "Install"
description: "Install the Assay collector, run assay init, and back up the content key."
---

Assay ships as a **signed macOS collector**. One binary. No Node. No source clone.

Downloads are **invite-only**. You need a link of this shape:

```bash
curl -fsSL https://download.assay.solutions/i/<invite>/install.sh | sh
```

The invite is in the URL. You do not paste a second secret. The installer picks the architecture, **checks the download against published checksums**, and puts `assay` on your `PATH`.

It does **not** create a store. It does **not** start a timer. It does **not** touch your session logs. `assay init` is a separate, deliberate step.

```bash
assay --version
```

This guide documents **v0.48.0**. If `assay --version` prints something else, treat that binary as the authority for flags.

<AccordionGroup>
  <Accordion title="assay: command not found">
    The installer puts the binary in `/usr/local/bin` when it can write there, otherwise `~/.local/bin`. Add that directory to `PATH` and reopen the shell.
  </Accordion>
  <Accordion title="macOS Gatekeeper">
    The collector is Developer ID signed and notarized. A browser or AirDrop download is not blocked. First run may fetch the notarization ticket online.
  </Accordion>
  <Accordion title="Linux or a host application">
    The compiled collector is macOS today. A host that embeds Assay as a library needs Node ≥ 20 and the package. See [Agent loop](/agent-loop).
  </Accordion>
</AccordionGroup>

## Initialize

```bash
assay init            # ./assay.config.json in this folder
# or
assay init --global   # ~/.config/assay/config.json for the machine
```

`init` does four things:

- Writes a **config file**, so later commands need no repeated flags.
- Creates an empty **store** (schema applied). `assay show` works immediately and returns an empty rollup.
- Creates the **content key** (`~/.config/assay/transcript.key`, mode `0600`).
- Prints next steps.

It is safe to run again. A second run reports what already exists. It never overwrites the key or the store. `--force` rewrites only the config file.

<Warning>
  **Back up the content key.** Conversation text is sealed with it. Lose the key and the sealed text is unreadable. Counts, hashes, and labels survive. The words do not. Keep the key file in a password manager or a backup you already trust.
</Warning>

## What you have after init

| Piece | Default |
|---|---|
| Config | `./assay.config.json` or `~/.config/assay/config.json` |
| Store | a SQLite file named in the config |
| Content key | `~/.config/assay/transcript.key` |
| Mode | `corpus` |
| Capture roots | Claude Code, Grok, Codex, OpenCode session folders |

No timer is installed yet. Capture and labelling stay off until you turn them on. See [After install](/first-run).

## Config resolution

Which file: `--config-file` → `$ASSAY_CONFIG` → `./assay.config.json` → `~/.config/assay/config.json` → none.

Each value: flag > env > config file > built-in default.

With no config file, behavior matches flag-only use. The config layer is additive.

When you write a config for a **newer** Assay, upgrade the installed binary too. Check with `assay --version`. An unknown **top-level** section is a warning and is ignored. The section still does nothing until the build that understands it is installed.

Pass `--strict-config` (or `$ASSAY_STRICT_CONFIG=1`) in CI, where a config naming a section the build cannot honour **is** the defect.

Full file: [Config](/config).
