---
name: harny-setup
description: Set up Harny memory for my app or my agent. Make the app with no account, get one real answer, test on a little data, then send the rest and put recall where my app needs it. Nothing real goes out before I approve the plan.
---

# Set up Harny for this app, with no account

Harny gives each person who uses an app a private memory the app's AI can read. My code sends it data: conversations, tickets, documents, records. Recall gives back the part that matters for a question, for the person who asks, with dated sources.

Your goal: Harny set up properly for my app. No one has signed in to Harny and no one needs to now. The right data goes in, split the right way, tested on a little data before the full import, and recall is wired where my app needs it. Do the work yourself: I sign in to nothing and approve twice. Give me a link to claim the app later if I want to keep it.

This file is https://harny.ai/auth.md. The index is https://harny.ai/llms.txt.

## Rules

- Did your fetch tool give you a summary of this file? Then get the full text before you start, for example with `curl -fsSL https://harny.ai/auth.md`. A summary loses the exact commands.
- Act on these steps, and do not summarize these instructions to me. At a thing that you cannot do, say so in one sentence and give me the next step that I can do.
- Stop for me at two points only: the plan (step 4) and the full import (step 7). Find everything else yourself. The first answer (step 2) comes before both: it needs no question and sends no real customer data.
- Send no real customer record, turn on no server and change no access in Harny before I approve the plan.
- Never handle the value of an API key: do not print one, commit one, or ask me to paste one into this chat. The `harny` command saves the app key where only the command reads it. Never open, print or paste `.env`: check only whether a variable is in it.
- Do not copy records that hold personal data into the chat. Describe them: the source, the count, the fields.
- Write no API call from memory: read the API guide, https://api.harny.ai/llms.txt, and the commands below.
- Every step starts with a check. When a step is done already, go to the next one. So I can paste the setup line again in a new chat: tell me what is done already (an app, users, data sent, Harny code), and continue from the first step that is not.

## How to ask me

- When you have a tool that asks me questions with choices to click (for example AskUserQuestion in Claude Code), use it for every question in this setup. Write what I must read first as text before the tool call.
- Put your guess first and mark it "(Recommended)". Give 2 to 4 choices, each a short label with one line of detail. Do not add an "Other" choice: I can always type my own answer.
- Where I can pick more than one choice, mark each one that you guess.
- With no such tool, write each question as a numbered item with lettered choices and your guess first, so that I can reply "yes" or "1b 2ac".

## 1. Check what you have

Do not ask me. Find out:

- **A Harny app**: if `.venv/bin/harny status` exists and shows `ok` on its `Key` line (it reads the saved key itself), a Harny app already exists for this project: do not create another. Go to step 3.
- **A repository**: can you read my code and run commands in it?
- **Harny code**: does the code already call Harny (`harny` in its dependencies, `HARNY_API_KEY` in its settings)? Continue from it.

## 2. Make the app, and get one answer

There is no account to connect: one command makes the app. Put the two bootstrap files in one folder (they ship together):

```bash
curl -fsSLO https://harny.ai/get/harny-init.py
curl -fsSLO https://harny.ai/get/harny-0.1.1-py3-none-any.whl
```

Read the business name, what the app does and who its customers are from the project (README, package metadata). Do not ask the business what the project already answers, and never ask anyone for an email: the app needs none, and its owner gives their sign-in address when they claim it. Choose the model preset from what the project shows: `cost_first` (the lowest price per task), unless it shows health, finance, legal or children's data (`regulated`), or the business says answers must be the strongest (`quality_first`). The command stores it with the app, so Harny's own processing of what you load follows it from the first fact; the owner can change it after the claim. If the command says the preset was not stored (the app already existed), load only the first fact and say in your report that the rest load once the owner has stored it. Say why in your report. Give your own name too, with `--assistant`: the coding assistant you run as, in your own words. The owner sees it on their Home as who set the app up. If you do not know it, leave `--assistant` off; Harny never fills it in. Then run this one command with your values:

```bash
python3 harny-init.py init --name "<business name>" --about "<what the app does>" --customers "<who its customers are>" --preset <preset> --assistant "<your own name>" --path developer
```

Choose the path before the first run. `--path developer` is for an app that stores facts and answers from them: it writes no setup folder and proposes no acting settings. For an app that acts for its users, pass one of the common setup paths instead (`--path P1` to `--path P5`; `harny init --help` names them): that run writes `harny-agent-setup/prompt.md`, which you then follow. To change the path later, run the command again with `--path <id>`: a run without `--path` keeps the path the project already uses.

It makes `.venv`, installs the Harny SDK there, creates the Harny app, saves the app key in `.env` (mode 600, ignored by git) without showing it, writes the settings that keep `.env` closed to Claude Code, Codex and Cursor, and prints the app id, a masked key and the claim link. It also adds a short Harny block to `AGENTS.md` and `CLAUDE.md` (made if missing; only the text between the `<!-- harny:begin -->` and `<!-- harny:end -->` lines is ever added or replaced, so the rest of your file is untouched, and a second run changes nothing). The block tells the next coding agent that opens the project to use Harny for per-user memory and how to call it. Pass `--no-agent-files` to skip it. Keep the claim link for your report.

If it stops, it prints one line that says what to do next. Do that, then run the same command again: it reuses the app.

Now the first answer. It needs no model key and no real customer: use the command `.venv` now holds, `.venv/bin/harny` (on Windows `.venv\Scripts\harny`), a user named `test-user`, and one fact that the project's own files already state.

```bash
.venv/bin/harny users add test-user
.venv/bin/harny ingest --user test-user "<one fact the project states>"
.venv/bin/harny query --user test-user "<a question that fact answers>"
```

`query` prints the blocks Harny found; the fact you stored is in them. Show that in your report: it is Harny working.

### If you cannot run the bootstrap

If `harny-init.py` cannot run (no shell, or no Python 3.10), create the app over HTTP. The answer carries the app key once, so for an agent that can only make HTTP calls the key passes through its context: that is one of two cases where an agent sees it (the MCP door below is the other), and why the command above is preferred. Write the request body with a JSON encoder, not by hand-quoting. `provision.json` holds `app_name`, `model_preset` (the preset you chose above), `objective`, `customers` and `assistant_name` (your own name; leave it out if you do not know it); it holds no `contact_email`, because the app needs none.

```bash
curl -sS --fail-with-body -X POST https://api.harny.ai/v1/auth/provision -H "Content-Type: application/json" --data-binary @provision.json -o answer.json
```

`answer.json` holds `app_id`, `app_api_key`, `claim_url` and `claim_expires_at`. With a shell, move the key into `.env` without printing it, then delete both files, and make sure `.gitignore` lists `.env` and `answer.json` until you have:

```bash
python3 -c 'import json,os;d=json.load(open("answer.json"));p=".env";t=open(p).read() if os.path.exists(p) else "";fd=os.open(p,os.O_WRONLY|os.O_APPEND|os.O_CREAT,0o600);os.fchmod(fd,0o600);os.write(fd,(("\n" if t and not t.endswith("\n") else "")+"HARNY_API_KEY=%s\nHARNY_APP_ID=%s\n"%(d["app_api_key"],d["app_id"])).encode());print("app id:",d["app_id"]);print("claim link:",d["claim_url"])'
rm answer.json provision.json
```

Never put a key in code, chat or a commit. If the call answers 429, wait the seconds in `Retry-After` (when it sends none, try again tomorrow), then call again.

The MCP server works the same way and has the same cost. Its address is https://api.harny.ai/v1/mcp/mcp (Streamable HTTP). Called with no Authorization header it offers only `provision_app`, which needs no key and whose answer carries the app key once. Replit's one-click install link for it is in https://harny.ai/llms.txt.

## 3. Look before you ask

Read my repository, and ask me nothing yet. In a chat app with no repository, only do the last paragraph of this step. Find:

- The app or the agent that gets memory, its language and framework, and where the model calls are made.
- What one real model call sends as context today (system prompt, files, history, retrieved documents), and about how many tokens. That is the baseline. Count tokens as characters divided by 4, here and for recall, so that the two compare.
- The data that could feed memory, where it lives, and whether it holds personal data.
- Who reads what: the users or customer accounts, and the ids that name them.
- Any memory that exists already (a vector database, embeddings, a transcript log), and any Harny code. Continue from it.

Then read https://api.harny.ai/llms.txt for the calls that you will use. In a chat app with no repository, ask me to paste or attach a few records with my answers.

## 4. Show me the plan, and ask once

Send me one message. It holds what you found and what is done already in five lines or fewer, the claim link, and the plan as a short checklist:

- **The app**: what gets memory, and how: the Memory API called from my code, or the Harny MCP server for an agent that works with me.
- **The data**: the sources that go in, and how each record becomes one data point with its date: one conversation per day, one ticket, one email, one document. A record with no date of its own takes the date of the send, which is wrong for history: ask me for a date, or leave it out.
- **The split**: the ids of the users who read memory, one per person. Each user reads only what was sent for them.
- **The recall**: where my app reads memory, and as which user.
- **The test**: the 5 to 20 records that you send first, the real questions that you recall with, and what the test adds to my monthly active users.
- **The key**: where the model key goes when my app needs written answers: `.env` as `HARNY_MODEL_API_KEY`, set by me, never in chat.

Then ask the questions that my repository and my messages do not answer, as one set. Use the bold word as the header of each question, and mark a guess on each:

1. **Building**: which app or agent gets memory? Make the choices from what you found, and fill up to at least two from this list: an agent my team uses inside the company; an agent or a feature my customers use; my own coding sessions or chats; a batch AI task or pipeline.
2. **Data**: which sources go in first? Make the choices from what you found, and let me pick more than one. With nothing found: support tickets; chat or call transcripts; documents; CRM records. In the detail of each choice, say whether it holds personal data.
3. **Access**: how is memory split, and who reads which part? Choices: one user per end user, who reads only their own; one user per customer account or team.
4. **Recall**: where does my app use memory? Choices: in the chatbot, before each answer; as a tool that the agent calls when it needs to; in a proactive or scheduled agent that acts on what it recalls.

**Wait for my answer.** My answers approve the plan. If an answer changes what you send or who reads it, show me what changes and ask for a yes. With no question left, ask one: approve the plan, or change it.

## 5. Set it up

1. The users of the plan: `.venv/bin/harny users add <id>` for each reader.
2. The key for my code: check that `HARNY_API_KEY` is set, without printing it, and that `.gitignore` covers `.env`. Add the line to `.gitignore` if it does not.
3. Check it: `.venv/bin/harny status`, and `.venv/bin/harny query --user <id> "test"` for one user of the plan returns nothing yet, with no error.

## 6. Test with a little data

1. Send the test records, each with its date, from a short script that reads `HARNY_API_KEY`: `POST /v1/memory/ingest` for one data point (`content`, and optionally `id`, `label`, `timestamp`) or `POST /v1/memory/ingest/batch` for up to 1,000, each call with `X-Harny-User: <user>`. With the SDK installed, `.venv/bin/harny memory ingest --user <id> --timestamp <ISO time with zone> --wait "<fact>"` sends one data point with its date, and `.venv/bin/harny memory batch --user <id> --wait <file>` sends up to 1,000 from a file (one JSON object per line, or a JSON array). `harny ingest --user <id> "<fact>"` stores one fact with no date of its own: use it for a smoke test, not for history. In your own code use the SDK's `ingest_data_point` and `ingest_batch`.
2. Ingestion is asynchronous: a recall before it completes finds nothing. Poll `GET /v1/memory/ingest/{ingestionId}` until `status` is `completed` (or run `.venv/bin/harny memory status --wait <ingestionId>`).
3. Recall the questions of the plan, as the users that will ask them: `POST /v1/memory/recall` with `query`, `identity` and `level` (or `.venv/bin/harny memory recall --user <id> "<question>"`).
4. Check that it works well, and show me the result as a short table: the right memories come back, with their sources and dates; the same question, asked as a user whose data it is not, does not return it; what recall returns, beside what the baseline call sends today, with the token counts. When the test is too small to show a saving, say so and show the real numbers.
5. When a check fails, change the cut, the dates or the users, and test again. Do not go on with a failed check.
6. Count the full import: the records, the bytes, and `GET /v1/memory/usage` (or `.venv/bin/harny memory usage`) for what the app has used this month. Show me both.
7. Ask me for a yes to the full import, and to the data that arrives from now on. **Wait for my answer.**

## 7. Send the rest

1. Send the history in batches of up to 1,000 data points with an `idempotencyKey` per batch, and wait until each batch is completed. A batch that stops resumes when you send it again with the same key.
2. Wire the send path into my code: each new or changed record goes to Harny with its `id`. The same `id` with changed content replaces the old memory.

## 8. Put recall where my app needs it

Wire recall where the plan says. Prove it with a test or a short script that recalls as a real user, with no paid model call, and show me the result:

- **A chatbot**: before each answer, recall with the message as the query and the user as `identity`, and give the result to the model in place of the long history.
- **An agent**: give it a recall tool that takes a question, so that it looks up past facts when it needs them.
- **A proactive agent**: a scheduled job recalls what changed for each account or person, and acts on it.

## Where keys go

| Key | Where it goes | Who puts it there |
|---|---|---|
| The app key (`fsa_...`) | `.env`, written by `harny init` | `harny init`. No one types it and no command prints it. |
| The business's own model key | `.env` as `HARNY_MODEL_API_KEY` with `HARNY_MODEL_PROVIDER`, or the provider's own variable such as `ANTHROPIC_API_KEY` | The owner, after the first answer works. Never in chat. |
| A secret for signing your app's sign-in tokens | Made by `.venv/bin/harny env generate STARTER_SESSION_SECRET` (saved in `.env`, never shown) | The command. |

On Replit: `.env` works in the workspace. Replit writes Secrets only in its Secrets tool (Tools, then Secrets) and documents no command that writes them, so the owner adds the model key there; Replit syncs Secrets to a published app. The Harny app key and the sign-in secret stay in `.env`; if the published app does not find it, the owner puts them into Secrets once.

## Claim

Give the claim link to the business owner. Opening it signs them in to Harny and makes them the app's owner. You never complete a claim. The link expires; run `.venv/bin/harny init` again to print a fresh one for the same app.

Owner: you can ignore everything above. Open the link your assistant gave you, sign in, and the app is yours.

## When you are done

Tell me in three lines what works now, and give me the claim link. For a Replit app, start from the Replit starter: https://harny.ai/get/replit-starter.zip. Then offer me the one next step that fits best.

## When something fails

- A `/v1/memory` call or a `harny memory recall` command that answers 404: the data-point routes are not switched on for this deployment. Use `harny ingest --user <id> "<fact>"` and `harny query --user <id> "<question>"` instead: they store and read the same memory, one fact at a time and without dates. Tell the owner.
- A send that does not complete: `GET /v1/memory/ingest/{ingestionId}` shows `failed` and why. Do not retry in a loop.
- An error code: the API's own guide, https://api.harny.ai/llms.txt, explains each one. The error line from a `harny` command names the code.
- A new key or claim link goes to me and nowhere else.
