@tpsdev-ai/flair 0.25.4 → 0.27.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.
Files changed (39) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +998 -50
  3. package/dist/doctor-client.js +47 -0
  4. package/dist/rem/runner.js +60 -3
  5. package/dist/resources/MemoryDedupStats.js +161 -0
  6. package/dist/resources/dedup-cluster.js +145 -0
  7. package/dist/resources/health.js +33 -1
  8. package/dist/resources/mcp-oauth.js +4 -2
  9. package/docs/assets/flair-cross-orchestrator.cast +33 -0
  10. package/docs/assets/flair-cross-orchestrator.gif +0 -0
  11. package/docs/assets/flair-demo.cast +18 -0
  12. package/docs/assets/flair-demo.gif +0 -0
  13. package/docs/auth.md +178 -0
  14. package/docs/bridges.md +291 -0
  15. package/docs/claude-code.md +202 -0
  16. package/docs/deployment.md +204 -0
  17. package/docs/entity-vocabulary.md +109 -0
  18. package/docs/federation.md +179 -0
  19. package/docs/integrations.md +197 -0
  20. package/docs/mcp-clients.md +240 -0
  21. package/docs/n8n-management.md +142 -0
  22. package/docs/n8n.md +122 -0
  23. package/docs/notes/adk-spike-findings-2026-05-05.md +331 -0
  24. package/docs/notes/mcp-agent-auth-consumer.md +229 -0
  25. package/docs/notes/mcp-oauth-model2.md +132 -0
  26. package/docs/notes/rem-ux.md +39 -0
  27. package/docs/openclaw.md +131 -0
  28. package/docs/quickstart.md +153 -0
  29. package/docs/releasing.md +173 -0
  30. package/docs/rem.md +60 -0
  31. package/docs/rerank-provisioning.md +67 -0
  32. package/docs/secrets-and-keys.md +173 -0
  33. package/docs/spoke-bringup.md +303 -0
  34. package/docs/supply-chain-policy.md +156 -0
  35. package/docs/system-requirements.md +42 -0
  36. package/docs/the-team.md +129 -0
  37. package/docs/troubleshooting.md +187 -0
  38. package/docs/upgrade.md +416 -0
  39. package/package.json +2 -1
@@ -0,0 +1,240 @@
1
+ # Flair via MCP — Claude Code, Gemini CLI, OpenAI Codex CLI
2
+
3
+ Flair ships an MCP server (`@tpsdev-ai/flair-mcp`) that any MCP-compatible client can use as its persistent memory + identity layer. One server, three (and counting) integrations. Switch between agent CLIs without losing your agent's memory.
4
+
5
+ This page is the install + config snippet for each of the three major CLIs. The bootstrap is the same:
6
+
7
+ 1. Install Flair and create an agent identity (one-time, ~2 min).
8
+ 2. Add the MCP server to your CLI of choice (1 command or 1 file).
9
+ 3. Verify the agent can call `memory_search` / `memory_store`.
10
+
11
+ If you've never set up Flair before, do step 1 first. If Flair is already running and you have an agent ID, jump to your CLI section.
12
+
13
+ ---
14
+
15
+ ## Step 1 — Install Flair (do once)
16
+
17
+ ```bash
18
+ # Install Flair globally
19
+ npm install -g @tpsdev-ai/flair
20
+
21
+ # Initialize the local Harper-backed server
22
+ flair init
23
+
24
+ # Provision an agent identity. Pick a name — typically per-project, per-purpose,
25
+ # or "me" if you want one durable identity across everything.
26
+ flair agent add my-project
27
+ # → writes ~/.flair/keys/my-project.key (Ed25519 PKCS8) and registers the agent
28
+
29
+ # Sanity check
30
+ flair status
31
+ ```
32
+
33
+ Flair runs as a local server at `http://127.0.0.1:19926` by default. The MCP server connects to it on demand via Ed25519-signed requests; nothing leaves your machine unless you explicitly route to a remote Flair instance.
34
+
35
+ ---
36
+
37
+ ## Step 2 — Wire the MCP server into your CLI
38
+
39
+ Pick whichever you use. The MCP server is the same package; only the config syntax differs.
40
+
41
+ ### Claude Code
42
+
43
+ The canonical approach is the `claude mcp add` CLI (writes to `~/.claude/mcp.json`):
44
+
45
+ ```bash
46
+ claude mcp add flair --scope user \
47
+ -e FLAIR_AGENT_ID=my-project \
48
+ -- npx -y @tpsdev-ai/flair-mcp
49
+ ```
50
+
51
+ Verify:
52
+
53
+ ```bash
54
+ claude mcp list
55
+ # → flair (stdio, npx -y @tpsdev-ai/flair-mcp)
56
+ ```
57
+
58
+ Or, if you prefer the project-scoped `.mcp.json` checked into your repo:
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "flair": {
64
+ "command": "npx",
65
+ "args": ["-y", "@tpsdev-ai/flair-mcp"],
66
+ "env": {
67
+ "FLAIR_AGENT_ID": "my-project"
68
+ }
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ #### Auto-recall on session start (optional hook)
75
+
76
+ The MCP server gives the agent *pull* access to memory — it calls `bootstrap` /
77
+ `memory_search` when it decides to. If you'd rather have Flair context loaded
78
+ automatically the moment a session opens (no "call the bootstrap tool" nudge),
79
+ register Flair's `SessionStart` hook. It's a separate bin shipped in the same
80
+ package and is entirely optional — it complements the MCP server, it doesn't
81
+ replace it.
82
+
83
+ The one-command way (recommended — idempotent, `--dry-run`-able, and
84
+ symmetric with `flair hook uninstall`/`flair hook status`):
85
+
86
+ ```bash
87
+ flair hook install # wires ~/.claude/settings.json for FLAIR_AGENT_ID/FLAIR_URL
88
+ flair hook install --dry-run # prints the exact JSON delta, writes nothing
89
+ flair hook status # wired? correct shape? which agent/instance?
90
+ flair hook uninstall # removes only Flair's hook entry
91
+ ```
92
+
93
+ `--harness claude-code` is the only supported value today (it's also the
94
+ default) — the flag exists so a future harness is an additive registry entry,
95
+ not a breaking change. `flair doctor` already checks for this same hook (see
96
+ below) and recognizes anything `flair hook install` writes.
97
+
98
+ Or wire it by hand — add a `SessionStart` hook to `~/.claude/settings.json`:
99
+
100
+ ```json
101
+ {
102
+ "hooks": {
103
+ "SessionStart": [
104
+ {
105
+ "hooks": [
106
+ {
107
+ "type": "command",
108
+ "command": "FLAIR_AGENT_ID=me npx -y @tpsdev-ai/flair-mcp flair-session-start"
109
+ }
110
+ ]
111
+ }
112
+ ]
113
+ }
114
+ }
115
+ ```
116
+
117
+ Swap `me` for your `FLAIR_AGENT_ID`. The hook reads Claude Code's SessionStart
118
+ payload on stdin, calls Flair's `bootstrap` (soul + relevant memories +
119
+ predicted context, scoped to your project by the session's working directory),
120
+ and emits it as `hookSpecificOutput.additionalContext` — which Claude Code
121
+ injects into the new session's context. The matcher is omitted, so it fires on
122
+ every session start (`startup`, `resume`, `clear`, `compact`); add
123
+ `"matcher": "startup"` to a hook group if you only want it on fresh sessions.
124
+
125
+ It honors the same env as the MCP server (`FLAIR_AGENT_ID`, `FLAIR_URL`,
126
+ `FLAIR_KEY_PATH`), plus `FLAIR_HOOK_TIMEOUT_MS` (default 8000, clamped
127
+ 500–30000) for the bootstrap timeout.
128
+
129
+ **It degrades to a no-op, always.** No `FLAIR_AGENT_ID`, Flair down, an auth
130
+ error, or a hung daemon (past the timeout) → the hook prints `{}` and exits 0.
131
+ Claude Code treats that as "no context to add" and starts normally. The hook
132
+ can never block or break session startup. The injected context is clamped to
133
+ ≤10,000 characters to keep the session-start payload small.
134
+
135
+ ### Gemini CLI
136
+
137
+ Edit `~/.gemini/settings.json` (create it if absent):
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "flair": {
143
+ "command": "npx",
144
+ "args": ["-y", "@tpsdev-ai/flair-mcp"],
145
+ "env": {
146
+ "FLAIR_AGENT_ID": "my-project"
147
+ }
148
+ }
149
+ }
150
+ }
151
+ ```
152
+
153
+ Restart your Gemini CLI session for the config to take effect. Then in chat:
154
+
155
+ ```
156
+ > @flair memory_search "what did we decide about auth last week?"
157
+ ```
158
+
159
+ ### OpenAI Codex CLI
160
+
161
+ Edit `~/.codex/config.toml` (create it if absent):
162
+
163
+ ```toml
164
+ [mcp_servers.flair]
165
+ command = "npx"
166
+ args = ["-y", "@tpsdev-ai/flair-mcp"]
167
+
168
+ [mcp_servers.flair.env]
169
+ FLAIR_AGENT_ID = "my-project"
170
+ ```
171
+
172
+ For project-scoped trust (per Codex's MCP guide), the same block in `.codex/config.toml` at the project root.
173
+
174
+ Restart your Codex CLI session and the `flair_*` tools become available to the agent.
175
+
176
+ ---
177
+
178
+ ## Step 3 — Verify
179
+
180
+ In any of the three CLIs, ask the agent to do this:
181
+
182
+ > Use the bootstrap tool to load my Flair memory context, then store a memory that says "successful first MCP integration test."
183
+
184
+ If you see (a) the agent calling the `bootstrap` tool returning soul + recent memories, and (b) `memory_store` confirming a write — you're wired up. The memory now persists across CLI sessions AND across CLIs. Switch to a different CLI tomorrow and `memory_search "MCP integration test"` will find it.
185
+
186
+ ---
187
+
188
+ ## What the MCP server exposes
189
+
190
+ Eleven tools, kept deliberately small:
191
+
192
+ | Tool | What it does |
193
+ |---|---|
194
+ | `memory_search` | Semantic search across your agent's memories |
195
+ | `memory_store` | Save a memory with type, durability, tags. Auto-dedups near-duplicates |
196
+ | `memory_update` | Update an existing memory by ID — overwrite in place, or version it with `preserveHistory` |
197
+ | `memory_get` | Fetch a specific memory by ID |
198
+ | `memory_delete` | Remove a memory |
199
+ | `relationship_store` | Record a subject-predicate-object relationship triple (e.g. "nathan manages flair") |
200
+ | `bootstrap` | Get session-start context: soul + recent memories + predicted-relevant context |
201
+ | `soul_set` | Set a personality/project/standards entry — included in every bootstrap |
202
+ | `soul_get` | Get a soul entry |
203
+ | `flair_workspace_set` | Set your agent's current workspace state (ref/branch, phase, task) in the Office Space |
204
+ | `flair_orgevent` | Publish an org-wide coordination event (claim/release/status) to the Office Space |
205
+
206
+ Writes are scoped per-agent (your `FLAIR_AGENT_ID`) and enforced by Flair's server, not by client convention — you can't write as another agent. Reads are more open by design: any agent on the same Flair instance can read any other agent's non-private memories (open-within-org read; see [SECURITY.md](../SECURITY.md)). Mark a memory `visibility: private` to keep it owner-only.
207
+
208
+ ---
209
+
210
+ ## Configuration reference
211
+
212
+ | Env var | Default | Notes |
213
+ |---|---|---|
214
+ | `FLAIR_AGENT_ID` | (none — required) | Must match `flair agent add <id>` |
215
+ | `FLAIR_URL` | `http://127.0.0.1:19926` | Override for remote Flair instances |
216
+ | `FLAIR_KEY_PATH` | `~/.flair/keys/<agent>.key` | Ed25519 PKCS8 key — created by `flair agent add` |
217
+
218
+ The MCP server has no client-side flags beyond these env vars; everything else (timeouts, dedup thresholds, error classification) is opinionated defaults from the underlying [`@tpsdev-ai/flair-client`](../packages/flair-client) package.
219
+
220
+ ---
221
+
222
+ ## What about Hermes (Nous Research)?
223
+
224
+ Hermes uses its own Python-native `MemoryProvider` ABC instead of MCP. It has its own Flair integration in [`packages/hermes-flair/`](../packages/hermes-flair). Same backend, same agent isolation, different plug shape.
225
+
226
+ Future MCP-capable agent CLIs (and there are more landing every month) will work out of the box with the MCP server above — no per-framework adapter required from us.
227
+
228
+ ---
229
+
230
+ ## Troubleshooting
231
+
232
+ **"FLAIR_AGENT_ID is required" on startup.** Set it in the MCP server's `env` block (per snippets above). The CLI's own env doesn't propagate to the spawned MCP subprocess unless declared.
233
+
234
+ **"connection_error: could not reach Flair at http://127.0.0.1:19926".** The Flair server isn't running. Run `flair status` to check; `flair start` to bring it up.
235
+
236
+ **"auth_error: …" on every call.** The agent identity doesn't match a registered key. Re-run `flair agent add <id>` (idempotent on re-add — won't lose existing memories).
237
+
238
+ **Tool calls succeed but the agent doesn't see results in subsequent turns.** Check that the CLI is actually invoking `bootstrap` at session start — most CLIs need an explicit prompt nudge ("call the bootstrap tool now") on first use. Subsequent turns should pick up automatically once the CLI sees the schema.
239
+
240
+ For deeper issues see [`troubleshooting.md`](troubleshooting.md) and the [`@tpsdev-ai/flair-mcp` repo](https://github.com/tpsdev-ai/flair/tree/main/packages/flair-mcp).
@@ -0,0 +1,142 @@
1
+ # n8n Workflow Management
2
+
3
+ Programmatic activation/deactivation of n8n workflows — the approach we use for ops automation.
4
+
5
+ ## The Problem
6
+
7
+ Direct SQLite edits to `workflow_entity.active` (or using `n8n update:workflow` while n8n is running) don't re-register schedule triggers in the in-memory scheduler. The schedule simply stops firing. Only the v1 public API's `POST /api/v1/workflows/:id/activate` (or flipping Active in the UI) properly registers the trigger.
8
+
9
+ **Root cause**: n8n tracks activation via `activeVersionId`, not the `active` boolean alone. The `activeWorkflowManager` in-memory scheduler only picks up workflows where `activeVersionId IS NOT NULL`. Direct SQLite edits that only set `active=1` without setting `activeVersionId` will not be picked up even on restart.
10
+
11
+ ## Recommended Approach: v1 Public API (live instance)
12
+
13
+ The **v1 public API** is the correct tool for managing workflows on a **running** n8n instance. It updates the DB AND calls the in-memory `ActiveWorkflowManager.add()` to register triggers immediately — no restart needed.
14
+
15
+ ### Endpoints
16
+
17
+ | Action | Method | Endpoint | Body |
18
+ |---|---|---|---|
19
+ | Activate | `POST` | `/api/v1/workflows/:id/activate` | `{}` or `{"versionId": "..."}` |
20
+ | Deactivate | `POST` | `/api/v1/workflows/:id/deactivate` | (none) |
21
+ | List | `GET` | `/api/v1/workflows` | — |
22
+ | Get one | `GET` | `/api/v1/workflows/:id` | — |
23
+
24
+ ### Authentication
25
+
26
+ All v1 API calls require `X-N8N-API-KEY` header with a valid API key (see [API Key Generation](#api-key-generation) below).
27
+
28
+ ### Examples
29
+
30
+ ```bash
31
+ # Activate workflow
32
+ curl -X POST "http://127.0.0.1:5678/api/v1/workflows/$WORKFLOW_ID/activate" \
33
+ -H "X-N8N-API-KEY: $N8N_API_KEY" \
34
+ -H "Content-Type: application/json" \
35
+ -d '{}'
36
+
37
+ # Deactivate workflow
38
+ curl -X POST "http://127.0.0.1:5678/api/v1/workflows/$WORKFLOW_ID/deactivate" \
39
+ -H "X-N8N-API-KEY: $N8N_API_KEY"
40
+
41
+ # Check if workflow is active
42
+ curl -s "http://127.0.0.1:5678/api/v1/workflows/$WORKFLOW_ID" \
43
+ -H "X-N8N-API-KEY: $N8N_API_KEY" | python3 -c "import json,sys; print(json.load(sys.stdin)['active'])"
44
+ ```
45
+
46
+ See `scripts/n8n/activate-workflow.sh` for a reusable wrapper.
47
+
48
+ ## Why PATCH Doesn't Work
49
+
50
+ n8n's v1 API docs mention `PATCH /api/v1/workflows/:id` with `{ "active": true }`. **This returns 405 Method Not Allowed on n8n 1.123.38.** The documented activation endpoints are `POST /api/v1/workflows/:id/activate` and `POST /api/v1/workflows/:id/deactivate`.
51
+
52
+ ## Alternative Approaches
53
+
54
+ ### Approach 2: CLI when n8n is stopped
55
+
56
+ The `n8n update:workflow` CLI command works when n8n is **not running**. It updates both `active` and `activeVersionId` in the DB. On the next `n8n start`, `ActiveWorkflowManager.init()` reads `getAllActiveIds()` and registers all workflows with non-null `activeVersionId`.
57
+
58
+ ```bash
59
+ # Stop n8n
60
+ launchctl stop ai.tpsdev.n8n
61
+
62
+ # Activate/deactivate via CLI
63
+ N8N_PATH="/opt/homebrew/opt/node@24/bin" npx n8n@1.123.38 update:workflow --id=$WORKFLOW_ID --active=true
64
+ # or
65
+ N8N_PATH="/opt/homebrew/opt/node@24/bin" npx n8n@1.123.38 update:workflow --id=$WORKFLOW_ID --active=false
66
+
67
+ # Start n8n
68
+ launchctl start ai.tpsdev.n8n
69
+ ```
70
+
71
+ **Caveats**:
72
+ - `update:workflow` is deprecated (n8n v2 will replace it with `publish:workflow`/`unpublish:workflow`)
73
+ - Requires a full stop/start cycle (downtime for all workflows)
74
+ - `npx` needs node@24 (`/opt/homebrew/opt/node@24/bin/node`)
75
+
76
+ ### Approach 3: Internal REST API (editor UI)
77
+
78
+ The `/rest/workflows/:id/activate` endpoint is what the editor UI uses. It requires session-based auth (cookie from `/rest/login`), which needs the admin password. Not practical for automation without storing credentials.
79
+
80
+ ```bash
81
+ # Requires session cookie from /rest/login
82
+ curl -X POST "http://127.0.0.1:5678/rest/workflows/$WORKFLOW_ID/activate" \
83
+ -b "fern-uid=...; n8n.session=..."
84
+ ```
85
+
86
+ **Not recommended** for ops automation — session cookies expire and the password is a higher-value secret than an API key.
87
+
88
+ ## API Key Generation
89
+
90
+ The v1 API key is a JWT signed with a secret derived from the encryption key. To create one programmatically:
91
+
92
+ ```javascript
93
+ const crypto = require('crypto');
94
+ const jwt = require('jsonwebtoken');
95
+ const fs = require('fs');
96
+
97
+ // Read encryption key from n8n config
98
+ const config = JSON.parse(fs.readFileSync(process.env.HOME + '/.n8n/config', 'utf8'));
99
+ const encKey = config.encryptionKey;
100
+
101
+ // Derive JWT secret: SHA256 of every-other-character of encryption key
102
+ let baseKey = '';
103
+ for (let i = 0; i < encKey.length; i += 2) {
104
+ baseKey += encKey[i];
105
+ }
106
+ const jwtSecret = crypto.createHash('sha256').update(baseKey).digest('hex');
107
+
108
+ // Sign JWT with user's ID (from `user` table in SQLite)
109
+ const userId = '<user-uuid-from-sqlite>'; // e.g., 'a6ce7ac9-ef6d-4157-835a-4b0f01dc788a'
110
+ const apiKey = jwt.sign(
111
+ { sub: userId, iss: 'n8n', aud: 'public-api' },
112
+ jwtSecret
113
+ );
114
+
115
+ // Store the returned key in the user_api_keys table so it persists
116
+
117
+ console.log('API key:', apiKey);
118
+ ```
119
+
120
+ Once stored in the DB, the key is valid until deleted. No expiration by default.
121
+
122
+ **Security note**: The encryption key is needed to derive the JWT secret. This is the same key used to decrypt workflow credentials. If the encryption key is compromised, so are the credentials. Keep it scoped to the n8n user.
123
+
124
+ ## Why Direct SQLite Edits Don't Work
125
+
126
+ The `workflow_entity` table has two activation fields:
127
+ - `active` (boolean): UI flag
128
+ - `activeVersionId` (varchar): points to the `workflow_history` record that defines the active version
129
+
130
+ The `ActiveWorkflowManager` only considers workflows where `activeVersionId IS NOT NULL`. If you only flip `active=1` without setting `activeVersionId`, n8n never picks up the workflow — not on restart, not on refresh.
131
+
132
+ Even with both fields set correctly, a live n8n instance has an in-memory scheduler that doesn't re-read the DB. Only the v1 API (or UI toggle) calls `activeWorkflowManager.add()` to register the trigger in-memory.
133
+
134
+ ## Quick Reference
135
+
136
+ | Scenario | Method | Restart needed? |
137
+ |---|---|---|
138
+ | Activate on running n8n | `POST /api/v1/workflows/:id/activate` | No |
139
+ | Deactivate on running n8n | `POST /api/v1/workflows/:id/deactivate` | No |
140
+ | Activate when stopped | `n8n update:workflow --id=X --active=true` | Yes |
141
+ | Direct DB edit (active + activeVersionId) | SQLite `UPDATE` | Yes, on restart |
142
+ | Direct DB edit (active only) | SQLite `UPDATE` | **Won't work** — needs activeVersionId too |
package/docs/n8n.md ADDED
@@ -0,0 +1,122 @@
1
+ # Flair + n8n
2
+
3
+ Use Flair as the memory backend for n8n's AI Agent. The same memories are readable from Claude Code, OpenClaw, and any other Flair client — that's the point.
4
+
5
+ ## When to use Flair vs n8n's built-in memory connectors
6
+
7
+ n8n ships memory connectors for Postgres, MongoDB, and Redis. Those are real, persistent, and work fine for **conversation-buffer** use cases inside a single n8n instance.
8
+
9
+ Flair is the right pick when you want:
10
+
11
+ | | Flair | n8n built-ins |
12
+ |---|---|---|
13
+ | **Shape** | Tagged + typed memories with semantic search, plus chat-buffer compatibility | Conversation-buffer only (LangChain `BaseMessage` records) |
14
+ | **Cross-orchestrator** | Same memory readable from Claude Code, OpenClaw, n8n | n8n-internal schema; nothing else reads it |
15
+ | **Cross-instance** | Hub-spoke federation built-in (local ↔ Fabric, etc.) | Single-instance unless you self-build replication |
16
+ | **Identity** | Ed25519 per-agent (planned) or admin-token (v1) | n8n credential per workflow |
17
+
18
+ If your AI Agent only needs to remember the last N turns of a single chat in a single n8n instance, Postgres-as-memory is fine. If you want the same memory to inform a Claude Code conversation tomorrow, or to persist across n8n redeploys via federated Flair, this package is the path.
19
+
20
+ ## Setup (5 minutes)
21
+
22
+ ### 1. Install Flair (if not already running)
23
+
24
+ ```bash
25
+ npm install -g @tpsdev-ai/flair
26
+ flair init
27
+ ```
28
+
29
+ This starts a local Flair server on `http://localhost:19926`. For shared/team setups, see [Deployment](./deployment.md).
30
+
31
+ ### 2. Install the n8n community node
32
+
33
+ In n8n: **Settings → Community Nodes → Install** → enter `@tpsdev-ai/n8n-nodes-flair` → confirm and restart.
34
+
35
+ ### 3. Create the credential
36
+
37
+ In n8n: **Credentials → New → Flair API**. Fill in:
38
+
39
+ | Field | Value |
40
+ |---|---|
41
+ | **Base URL** | `http://localhost:19926` (or your team's Flair URL) |
42
+ | **Agent ID** | Logical identity that will own memories from this n8n workspace. Workflows that share an Agent ID share memory ownership. Use distinct IDs when isolation matters. |
43
+ | **Admin Password** | Your Flair admin password (in `~/.flair/admin-pass` for local installs). **Sensitive** — see [Security](#security). |
44
+
45
+ Click **Test** — if the test request to `/Memory` returns 200, the credential is good.
46
+
47
+ ### 4. Wire the nodes
48
+
49
+ Three nodes ship in the package:
50
+
51
+ - **Flair Chat Memory** — connects to an AI Agent's `Memory` socket. Stores chat history in Flair, scoped by Subject. Defaults to per-workflow memory; set the optional Session Sub-Key to `={{ $execution.id }}` for per-run isolation.
52
+ - **Flair Search** — connects to an AI Agent's `Tool` socket. Two operations:
53
+ - *Semantic Search* — agent calls `flair_search({ query })`, gets memories ranked by similarity.
54
+ - *Get By Subject* — agent calls `flair_get_by_subject()`, gets memories under a config-time-bound subject.
55
+ - **Flair Write** — a regular Main-input/Main-output pipeline node (not wired to the AI Agent's Tool socket). Takes an incoming item and writes its content as a Flair memory, with Subject, Tags, and Durability fields. For operator-driven capture-and-archive flows (mail → memory, webhook → memory, parsed-doc → memory) where the write is the workflow author's choice, not the LLM's.
56
+
57
+ A typical workflow:
58
+
59
+ ```
60
+ [Webhook] → [AI Agent]
61
+ ├─ Model: Claude / OpenAI / etc.
62
+ ├─ Memory: Flair Chat Memory (Subject: customer-support)
63
+ ├─ Tool: Flair Search (Operation: Semantic Search)
64
+ └─ Tool: HTTP Request (etc.)
65
+ ```
66
+
67
+ The agent now answers using both its current chat history (from Flair Chat Memory) and any relevant historical memories it pulls in via Flair Search.
68
+
69
+ ## Subject and SessionId guidance
70
+
71
+ n8n memory connectors expose a `sessionKey` parameter that scopes the chat history. Flair has a richer model:
72
+
73
+ - **Subject** (required) — the entity / conversation / topic the memory is about. Indexed in Flair's schema; efficient to filter on. Default: `={{ $workflow.name }}`.
74
+ - **Session Sub-Key** (optional) — appended to the subject as `<subject>:<sessionKey>`. Use the n8n execution id (`={{ $execution.id }}`) for per-run isolation, or a customer/user id for per-customer scoping, or leave blank to share across runs.
75
+
76
+ Patterns:
77
+
78
+ - **"This assistant remembers"** — set Subject to a stable string (`customer-support`, `daily-standup`). Leave Session Sub-Key blank. All runs share memory.
79
+ - **Per-conversation isolation** — set Subject to the conversation owner (`customer:1234`), leave Session Sub-Key blank. Each conversation is isolated by subject.
80
+ - **Per-execution isolation** — set Session Sub-Key to `={{ $execution.id }}`. Each n8n run gets its own memory window. (This is most similar to n8n's default `sessionKey={{ $execution.id }}`.)
81
+
82
+ ## Security
83
+
84
+ > **The admin password gives every workflow with this credential read/write access to the entire Flair instance**, not just the configured Agent ID. The blast radius is the whole memory store. Treat the credential as highly sensitive: n8n encrypts credentials at rest, but any n8n admin or backup restore can extract it.
85
+
86
+ For production deployments where untrusted workflow inputs reach Flair, wait for **Ed25519 per-agent authentication** (planned). v1 (admin password) is appropriate when:
87
+
88
+ - The n8n instance is single-tenant and operator-controlled
89
+ - Workflow inputs are trusted (your own CRM, your own webhook source)
90
+ - Memory leakage between agents is acceptable for the use case
91
+
92
+ If any of those don't hold, use Flair's CLI / SDK clients (which support per-agent Ed25519 today) and wait for the n8n credential update.
93
+
94
+ ## Get By Tag — coming soon
95
+
96
+ The Flair Search node currently exposes Semantic Search and Get By Subject. **Get By Tag** is deferred until `flair-client.memory.list` exposes a `tags` filter (tracked in the [n8n-node spec](https://github.com/tpsdev-ai/flair/blob/main/specs/N8N-NODE-q3qf.md) §6). Workaround for now: use Semantic Search and let the model filter results by tags in the response.
97
+
98
+ ## Worked examples
99
+
100
+ Two example workflows are coming in a follow-up release; they're authored inside a real n8n instance and round-tripped via Export so they import cleanly:
101
+
102
+ - **`chat-memory-demo.json`** — Webhook → AI Agent (Claude + Flair Chat Memory) → Respond. Demonstrates the conversation-buffer use case. Run twice with the same input to see memory replay.
103
+ - **`knowledge-search-demo.json`** — Schedule → AI Agent (Claude + Flair Chat Memory + Flair Search as Tool) → action. Demonstrates the structured-knowledge-search use case.
104
+
105
+ In the interim, follow the [Setup](#setup-5-minutes) and [Subject and SessionId guidance](#subject-and-sessionid-guidance) sections — wiring is straightforward without an example file.
106
+
107
+ ## Compared to other Flair surfaces
108
+
109
+ | Surface | Use case | Setup |
110
+ |---|---|---|
111
+ | [Claude Code](./claude-code.md) | Personal AI assistant memory across CLI sessions | npm install + `flair init` |
112
+ | [OpenClaw](./openclaw.md) | Multi-agent OpenClaw deployments | OpenClaw plugin install |
113
+ | [MCP](./mcp-clients.md) | Any MCP client (Claude Desktop, etc.) | MCP server registration |
114
+ | **n8n (this doc)** | Workflow-engine AI Agents | n8n community-node install |
115
+
116
+ Same Flair instance, same memories, different surfaces.
117
+
118
+ ## See also
119
+
120
+ - [Spec — `@tpsdev-ai/n8n-nodes-flair`](https://github.com/tpsdev-ai/flair/blob/main/specs/N8N-NODE-q3qf.md) — implementation plan, design decisions, anti-patterns
121
+ - [Bridges](./bridges.md) — how Flair memories flow between hosts and instances
122
+ - [Federation](./federation.md) — hub-and-spoke replication