@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.
- package/README.md +80 -54
- package/SECURITY.md +7 -0
- package/config.yaml +34 -0
- package/dist/cli.js +349 -117
- package/dist/resources/Memory.js +24 -2
- package/dist/resources/in-process-api.js +386 -0
- package/dist/resources/mcp-tools.js +40 -0
- package/docs/deployment-shapes.md +35 -0
- package/docs/deployment.md +2 -2
- package/docs/embedding-in-a-harper-app.md +175 -75
- package/docs/hosted-on-fabric.md +203 -0
- package/docs/mcp-clients.md +4 -2
- package/docs/quickstart.md +29 -4
- package/docs/secrets-and-keys.md +4 -4
- package/docs/standalone-local.md +243 -0
- package/docs/the-team.md +8 -4
- package/docs/troubleshooting.md +1 -1
- package/docs/upgrade.md +6 -2
- package/package.json +7 -1
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
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.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -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`:**
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
},
|