@tpsdev-ai/flair 0.30.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +194 -377
  2. package/dist/cli.js +1434 -288
  3. package/dist/deploy.js +212 -24
  4. package/dist/fabric-upgrade.js +16 -1
  5. package/dist/federation/scheduler.js +500 -0
  6. package/dist/install/clients.js +111 -53
  7. package/dist/lib/mcp-spec.js +128 -0
  8. package/dist/lib/safe-snapshot-extract.js +231 -0
  9. package/dist/lib/scheduler-platform.js +128 -0
  10. package/dist/lib/xml-escape.js +54 -0
  11. package/dist/rem/scheduler.js +35 -87
  12. package/dist/rem/snapshot.js +13 -0
  13. package/dist/replication-convergence.js +505 -0
  14. package/dist/resources/AdminPrincipals.js +10 -1
  15. package/dist/resources/Agent.js +105 -11
  16. package/dist/resources/AgentSeed.js +10 -2
  17. package/dist/resources/MemoryBootstrap.js +7 -8
  18. package/dist/resources/MemoryUsage.js +18 -0
  19. package/dist/resources/Presence.js +8 -1
  20. package/dist/resources/SemanticSearch.js +17 -45
  21. package/dist/resources/abstention.js +1 -1
  22. package/dist/resources/agent-admin.js +149 -0
  23. package/dist/resources/agent-auth.js +98 -5
  24. package/dist/resources/auth-middleware.js +92 -19
  25. package/dist/resources/embeddings-boot.js +10 -12
  26. package/dist/resources/embeddings-provider.js +10 -7
  27. package/dist/resources/health.js +24 -19
  28. package/dist/resources/in-process.js +234 -0
  29. package/dist/resources/mcp-handler.js +14 -4
  30. package/dist/resources/mcp-tools.js +23 -17
  31. package/dist/resources/migration-boot.js +80 -10
  32. package/dist/resources/migrations/data-dir.js +205 -0
  33. package/dist/resources/migrations/progress.js +33 -0
  34. package/dist/resources/migrations/runner.js +29 -2
  35. package/dist/resources/migrations/state.js +13 -2
  36. package/dist/resources/models-dir.js +18 -9
  37. package/dist/resources/presence-internal.js +6 -1
  38. package/dist/resources/record-owner-guard.js +149 -0
  39. package/dist/resources/semantic-retrieval-core.js +5 -4
  40. package/dist/src/lib/scheduler-platform.js +128 -0
  41. package/dist/src/lib/xml-escape.js +54 -0
  42. package/dist/src/rem/scheduler.js +35 -87
  43. package/docs/deploying-on-fabric.md +267 -0
  44. package/docs/deployment.md +5 -0
  45. package/docs/embedding-in-a-harper-app.md +303 -0
  46. package/docs/federation.md +61 -4
  47. package/docs/integrations.md +3 -0
  48. package/docs/mcp-clients.md +16 -7
  49. package/docs/quickstart.md +80 -54
  50. package/docs/releasing.md +72 -38
  51. package/docs/supply-chain-policy.md +36 -0
  52. package/docs/troubleshooting.md +24 -0
  53. package/docs/upgrade.md +99 -4
  54. package/package.json +1 -11
  55. package/templates/bin/flair-federation-sync.sh.tmpl +28 -0
  56. package/templates/launchd/dev.flair.federation.sync.plist.tmpl +47 -0
  57. package/templates/systemd/flair-federation-sync.service.tmpl +21 -0
  58. package/templates/systemd/flair-federation-sync.timer.tmpl +16 -0
  59. package/dist/resources/rerank-provider.js +0 -569
  60. package/docs/rerank-provisioning.md +0 -101
package/README.md CHANGED
@@ -6,7 +6,13 @@
6
6
 
7
7
  > **The identity and memory substrate for AI agents. Crypto-pinned. Federated. Self-hosted.**
8
8
 
9
- Flair is the **identity + memory substrate for AI agents**. Cryptographic per-agent identity (Ed25519). Soul as a first-class primitive, separate from memory. Federation across hosts (hub/spoke). Same agent, every orchestrator — memory follows.
9
+ Every agent framework gives you chat history. None give you *identity*. Flair gives an agent three things that survive a restart and follow it between orchestrators:
10
+
11
+ - **Identity** — an Ed25519 keypair. The agent signs every request. No shared secrets.
12
+ - **Memory** — persistent knowledge with semantic search, embedded in-process. No API calls.
13
+ - **Soul** — the personality, values and procedures that make it *that* agent.
14
+
15
+ Self-hosted on [Harper](https://harper.fast) as a single process. No sidecars, no vector database, no embedding API.
10
16
 
11
17
  ```
12
18
  ┌──────────────────────────────────────────────────────────────────┐
@@ -30,309 +36,154 @@ Flair is the **identity + memory substrate for AI agents**. Cryptographic per-ag
30
36
  └──────────────────────────────────────────────────────────────────┘
31
37
  ```
32
38
 
33
- 11 harness surfaces today. Pick whichever you're shipping in; the memory layer doesn't care. **[See the full integrations catalog →](docs/integrations.md)**
34
-
35
- ## What it looks like
36
-
37
- ![Flair: write a memory, find it by meaning, list of supported harnesses](docs/assets/flair-demo.gif)
38
-
39
- `flair memory add` writes a memory; `flair search` finds it by meaning, not keywords. The same memory is then visible to every harness in the catalog above.
40
-
41
- ### Same identity, every orchestrator
42
-
43
- ![Flair cross-orchestrator: one agent, one memory store, three MCP-capable CLIs](docs/assets/flair-cross-orchestrator.gif)
44
-
45
- Same Ed25519 identity, same memory store, three different MCP-capable CLIs (Claude Code, Codex CLI, Gemini CLI). A memory written from one is immediately retrievable from the next. Your agent's identity and history aren't bound to a single orchestrator's runtime.
46
-
47
- ## How Flair compares
48
-
49
- | | Flair | Mem0 | Honcho | Letta (MemGPT) | Built-ins (OAI/Anthropic/Google) |
50
- |---|---|---|---|---|---|
51
- | **Identity model** | **Ed25519 per agent (crypto-pinned)** | tenant-isolation | per-user soft tenant | runtime-bound | account-scoped |
52
- | **Federation (peer-to-peer)** | **yes — hub/spoke validated** | no | no | no | no |
53
- | **Cross-orchestrator** | **11+ harnesses, same memory** | several | several | runtime-bound | vendor-locked |
54
- | **Soul / persistent character** | **first-class** | optional | persona-shaped | optional | no |
55
-
56
- Four rows where Flair holds a cell no other system holds cleanly today. Parity rows (license, self-host, semantic search) are table-stakes for this neighborhood — Mem0, Honcho, and Letta are all open-source and self-hostable — so they're omitted to keep the moat visible.
57
-
58
- The honest gaps:
59
-
60
- - Mem0's **cloud sync UX** is more polished if you're OK with their hosting.
61
- - Honcho's **persona model** is more developed if rich personality modeling is your priority.
62
- - Letta's **runtime integration** is tighter if you're building on their agent loop.
63
-
64
- If you need any of those specifically, use them. If you need crypto-pinned identity + federation + cross-orchestrator breadth + soul-as-a-feature — that's the gap Flair fills.
65
-
66
- ### Memory curation: vs Claude Dreams
67
-
68
- Anthropic shipped [Claude Dreams](https://platform.claude.com/docs/en/managed-agents/dreams) (research preview, April 2026) — async pipeline that reads a memory store + session transcripts and produces a curated output store: duplicates merged, stale entries replaced, insights surfaced. Validates the category: agent memory accumulates drift and needs cleanup.
69
-
70
- Flair ships both the on-demand curation surface (`flair rem rapid`) AND the scheduled nightly cycle, per [`docs/rem.md`](docs/rem.md) and its [distillation UX design note](docs/notes/rem-ux.md). **REM requires a configured generative backend** (Ollama, OpenAI, Anthropic, etc.) — without one, `flair rem rapid` fails with `Reflection error: No generative backend configured`. Config recipe (Ollama zero-key default, hosted-provider egress warning, clustered-deploy rules): [`docs/rem.md`](docs/rem.md).
71
-
72
- - **`flair rem rapid`** — reflects and distills server-side by default, staging candidates in one bounded call. `--focus {lessons_learned, patterns, decisions, errors}` mirrors Dreams' `instructions` parameter. `--prompt-only` falls back to the bring-your-own-model handoff. Outputs *candidates*, not a wholesale store swap.
73
- - **`flair rem candidates` / `flair rem promote <id> --rationale "<why>"` / `flair rem reject <id>`** — review and promote distilled candidates with required rationale.
74
- - **`flair rem nightly enable [--at HH:MM]`** — scheduled automation via platform-native scheduler (launchd / systemd). Pre-cycle snapshot to `~/.flair/snapshots/<agent>/<iso>.tar.gz`. Maintenance (soft-delete expired + soft-archive stale) and distillation (staged candidates) both run each cycle. Audit log to `~/.flair/logs/rem-nightly.jsonl`. `flair rem pause` / `resume` for emergency stop.
75
- - **`flair rem restore <date> --apply`** — rewinds Harper state to a snapshot. Takes a pre-restore snapshot of current state first, so the rewind itself is reversible.
76
- - *Next* — trust-tier filter on REM input, cross-agent restore. Until the trust-tier arc lands, the input filter stays scope-based (own agent, non-archived, non-permanent, scope window); the structural safety net is unchanged either way — candidates are staged, never auto-promoted.
77
-
78
- The substantive difference is the **promotion contract**:
79
-
80
- | | Claude Dreams | Flair REM (today) |
81
- |---|---|---|
82
- | **Output** | New memory store — accept or discard | Staged candidates — per-candidate decision |
83
- | **Promotion gate** | None — accept the whole store | `flair rem promote <id> --rationale "<why>"` |
84
- | **Reversibility** | Input store is never modified (real safety property) | Pre-cycle snapshot + `rem restore <date> --apply` (rewinds Harper state, takes a pre-restore snapshot too) |
85
- | **Where it runs** | Anthropic Managed Agents (SaaS, Anthropic models only) | Self-hosted, any model |
86
-
87
- Dreams is easier to start with — one API call, and the input-never-modified contract gives you a clean rollback by simply not accepting the output. REM is the more granular surface — per-candidate decisions with required rationale — for operators who want to merge what's right and reject what's wrong on the same nightly cycle. Both are legitimate choices; the right one depends on whether you want store-level or candidate-level review.
88
-
89
- ## Why this exists
90
-
91
- Every agent framework gives you chat history. None of them give you *identity*.
92
-
93
- An agent that can't remember what it learned yesterday, can't prove who it is to another agent, and loses its personality on restart isn't really an agent. It's a stateless function with a system prompt.
94
-
95
- Flair fixes that with three primitives:
96
-
97
- - **Identity** — Ed25519 key pairs. Agents sign every request. No passwords, no API keys, no shared secrets. Write isolation (no agent can write as another) is enforced at the server, not by client convention; reads are open within the org for non-private memories by design (see [SECURITY.md](SECURITY.md)).
98
- - **Memory** — Persistent knowledge with semantic search (in-process [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF), 768-dim, no API calls). Tiered durability (`permanent` / `persistent` / `standard` / `ephemeral`). Temporal validity. Decay-and-retrieval-aware composite scoring.
99
- - **Soul** — Personality, values, procedures. The stuff that makes an agent *that agent*. Re-injected every turn via the context-engine plugin so it doesn't drift across long sessions.
100
-
101
- Built on [Harper](https://harper.fast). Single process. No sidecars. Zero external API calls for embeddings. **[Supply-chain policy](docs/supply-chain-policy.md)** documents the bake-time + dep-pinning we run to keep this honest.
102
-
103
- See **[DESIGN.md](DESIGN.md)** for the design invariants behind these three primitives — why they're shaped the way they are.
104
-
105
- ## How It Works
106
-
107
- Flair is a native [Harper v5](https://harper.fast) application. Harper handles HTTP, persistence (RocksDB), and application logic in a single process.
108
-
109
- ```
110
- Agent ──[Ed25519-signed request]──▶ Flair (Harper)
111
- ├── Auth middleware (verify signature)
112
- ├── Identity (Agent + Integration tables)
113
- ├── Memory (write → auto-embed → store)
114
- ├── Soul (permanent personality/values)
115
- └── Search (semantic + keyword, ranked)
116
- ```
117
-
118
- **No external dependencies at runtime.** Embeddings are generated in-process using [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) via a Harper plugin. Model runs on CPU or GPU (Metal, CUDA). No API calls, no sidecar processes, no network hops.
39
+ 11 harness surfaces today. Pick whichever you're shipping in; the memory layer doesn't care. **[Full integrations catalog →](docs/integrations.md)**
119
40
 
120
- ## Features
41
+ ## Quick start
121
42
 
122
- ### Cryptographic Identity
123
- Every agent has an Ed25519 key pair. Requests are signed with `agentId:timestamp:nonce:METHOD:/path` and verified against the agent's registered public key. 30-second replay window with nonce deduplication.
43
+ Needs **Node.js 22+** and a **user-writable npm global prefix**.
124
44
 
125
- ### Semantic Memory
126
- Memories are automatically embedded on write using [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) (768 dimensions). Search by meaning:
45
+ > ⚠️ **Never `sudo npm install -g @tpsdev-ai/flair`.** A root-owned install can't write the embedding model into its own package directory, so semantic search silently degrades to keyword-only. `flair init` and `flair doctor` will warn you loudly. Use `nvm`, or point npm at your home directory: `npm config set prefix ~/.npm-global` and add `~/.npm-global/bin` to `PATH`.
127
46
 
128
47
  ```bash
129
- # Write a memory (--agent is your registered agent id)
130
- flair memory add --agent myagent "Harper v5 sandbox blocks node:module but process.dlopen works"
131
-
132
- # Find it later by concept, not exact words
133
- flair memory search --agent myagent "native addon loading in sandboxed runtimes"
134
- # → [0.67] Harper v5 sandbox blocks node:module but process.dlopen works
135
- ```
136
-
137
- ### Trust-Graded Recall
138
- Recall can carry an opt-in **trust-evidence block** per result — provenance (verified vs claimed author), usage signal, freshness/validity, supersession — so an agent weighs *what to trust*, not just *what matched*. On top of it:
139
-
140
- - **Confidence bands** (`matchQuality`): each result is labeled `strong` / `moderate` / `breadcrumb` from its absolute similarity — a weak-but-relevant hit is taken for what it is, not mistaken for a confident one.
141
- - **First-class abstention** (`abstain`): when nothing clears a confidence floor, recall returns an honest "no memory covers this" verdict instead of the N weakest matches.
142
- - **Citation-on-write** (`usedMemoryIds`) + **`record_usage`**: report which memories actually grounded an answer — a deduped, principal-bound usage signal (honest evidence, never retrieval-popularity) that strengthens future recall.
143
-
144
- Opt-in and additive (`includeTrust` / `abstain` on the recall path) — off by default, byte-identical when unused. Reachable today via the authenticated HTTP API and the native `/mcp` tools; first-class exposure in the `flair` CLI, `@tpsdev-ai/flair-client`, and the `flair-mcp` bridge is a follow-up. Full arc in the [CHANGELOG](CHANGELOG.md) (flair#744).
145
-
146
- ### Tiered Durability
147
- Not all memories are equal:
148
-
149
- | Durability | Delete | TTL | Use Case |
150
- |------------|--------|-----|----------|
151
- | `permanent` | ❌ Rejected | None | Identity, values, core knowledge |
152
- | `persistent` | ✅ Allowed | None | Daily logs, project context |
153
- | `standard` | ✅ Allowed | None | Working memory (default) |
154
- | `ephemeral` | ✅ Allowed | 24h | Scratch space, temp context |
155
-
156
- ### Temporal Validity
157
- Memories can be time-bounded with `validFrom` and `validTo` fields. Expired memories are excluded from search and bootstrap automatically — no manual cleanup.
158
-
159
- ### Relationship Graph
160
- Entity-to-entity triples with temporal bounds. Model structured knowledge — "Alice works-with Bob since 2024-01-01" — queryable alongside semantic memory.
161
-
162
- ### Real-Time Feeds
163
- Subscribe to memory or soul changes via WebSocket/SSE. Useful for dashboards, cross-agent sync, or audit trails.
164
-
165
- ### Multi-Agent
166
- One Flair instance serves any number of agents. Each agent has its own keys, memories, and soul. Reads are open within the org: any agent can read any other agent's non-private memory, no grant required — `private` is the one owner-only exception. See [DESIGN.md](DESIGN.md#access-model-open-within-the-org-closed-at-the-federation-edge) for the full model.
167
-
168
- ### OAuth 2.1 Authorization Server
169
- Built-in OAuth 2.1 server with PKCE, dynamic client registration, and a standards-compliant token endpoint. Agents and services can delegate auth to Flair without a separate IdP.
170
-
171
- ### XAA (Enterprise-Managed Authorization)
172
- IdP integration for Google Workspace, Azure AD, and Okta. Bind agent identities to enterprise accounts — access follows your org's user lifecycle.
173
-
174
- ### Web Admin
175
- Server-rendered admin UI for managing principals, connectors, IdPs, and instance configuration. No separate dashboard service.
176
-
177
- ### Federation
178
- Hub-and-spoke sync between Flair instances using signed requests and pairing tokens. Originator enforcement prevents replay across federated nodes. Share memories across offices without giving any node raw access.
179
-
180
- ### Predictive Bootstrap
181
- Context-signal-aware preloading. Bootstrap reads active project context, recent activity, and agent role to select the most relevant memories — not just the most recent ones.
182
-
183
- ### Auto Entity Detection
184
- Passive extraction of entities from memory content on write. Entities are indexed automatically — no tagging required. Feeds the relationship graph without agent intervention.
185
-
186
- ### Memory Bridges
187
- Pluggable import/export to foreign memory systems. Every agent-memory format (agentic-stack, Mem0, Letta, Anthropic memory, the next viral one) shouldn't need its own Flair PR. Bridges give you one contract with two shapes — a YAML descriptor for file-format targets or a code plugin for API targets — and a scaffold/test loop that lets an agent ship a working adapter in one pass. See [docs/bridges.md](docs/bridges.md).
188
-
189
- ### Embedding benchmarks (`flair-bench`)
190
- A standalone benchmark you can run anywhere — no Flair install, no server, just Node and a GGUF file. It ships the same 126-query recall corpus and scoring Flair's own CI gates on, so its numbers are directly comparable: benchmark candidate embedding models (`--model-file`, batchable), get a model recommendation for the host you're on backed by the numbers it just measured (`recommend`), and optionally save a redacted, shareable result (`--share`) — including a `--label` for tagging host classes when characterizing fleet hardware. See [packages/flair-bench](packages/flair-bench/README.md).
191
-
192
- ## Quick Start
193
-
194
- ### Prerequisites
48
+ # 1. Install the CLI (no sudo)
49
+ npm install -g @tpsdev-ai/flair
195
50
 
196
- **1. Node.js 22+.** On a fresh box, install a current Node — the version in some distro repos is too old.
51
+ # 2. Bootstrap the instance and register an agent
52
+ flair init --agent mybot
197
53
 
198
- ```bash
199
- # Linux (Debian/Ubuntu) NodeSource:
200
- curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt-get install -y nodejs
54
+ # 3. Write a memory
55
+ flair memory add --agent mybot "Harper v5 sandbox blocks node:module but process.dlopen works"
201
56
 
202
- # macOS / Linux nvm (no root, recommended):
203
- curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
204
- # restart your shell, then:
205
- nvm install 22
206
-
207
- # Verify:
208
- node --version # → v22.x or newer
57
+ # 4. Find it back by meaning, not by keyword
58
+ flair search --agent mybot "native addon loading in sandboxed runtimes"
209
59
  ```
210
60
 
211
- **2. A user-writable npm global prefix (avoid `sudo`).** Installing globally with `sudo` makes the package root-owned. Flair's in-process embeddings component downloads/symlinks a model file under the package at runtime; when Harper later runs as **you** (not root) it gets `EACCES` and **semantic search silently degrades to keyword-only**. Point npm's global prefix at your home dir instead:
61
+ Step 4 finds the memory you never keyword-matched:
212
62
 
213
- ```bash
214
- mkdir -p ~/.npm-global
215
- npm config set prefix ~/.npm-global
216
- # add to your shell rc (~/.bashrc, ~/.zshrc) so it persists:
217
- export PATH="$HOME/.npm-global/bin:$PATH"
63
+ ```
64
+ Harper v5 sandbox blocks node:module but process.dlopen works
65
+ ( 2026-07-28 · standard · 100% )
218
66
  ```
219
67
 
220
- > ⚠️ **Do not `sudo npm install -g @tpsdev-ai/flair`.** A root-owned install breaks the embeddings component (the package dir isn't writable by the user Harper runs as), and you'll get the loud `Semantic search DEGRADED` warning from `flair init` / `flair doctor`. Use the user-writable prefix above instead. `nvm` installs already give you a user-owned prefix, so no `sudo` is needed there.
221
-
222
- ### Install & Run
223
-
224
- `flair init` is the front door. The mental model is git's: install the CLI globally, then `init`. One command does everything: installs and starts Harper, creates your agent's Ed25519 identity, verifies semantic search actually works, detects and wires your MCP clients (Claude Code / Cursor / Codex / Gemini) to the zero-install `npx -y @tpsdev-ai/flair-mcp` server, and runs a smoke test.
68
+ That trailing figure is a rank score, normalized so the top hit is always near 100% ordering, not confidence.
225
69
 
226
- ```bash
227
- # Install the CLI (no sudo — see prereqs above)
228
- npm install -g @tpsdev-ai/flair
70
+ `flair init` installs and starts Harper, creates the agent's Ed25519 keypair, verifies semantic search actually works, wires every MCP client it detects (Claude Code, Cursor, Codex CLI, Gemini CLI) to `npx -y @tpsdev-ai/flair-mcp`, and runs a smoke test. Restart your MCP client afterwards, then ask the agent *"what do you remember about me?"*
229
71
 
230
- # One command: instance + agent + semantic-search check + MCP wiring + smoke test
231
- flair init
232
- ```
72
+ > **Pass `--agent`.** A bare `flair init` bootstraps the instance and stops there no agent, no keypair, no MCP wiring.
233
73
 
234
- That's it. Your agent now has identity and memory, and any detected MCP client is wired up. Restart your MCP client (e.g. Claude Code) to pick up the new config, then ask the agent "what do you remember about me?"
74
+ Full walkthrough with expected output at every step: **[docs/quickstart.md](docs/quickstart.md)**.
235
75
 
236
- Useful flags:
76
+ ### Useful flags
237
77
 
238
78
  ```bash
239
- flair init --agent mybot # name the agent (--agent-id also works)
240
- flair init --client claude-code # wire one specific client (claude-code, codex, gemini, cursor, all, none)
79
+ flair init --client claude-code # wire one client: claude-code, codex, gemini, cursor, all, none
241
80
  flair init --no-mcp # instance + agent only, skip MCP wiring
242
- flair init --skip-smoke # skip the MCP smoke test
81
+ flair init --skip-soul # skip the interactive personality wizard
82
+ flair init --port 8000 # non-default port, remembered in ~/.flair/config.yaml
243
83
  ```
244
84
 
245
- > Running in a non-interactive shell (CI, Docker, an unattended setup script)? Bare `flair init` with no `--agent` bootstraps the instance only and silently skips agent registration, MCP client wiring, and the smoke test. Pass the flags explicitly: `flair init --agent <id> --client all`.
246
-
247
- Lifecycle management:
85
+ ### Lifecycle
248
86
 
249
87
  ```bash
250
- flair status # Check everything is working
251
- flair stop # Stop the Flair instance
252
- flair restart # Restart the Flair instance
253
- flair uninstall # Remove the service (keeps data)
254
- flair uninstall --purge # Remove everything including data and keys
88
+ flair status # instance health, memory stats, agents
89
+ flair doctor # diagnose common problems and suggest fixes
90
+ flair stop # stop the instance
91
+ flair restart # restart it
92
+ flair uninstall # remove the service, keep data and keys
93
+ flair uninstall --purge # remove everything, including data and keys
255
94
  ```
256
95
 
257
96
  ### Upgrading
258
97
 
259
- `flair status` and `flair doctor` both check your installed version against the latest published release (cached, offline-tolerant — this never blocks or fails either command) and print a nudge when you're behind:
98
+ `flair status` and `flair doctor` compare your installed version against the latest published release and print a nudge when you're behind:
260
99
 
261
100
  ```
262
101
  ⚠ flair 0.16.1 is behind — latest is 0.20.1 (4 releases behind). Upgrade: npm i -g @tpsdev-ai/flair@latest
263
102
  ```
264
103
 
265
- To upgrade:
266
-
267
104
  ```bash
268
- npm install -g @tpsdev-ai/flair@latest
269
-
270
- # Or check what's outdated across the whole toolchain (flair, flair-mcp, the
271
- # openclaw-flair plugin) without installing anything:
272
- flair upgrade --check
273
-
274
- # Then apply:
275
- flair upgrade
105
+ flair upgrade --check # show the plan across flair, flair-mcp and the openclaw-flair plugin
106
+ flair upgrade # apply it; the instance restarts automatically
276
107
  ```
277
108
 
278
- `flair upgrade` also restarts the running instance for you with `--restart`. If you deployed Flair to a Harper Fabric cluster (rather than running it locally), use `flair upgrade --target <fabric-url>` instead — see `flair upgrade --help`.
109
+ Deployed to a Harper Fabric cluster instead of running locally? Use `flair upgrade --target <fabric-url>`.
279
110
 
280
- ### Advanced / manual setup
111
+ ## What it looks like
281
112
 
282
- Prefer to drive each step yourself, or scripting an unattended setup? Run `flair init --no-mcp` to bootstrap the instance + agent without wiring any MCP clients, then drive each step on its own:
113
+ ![Flair: write a memory, find it by meaning, list of supported harnesses](docs/assets/flair-demo.gif)
283
114
 
284
- ```bash
285
- # Bootstrap a Flair instance without registering an agent or wiring MCP
286
- flair init --no-mcp
115
+ Write a memory, then find it by meaning. The same memory is visible to every harness in the catalog.
287
116
 
288
- # Register your first agent (generates an Ed25519 keypair, registers it)
289
- flair agent add mybot --name "My Bot"
117
+ ![Flair cross-orchestrator: one agent, one memory store, three MCP-capable CLIs](docs/assets/flair-cross-orchestrator.gif)
290
118
 
291
- # Check everything is working
292
- flair status
293
- ```
119
+ One Ed25519 identity, one memory store, three MCP-capable CLIs. A memory written from Claude Code is retrievable from Codex CLI and Gemini CLI a moment later. Identity and history aren't bound to one orchestrator's runtime.
294
120
 
295
- `flair init --agent mybot --no-mcp` bootstraps the instance and registers an agent in one step without touching any MCP client config. To wire clients later, re-run `flair init --agent mybot --client <name>`, or wire them manually using the snippets in **[docs/mcp-clients.md](docs/mcp-clients.md)** — all of them use the `npx -y @tpsdev-ai/flair-mcp` zero-install form.
121
+ ## How it works
296
122
 
297
- ## Integration
123
+ Flair is a native [Harper v5](https://harper.fast) application. Harper handles HTTP, persistence (RocksDB), and application logic in one process.
298
124
 
299
- Flair works with any agent runtime. Pick the path that fits yours.
125
+ ```
126
+ Agent ──[Ed25519-signed request]──▶ Flair (Harper)
127
+ ├── Auth middleware (verify signature)
128
+ ├── Identity (Agent + Integration tables)
129
+ ├── Memory (write → auto-embed → store)
130
+ ├── Soul (permanent personality/values)
131
+ └── Search (semantic + keyword, ranked)
132
+ ```
300
133
 
301
- ### Standalone (Flair CLI)
134
+ Embeddings are generated in-process by [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) (768-dim) via a Harper plugin, on CPU or GPU (Metal, CUDA). No API calls, no sidecar, no network hop. **[Supply-chain policy](docs/supply-chain-policy.md)** covers the bake-time and dependency pinning that keep it that way.
302
135
 
303
- Use the `flair` CLI directly from any agent that can run shell commands.
136
+ Requests are signed as `agentId:timestamp:nonce:METHOD:/path` and verified against the agent's registered public key, with a 30-second replay window and nonce deduplication.
304
137
 
305
- ```bash
306
- # Write a memory
307
- flair memory add --agent mybot --content "learned something important"
138
+ See **[DESIGN.md](DESIGN.md)** for the invariants behind the three primitives — why they're shaped the way they are.
308
139
 
309
- # Search by meaning
310
- flair memory search --agent mybot --q "that important thing"
140
+ ## Features
311
141
 
312
- # Set personality
313
- flair soul set --agent mybot --key role --value "Security reviewer"
142
+ | Feature | What it does |
143
+ |---|---|
144
+ | **Semantic memory** | Auto-embedded on write. Search by meaning, not keywords. |
145
+ | **Tiered durability** | `permanent` (delete rejected) / `persistent` / `standard` (default) / `ephemeral` (24h TTL). |
146
+ | **Temporal validity** | `validFrom` / `validTo` bounds. Expired memories drop out of search and bootstrap automatically. |
147
+ | **Trust-graded recall** | Opt-in per-result evidence: provenance, usage signal, freshness, supersession. Confidence bands (`strong`/`moderate`/`breadcrumb`) and first-class **abstention** when nothing clears the floor. |
148
+ | **Relationship graph** | Entity-to-entity triples with temporal bounds, queryable alongside semantic memory. |
149
+ | **Auto entity detection** | Entities extracted from memory content on write. No tagging required. |
150
+ | **Predictive bootstrap** | Cold-start context selected from active project, recent activity and agent role — not just recency. |
151
+ | **Multi-agent** | One instance, any number of agents, each with its own keys, memories and soul. |
152
+ | **Federation** | Hub-and-spoke sync between instances using signed requests and pairing tokens. Originator enforcement blocks cross-node replay. [docs/federation.md](docs/federation.md) |
153
+ | **Memory hygiene (REM)** | On-demand (`flair rem rapid`) and scheduled nightly distillation. Candidates are staged and promoted one at a time with a required rationale — never auto-applied. [docs/rem.md](docs/rem.md) |
154
+ | **Memory bridges** | Import/export to foreign memory systems via a YAML descriptor or a code plugin. [docs/bridges.md](docs/bridges.md) |
155
+ | **Real-time feeds** | Subscribe to memory or soul changes over WebSocket/SSE. |
156
+ | **OAuth 2.1 server** | PKCE, dynamic client registration, standards-compliant token endpoint. Delegate auth to Flair without a separate IdP. [docs/auth.md](docs/auth.md) |
157
+ | **XAA** | Bind agent identities to Google Workspace, Azure AD or Okta accounts. |
158
+ | **Web admin** | Server-rendered UI for principals, connectors, IdPs and instance config. No separate dashboard service. |
159
+ | **Benchmarks** | [`flair-bench`](packages/flair-bench/README.md) scores candidate embedding models against the same recall corpus Flair's CI gates on. Runs standalone — no Flair install, no server. |
160
+
161
+ Trust-graded recall reaches the authenticated HTTP API and the native `/mcp` tools today; CLI, `@tpsdev-ai/flair-client` and `flair-mcp` exposure is a follow-up. REM needs a configured generative backend (Ollama, OpenAI, Anthropic, …) — without one, `flair rem rapid` fails with `Reflection error: No generative backend configured`.
314
162
 
315
- # Cold-start bootstrap (soul + recent memories)
316
- flair bootstrap --agent mybot --max-tokens 4000
163
+ ## How Flair compares
317
164
 
318
- # Backup / restore
319
- flair backup --admin-pass "$FLAIR_ADMIN_PASS"
320
- flair restore ./backup.json --admin-pass "$FLAIR_ADMIN_PASS"
321
- ```
165
+ | | Flair | Mem0 | Honcho | Letta (MemGPT) | Built-ins (OAI/Anthropic/Google) |
166
+ |---|---|---|---|---|---|
167
+ | **Identity model** | **Ed25519 per agent (crypto-pinned)** | tenant-isolation | per-user soft tenant | runtime-bound | account-scoped |
168
+ | **Federation (peer-to-peer)** | **yes — hub/spoke validated** | no | no | no | no |
169
+ | **Cross-orchestrator** | **11+ harnesses, same memory** | several | several | runtime-bound | vendor-locked |
170
+ | **Soul / persistent character** | **first-class** | optional | persona-shaped | optional | no |
322
171
 
323
- ### OpenClaw
172
+ Parity rows are omitted: Mem0, Honcho and Letta are all open-source, self-hostable, and do semantic search. Those are table stakes here.
324
173
 
325
- One command. Zero config.
174
+ The honest gaps — if you need one of these specifically, use that tool:
326
175
 
327
- ```bash
328
- openclaw plugins install @tpsdev-ai/openclaw-flair
329
- ```
176
+ - Mem0's **cloud sync UX** is more polished, if you're happy with their hosting.
177
+ - Honcho's **persona model** is more developed, if rich personality modeling is the priority.
178
+ - Letta's **runtime integration** is tighter, if you're building on their agent loop.
330
179
 
331
- The plugin auto-detects your agent identity, provides `memory_store`/`memory_recall`/`memory_get` tools, and injects relevant memories at session start. See the [plugin README](packages/openclaw-flair/README.md) for details.
180
+ ## Integration
332
181
 
333
- ### Claude Code / Gemini CLI / OpenAI Codex CLI / Cursor (MCP)
182
+ Flair works with any agent runtime. Pick the path that fits yours — **[full catalog](docs/integrations.md)**.
334
183
 
335
- One MCP server, many CLIs. Install the MCP server for native tool integration in any MCP-capable client:
184
+ ### Claude Code / Cursor / Codex CLI / Gemini CLI (MCP)
185
+
186
+ `flair init` wires these automatically. To do it by hand:
336
187
 
337
188
  ```json
338
189
  // .mcp.json in your project root (Claude Code / Cursor format)
@@ -347,28 +198,46 @@ One MCP server, many CLIs. Install the MCP server for native tool integration in
347
198
  }
348
199
  ```
349
200
 
350
- Add to your `CLAUDE.md`:
201
+ Then add to your `CLAUDE.md`:
351
202
 
352
203
  At the start of every session, run mcp__flair__bootstrap before responding.
353
204
 
354
- Your agent's memory **follows it across CLIs** — same Flair instance, same agent identity, switch from Claude Code to Gemini CLI to Codex CLI without losing state. The `flair-mcp` server — the bridge these CLIs connect to — exposes `memory_store`, `memory_search`, `memory_update`, `memory_get`, `memory_delete`, `relationship_store`, `bootstrap`, `soul_set`, `soul_get`, `flair_workspace_set`, and `flair_orgevent`. (Flair's in-Harper native `/mcp` surface is a separate, still-experimental tool set with `attention` + `record_usage` — see Trust-Graded Recall above.)
355
-
356
- For per-CLI config snippets (Gemini CLI's `~/.gemini/settings.json`, Codex CLI's `~/.codex/config.toml`, etc.), see **[docs/mcp-clients.md](docs/mcp-clients.md)**. For a deeper Claude Code walk-through with `CLAUDE.md` patterns, see [docs/claude-code.md](docs/claude-code.md).
205
+ The `flair-mcp` server exposes `memory_store`, `memory_search`, `memory_update`, `memory_get`, `memory_delete`, `relationship_store`, `bootstrap`, `soul_set`, `soul_get`, `flair_workspace_set` and `flair_orgevent`. Memory follows the agent across CLIs same instance, same identity, switch harness without losing state.
357
206
 
358
- ### n8n (community node)
207
+ Per-CLI config snippets (Gemini CLI's `~/.gemini/settings.json`, Codex CLI's `~/.codex/config.toml`) are in **[docs/mcp-clients.md](docs/mcp-clients.md)**; a deeper Claude Code walk-through is in [docs/claude-code.md](docs/claude-code.md).
359
208
 
360
- Use Flair as the memory backend for n8n's AI Agent. Same memories readable from Claude Code and OpenClaw — that's the point.
209
+ ### OpenClaw
361
210
 
362
211
  ```bash
363
- # In n8n: Settings → Community Nodes → Install
364
- @tpsdev-ai/n8n-nodes-flair
212
+ openclaw plugins install @tpsdev-ai/openclaw-flair
213
+ ```
214
+
215
+ Auto-detects the agent identity, provides `memory_store` / `memory_recall` / `memory_get`, and injects relevant memories at session start. See the [plugin README](packages/openclaw-flair/README.md).
216
+
217
+ ### n8n
218
+
219
+ ```
220
+ Settings → Community Nodes → Install → @tpsdev-ai/n8n-nodes-flair
365
221
  ```
366
222
 
367
- Three nodes ship: **Flair Chat Memory** (Memory port, conversation buffer), **Flair Search** (Tool port, semantic search + get-by-subject), and **Flair Write** (Tool port, store memories). Setup walkthrough, subject/sessionId patterns, and security guidance in **[docs/n8n.md](docs/n8n.md)**.
223
+ Three nodes: **Flair Chat Memory** (Memory port), **Flair Search** and **Flair Write** (Tool ports). Setup and security guidance in **[docs/n8n.md](docs/n8n.md)** — read the auth note below first.
368
224
 
369
- ### JavaScript / TypeScript (Client Library)
225
+ ### Flair CLI
370
226
 
371
- For custom integrations, use the lightweight client no Harper, no embeddings, just HTTP + auth:
227
+ Any agent that can run a shell command can use Flair directly.
228
+
229
+ ```bash
230
+ flair memory add --agent mybot "learned something important"
231
+ flair search --agent mybot "that important thing"
232
+ flair soul set --agent mybot --key role --value "Security reviewer"
233
+ flair bootstrap --agent mybot --max-tokens 4000 # cold-start: soul + relevant memories
234
+ flair backup --admin-pass-file ~/.flair/admin-pass # logical JSON export
235
+ flair restore ./backup.json --admin-pass-file ~/.flair/admin-pass
236
+ ```
237
+
238
+ `--admin-pass-file` is preferred over `--admin-pass`: it keeps the secret out of `ps` and your shell history.
239
+
240
+ ### JavaScript / TypeScript
372
241
 
373
242
  ```bash
374
243
  npm install @tpsdev-ai/flair-client
@@ -383,185 +252,133 @@ const flair = new FlairClient({
383
252
  // key auto-resolved from ~/.flair/keys/mybot.key
384
253
  })
385
254
 
386
- // Write a memory
387
255
  await flair.memory.write('Harper v5 sandbox blocks bare imports')
388
-
389
- // Search by meaning
390
256
  const results = await flair.memory.search('native module loading')
391
-
392
- // Cold-start bootstrap
393
257
  const ctx = await flair.bootstrap({ maxTokens: 4000 })
394
-
395
- // Set personality
396
258
  await flair.soul.set('role', 'Security reviewer')
397
259
  ```
398
260
 
399
- See the [client README](packages/flair-client/README.md) for the full API.
261
+ No Harper, no embeddings — just HTTP and auth. Full API in the [client README](packages/flair-client/README.md).
400
262
 
401
- ### HTTP API (Any Language)
263
+ ### HTTP API (any language)
402
264
 
403
- Flair is a pure HTTP API. Use it from Python, Go, Rust, shell scripts — anything that can make HTTP requests and sign with Ed25519.
265
+ Anything that can make an HTTP request and sign with Ed25519.
404
266
 
405
267
  ```bash
406
- # Search memories
407
268
  curl -H "Authorization: TPS-Ed25519 mybot:$TS:$NONCE:$SIG" \
408
269
  -X POST http://localhost:19926/SemanticSearch \
409
270
  -d '{"agentId": "mybot", "q": "deployment procedure", "limit": 5}'
410
271
 
411
- # Write a memory
412
272
  curl -H "Authorization: TPS-Ed25519 mybot:$TS:$NONCE:$SIG" \
413
273
  -X PUT http://localhost:19926/Memory/mybot-123 \
414
274
  -d '{"id": "mybot-123", "agentId": "mybot", "content": "...", "durability": "standard"}'
415
-
416
- # Bootstrap (soul + recent memories)
417
- curl -H "Authorization: TPS-Ed25519 mybot:$TS:$NONCE:$SIG" \
418
- -X POST http://localhost:19926/BootstrapMemories \
419
- -d '{"agentId": "mybot", "maxTokens": 4000}'
420
275
  ```
421
276
 
422
- Auth is Ed25519 — sign `agentId:timestamp:nonce:METHOD:/path` with your private key. See [SECURITY.md](SECURITY.md) for the full protocol.
277
+ Sign `agentId:timestamp:nonce:METHOD:/path` with the agent's private key. Protocol in [SECURITY.md](SECURITY.md).
423
278
 
424
- ### Auth across surfaces
279
+ ### Embedded in a Harper app (in-process)
425
280
 
426
- The default, secure path everywhere is **Ed25519 per-agent**: each agent holds its own key (`~/.flair/keys/<agent>.key`) and signs every request. That guarantees write isolation (no agent can write as another) and identity-verified reads — it does **not** mean cross-agent reads are refused: within one Flair instance, any verified agent can read any other agent's non-private memory by design (open-within-org read; the hard boundary is the federation edge, not intra-instance reads see [SECURITY.md](SECURITY.md)). The CLI, the `flair-mcp` server, and the OpenClaw / pi / Hermes plugins all use this model.
281
+ Flair *is* a Harper component. If your application already runs on Harper, load Flair into the same instance and call its resources directlya method call instead of an HTTP round trip.
427
282
 
428
- One exception: the **`n8n-nodes-flair`** community node authenticates with the Harper **admin password** (Basic auth), which bypasses agent scoping entirely — including read of other agents' `visibility: private` memories and write-as-anyone, not just the org-wide non-private reads an Ed25519 identity already gets. That's acceptable only on a single-tenant, operator-controlled n8n with trusted workflow inputs; otherwise prefer the CLI/SDK Ed25519 path. Full breakdown in **[docs/auth.md](docs/auth.md#auth-across-surfaces-read-this-first)**.
283
+ ```javascript
284
+ import { server } from "harper";
429
285
 
430
- ## Architecture
431
-
432
- ```
433
- flair/
434
- ├── src/cli.ts # CLI: init, agent, status, backup, grant
435
- ├── config.yaml # Harper app configuration
436
- ├── schemas/
437
- │ ├── agent.graphql # Agent + Integration + MemoryGrant tables
438
- │ └── memory.graphql # Memory + Soul tables
439
- ├── resources/
440
- │ ├── auth-middleware.ts # Ed25519 verification + agent scoping
441
- │ ├── embeddings-provider.ts # In-process nomic embeddings
442
- │ ├── Memory.ts # Durability enforcement + auto-embed
443
- │ ├── Soul.ts # Permanent-by-default personality
444
- │ ├── SemanticSearch.ts # Hybrid semantic + keyword search
445
- │ ├── MemoryBootstrap.ts # Cold start context assembly
446
- │ └── MemoryFeed.ts # Real-time memory changes
447
- ├── plugins/
448
- │ └── openclaw-flair/ # @tpsdev-ai/openclaw-flair plugin
449
- └── SECURITY.md # Threat model + auth documentation
286
+ const Memory = server.resources.get("Memory").Resource; // the resource, not the table
287
+ const h = new Memory(undefined, { request: { tpsAgent: "mybot" } });
288
+ await h.post({ agentId: "mybot", content: "...", durability: "standard" });
450
289
  ```
451
290
 
452
- ### Key Design Decisions
291
+ `databases.flair.Memory` is the **table** (raw storage); the exported `Memory` class is the **resource**, where auth, read-scoping, visibility and embedding live. A context-less call runs unfiltered. Full guide: **[docs/embedding-in-a-harper-app.md](docs/embedding-in-a-harper-app.md)**.
292
+
293
+ ### Auth across surfaces
453
294
 
454
- - **Harper-native**No Express, no middleware frameworks. Harper IS the runtime.
455
- - **In-process embeddings** — Native [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) (768 dimensions) via [llama.cpp](https://github.com/ggerganov/llama.cpp). Runs on CPU or GPU (Metal, CUDA). No API calls, no OpenAI key needed.
456
- - **Schema-driven** — GraphQL schemas with `@table @export` auto-generate REST CRUD. Custom resources extend behavior (durability guards, auto-embedding, search).
457
- - **Admin credentials** — `flair init` auto-generates an admin password stored at `~/.flair/admin-pass` (mode 0600). Can also be set via `HDB_ADMIN_PASSWORD`. See [SECURITY.md](SECURITY.md) for the full model.
295
+ The default everywhere is **Ed25519 per-agent**: each agent holds its own key at `~/.flair/keys/<agent>.key` and signs every request. That gives write isolation no agent can write as another — and identity-verified reads. It does *not* refuse cross-agent reads: within one instance, any verified agent can read any other agent's non-private memory by design. The hard boundary is the federation edge, not intra-instance reads. See [SECURITY.md](SECURITY.md).
296
+
297
+ One exception: the **`n8n-nodes-flair`** node authenticates with the Harper **admin password** (Basic auth), which bypasses agent scoping entirely it can read other agents' `visibility: private` memories and write as anyone. That is acceptable only on a single-tenant, operator-controlled n8n with trusted workflow inputs. Otherwise prefer the Ed25519 path. Full breakdown in **[docs/auth.md](docs/auth.md#auth-across-surfaces-read-this-first)**.
458
298
 
459
299
  ## Deployment
460
300
 
461
301
  ### Local (default)
462
302
 
463
303
  ```bash
464
- flair init
304
+ flair init --agent mybot
465
305
  ```
466
306
 
467
- Your data stays on your machine. Best for personal agents, dev teams, and privacy-first setups. Flair runs as a single Harper process no Docker, no cloud, no external services.
468
-
469
- #### Custom Ports
470
- If the default port (`19926`) is already in use, initialize with a custom port:
471
- ```bash
472
- flair init --port 8000
473
- ```
474
- Flair will automatically remember this port for future CLI commands by saving it to `~/.flair/config.yaml`.
307
+ Data stays on your machine. A single Harper process — no Docker, no cloud, no external services. If port `19926` is taken, `flair init --port 8000` records the choice in `~/.flair/config.yaml` for future commands.
475
308
 
476
309
  ### Remote Server
477
310
 
478
- Run Flair on a VPS or cloud instance. Agents connect over HTTPS:
311
+ Run Flair on a VPS or cloud instance; agents connect over HTTPS.
479
312
 
480
313
  ```bash
481
314
  # On the server
482
- flair init --port 19926
483
- # Agents connect with:
484
- FLAIR_URL=https://your-server:19926 flair agent add mybot
315
+ flair init --agent mybot --port 19926
316
+
317
+ # On each client — --target seeds the agent on the remote instance
318
+ flair agent add otherbot --target https://your-server:19926
485
319
  ```
486
320
 
487
- Good for teams with multiple machines or always-on agents.
321
+ `--target` derives the operations API as *REST port − 1*. If that isn't where your ops API lives, pass `--ops-target` explicitly. Good for teams with multiple machines or always-on agents.
488
322
 
489
323
  ### Harper Fabric
490
324
 
491
- Deploy Flair on [Harper Fabric](https://www.harperdb.io/) for managed hosting with multi-region replication and failover. Federation runs against Harper Fabric hubs (e.g. `flair.your-org.harperfabric.com`) — pair your local instance to sync memories across nodes.
325
+ Managed hosting with multi-region replication and failover. Federation runs against Harper Fabric hubs — pair your local instance to sync memories across nodes. Full guide: **[docs/deploying-on-fabric.md](docs/deploying-on-fabric.md)**.
492
326
 
493
327
  ## Security
494
328
 
495
- See [SECURITY.md](SECURITY.md) for the full security model, threat analysis, and recommendations.
329
+ Full model, threat analysis and recommendations in [SECURITY.md](SECURITY.md).
496
330
 
497
- **Key points:**
498
- - Ed25519 cryptographic identity agents sign every request
499
- - Reads are open within the org any agent can read any other agent's non-private memory, no grant required; `private` is the one owner-only exception (see [DESIGN.md](DESIGN.md))
500
- - Admin password auto-generated on init, stored at `~/.flair/admin-pass` (mode 0600)
501
- - Key rotation via `flair agent rotate-key`
502
- - Writes are always agent-scoped — an agent can only write its own records
331
+ - Ed25519 cryptographic identity — agents sign every request.
332
+ - Writes are always agent-scoped. An agent can only write its own records.
333
+ - Reads are open within the org: any agent can read any other agent's non-private memory, no grant required. `private` is the one owner-only exception ([DESIGN.md](DESIGN.md#access-model-open-within-the-org-closed-at-the-federation-edge)).
334
+ - The admin password is generated by `flair init` and written to `~/.flair/admin-pass` (mode 0600). The CLI prints the path, never the value. Prefer `--admin-pass-file` over `--admin-pass` so it stays out of `ps` and shell history.
335
+ - Key rotation via `flair agent rotate-key`.
503
336
 
504
- ## Development
337
+ ## Architecture
505
338
 
506
- ```bash
507
- bun install # Install dependencies
508
- bun run build # Compile TypeScript dist/
509
- bun test # Run unit + integration tests
339
+ ```
340
+ flair/
341
+ ├── src/cli.ts # CLI: init, agent, status, backup, grant
342
+ ├── config.yaml # Harper app configuration
343
+ ├── schemas/*.graphql # Agent, Memory, Soul, Federation, OAuth tables
344
+ ├── resources/
345
+ │ ├── auth-middleware.ts # Ed25519 verification + agent scoping
346
+ │ ├── embeddings-provider.ts # In-process nomic embeddings
347
+ │ ├── Memory.ts # Durability enforcement + auto-embed
348
+ │ ├── Soul.ts # Permanent-by-default personality
349
+ │ ├── SemanticSearch.ts # Hybrid semantic + keyword search
350
+ │ ├── MemoryBootstrap.ts # Cold-start context assembly
351
+ │ └── MemoryFeed.ts # Real-time memory changes
352
+ ├── packages/ # flair-mcp, flair-client, openclaw-flair, n8n-nodes-flair,
353
+ │ # langgraph-flair, hermes-flair, pi-flair, flair-bench
354
+ └── SECURITY.md # Threat model + auth documentation
510
355
  ```
511
356
 
512
- Integration tests spin up a real Harper instance on a random port, run the test suite, and tear down. No mocks for the database layer.
357
+ Key decisions:
513
358
 
514
- ### Test Coverage
359
+ - **Harper-native** — no Express, no middleware framework. Harper *is* the runtime.
360
+ - **In-process embeddings** — [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) via [llama.cpp](https://github.com/ggerganov/llama.cpp), CPU or GPU. No OpenAI key needed.
361
+ - **Schema-driven** — GraphQL `@table @export` auto-generates REST CRUD; custom resources add durability guards, auto-embedding and search.
515
362
 
516
- **203+ unit tests** across 19 test files, covering 7 CI checks on every commit.
363
+ ## Development
517
364
 
518
- | Category | Tests | What's covered |
519
- |----------|-------|----------------|
520
- | **Auth & Identity** | auth-middleware, auth-scoping, key-paths-and-rotation | Ed25519 signature verification, agent isolation, key rotation |
521
- | **Memory** | data-scoping, backup-restore, agent-remove-and-grants | Private-memory exclusion, open within-org read scoping, data durability, grant lifecycle |
522
- | **Content Safety** | content-safety | Prompt injection detection, identity hijacking, format injection, exfiltration patterns |
523
- | **Search** | temporal-scoring, embeddings | Temporal decay, relevance scoring, embedding generation |
524
- | **Rate Limiting** | rate-limiter | Per-agent rate limiting, bucket isolation |
525
- | **Integration** | smoke, durability-guard | End-to-end write/search/bootstrap, durability tier enforcement |
526
- | **CLI** | cli-v2, cli-api, first-run-soul | Full CLI command coverage, API layer, soul onboarding |
365
+ ```bash
366
+ bun install # install dependencies
367
+ bun run build # compile TypeScript dist/
368
+ bun test # unit + integration tests
369
+ ```
527
370
 
528
- CI pipeline: unit tests, integration tests, type check, dependency audit, Semgrep SAST, CodeQL SAST, Docker from-scratch validation.
371
+ Integration tests spin up a real Harper instance on a random port and tear it down afterwards — no mocks for the database layer. Every commit runs unit tests, integration tests, type check, dependency audit, Semgrep and CodeQL SAST, and a from-scratch Docker validation. See [CONTRIBUTING.md](CONTRIBUTING.md).
529
372
 
530
373
  ## Status
531
374
 
532
- > **Note:** Flair uses [Harper v5](https://harper.fast), currently in beta. We run it in production daily and track upstream closely. Pin your Harper version.
533
-
534
- Flair is in active development and daily use. We dogfood it the agents that build Flair use Flair for their own memory and identity.
535
-
536
- **What works:**
537
- - ✅ Ed25519 agent identity and auth
538
- - CLI: init, agent add/remove/rotate-key, status, backup/restore, export/import, grant/revoke
539
- - ✅ Memory CRUD with durability enforcement and near-duplicate detection
540
- - ✅ In-process semantic embeddings (768-dim nomic-embed-text via harper-fabric-embeddings)
541
- - ✅ Hybrid search (semantic + keyword + temporal intent detection)
542
- - ✅ Soul (permanent personality/values)
543
- - ✅ Real-time feeds (WebSocket/SSE)
544
- - ✅ Agent-scoped data isolation
545
- - ✅ Cold start bootstrap with adaptive time window
546
- - ✅ Predictive bootstrap (context-signal-aware preloading)
547
- - ✅ Temporal validity (`validFrom`/`validTo` on memories)
548
- - ✅ Relationship graph (entity-to-entity triples with temporal bounds)
549
- - ✅ Auto entity detection (passive extraction from memory content)
550
- - ✅ OAuth 2.1 authorization server (PKCE, dynamic client registration, token endpoint)
551
- - ✅ XAA enterprise authorization (Google Workspace, Azure AD, Okta)
552
- - ✅ Web admin UI (principals, connectors, IdPs, instance config)
553
- - ✅ Federation (hub-and-spoke sync with signed requests and pairing tokens)
554
- - ✅ OpenClaw memory plugin
555
- - ✅ MCP server for Claude Code / Cursor / Codex / Gemini CLI
556
- - ✅ Lightweight client library (`@tpsdev-ai/flair-client`)
557
- - ✅ Portable agent identity (export/import between instances)
558
- - ✅ `flair --version`, `flair upgrade`
559
- - ✅ First-run soul wizard (interactive personality setup)
560
-
561
- **What's next:**
562
- - [ ] Git-backed memory sync
563
- - [ ] Encryption at rest (opt-in AES-256-GCM per memory)
564
- - [ ] Harper Fabric deployment (managed multi-office)
375
+ Flair is in active development and daily use. We dogfood it: the agents that build Flair use Flair for their own memory and identity.
376
+
377
+ Shipped: Ed25519 identity and auth · memory CRUD with durability enforcement and near-duplicate detection · in-process semantic embeddings · hybrid search with temporal intent detection · soul · relationship graph · auto entity detection · temporal validity · real-time feeds · predictive bootstrap · federation · OAuth 2.1 and XAA · web admin · REM memory hygiene · MCP server · OpenClaw plugin · client library · portable agent export/import · `flair upgrade`.
378
+
379
+ Next: git-backed memory sync · opt-in encryption at rest (AES-256-GCM per memory).
380
+
381
+ > **Note:** Flair runs on [Harper v5](https://harper.fast), currently in beta. We run it in production daily and track upstream closely. Pin your Harper version.
565
382
 
566
383
  ## License
567
384