@tpsdev-ai/flair 0.26.0 → 0.27.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.
@@ -0,0 +1,156 @@
1
+ # Flair supply-chain policy
2
+
3
+ How we keep Flair's published packages safe from upstream supply-chain attacks. This document describes both our policies and the automation that enforces them.
4
+
5
+ > **Why this exists.** Mini Shai-Hulud worm attack (Apr 30 2026, Intercom npm + Composer PHP). Sleeper malicious Ruby gems and Go modules (May 1). NuGet typosquats with crypto-wallet stealers (May 6). The window between "package compromised" and "compromise widely flagged" is the entire risk surface, and it's been hours-to-days, not weeks. As Flair adds integration adapters across more ecosystems, our exposure grows; this is the policy + automation that bounds it.
6
+
7
+ ---
8
+
9
+ ## Policies
10
+
11
+ ### 1. Bake-time policy: 7 days minimum for new dep versions
12
+
13
+ We don't pull in any newly-published dep version for **at least 7 days** after its publish date.
14
+
15
+ - The most-attacked window is "compromise published, defenders haven't yet noticed." Most malicious packages get flagged by Socket.dev, npm advisory, GitHub security advisory, or human reports within 1-7 days. Our delay puts us behind that detection front.
16
+ - pnpm 11 shipped this as a default at 1 day (May 4 2026). We chose 7 as a more conservative posture for a security-adjacent project.
17
+ - Workspace-internal `@tpsdev-ai/*` deps are exempt. We publish ourselves; we have direct visibility into our own changes; our 0.8.0 → 0.8.1 patch turnaround was same-day and we want to keep that latitude.
18
+ - Tunable via `FLAIR_DEP_MIN_AGE_DAYS` env var if a specific run needs a different threshold. Don't bypass; document the exception.
19
+
20
+ #### 1a. Keep-current allow-list
21
+
22
+ Some deps are tightly coupled to Flair's runtime correctness — Harper bug fixes and security patches land in `@harperfast/harper`, embedding-pipeline fixes land in `harper-fabric-embeddings`. We accept the bake-time risk and pull these eagerly. Current allow-list:
23
+
24
+ | Package | Why kept current |
25
+ |---------|------------------|
26
+ | `@harperfast/harper` | Foundational. Vector-index and HNSW correctness fixes land here; we want them ASAP. High-volume upstream, fast detection if compromised. |
27
+ | `harper-fabric-embeddings` | Embedding model loader. Coupled to Harper version. Same trust-and-volume reasoning. |
28
+ | `@harperfast/oauth` | Same high-trust `@harperfast/*` owner as `@harperfast/harper`. Used ONLY by the **default-OFF** native-MCP OAuth surface (`FLAIR_MCP_OAUTH`), which dynamically imports it only when the flag is on — it is **not loaded in the shipped default build**, so bake-time exposure is zero until an operator explicitly opts in. Pinned to the exact version whose `withMCPAuth` API the surface was built against; the API surface (not a floating range) is what we depend on. |
29
+
30
+ Adding to this list is a deliberate decision. The bar:
31
+ - The upstream is well-known and high-volume (gets eyeballs fast).
32
+ - We have a direct reason to want patches as soon as published (a known bug we're tracking, a security patch we need, or correctness coupling).
33
+ - We accept that a freshly-malicious version could land in our build before broader detection.
34
+
35
+ Document any addition here, in this section, alongside the package name. The doc is the audit trail.
36
+
37
+ Override per-run via `FLAIR_DEP_KEEP_CURRENT="pkg1,pkg2,@scope/pkg3"` env (additive — adds to the default allow-list, doesn't replace it).
38
+
39
+ ### 2. Exact-version pinning for production deps
40
+
41
+ Every `dependencies` entry in any `package.json` must be a single concrete version (`"5.0.9"`), not a range (`"^5.0"`, `"~5.0.9"`, `">=5"`). Range specifiers expose us to silent supply-chain swaps every install — exactly the surface attackers exploit.
42
+
43
+ - `peerDependencies` may use ranges (host-provided; never installed by us). `devDependencies` are also exact-pinned for build reproducibility, though they don't ship in our published tarballs.
44
+ - `bun.lock` is committed and frozen-lockfile installed in CI. Any unintended dep drift fails the workspace-deps consistency gate.
45
+ - Pin updates happen via deliberate, test-gated PRs — never auto-merged. **Renovate is enabled** (`.github/renovate.json`) to *propose* these updates on a schedule, but it respects the bake-time cooldown (`minimumReleaseAge: "7 days"`, matching `FLAIR_DEP_MIN_AGE_DAYS`) and opens PRs only — `automerge` is off, so every bump flows through the full test suite + K&S review. Renovate uses `rangeStrategy: "pin"` so it proposes exact-version bumps (never re-widens to ranges) and shares the keep-current allow-list with `check-dep-ages.mjs`. Vulnerability alerts bypass the cooldown so security fixes aren't delayed.
46
+
47
+ ### 3. Internal dep version lockstep
48
+
49
+ Every `@tpsdev-ai/*` dep declared in any workspace package must match the version that workspace package ships. Enforced by `scripts/check-workspace-deps.mjs` in the test-unit CI job.
50
+
51
+ - Why: prevents the v0.8.0 bug shape where `openclaw-flair@0.8.0` declared `@tpsdev-ai/flair-client@0.5.0`, shipping a 3-version-old client to consumers of the published tarball.
52
+ - See `notes/dogfood-log.md` for the full incident.
53
+
54
+ ### 4. Workspace `bun.lock` is the source of truth
55
+
56
+ Direct `bun.lock` regenerations (e.g. `rm bun.lock && bun install`) are discouraged. They can rewrite git URLs to use ssh-protocol resolution that breaks Docker builds (the libsignal incident on PR #368) and reset other resolution choices.
57
+
58
+ - Instead: use `bun install` with the existing lockfile, or surgical edits for known bug fixes.
59
+ - All lockfile changes are reviewed; any cross-protocol or cross-version churn beyond the stated scope of the PR is a red flag.
60
+
61
+ ### 5. Socket.dev CI job is mandatory
62
+
63
+ Every PR runs the Socket.dev Supply Chain check. Failure blocks merge. The Socket scan complements the bake-time policy — Socket catches *known* compromises; the 7-day delay catches *not-yet-known* ones.
64
+
65
+ ### 6. Publish surface
66
+
67
+ Only Nathan publishes to npm (per the existing MFA boundary). Flint preps the release commit + version bump + CHANGELOG; Nathan runs `./scripts/release.sh <ver> --publish` from his laptop.
68
+
69
+ - The build host is not logged into npm by design.
70
+ - A planned post-publish smoke job will add an automated round-trip check after each publish to ensure cross-package resolution works on the actually-published artifacts.
71
+
72
+ ---
73
+
74
+ ## Automation
75
+
76
+ ### `.github/renovate.json` — deliberate, cooldown-gated update proposals
77
+
78
+ Renovate opens PRs to propose dependency updates so we don't drift behind upstream indefinitely — but on our terms, not the registry's. It is configured to never auto-merge (`automerge: false`), to pin (`rangeStrategy: "pin"`, consistent with §2), and to respect the bake-time cooldown (`minimumReleaseAge: "7 days"`, matching `FLAIR_DEP_MIN_AGE_DAYS` in `check-dep-ages.mjs`) so it only proposes versions that have already cleared the detection window. Non-major updates are grouped; majors land as isolated PRs. The keep-current allow-list (`@harperfast/harper`, `harper-fabric-embeddings`, `@harperfast/oauth`) mirrors the script's `DEFAULT_KEEP_CURRENT` — keep the two in lockstep when either changes. Vulnerability alerts bypass the cooldown. Every Renovate PR still runs the full CI suite (including the bake-time and workspace-deps gates) and is K&S-reviewed before merge.
79
+
80
+ ### `scripts/check-workspace-deps.mjs` (already shipped, PR #368)
81
+
82
+ Fails any PR where a workspace package declares an internal `@tpsdev-ai/*` dep at a version other than what that workspace package ships. Wired into the `test-unit` job.
83
+
84
+ ### `scripts/check-dep-ages.mjs` (this PR)
85
+
86
+ Fails any PR with an external pinned production dep version published less than `FLAIR_DEP_MIN_AGE_DAYS` ago (default 7). Queries the npm registry's `time` map. Workspace-internal deps exempt. Wired into the `test-unit` job.
87
+
88
+ Configurable:
89
+
90
+ ```bash
91
+ # Run with a different threshold:
92
+ FLAIR_DEP_MIN_AGE_DAYS=14 node scripts/check-dep-ages.mjs
93
+
94
+ # Run against a private registry:
95
+ FLAIR_NPM_REGISTRY=https://my-registry.example/ node scripts/check-dep-ages.mjs
96
+ ```
97
+
98
+ ### Pre-commit secret-guard hook (already shipped, `ops/scripts/git-hooks/`)
99
+
100
+ Blocks at stage time:
101
+ - Secret-shaped filenames (`.pem`, `.key`, `.env*`, `*api-key*`, `*pat*`, `*secret*`, etc.)
102
+ - Embedded git clones added without a `.gitmodules` entry
103
+ - Any single staged file >2MB
104
+
105
+ Available in `ops/scripts/git-hooks/install.sh`. Required for any agent or operator with commit access.
106
+
107
+ ### Flair pre-commit hook (`scripts/git-hooks/`)
108
+
109
+ Mirrors the CI test-unit gates locally so issues are caught at `git commit` time, not after the runner round-trip:
110
+
111
+ ```bash
112
+ ./scripts/git-hooks/install.sh
113
+ ```
114
+
115
+ Runs three checks before each commit:
116
+ - `check-workspace-deps.mjs` — workspace internal-dep version lockstep
117
+ - `check-dep-ages.mjs` — supply-chain bake-time (≥7 days for external pinned deps)
118
+ - `check-impl-term-leaks.sh` — no Bead refs / impl labels in user-facing docs
119
+
120
+ Each check matches a CI gate exactly so the local and remote outcomes can't drift. Bypass with `git commit --no-verify` when warranted (rare; CI will still catch you). Skip just the dep-ages check (the slowest one, ~2-5s of registry fetches) with `FLAIR_PRECOMMIT_SKIP_DEP_AGES=1 git commit`.
121
+
122
+ ---
123
+
124
+ ## Adopting this policy in a downstream project
125
+
126
+ If you're building on top of `@tpsdev-ai/flair-client` and want the same posture:
127
+
128
+ ```bash
129
+ # Copy the dep-age guard into your repo
130
+ curl -fsSL https://raw.githubusercontent.com/tpsdev-ai/flair/main/scripts/check-dep-ages.mjs \
131
+ -o scripts/check-dep-ages.mjs
132
+ chmod +x scripts/check-dep-ages.mjs
133
+
134
+ # Wire it into your CI as a fast pre-test step
135
+ - run: node scripts/check-dep-ages.mjs
136
+ ```
137
+
138
+ The script has no external dependencies — node 18+ is enough.
139
+
140
+ ---
141
+
142
+ ## Exceptions and incident response
143
+
144
+ - **Bypass for known-good fresh dep:** set `FLAIR_DEP_MIN_AGE_DAYS=0` for the affected CI run AND open a PR to add a comment-row in this doc explaining the exception. Don't bypass silently.
145
+ - **Confirmed upstream compromise affecting Flair:** rotate any affected credential, revert the offending dep version, ship a patch release, file a public advisory at `github.com/tpsdev-ai/flair/security/advisories`. Notify Nathan immediately; don't act unilaterally.
146
+ - **Suspected (not confirmed) compromise:** open an issue with the evidence; treat it as P0 in our backlog until disproven.
147
+
148
+ ---
149
+
150
+ ## See also
151
+
152
+ - `notes/dogfood-log.md` — internal incidents that have shaped this policy
153
+ - `scripts/check-workspace-deps.mjs` — the workspace-internal dep consistency gate
154
+ - `scripts/check-dep-ages.mjs` — the bake-time dep guard
155
+ - `ops/scripts/git-hooks/pre-commit-secret-guard.sh` — pre-commit secret blocker (cross-repo)
156
+ - `scripts/git-hooks/pre-commit` + `scripts/git-hooks/install.sh` — flair-specific pre-commit (mirrors test-unit CI gates)
@@ -0,0 +1,42 @@
1
+ # System Requirements
2
+
3
+ Flair runs Harper v5 (a Node.js HTTP+storage runtime) plus a small CLI/MCP layer. This page documents what to expect at idle, with measured numbers from in-production deployments.
4
+
5
+ ## Minimum
6
+
7
+ | Resource | Spec | Notes |
8
+ |---|---|---|
9
+ | RAM | 1 GB free | 500–800 MB resident is typical for a single-agent spoke. |
10
+ | Disk | 250 MB | Harper data dir grows ~50–200 MB per active agent over weeks. |
11
+ | Node | 22 LTS or 24 LTS | Native fetch + WebStreams. Verified on 22.22.x and 25.9.x. |
12
+ | Network | Outbound HTTPS | For federation-sync to a hub. Local-only deployments need none. |
13
+
14
+ ## Measured at idle (single agent, no load)
15
+
16
+ | Host | RAM (RSS) | Data dir | Node | Uptime | Notes |
17
+ |---|---|---|---|---|---|
18
+ | Mac mini (16 GB) | 740 MB daemon + ~175 MB across 4 flair-mcp clients = ~915 MB total | 163 MB | 25.9.0 | 35 min | Federation hub; 4 local agents. |
19
+ | Linux VM (19 GB pool) | 500 MB | 88 MB | 22.22.0 | 3d 20h | Federation spoke; 1 agent. |
20
+ | Linux VM (19 GB pool) | (not running) | 71 MB | 22.22.1 | — | Linux deps issue (backlog). |
21
+
22
+ ## What drives the numbers
23
+
24
+ - **Embedding cache.** First semantic search per cold daemon loads `nomic-embed-text-v1.5` into memory (~270 MB). Subsequent searches reuse it. If you disable embeddings (text-only search), strip ~270 MB.
25
+ - **HNSW index.** In-memory vector index over the agent's memories. Grows linearly with memory count; expect ~1 KB per memory plus the 768-dim vector (~1.5 KB).
26
+ - **Harper transaction log.** Bounded by retention window; grows during writes, compacts on idle.
27
+ - **MCP clients.** Each `flair-mcp` subprocess holds ~40–50 MB. Long-lived MCP host (Claude Code) restarts spawn fresh ones; orphaned ones from the host crashing should be cleaned up by the parent-exit watcher (PR pending).
28
+
29
+ ## Scaling expectations
30
+
31
+ The numbers above are 1-agent steady state. Per additional agent on the same daemon:
32
+
33
+ - ~50 MB additional RSS (per-agent HNSW index + small per-agent caches).
34
+ - ~10–30 MB additional data-dir growth per week of active use.
35
+
36
+ A 4-agent Mac mini at full embeddings + federation runs comfortably in 1 GB. An 8-agent host is fine in 2 GB. Multi-org hubs with hundreds of agents would want measured sizing — file an issue or join the Discord.
37
+
38
+ ## Known constraints
39
+
40
+ - **Free Fabric tier.** ~512 MB plan ceiling. The full embedding model + HNSW + Harper is tight at that ceiling for a multi-agent spoke; a 1-agent personal spoke fits. Larger deployments (Phase 2 SLM-summarization, multi-agent hubs) require a paid Fabric tier or self-host.
41
+ - **Cold-start.** Embedding model load is ~3–5 s on Mac arm64, ~8–12 s on commodity Linux x86. Subsequent operations are warm.
42
+ - **No GPU required.** Embeddings run on CPU. HNSW is in-memory and CPU-only. GPU only matters if you deploy a Phase 2 SLM-based summarizer (separate process — see [bridges.md](./bridges.md#phase-2-summary-service)).
@@ -0,0 +1,129 @@
1
+ # The team behind Flair
2
+
3
+ This is how LifestyleLab actually runs the multi-agent team that builds Flair, TPS, and the rest of our open-source stack. We dogfood every part of what we ship — the agents themselves are the reference implementation.
4
+
5
+ If you're trying to run your own multi-agent team using Flair as the memory layer, this is the most concrete example you'll find. Steal whatever's useful.
6
+
7
+ ## Roster
8
+
9
+ | Agent | Role | Runtime | Model | Where it runs |
10
+ |---|---|---|---|---|
11
+ | **Flint** | Strategy, product, PR review | Claude Code | Claude Opus | always-on local host |
12
+ | **Anvil** | Implementation, PR opener | OpenClaw | Claude Sonnet (API) | cloud VM |
13
+ | **Kern** | Architecture / perf review | OpenClaw | Open-source via Ollama | local inference box |
14
+ | **Sherlock** | Security review | OpenClaw | Open-source via Ollama (local-only) | local inference box |
15
+ | **Pulse** | EA / intel scanning / coordination | OpenClaw | Claude API | cloud VM |
16
+ | **Nathan** | Founder / product owner / human-in-the-loop | (human) | (human) | wherever |
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.
19
+
20
+ ## How memory flows
21
+
22
+ ```
23
+ ┌────────────────────────┐
24
+ │ Flair (self-hosted) │
25
+ │ │
26
+ │ Write isolation + │
27
+ │ open-within-org read, │
28
+ │ enforced server-side │
29
+ │ via Ed25519 signing │
30
+ └─────────▲──────────────┘
31
+
32
+ ┌─────────────────┬───────────────┼──────────────┬─────────────────┐
33
+ │ │ │ │ │
34
+ Flint Anvil Kern Sherlock Pulse
35
+ (local) (cloud VM) (inference box) (inference box) (cloud VM)
36
+ │ │ │ │ │
37
+ writes own writes own writes own writes own writes own
38
+ memories only memories only memories only memories only memories only
39
+ │ │ │ │ │
40
+ └─────────────────┴────────┬──────┴──────────────┴─────────────────┘
41
+
42
+ (every agent can read every other
43
+ agent's non-private memories —
44
+ `visibility: private` stays owner-only)
45
+ ```
46
+
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.
48
+
49
+ 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
+
51
+ ## Why these splits
52
+
53
+ ### Different runtimes for different work
54
+
55
+ - **Claude Code (Flint)** — strategic + code review needs Opus's depth, and Claude Code's tool ecosystem (Bash, Read/Edit/Write, web fetch, MCP) is the broadest available for "do real work in a real repo."
56
+ - **OpenClaw (Anvil, Kern, Sherlock, Pulse)** — for agents that don't need a full IDE-grade tool surface but DO need stable always-on background capability with model-fallback routing, OpenClaw is the right runtime. It's also the one we built into TPS, so we eat our own dog food.
57
+
58
+ This isn't a value judgment of one runtime over another — it's about matching the runtime to what the agent has to do. **The whole team uses Flair as the memory layer regardless of runtime.** That's the point: Flair is orchestrator-agnostic.
59
+
60
+ ### Local vs API for inference
61
+
62
+ - **Anvil + Pulse on the Anthropic API** — high-throughput implementation work and EA-shaped intel scanning need frontier model quality and consistent latency. Worth the API spend.
63
+ - **Kern + Sherlock on local Ollama** — review work can be slower and is bursty (a few PRs/day). Self-hosting on a local Ollama box means no rate limits, no session-locks, no third-party data exposure. Both run a large open-weight model (~120B class, permissively licensed) as primary, with smaller open models in the local fallback chain. **Sherlock is local-only as a deliberate privacy decision** — security findings are pre-disclosure-sensitive, not appropriate to send to any external inference provider.
64
+ - **Flint on Opus** — strategy + spec writing is rate-of-thought, not rate-of-tokens. Opus's reasoning depth matters more than throughput.
65
+
66
+ > **Note on migration safety nets:** when we moved the review agents off a previous cloud model onto local inference, we kept the old model as the *last* fallback for a short trial window to catch quality regressions, then removed it on a fixed date. If you're copying this setup, decide upfront whether you want a cloud safety net during your own migration — and remove it on a known date.
67
+
68
+ ### Different hardware for different load
69
+
70
+ - **Always-on local host** — lightweight, runs the founder-facing agent + a watchdog + the local Flair Harper instance.
71
+ - **Local inference box** — heavier local inference on a workstation with strong unified memory / GPU. Hosts Ollama; the review agents target this box.
72
+ - **Cloud VMs** — agents that need internet-side work (intel fetching, opening GitHub PRs from a clean network space). Independent failure domain from the local stack.
73
+
74
+ ## The handoff loop
75
+
76
+ Standard PR-shaped work flows like this:
77
+
78
+ ```
79
+ 1. Nathan brings a need to Flint (Discord)
80
+ 2. Flint writes a spec, files it in the planning repo, updates Beads
81
+ 3. Flint mails Kern + Sherlock for arch + security review of the SPEC
82
+ (catch issues at design time, not after implementation)
83
+ 4. K&S respond with concerns or sign-off
84
+ 5. Flint refines spec, hands off to Anvil:
85
+ @Anvil <spec-path> branch:<name>. Open PR to main when done.
86
+ 6. Anvil works on a feature branch, opens PR
87
+ 7. Flint reviews PR, requests K&S review on the implementation
88
+ 8. K&S review, comment, approve
89
+ 9. CI green + 1 approval (or 2 for security-surface PRs) → merge
90
+ 10. Pulse's intel cron picks up the merge in the next 24h cycle and
91
+ adds it to the team's situational awareness
92
+ ```
93
+
94
+ The rule that keeps this honest: **K&S approvals are individually load-bearing.** A "yes I approve" with a templated body that doesn't engage with the actual code is rejected — they have to write their own one-line rationale based on what they actually found. Otherwise the gate is theatrics. (This was a real lesson; we learned it the hard way after a rubber-stamp made it into the audit log.)
95
+
96
+ ## How Flair fits in
97
+
98
+ Flair is the connective tissue:
99
+
100
+ - **Identity:** every agent has an Ed25519 keypair in Flair (`flair agent add <id>`). All signed requests, no shared passwords, no env-var secrets to leak.
101
+ - **Memory:** each agent writes its own lessons, decisions, observations. Flint's strategic memory survives a session crash. Anvil's "this codebase pattern works for X but fails for Y" persists across PR iterations.
102
+ - **Soul:** each agent has a permanent personality block — role, voice, constraints. Loaded on every bootstrap so the agent stays *themselves* across sessions.
103
+ - **Bridges:** when an agent needs context from a foreign system (e.g., Anvil needs to import lessons from another repo), bridges import them into Flair without a custom integration per source.
104
+
105
+ The MCP server (`@tpsdev-ai/flair-mcp`) is what makes this orchestrator-agnostic — Flint's Claude Code, Anvil/Kern/Sherlock/Pulse's OpenClaw all hit the same Flair server with the same write-isolation-plus-open-read guarantees.
106
+
107
+ ## What we deliberately don't do
108
+
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.
110
+ - **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
+ - **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
+ - **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.
113
+ - **No password-based access to memory.** A leaked Flair admin password lets you read the database via Harper directly, but doesn't let you impersonate an agent — you can't write under their identity without their key. We treat that as the right asymmetric defense.
114
+
115
+ ## What we're still figuring out
116
+
117
+ - **Trust-weighting the open read pool.** Open-within-org read (#578, shipped in 0.21.0) means Flint no longer has to round-trip TPS mail to see Sherlock's recent security findings — `memory_search` already surfaces them directly. What's still unbuilt is any consolidation or trust-discounting of that shared pool: today it's a bigger unfiltered pile, not a ranked or corroborated one. That's the next arc (org-identity, emergent trust from provenance/corroboration/supersession) — it needs a founder-engaged design pass before we build it, not a solo build.
118
+ - **Rhythm agent v1.** Today's v0 is a shell-cron polling for state changes and posting to Discord. v1 moves to a dedicated low-power device, uses a small local model to summarize, and escalates only when truly stuck. Post-1.0 polish.
119
+
120
+ ## Try this with your own team
121
+
122
+ Pick a starting point that matches your scale:
123
+
124
+ - **Solo, want continuity across sessions:** install Flair, give Claude Code an MCP-wired identity (see [`docs/mcp-clients.md`](mcp-clients.md)). One agent. Done.
125
+ - **Pair, want explicit handoffs without losing context:** add a second agent identity, each with their own MCP config + Flair agentId. Pass work via TPS mail or your own coordination channel.
126
+ - **Small team, want to see this rig work end-to-end:** clone our setup. Use our Beads issue tracker, our TPS mail, our agent role-splits. Replace Nathan with whoever's playing founder/product-owner.
127
+ - **Bigger team:** federate Flair instances (per [`docs/federation.md`](federation.md)). Each office has its own Flair — that org boundary (the federation edge) is what stays hard across nodes; reads are already open within each office's own instance.
128
+
129
+ Read the rest of the docs from there.
@@ -0,0 +1,187 @@
1
+ # Troubleshooting
2
+
3
+ Start with `flair doctor` — it diagnoses most common issues automatically.
4
+
5
+ ```bash
6
+ flair doctor
7
+ ```
8
+
9
+ ## Common Issues
10
+
11
+ ### "Harper is not running"
12
+
13
+ **Symptoms:** `flair status` shows not running, bootstrap fails.
14
+
15
+ **Fix:**
16
+ ```bash
17
+ flair start
18
+ ```
19
+
20
+ If it fails to start:
21
+ ```bash
22
+ # Check for port conflict
23
+ lsof -i :19926
24
+
25
+ # Check logs (macOS)
26
+ cat ~/.flair/data/log/hdb.log | tail -50
27
+
28
+ # Check logs (Linux)
29
+ journalctl --user -u flair --since "10 minutes ago"
30
+ ```
31
+
32
+ ### "Semantic search DEGRADED — embeddings not loaded"
33
+
34
+ **Symptoms:** `flair doctor` or `flair init` reports `Semantic search DEGRADED — embeddings not loaded; recall-by-meaning will NOT work.` A paraphrase search doesn't recall a memory it should match by meaning; search only finds exact keyword overlaps.
35
+
36
+ **Cause:** The in-process embeddings component (`harper-fabric-embeddings` / the nomic model) failed to initialize, so `SemanticSearch` fell back to a keyword-only scan. The most common cause on a fresh box is a **root-owned global install**: `sudo npm install -g @tpsdev-ai/flair` makes the package directory owned by root, but Harper runs as your user and gets `EACCES` when the embeddings component tries to download/symlink the model file under that package.
37
+
38
+ **Fix — reinstall without sudo (recommended):**
39
+ ```bash
40
+ # Use a user-writable npm prefix so the package dir is yours (see README Quick Start)
41
+ mkdir -p ~/.npm-global && npm config set prefix ~/.npm-global
42
+ export PATH="$HOME/.npm-global/bin:$PATH" # add to your shell rc to persist
43
+
44
+ npm uninstall -g @tpsdev-ai/flair # remove the root-owned copy (may need sudo to remove it)
45
+ npm install -g @tpsdev-ai/flair # reinstall, no sudo
46
+ flair restart
47
+ flair doctor # should now report semantic search operational
48
+ ```
49
+
50
+ **Other causes:** a missing native llama.cpp addon for your platform, or a corrupted/partial model download. `flair doctor` prints the underlying init error; `flair reembed` re-downloads the model and regenerates embeddings once the component loads.
51
+
52
+ **HuggingFace outage:** the model normally resolves from HuggingFace (`nomic-ai/nomic-embed-text-v1.5-GGUF`). If HF is down or 403/429-ing, point `FLAIR_MODELS_DIR` at a directory containing your own copy of `nomic-embed-text-v1.5.Q4_K_M.gguf` instead of waiting it out:
53
+ ```bash
54
+ mkdir -p ~/models
55
+ curl -fSL -o ~/models/nomic-embed-text-v1.5.Q4_K_M.gguf \
56
+ https://github.com/tpsdev-ai/flair/releases/download/ci-models/nomic-embed-text-v1.5.Q4_K_M.gguf
57
+ sha256sum ~/models/nomic-embed-text-v1.5.Q4_K_M.gguf
58
+ # expect: d4e388894e09cf3816e8b0896d81d265b55e7a9fff9ab03fe8bf4ef5e11295ac
59
+
60
+ export FLAIR_MODELS_DIR=~/models # add to your shell rc to persist
61
+ flair restart
62
+ ```
63
+ The `ci-models` release above is a first-party mirror of the same file (public, no auth required) that flair's own CI falls back to for the same reason — same-origin with GitHub, no dependency on HF's availability. Always verify the sha256 against the value printed here (or in `scripts/ci/model-checksums.txt` in the repo) before pointing Harper at a manually-downloaded file.
64
+
65
+ ### "Embeddings: hash-fallback (512-dim)"
66
+
67
+ **Symptoms:** `flair status` shows hash-fallback instead of nomic. Search returns poor results.
68
+
69
+ **Cause:** The nomic-embed-text model failed to load. Usually a missing native binary or corrupted model file.
70
+
71
+ **Fix:**
72
+ ```bash
73
+ flair doctor # shows the specific error
74
+ flair reembed # re-downloads model and regenerates embeddings
75
+ ```
76
+
77
+ If `flair doctor` shows a native addon error:
78
+ ```bash
79
+ # Reinstall with native dependencies
80
+ npm install -g @tpsdev-ai/flair --force
81
+ flair restart
82
+ ```
83
+
84
+ ### "invalid_signature" errors
85
+
86
+ **Symptoms:** API calls return `{"error": "invalid_signature"}`.
87
+
88
+ **Causes:**
89
+ 1. Agent key doesn't match what's registered in Flair
90
+ 2. Clock skew (signature includes timestamp)
91
+ 3. Wrong agent ID
92
+
93
+ **Fix:**
94
+ ```bash
95
+ # Verify the agent exists
96
+ flair agent list
97
+
98
+ # Re-register the agent's public key
99
+ flair agent rotate-key <agent-id>
100
+
101
+ # Check system clock
102
+ date
103
+ ```
104
+
105
+ If using the MCP server, restart Claude Code after rotating keys.
106
+
107
+ ### Port conflict
108
+
109
+ **Symptoms:** `flair start` fails, "address already in use".
110
+
111
+ **Fix:**
112
+ ```bash
113
+ # Find what's using the port
114
+ lsof -i :19926
115
+
116
+ # If it's a stale Flair process
117
+ flair stop
118
+ flair start
119
+
120
+ # If it's another application, use a different port
121
+ flair init --port 29926
122
+ # Or edit ~/.flair/config.yaml and restart
123
+ ```
124
+
125
+ ### MCP server can't connect
126
+
127
+ **Symptoms:** Claude Code shows "Flair tools unavailable" or bootstrap returns nothing.
128
+
129
+ **Check:**
130
+ ```bash
131
+ # Is Flair running?
132
+ flair status
133
+
134
+ # Can you reach it?
135
+ curl http://localhost:19926/Health
136
+
137
+ # Is the agent registered?
138
+ flair agent list
139
+ ```
140
+
141
+ **Common fixes:**
142
+ - Set `FLAIR_URL` in your MCP config if using a non-default port
143
+ - Ensure `FLAIR_AGENT_ID` matches a registered agent
144
+ - Restart Claude Code after config changes
145
+
146
+ ### Memories not showing up in search
147
+
148
+ **Symptoms:** You wrote a memory but search doesn't find it.
149
+
150
+ **Possible causes:**
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
+ 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.
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
+
156
+ ### High memory usage
157
+
158
+ **Symptoms:** Harper process using excessive RAM.
159
+
160
+ **Context:** Harper with nomic-embed-text loads a ~270MB model into memory. This is normal. Total memory usage should stabilize around 400-600MB.
161
+
162
+ If memory keeps growing:
163
+ ```bash
164
+ flair restart # clean restart
165
+ flair doctor # check for issues
166
+ ```
167
+
168
+ ### "content_safety_violation" on write
169
+
170
+ **Symptoms:** Memory write rejected with safety error.
171
+
172
+ **Cause:** Content matched a prompt injection pattern and strict mode is enabled (`FLAIR_CONTENT_SAFETY=strict`).
173
+
174
+ **Fix:** Either rephrase the content to avoid injection patterns, or switch to default mode (remove `FLAIR_CONTENT_SAFETY=strict` from environment). In default mode, flagged content is stored but tagged — not rejected.
175
+
176
+ ## Getting Help
177
+
178
+ ```bash
179
+ flair doctor # automated diagnosis
180
+ flair status # server state
181
+ flair --help # all commands
182
+ flair <command> -h # command-specific help
183
+ ```
184
+
185
+ Logs: `~/.flair/data/log/hdb.log`
186
+
187
+ File issues: [github.com/tpsdev-ai/flair/issues](https://github.com/tpsdev-ai/flair/issues)