# HeurChain API — Agent Onboarding

**Base URL:** `https://api.heurchain.com`

You are an AI agent connecting to HeurChain — a persistent vector memory broker.
Read this once at the start of any new session. It answers: what to store, when
to store it, how to retrieve it, and how sessions work.

---

## Authentication

Every endpoint except `GET /` and `GET /health` requires two headers:

```
X-HeurChain-API-Key: hc_<32-hex>
X-HeurChain-Tenant: <uuid>
```

**If you don't have these:** ask the user once, then persist them durably (e.g.
`~/.kimi/HEURCHAIN.md`, `~/.config/heurchain`, or your agent config file). Tag
the stored item `credential` so future sessions can find them. Never log the API key.

---

## First-run checklist

Run these steps in order at the start of every new session:

1. **`GET /memory/manifest`** — see what's already stored (tag counts, agent
   counts, 10 most-recent items). Do this BEFORE asking the user for anything
   that might already be in memory (credentials, project context, decisions).
2. **Check for `credential`-tagged items.** If the manifest shows any, retrieve
   them with `POST /query` before asking the user for API keys or passwords.
3. **`POST /session/start`** — open a session. Save the returned `session_id`
   and pass it in `metadata.session_id` on every `/store` call this conversation.
4. **`GET /agent/{your_agent_id}`** — recall your agent's own recent memories.
   Review before starting work.
5. **At session end:** call `POST /session/end`, then write a session summary
   (see _What to store and when_ below).

---

## Core write/read endpoints

### `POST /store` — write a memory item

```json
{
  "text":     "the content to remember",
  "agent_id": "kimi",
  "tags":     ["fact", "project-context"],
  "metadata": {
    "session_id": "ses_abc123",
    "source":     "user-statement",
    "project":    "openclaw"
  }
}
```

Optional top-level fields:
- `id` — stable key for this item. Auto-UUID if omitted. Reposting with the same `id` overwrites (safe to retry on transient errors).
- `embedding` (float[]) — bring your own 768-dim vector. Omit to let the server embed via BAAI/bge-base-en-v1.5.

Response `200`:
```json
{ "id": "uuid-or-your-id", "stored": true }
```

---

### `POST /query` — semantic similarity search

```json
{
  "text":      "what should I retrieve",
  "agent_id":  "kimi",
  "tags":      ["credential"],
  "top_k":     5,
  "threshold": 0.6
}
```

- `agent_id` — optional; filters to that agent's writes only
- `tags` — optional; AND semantics (all tags must match)
- `top_k` — default 10, max 100
- `threshold` — cosine similarity floor, default 0.0

Response `200`:
```json
{
  "count": 2,
  "results": [
    {
      "id":         "uuid",
      "score":      0.87,
      "text":       "the stored content",
      "agent_id":   "kimi",
      "tags":       ["credential"],
      "metadata":   { "session_id": "ses_abc123" },
      "created_at": "2026-05-13T18:00:00Z"
    }
  ]
}
```

---

### `POST /search` — hybrid BM25 + dense search (RRF fusion)

Same body as `/query`. Better for short keyword lookups (a project name, a credential label).
Prefer `/query` for natural-language retrieval. Response shape is identical; results
may additionally include `bm25_score`.

---

### `POST /embed` — embed without storing

```json
{ "text": "..." }
```

Response: `{ "embedding": [...768 floats...] }`. Use when you control storage yourself.

---

## Session lifecycle

Sessions correlate writes across a conversation so you can replay the full
context of any prior session later.

### `POST /session/start`

```json
{ "agent_id": "kimi", "ttl_seconds": 86400 }
```

Response: `{ "session_id": "ses_..." }`

Save `session_id` and pass it in `metadata.session_id` on every `/store` call
this conversation. `ttl_seconds` defaults to 86400 (24 h) if omitted.

### `POST /session/end`

```json
{ "session_id": "ses_..." }
```

Response: `{ "ok": true }`

Call at conversation end, then immediately store a session summary (see below).

### `GET /session/{session_id}/context?n=20`

Returns up to 50 items written under that session, ordered by recency:

```json
{
  "items": [
    { "id": "...", "text": "...", "tags": [...], "created_at": "..." }
  ]
}
```

Use this to resume a prior conversation: pass the previous session ID to
re-hydrate context without re-querying the user.

---

## Agent recall

### `GET /agent/{agent_id}` — your agent's recent memories

Returns recent memories written by this `agent_id`. Call at session start to
re-orient before starting any task.

### `GET /agents` — list active agents

Returns distinct `agent_id` values from the last 7 days. Use to discover what
other agents have contributed to this tenant's memory.

---

## Memory manifest

### `GET /memory/manifest`

```json
{
  "total":  42,
  "tags":   [{ "tag": "credential", "count": 3 }],
  "agents": [{ "agent_id": "kimi", "count": 18 }],
  "recent": [{ "id": "...", "agent_id": "...", "tags": [...], "created_at": "..." }],
  "tag_taxonomy": ["credential","decision","fact","project-context","system-config","conversation","code"],
  "generated_at": "2026-05-13T18:00:00Z"
}
```

**Always call this at the start of any non-trivial task.**

---

## Vault

### `GET /vault/stats`

Vector count, byte estimate, oldest/newest item timestamps for this tenant.

### `POST /vault/flush-working-memory`

Deletes items tagged `conversation` (or a custom tag set you specify). Use at
session end to prune conversational chaff before it pollutes future retrieval.

### `GET /vault/export`

NDJSON stream of every vector item for this tenant. Use for backup or migration.
The dashboard at https://heurchain.com/dashboard also has a UI-driven export.

---

## What to store and when

**What goes in `text`:** anything that should survive past this conversation.

| Content | Tag | Example |
|---|---|---|
| API key / token | `credential` | `"GitHub token: ghp_abc (expires 2026-06-01)"` |
| Architecture decision | `decision` | `"Chose PostgreSQL over MySQL — reason: JSON operators"` |
| User-stated fact | `fact` | `"Peter's email is peter@carlssoncreative.com"` |
| Project layout | `project-context` | `"OpenClaw: VM 242, user rm, pnpm monorepo at ~/openclaw"` |
| Server / env config | `system-config` | `"HeurChain tenant abc-123, key rotated 2026-05-13"` |
| Session summary | `conversation` | One-paragraph summary of what was done and what's pending |
| Code snippet | `code` | Small, self-contained snippet useful across sessions |

**What NOT to store:** raw conversation transcripts, large file contents, data
that changes every run (dynamic UUIDs, ephemeral timestamps), anything that
belongs in a repo or config file.

**When to call `/store`:**

- **Credential disclosed** — immediately when the user shares an API key, token,
  or password. Tag `credential`.
- **Decision made** — when you and the user agree on an approach, architecture
  choice, or policy. Tag `decision`.
- **User states a fact** — name, email, preference, account info. Tag `fact`.
- **Context eviction** — context window filling up; store a summary before
  truncating. Tag `conversation`.
- **Session end** — one-paragraph summary of accomplishments and open items.
  Tag `conversation`.
- **NOT after every message** — that produces retrieval noise. Store selectively.

**Chunking:** max 512 tokens (~2000 chars) per item. Split larger content into
segments; link them via `metadata.session_id` or a shared `id` prefix
(e.g. `doc-plan-1`, `doc-plan-2`).

---

## Tags

Tag rules: lowercase alphanumeric, dash or underscore, max 32 chars, max 16 per item.

**Taxonomy** — use these names for cross-agent consistency:

| Tag | Use for |
|---|---|
| `credential` | API keys, passwords, tokens, secrets |
| `decision` | Architecture, tooling, or policy choices |
| `fact` | User-stated facts, preferences, account info |
| `project-context` | Project structure, stack, file locations |
| `system-config` | Server config, env vars, host addresses |
| `conversation` | Session summaries, ephemeral notes |
| `code` | Code snippets, scripts, config files |

---

## Error handling

| Status | Meaning | Action |
|---|---|---|
| `200` | Success | — |
| `400` | Bad request (missing field, malformed JSON) | Fix payload, do not retry |
| `401` | Auth failed (bad/missing key or tenant) | Ask user for correct credentials |
| `404` | Item or session not found | Do not retry |
| `429` | Rate limit exceeded | Body: `{"limit":20,"current":23}`. Back off 60 s then retry |
| `5xx` | Server error | Exponential backoff, max 3 attempts. Report if persistent |

All error responses are JSON: `{ "error": "description" }`.

---

## OpenClaw / Hermes integration

- Set `agent_id` to `"openclaw"` or `"hermes"` consistently across all sessions for this tenant.
- At first boot: store your MCP server list, model routing config, and workspace
  path under tag `system-config`.
- Each session start: call `GET /agent/openclaw` (or `/agent/hermes`) before any task.
- If the HeurChain MCP server is configured, prefer MCP tools
  (`mcp__heurchain__heurchain_search`, `mcp__heurchain__heurchain_export`).
  Fall back to direct HTTP if MCP is unavailable.
- `POST /promote` — increments a memory item's retrieval weight. Call after a
  human confirms a stored fact is correct.

---

## Discovery

- `GET /` — this document (`text/markdown` default; `Accept: application/json` for structured spec). Send tenant headers to get a manifest summary appended.
- `GET /health` — service liveness (no auth)
- `GET /memory/manifest` — tenant memory summary (auth required)
- `GET /openapi.json` — OpenAPI 3 spec (no auth)

Dashboard: https://heurchain.com/dashboard (key rotation, vault export, billing)
