@tpsdev-ai/flair 0.31.1 → 0.33.0

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.
@@ -0,0 +1,243 @@
1
+ # Standalone Local Deployment
2
+
3
+ `flair init` installs and runs its own Harper process. This is the default path and what most operators use: a single process on a single machine, no Fabric, no external services.
4
+
5
+ If you're starting from zero, begin with the [quickstart](quickstart.md). This page covers the full lifecycle: install, configuration, authentication, verification, and upgrade.
6
+
7
+ ---
8
+
9
+ ## Install & deploy
10
+
11
+ **Prerequisites:** Node.js 22+ (LTS or current). No Docker, no database, no API keys.
12
+
13
+ ### 1. Install the CLI
14
+
15
+ Use a **user-writable npm prefix** so the package directory is owned by you. A root-owned install (`sudo npm install -g`) breaks the embeddings component at runtime:
16
+
17
+ ```bash
18
+ mkdir -p ~/.npm-global
19
+ npm config set prefix ~/.npm-global
20
+ export PATH="$HOME/.npm-global/bin:$PATH" # add to your shell rc to persist
21
+
22
+ npm install -g @tpsdev-ai/flair
23
+ ```
24
+
25
+ > ⚠️ **Never `sudo npm install -g @tpsdev-ai/flair`.** A root-owned install makes the package directory unwritable by the user Harper runs as. At runtime the embeddings component gets `EACCES` and semantic search silently degrades to keyword-only. `flair init` and `flair doctor` will warn you loudly.
26
+
27
+ ### 2. Bootstrap the instance
28
+
29
+ ```bash
30
+ flair init
31
+ ```
32
+
33
+ `flair init` does everything in one step:
34
+
35
+ 1. Installs the embedded Harper (memory store) into `~/.flair/data/`.
36
+ 2. Downloads the local embedding model (~80 MB — first run only).
37
+ 3. Starts Flair as a launchd / systemd service on port `19926`.
38
+ 4. Creates a default agent identity (Ed25519 keypair, stored at `~/.flair/keys/<agent>.key`).
39
+ 5. Runs a smoke test to confirm semantic search works.
40
+
41
+ Useful flags:
42
+
43
+ ```bash
44
+ flair init --agent mybot # name the agent (--agent-id also works)
45
+ flair init --client claude-code # wire one specific MCP client
46
+ flair init --no-mcp # instance + agent only, skip MCP wiring
47
+ flair init --skip-smoke # skip the MCP smoke test
48
+ flair init --port 8000 # use a non-default port
49
+ ```
50
+
51
+ > **Non-interactive shell:** bare `flair init` with no `--agent` bootstraps the instance only and skips agent registration, MCP client wiring, and the smoke test. Pass flags explicitly: `flair init --agent <id> --client all`.
52
+
53
+ ### 3. Lifecycle management
54
+
55
+ ```bash
56
+ flair status # check everything is working
57
+ flair stop # stop the service (keeps data)
58
+ flair restart # restart the service
59
+ flair uninstall # remove the service (keeps data + keys)
60
+ flair uninstall --purge # remove everything including data and keys
61
+ ```
62
+
63
+ On macOS the service is a launchd plist at `~/Library/LaunchAgents/ai.tpsdev.flair.plist`. On Linux it is a systemd unit at `~/.config/systemd/user/flair.service`. Both auto-start on login/boot and restart on crash.
64
+
65
+ ### Docker
66
+
67
+ Flair does not have a foreground daemon mode today (`flair start` has no `--foreground` option and `flair init` always installs a service manager unit). There is no supported Docker recipe — run Flair directly on the host or use [Harper Fabric](https://www.harperdb.io/) for managed hosting.
68
+
69
+ Embeddings run on CPU in any containerized environment (no Metal acceleration). Performance is acceptable for small-to-medium memory stores (< 10K memories).
70
+
71
+ See also: [system-requirements.md](system-requirements.md) for measured resource usage.
72
+
73
+ ---
74
+
75
+ ## Configuration
76
+
77
+ All configuration lives in `~/.flair/`:
78
+
79
+ ```
80
+ ~/.flair/
81
+ ├── config.yaml # port, host, embedding model
82
+ ├── data/ # Harper database (RocksDB)
83
+ ├── keys/ # Ed25519 keypairs per agent (mode 0600)
84
+ └── backups/ # flair backup output
85
+ ```
86
+
87
+ ### Key config options (`~/.flair/config.yaml`)
88
+
89
+ ```yaml
90
+ http:
91
+ port: 19926 # API port (ops port = this - 1)
92
+ host: 127.0.0.1 # bind address (0.0.0.0 for remote access)
93
+
94
+ clustering:
95
+ nodeName: flair
96
+
97
+ logging:
98
+ level: warn
99
+ stdStreams: true
100
+ ```
101
+
102
+ ### Environment variables
103
+
104
+ | Variable | What it does | When to set it |
105
+ |----------|--------------|----------------|
106
+ | `FLAIR_PUBLIC_URL` | The URL operators reach this Flair on. Used by OAuth metadata and A2A discovery. | Set on VPS / internet-facing deployments. |
107
+ | `HDB_ADMIN_PASSWORD` | Bootstrap password for the embedded Harper. After first start, the persisted user record is the source of truth. | Set at install time. See [secrets-and-keys.md](secrets-and-keys.md) for rotation. |
108
+ | `FLAIR_KEY_PASSPHRASE` | Passphrase for AES-256-GCM encryption of federation private-key seeds. | Set explicitly for production federation deployments. |
109
+ | `FLAIR_URL` | Override the Flair base URL for CLI commands (points to a remote instance). | When connecting from a different machine. |
110
+
111
+ ---
112
+
113
+ ## Agent authentication
114
+
115
+ Agents authenticate with **Ed25519 per-agent keys**:
116
+
117
+ ```bash
118
+ # Register an agent (generates Ed25519 keypair at ~/.flair/keys/myagent.key)
119
+ flair agent add myagent
120
+
121
+ # List registered agents
122
+ flair agent list
123
+ ```
124
+
125
+ Every request to Flair is signed with the agent's private key. The signed payload is `agentId:timestamp:nonce:METHOD:/path` with a 30-second replay window and nonce deduplication. Unsigned requests are rejected.
126
+
127
+ This guarantees **write isolation** (no agent can write as another) and identity-verified reads. Reads are intentionally more open: any verified agent on the same instance can read any other agent's non-private memories. Only `visibility: private` memories are owner-only. See [SECURITY.md](../SECURITY.md) for the full model.
128
+
129
+ ### The private key
130
+
131
+ - Lives at `~/.flair/keys/<agent>.key` (PKCS8 base64, mode `0600`).
132
+ - **Stays on the host that owns the agent.** Don't copy it to another machine — register a new agent identity there.
133
+ - **Don't check it into git.** Rotate first if compromised: `flair agent rotate-key <id>`.
134
+ - `flair backup` excludes private keys by default. Back them up separately if you want offsite recovery.
135
+
136
+ See [secrets-and-keys.md](secrets-and-keys.md) for the full threat model and key lifecycle.
137
+
138
+ ---
139
+
140
+ ## Verify it works
141
+
142
+ ### Quick health check
143
+
144
+ ```bash
145
+ flair status
146
+ ```
147
+
148
+ The **🟢** icon means everything is healthy. A **🟡** means something worth looking at; **🔴 unreachable** means the server isn't running.
149
+
150
+ ```bash
151
+ flair status --agent local # full detail: memory counts, soul entries
152
+ flair doctor # automated diagnosis + fix suggestions
153
+ ```
154
+
155
+ ### End-to-end smoke test
156
+
157
+ ```bash
158
+ # Write a memory
159
+ flair memory add --agent myagent "Harper v5 sandbox blocks node:module but process.dlopen works"
160
+
161
+ # Find it by meaning (not keywords)
162
+ flair memory search --agent myagent "native addon loading in sandboxed runtimes"
163
+ # → [0.67] Harper v5 sandbox blocks node:module but process.dlopen works
164
+ ```
165
+
166
+ ### Connectivity
167
+
168
+ ```bash
169
+ curl http://localhost:19926/Health # public, no auth needed
170
+ flair doctor # checks embeddings, auth, connectivity
171
+ ```
172
+
173
+ See [troubleshooting.md](troubleshooting.md) for common issues and fixes.
174
+
175
+ ---
176
+
177
+ ## Upgrade
178
+
179
+ `flair upgrade` is install → restart → verify → rollback-on-failure in one step:
180
+
181
+ ```bash
182
+ # 1. Back up first, always
183
+ flair backup --output ~/flair-backup-$(date +%Y%m%d).json --admin-pass-file ~/.flair/admin-pass
184
+
185
+ # 2. Check what's outdated (doesn't install anything)
186
+ flair upgrade --check
187
+
188
+ # 3. Upgrade — installs, restarts, and verifies in one step
189
+ flair upgrade
190
+
191
+ # 4. Verify
192
+ flair status
193
+ flair doctor
194
+ ```
195
+
196
+ Optional: `flair upgrade --snapshot` takes a byte-exact snapshot of `~/.flair/data` before upgrading, so you can restore the physical data directory if the new version writes data the old version can't read.
197
+
198
+ See [upgrade.md](upgrade.md) for the full walkthrough including re-embedding, rollback, and downgrade.
199
+
200
+ ---
201
+
202
+ ## Backup & restore
203
+
204
+ ```bash
205
+ # Backup all data (agents, memories, souls)
206
+ flair backup --output ~/flair-backup-$(date +%Y%m%d).json
207
+
208
+ # Restore to a fresh instance
209
+ flair restore ~/flair-backup-20260405.json
210
+ ```
211
+
212
+ Always backup before upgrades. `flair backup` excludes private keys.
213
+
214
+ ---
215
+
216
+ ## Federation
217
+
218
+ Available. Pair a local instance as a hub or spoke with another Flair instance:
219
+
220
+ ```bash
221
+ # On the hub — generate a one-time pairing token triple
222
+ FLAIR_ADMIN_PASS=<hub-admin-password> flair federation token > triple.json
223
+
224
+ # On the spoke — pair to the hub
225
+ flair federation pair <hub-url> --token-from ./triple.json
226
+
227
+ # Sync (one-shot)
228
+ flair federation sync --admin-pass-file ~/.flair/admin-pass
229
+ ```
230
+
231
+ Full walkthrough: [federation.md](federation.md).
232
+
233
+ ---
234
+
235
+ ## See also
236
+
237
+ - [deployment-shapes.md](deployment-shapes.md) — choose your shape
238
+ - [quickstart.md](quickstart.md) — zero to working in 5 minutes
239
+ - [upgrade.md](upgrade.md) — full upgrade mechanics (re-embedding, rollback, downgrade)
240
+ - [federation.md](federation.md) — hub-and-spoke sync between instances
241
+ - [troubleshooting.md](troubleshooting.md) — common issues and automated diagnosis
242
+ - [system-requirements.md](system-requirements.md) — measured resource usage
243
+ - [secrets-and-keys.md](secrets-and-keys.md) — agent keys, admin password, threat model
package/docs/the-team.md CHANGED
@@ -15,7 +15,7 @@ If you're trying to run your own multi-agent team using Flair as the memory laye
15
15
  | **Pulse** | EA / intel scanning / coordination | OpenClaw | Claude API | cloud VM |
16
16
  | **Nathan** | Founder / product owner / human-in-the-loop | (human) | (human) | wherever |
17
17
 
18
- Every agent has its own Ed25519 identity in Flair. They sign every memory write and every read. **Writes are isolated at the Flair API layer** — Sherlock can't accidentally (or maliciously) write into Pulse's memory, because the signature won't verify for anyone but Pulse. Reads are a different story: within one Flair instance, any verified agent can read any other agent's **non-private** memory — that's the shipped model (open-within-org read, no grant needed), not a gap. An agent keeps something genuinely sensitive owner-only by writing it with `visibility: private`. The hard access boundary is the **federation edge** (a separate Flair instance), not reads within one.
18
+ Every agent has its own Ed25519 identity in Flair. They sign every memory write and every read. **Writes are isolated at the Flair API layer** — Sherlock can't accidentally (or maliciously) write into Pulse's memory, because the signature won't verify for anyone but Pulse. Reads are a different story: within one Flair instance, any verified agent can read any other agent's **non-private** memory — that's the shipped model (open-within-org read, no grant needed), not a gap. Which memories are non-private is decided at write time: visibility defaults from durability, so `permanent`/`persistent` writes land `shared` and `standard`/`ephemeral` writes land `private`. A teammate's scratch context is therefore owner-only until someone shares it deliberately, and an agent keeps something genuinely sensitive owner-only regardless of durability by writing it with `visibility: private`. The hard access boundary is the **federation edge** (a separate Flair instance), not reads within one.
19
19
 
20
20
  ## How memory flows
21
21
 
@@ -41,10 +41,14 @@ Every agent has its own Ed25519 identity in Flair. They sign every memory write
41
41
 
42
42
  (every agent can read every other
43
43
  agent's non-private memories —
44
- `visibility: private` stays owner-only)
44
+ permanent/persistent land shared,
45
+ standard/ephemeral land private,
46
+ and private stays owner-only)
45
47
  ```
46
48
 
47
- No agent can write into another agent's memory — that's enforced server-side by signature verification, no exceptions. Reads are intentionally open within the org: when Flint commits a piece of strategy, any agent can find it on `memory_search` unless Flint marked it `private`. **By design** — the goal is relevance and findability across the team, not secrecy between roles. An agent that genuinely needs something to stay owner-only (a draft not ready for the team, a sensitive finding pre-disclosure) marks it `visibility: private`; everything else is fair game for any teammate to search.
49
+ No agent can write into another agent's memory — that's enforced server-side by signature verification, no exceptions. Reads are intentionally open within the org: when Flint commits a piece of strategy as a `permanent` or `persistent` memory, it lands `shared` and any agent can find it on `memory_search`. **By design** — the goal is relevance and findability across the team, not secrecy between roles.
50
+
51
+ The reverse also holds, and it is the part worth internalising: a `standard` or `ephemeral` write lands `private`, so an agent's day-to-day working context is *not* team-searchable by default. Commit something at `permanent`/`persistent` durability, or pass `visibility: shared`, when you mean the team to find it. An agent that needs something owner-only whatever its durability (a draft not ready for the team, a sensitive finding pre-disclosure) marks it `visibility: private` explicitly.
48
52
 
49
53
  When agents need to *coordinate* — a direct, targeted handoff rather than ambient searchable memory — they pass **explicit messages** through TPS mail (a separate signed delivery channel; see [tpsdev-ai/cli](https://github.com/tpsdev-ai/cli)). That's a different concern from memory visibility: TPS mail is for "I need you, specifically, to see this now"; Flair memory is the shared, searchable record everyone (except where `private`) can draw on later.
50
54
 
@@ -106,7 +110,7 @@ The MCP server (`@tpsdev-ai/flair-mcp`) is what makes this orchestrator-agnostic
106
110
 
107
111
  ## What we deliberately don't do
108
112
 
109
- - **No shared write identity.** Every memory is written and owned by exactly one agent's Ed25519 key — there's no merged "team" identity that can write on another agent's behalf. Reads are a separate story: within the org, any agent can search any other's non-private memory by default (see [SECURITY.md](../SECURITY.md)) — that's intentional, not a leak. TPS mail is still how agents route a message to a *specific* teammate; it's for targeted delivery, not for gating ambient visibility.
113
+ - **No shared write identity.** Every memory is written and owned by exactly one agent's Ed25519 key — there's no merged "team" identity that can write on another agent's behalf. Reads are a separate story: within the org, any agent can search any other's non-private memory by default (see [SECURITY.md](../SECURITY.md)) — that's intentional, not a leak. "Non-private" is set at write time from durability, not by a per-pair grant. TPS mail is still how agents route a message to a *specific* teammate; it's for targeted delivery, not for gating ambient visibility.
110
114
  - **No silent LLM-driven memory extraction.** Each agent decides what it remembers. No background "summarize and persist" on every turn — that's how memory drifts away from intent.
111
115
  - **No multiple agents on one identity.** "Anvil" and "Anvil-2" would be two separate agentIds with two separate keys. Same workload, different identities, separately-owned memories.
112
116
  - **No replay-safe-but-otherwise-unsigned reads.** Every Flair request is Ed25519-signed and verified, including reads. Even on a private network we don't trust the network.
@@ -150,7 +150,7 @@ flair agent list
150
150
  **Possible causes:**
151
151
  1. **Hash-fallback embeddings:** Check `flair status` — if embeddings are in hash mode, semantic search won't work properly. Fix with `flair reembed`.
152
152
  2. **Content safety flags:** The memory might have been flagged. Search for it directly: `flair memory list --agent <id>`.
153
- 3. **`visibility: private`:** Reads are open within the org by default any agent can find any other agent's non-private memories. If the memory was written with `visibility: private`, only its author can find it; search as that agent instead.
153
+ 3. **`visibility: private`:** Only its author can find a `private` memory. This is the most common cause when one agent wrote the memory and another is searching for it, because **`private` is what a bare write lands on**: visibility defaults from durability (`permanent`/`persistent` → `shared`, `standard`/`ephemeral` → `private`), and a write with no `--durability` is `standard`. Check what the memory landed on with `flair memory list --agent <author> --json` (the table view doesn't show visibility, the JSON records do), then either search as its author, or rewrite it with `--visibility shared` so every agent on the instance can find it (no grant needed non-private reads are open within the instance).
154
154
  4. **Dedup threshold:** If the content is very similar to an existing memory, it may have been deduplicated. Check with `flair memory list`.
155
155
 
156
156
  ### High memory usage
package/docs/upgrade.md CHANGED
@@ -17,7 +17,11 @@ There are two things you might be upgrading:
17
17
 
18
18
  ```bash
19
19
  # 1. Back up first, always
20
- flair backup > ~/flair-backup-$(date +%Y%m%d).json
20
+ # --admin-pass-file keeps the secret out of ps and shell history.
21
+ # --output is required — the archive goes to a file, not stdout.
22
+ flair backup \
23
+ --output ~/flair-backup-$(date +%Y%m%d).json \
24
+ --admin-pass-file ~/.flair/admin-pass
21
25
 
22
26
  # 2. Check what's outdated (doesn't install anything)
23
27
  flair upgrade --check
@@ -352,7 +356,7 @@ npm install -g @tpsdev-ai/flair@<previous-version>
352
356
  flair restart
353
357
 
354
358
  # If data looks wrong, restore from your pre-upgrade backup
355
- flair restore < ~/flair-backup-<date>.json
359
+ flair restore ~/flair-backup-<date>.json
356
360
  ```
357
361
 
358
362
  `flair upgrade` does this automatically on a failed post-restart verification — see
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/flair",
3
- "version": "0.31.1",
3
+ "version": "0.33.0",
4
4
  "packageManager": "bun@1.3.10",
5
5
  "description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
6
6
  "type": "module",
@@ -25,6 +25,12 @@
25
25
  "llm",
26
26
  "openclaw"
27
27
  ],
28
+ "main": "./dist/resources/in-process-api.js",
29
+ "exports": {
30
+ ".": "./dist/resources/in-process-api.js",
31
+ "./server": "./dist/resources/in-process.js",
32
+ "./package.json": "./package.json"
33
+ },
28
34
  "bin": {
29
35
  "flair": "dist/cli-shim.cjs"
30
36
  },