@tpsdev-ai/flair 0.26.0 → 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.
- package/README.md +2 -0
- package/dist/cli.js +434 -50
- package/dist/doctor-client.js +47 -0
- package/docs/assets/flair-cross-orchestrator.cast +33 -0
- package/docs/assets/flair-cross-orchestrator.gif +0 -0
- package/docs/assets/flair-demo.cast +18 -0
- package/docs/assets/flair-demo.gif +0 -0
- package/docs/auth.md +178 -0
- package/docs/bridges.md +291 -0
- package/docs/claude-code.md +202 -0
- package/docs/deployment.md +204 -0
- package/docs/entity-vocabulary.md +109 -0
- package/docs/federation.md +179 -0
- package/docs/integrations.md +197 -0
- package/docs/mcp-clients.md +240 -0
- package/docs/n8n-management.md +142 -0
- package/docs/n8n.md +122 -0
- package/docs/notes/adk-spike-findings-2026-05-05.md +331 -0
- package/docs/notes/mcp-agent-auth-consumer.md +229 -0
- package/docs/notes/mcp-oauth-model2.md +132 -0
- package/docs/notes/rem-ux.md +39 -0
- package/docs/openclaw.md +131 -0
- package/docs/quickstart.md +153 -0
- package/docs/releasing.md +173 -0
- package/docs/rem.md +60 -0
- package/docs/rerank-provisioning.md +67 -0
- package/docs/secrets-and-keys.md +173 -0
- package/docs/spoke-bringup.md +303 -0
- package/docs/supply-chain-policy.md +156 -0
- package/docs/system-requirements.md +42 -0
- package/docs/the-team.md +129 -0
- package/docs/troubleshooting.md +187 -0
- package/docs/upgrade.md +416 -0
- package/package.json +2 -1
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Native /mcp OAuth surface — Model 2 (experimental, default-OFF)
|
|
2
|
+
|
|
3
|
+
> **Status: experimental, opt-in, DEFAULT-OFF.** Gated behind `FLAIR_MCP_OAUTH`.
|
|
4
|
+
> When the flag is unset, flair boots byte-identically to before — no `/mcp`
|
|
5
|
+
> route, no authorization-server load, no change to the default auth chain.
|
|
6
|
+
> Do NOT enable in production until Sherlock signs off on live enablement.
|
|
7
|
+
|
|
8
|
+
This is the **Model 2** native-MCP path: a custom in-process `/mcp` JSON-RPC
|
|
9
|
+
handler guarded by `@harperfast/oauth`'s `withMCPAuth`, serving the 9 curated
|
|
10
|
+
flair tools with a per-agent OAuth identity. It is distinct from the
|
|
11
|
+
native-application-MCP surface (design A / `FLAIR_MCP_ENABLED`); Model 2 does not
|
|
12
|
+
use Harper's native MCP transport, so it is not blocked by the Harper native-MCP
|
|
13
|
+
gating gaps.
|
|
14
|
+
|
|
15
|
+
## What it is
|
|
16
|
+
|
|
17
|
+
- `resources/mcp-handler.ts` — a minimal MCP (JSON-RPC 2.0) handler over
|
|
18
|
+
Streamable HTTP: `initialize` / `tools/list` / `tools/call` / `ping`. On
|
|
19
|
+
`tools/call` it resolves the verified token `sub` → a flair `Agent`, then
|
|
20
|
+
dispatches to the curated tool.
|
|
21
|
+
- `resources/mcp-tools.ts` — the 9 curated tools (memory_search, memory_store,
|
|
22
|
+
memory_get, memory_delete, bootstrap, soul_set, soul_get, flair_workspace_set,
|
|
23
|
+
flair_orgevent), each a thin wrapper over the existing resource handler
|
|
24
|
+
(Memory / SemanticSearch / BootstrapMemories / Soul / WorkspaceState /
|
|
25
|
+
OrgEvent). No raw CRUD surface — the only path to the datastore through `/mcp`
|
|
26
|
+
is one of these 9 semantic tools. Curated **by construction**.
|
|
27
|
+
- `resources/mcp-oauth.ts` — registers `server.http(withMCPAuth(mcpHandler),
|
|
28
|
+
{ urlPath: '/mcp' })` **only when `FLAIR_MCP_OAUTH` is on.** `/mcp` runs on its
|
|
29
|
+
own dispatch chain; flair's default auth-middleware does not run for it.
|
|
30
|
+
- `resources/mcp-oauth-flag.ts` — the flag + issuer/resource config helpers.
|
|
31
|
+
|
|
32
|
+
## The sub → Agent mapping (identity)
|
|
33
|
+
|
|
34
|
+
`withMCPAuth` verifies the RS256 JWT and sets `request.mcp = { sub, client_id,
|
|
35
|
+
aud, scope }`. The handler maps `sub` → a flair `Agent` id:
|
|
36
|
+
|
|
37
|
+
1. Look up `Credential` where `kind === "idp"` AND `idpSubject === sub` → its
|
|
38
|
+
`principalId` is the Agent id. (Same credential surface XAA's ID-JAG path
|
|
39
|
+
uses — one identity model.)
|
|
40
|
+
2. If no mapping and `FLAIR_MCP_JIT_PROVISION` is on, JIT-provision a
|
|
41
|
+
non-admin `Agent` + `Credential(kind:"idp")` from the sub.
|
|
42
|
+
3. Otherwise **deny** — an unresolvable sub never runs as anonymous or admin.
|
|
43
|
+
|
|
44
|
+
The resolved agent is set as `request.tpsAgent` on a flair-shaped delegation
|
|
45
|
+
context, so the wrapped handler scopes to the verified agent exactly as an
|
|
46
|
+
Ed25519-signed REST call would. Identity always comes from the resolved agent,
|
|
47
|
+
never from the tool arguments (no forging of agentId / authorId).
|
|
48
|
+
|
|
49
|
+
## Enabling (operator checklist)
|
|
50
|
+
|
|
51
|
+
1. **Install the AS plugin** — add `@harperfast/oauth` (already an exact-pinned
|
|
52
|
+
dependency) and declare it in `config.yaml`:
|
|
53
|
+
|
|
54
|
+
```yaml
|
|
55
|
+
'@harperfast/oauth':
|
|
56
|
+
package: '@harperfast/oauth'
|
|
57
|
+
providers:
|
|
58
|
+
github:
|
|
59
|
+
clientId: ${OAUTH_GITHUB_CLIENT_ID}
|
|
60
|
+
clientSecret: ${OAUTH_GITHUB_CLIENT_SECRET}
|
|
61
|
+
mcp:
|
|
62
|
+
enabled: true
|
|
63
|
+
issuer: ${FLAIR_MCP_ISSUER} # pin to your public origin — REQUIRED
|
|
64
|
+
resource: ${FLAIR_MCP_ISSUER}/mcp # RFC-8707 audience the /mcp token binds to
|
|
65
|
+
accessTokenTtl: 900 # 5–15 min (Sherlock req 1) — short-lived
|
|
66
|
+
dynamicClientRegistration:
|
|
67
|
+
enabled: false # DCR is NOT SUPPORTED (flair#756) — explicit, not omitted (an absent block leaves DCR OPEN by the plugin's own default)
|
|
68
|
+
clientIdMetadataDocuments:
|
|
69
|
+
allowedHosts: # CIMD is the only supported client-registration path
|
|
70
|
+
- claude.ai
|
|
71
|
+
- claude.com
|
|
72
|
+
signingKeyPem: ${FLAIR_MCP_SIGNING_KEY_PEM} # pin in clusters
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**DCR is not supported; clients connect via CIMD (Client ID Metadata
|
|
76
|
+
Documents).** `flair mcp enable` (flair#756) writes exactly this shape —
|
|
77
|
+
see "Legacy clients" below.
|
|
78
|
+
|
|
79
|
+
The `config.yaml` block is intentionally NOT committed to the live config in
|
|
80
|
+
this slice — adding it changes boot behavior, which would break the
|
|
81
|
+
default-OFF / byte-identical contract. An operator adds it deliberately when
|
|
82
|
+
turning the surface on.
|
|
83
|
+
|
|
84
|
+
2. **Set the env:**
|
|
85
|
+
- `FLAIR_MCP_OAUTH=1` — turns on the `/mcp` route registration.
|
|
86
|
+
- `FLAIR_MCP_ISSUER=https://your-public-origin` (or `FLAIR_PUBLIC_URL`).
|
|
87
|
+
- `FLAIR_MCP_JIT_PROVISION=1` — ONLY if you want unknown subjects
|
|
88
|
+
auto-provisioned (default OFF; pre-provision Agent+Credential otherwise).
|
|
89
|
+
|
|
90
|
+
3. **Restart flair.** `/mcp` mounts, OAuth-guarded.
|
|
91
|
+
|
|
92
|
+
## Sherlock's 4 requirements — how they are met
|
|
93
|
+
|
|
94
|
+
1. **Token lifetime.** `mcp.accessTokenTtl: 900` (5–15 min) in the AS config +
|
|
95
|
+
the standard OAuth refresh flow (the plugin rotates refresh tokens on use).
|
|
96
|
+
`withMCPAuth` validates `exp` strictly. Documented as a required config value,
|
|
97
|
+
not a default (the plugin's own default is 1h — too long).
|
|
98
|
+
2. **RS256 pinning.** The `@harperfast/oauth` plugin mints and verifies RS256-only
|
|
99
|
+
(per its docs: "Signing algorithms other than RS256 … are not supported"), so
|
|
100
|
+
`none`/HS256 confusion is structurally rejected — the verifier only knows
|
|
101
|
+
RS256. No configurable `alg` to widen.
|
|
102
|
+
3. **Dual-auth precedence.** `/mcp` is OAuth-only on its own urlPath chain;
|
|
103
|
+
flair's default chain (Ed25519) never runs for `/mcp`, and the OAuth Bearer
|
|
104
|
+
never reaches the default chain. They cannot collide on the same request —
|
|
105
|
+
`/mcp` sees only the token, every other path sees only Ed25519/Basic. There is
|
|
106
|
+
no path that carries both.
|
|
107
|
+
4. **Client registration.** DCR is not supported; clients connect via CIMD
|
|
108
|
+
(Client ID Metadata Documents) — `mcp.dynamicClientRegistration.enabled:
|
|
109
|
+
false` explicitly closes RFC 7591 registration (open DCR would let an
|
|
110
|
+
attacker register as any agent; leaving the block unset does NOT close it —
|
|
111
|
+
see `src/lib/mcp-enable.ts`'s module header for the ground-truth citation),
|
|
112
|
+
and `mcp.clientIdMetadataDocuments.allowedHosts` restricts which hosts may
|
|
113
|
+
present a CIMD client_id URL. On the resolution side, JIT-provisioning of
|
|
114
|
+
an unknown sub is itself gated (`FLAIR_MCP_JIT_PROVISION`, default OFF) —
|
|
115
|
+
a second explicit trust anchor.
|
|
116
|
+
|
|
117
|
+
## Legacy clients
|
|
118
|
+
|
|
119
|
+
DCR (RFC 7591 Dynamic Client Registration) is UNSUPPORTED on this surface —
|
|
120
|
+
not a fallback, not a flag. `flair mcp enable` (flair#756) writes
|
|
121
|
+
`dynamicClientRegistration: { enabled: false }`, which 404s
|
|
122
|
+
`/oauth/mcp/register`. A client that cannot present a CIMD client_id URL
|
|
123
|
+
cannot connect to this surface.
|
|
124
|
+
|
|
125
|
+
## Deferred (not in this slice)
|
|
126
|
+
|
|
127
|
+
- Live `config.yaml` wiring of the `@harperfast/oauth` plugin (kept out to
|
|
128
|
+
preserve the byte-identical flag-OFF contract; documented above for operators).
|
|
129
|
+
- Migrating the homegrown `OAuth.ts` / `XAA.ts` opaque-token AS to the plugin.
|
|
130
|
+
Per Kern: deprecate-don't-delete — they stay for the Ed25519/signed-REST path.
|
|
131
|
+
XAA's JIT-provisioning is kept; the Model-2 handler reuses the same
|
|
132
|
+
`Credential(kind:"idp")` surface.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# REM UX — trigger model, attach semantics, review loop
|
|
2
|
+
|
|
3
|
+
> Design note accompanying REM slice 2 (#707). Describes the intended user experience of in-process distillation so the CLI/docs surfaces stay coherent as the feature grows. Parent spec: `specs/FLAIR-NIGHTLY-REM.md`; slice spec: `specs/FLAIR-NIGHTLY-REM-SLICE-2-DISTILLATION.md`.
|
|
4
|
+
|
|
5
|
+
## Triggers — three, nothing implicit
|
|
6
|
+
|
|
7
|
+
1. **Interactive:** an agent (or a human at the CLI) runs `flair rem rapid` — one bounded distillation of that agent's own recent memories. Non-admin actors can only reflect on themselves; an admin can run it for any agent.
|
|
8
|
+
2. **Scheduled:** the nightly cycle, per agent, only where deliberately enabled (`flair rem nightly enable`). In a multi-node deploy, exactly one node gets the timer (see #709).
|
|
9
|
+
3. **Admin-run:** same endpoint, another agent's corpus, admin credentials.
|
|
10
|
+
|
|
11
|
+
REM never fires as a side effect of writes, searches, or boot. Distillation is always a deliberate act with an audit trail.
|
|
12
|
+
|
|
13
|
+
## Locality — the model call runs next to the data
|
|
14
|
+
|
|
15
|
+
The CLI is a thin HTTP trigger pointed at whatever Flair instance it is configured for (local or remote). Distillation executes **server-side** in the Flair component via Harper's model-access API. Consequences:
|
|
16
|
+
|
|
17
|
+
- Memory content never transits the operator's machine on its way to a model.
|
|
18
|
+
- Data egress is determined solely by the *server's* `models:` configuration — a local backend means nothing leaves the box; a hosted provider is an explicit, documented choice (keys ride Harper env-secret encryption on managed deploys).
|
|
19
|
+
- The same trigger UX works identically against a laptop instance and a managed deployment.
|
|
20
|
+
|
|
21
|
+
## Attach semantics — synchronous now, and the rule for when that changes
|
|
22
|
+
|
|
23
|
+
**Interactive mode stays attached.** One request, one bounded generate call (gather cap 50 memories, bounded output tokens), a staged-candidate summary printed on return. Seconds, not minutes — request/response is the honest shape for it, and `--prompt-only` preserves the bring-your-own-model handoff.
|
|
24
|
+
|
|
25
|
+
**Nightly mode is fully detached.** The scheduler fires the cycle; results land as pending candidates plus an audit row; the operator reviews next morning.
|
|
26
|
+
|
|
27
|
+
**The rule for revisiting:** any run shape that exceeds a single bounded generate call — hierarchical/recursive consolidation, org-level REM across many agents — gets a real job model (run id, `flair rem status <id>`, resumability) *designed before that slice ships*. The failure mode to avoid is a timeout bug forcing an ad-hoc job system into existence.
|
|
28
|
+
|
|
29
|
+
## The review loop — where REM's UX actually lives
|
|
30
|
+
|
|
31
|
+
Distillation is the cheap half; the reviewable stream of candidates is the product surface:
|
|
32
|
+
|
|
33
|
+
- **Today (CLI):** `flair rem candidates` lists pending rows; `flair rem promote <id> --rationale` / `flair rem reject <id> --reason` decide them. Every candidate carries its claim, source memory ids, generating model, and timestamp — enough to judge provenance at a glance.
|
|
34
|
+
- **Direction:** a reviewable feed — candidates as a stream with one-glance provenance and one-action promote/reject, recurring rejected claims surfaced via their `supersedes` chains rather than appearing fresh each time. The nightly diff report should point at that surface, making morning review a two-minute ritual instead of a CLI expedition.
|
|
35
|
+
- **Invariant either way:** nothing self-promotes. The feed can get faster and friendlier; the explicit-decision gate is load-bearing and stays.
|
|
36
|
+
|
|
37
|
+
## Configuration UX — one decision, one knob
|
|
38
|
+
|
|
39
|
+
Wanting REM should reduce to: *point the server's `models:` block at a backend.* Local Ollama works with zero credentials; a hosted provider takes an API key stored as an encrypted env secret. `FLAIR_REM_MODEL` selects a logical model name when the default routing isn't right. There is no REM-specific provider code, wiring, or plugin to install — if the server can `generate()`, REM works.
|
package/docs/openclaw.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Flair + OpenClaw
|
|
2
|
+
|
|
3
|
+
Give OpenClaw agents persistent memory and identity.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### 1. Install Flair (if not already running)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @tpsdev-ai/flair
|
|
11
|
+
flair init
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### 2. Install the OpenClaw plugin
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
openclaw plugins install @tpsdev-ai/openclaw-flair
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 3. Create an agent identity
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
flair agent add my-agent
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 4. Configure the plugin
|
|
27
|
+
|
|
28
|
+
In your OpenClaw agent config, add the Flair plugin:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"plugins": {
|
|
33
|
+
"@tpsdev-ai/openclaw-flair": {
|
|
34
|
+
"agentId": "my-agent",
|
|
35
|
+
"flairUrl": "http://localhost:19926"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or set environment variables:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
export FLAIR_AGENT_ID=my-agent
|
|
45
|
+
export FLAIR_URL=http://localhost:19926
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 5. Restart the gateway
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
openclaw gateway restart
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## What the Plugin Provides
|
|
55
|
+
|
|
56
|
+
The Flair plugin adds these tools to your OpenClaw agent:
|
|
57
|
+
|
|
58
|
+
| Tool | Description |
|
|
59
|
+
|------|-------------|
|
|
60
|
+
| `memory_store` | Write a memory with optional type, durability, and tags |
|
|
61
|
+
| `memory_recall` | Semantic search over stored memories |
|
|
62
|
+
| `memory_get` | Retrieve a specific memory by ID |
|
|
63
|
+
|
|
64
|
+
### Automatic Bootstrap
|
|
65
|
+
|
|
66
|
+
On each new conversation, the plugin injects relevant context from Flair:
|
|
67
|
+
- Soul entries (persistent personality and project context)
|
|
68
|
+
- Recent memories (last 24h)
|
|
69
|
+
- Relevant memories (semantically matched to the conversation topic)
|
|
70
|
+
|
|
71
|
+
This happens automatically — no agent configuration needed beyond the plugin setup.
|
|
72
|
+
|
|
73
|
+
## Multi-Agent
|
|
74
|
+
|
|
75
|
+
Each OpenClaw agent gets its own isolated memory space:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
flair agent add research-agent
|
|
79
|
+
flair agent add coding-agent
|
|
80
|
+
flair agent add review-agent
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Agents can share memories via grants:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Let review-agent read coding-agent's memories
|
|
87
|
+
flair grant coding-agent review-agent --scope read
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Soul (Personality)
|
|
91
|
+
|
|
92
|
+
Set persistent context that shapes how the agent behaves:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
flair soul set --agent my-agent --key role \
|
|
96
|
+
--value "Senior engineer focused on reliability. Ship quality over speed."
|
|
97
|
+
|
|
98
|
+
flair soul set --agent my-agent --key project \
|
|
99
|
+
--value "E-commerce API. Node.js, PostgreSQL. 200K DAU."
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Soul entries are included in every bootstrap — they're the agent's persistent identity.
|
|
103
|
+
|
|
104
|
+
## Key Resolution
|
|
105
|
+
|
|
106
|
+
The plugin resolves Ed25519 keys in this order:
|
|
107
|
+
1. `FLAIR_KEY_PATH` environment variable
|
|
108
|
+
2. `~/.flair/keys/<agent-id>.key`
|
|
109
|
+
3. `~/.tps/secrets/flair/<agent-id>-priv.key` (legacy TPS path)
|
|
110
|
+
|
|
111
|
+
## Troubleshooting
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Verify Flair is running
|
|
115
|
+
flair status
|
|
116
|
+
|
|
117
|
+
# Verify the agent exists
|
|
118
|
+
flair agent list
|
|
119
|
+
|
|
120
|
+
# Test memory roundtrip
|
|
121
|
+
flair memory add --agent my-agent --content "test memory"
|
|
122
|
+
flair search "test" --agent my-agent
|
|
123
|
+
|
|
124
|
+
# Check plugin is loaded
|
|
125
|
+
openclaw plugins list
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
If the plugin fails to load, check the gateway logs for Flair connection errors. Common issues:
|
|
129
|
+
- Wrong port (default changed to 19926 in v0.4.0)
|
|
130
|
+
- Agent not registered (`flair agent add <id>`)
|
|
131
|
+
- Key file missing (`~/.flair/keys/<agent-id>.key`)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Quick Start
|
|
2
|
+
|
|
3
|
+
From zero to a persistent agent memory in five minutes.
|
|
4
|
+
|
|
5
|
+
## 0. Prerequisite
|
|
6
|
+
|
|
7
|
+
**Node.js 22 or newer.** That's it — no Docker, no database to install, no API keys. Flair runs in a single process with embeddings computed locally.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
node --version # v22.x.x or higher
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
If you need Node 22: [nodejs.org](https://nodejs.org/) or `brew install node@24`.
|
|
14
|
+
|
|
15
|
+
## 1. Install (30 seconds)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @tpsdev-ai/flair
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`flair`, `flair-mcp`, and the client library all come in under one install.
|
|
22
|
+
|
|
23
|
+
## 2. Bootstrap Flair (1–2 minutes)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
flair init
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
First run does a few things:
|
|
30
|
+
|
|
31
|
+
1. Installs the embedded Harper (memory store) into `~/.flair/data/`.
|
|
32
|
+
2. Downloads the local embedding model (~80 MB — first run only).
|
|
33
|
+
3. Starts Flair as a launchd / systemd service on port 19926.
|
|
34
|
+
4. Creates a default agent (`--agent-id local` unless you pass one).
|
|
35
|
+
5. Opens a short **soul wizard** so your agent knows who it is.
|
|
36
|
+
|
|
37
|
+
The soul wizard offers a few shapes:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
🎭 Agent personality setup
|
|
41
|
+
Soul entries shape what every future session starts with.
|
|
42
|
+
|
|
43
|
+
What best describes this agent?
|
|
44
|
+
(1) Solo developer — helps you with code on this machine
|
|
45
|
+
(2) Team agent — runs in a shared repo / ops flow
|
|
46
|
+
(3) Research assistant — surveys sources, writes notes
|
|
47
|
+
(4) Draft from Claude — paste a Claude-generated JSON draft
|
|
48
|
+
(5) Custom — I'll prompt for each field with examples
|
|
49
|
+
(s) Skip — set up later; `flair doctor` will nudge
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Pick the template that matches how you'll use this agent. You can edit or replace any entry later with `flair soul set`.
|
|
53
|
+
|
|
54
|
+
## 3. Confirm it's running
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
flair status
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
A bare `flair status` (no agent, no admin credentials) only shows the public health
|
|
61
|
+
summary:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Flair vX.Y.Z — 🟢 running (PID 12345, uptime 1m)
|
|
65
|
+
URL: http://127.0.0.1:19926
|
|
66
|
+
|
|
67
|
+
✓ all checks passing
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The **🟢** icon means everything is healthy. A **🟡** would mean there's something worth looking at — usually surfaced with a recommended command inline. See [docs/troubleshooting.md](troubleshooting.md) if you see **🔴 unreachable**.
|
|
71
|
+
|
|
72
|
+
For the full picture — Memory, Agents, and Soul detail — pass the agent you just created:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
flair status --agent local
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
Flair vX.Y.Z — 🟢 running (PID 12345, uptime 1m)
|
|
80
|
+
URL: http://127.0.0.1:19926
|
|
81
|
+
|
|
82
|
+
Memory:
|
|
83
|
+
Total: 0
|
|
84
|
+
Durability: 0 permanent / 0 persistent / 0 standard / 0 ephemeral
|
|
85
|
+
|
|
86
|
+
Agents:
|
|
87
|
+
1 total — local
|
|
88
|
+
|
|
89
|
+
Soul:
|
|
90
|
+
3 entries — 0 critical / 0 high / 3 standard / 0 low
|
|
91
|
+
|
|
92
|
+
✓ all checks passing
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 4. Write your first memory
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
flair memory add --agent local --content "Harper v5 sandbox blocks node:module but process.dlopen works"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Flair generates a semantic embedding locally and stores it. No network calls.
|
|
102
|
+
|
|
103
|
+
## 5. Find it back by meaning
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
flair memory search --agent local --q "native addon loading in sandboxed runtimes"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
Harper v5 sandbox blocks node:module but process.dlopen works
|
|
111
|
+
(2026-04-22 · memory · 67%)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**You searched for a concept, not the keywords.** The 67% is the semantic-similarity score.
|
|
115
|
+
|
|
116
|
+
## 6. Give your agent context on boot
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
flair bootstrap --agent local --max-tokens 2000
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This returns a formatted text block that includes the soul entries you just set plus recent/relevant memories. Paste that into any LLM session — Claude Code, Codex, Cursor, an Anthropic API call — to give the agent its identity + memory in one shot.
|
|
123
|
+
|
|
124
|
+
If you use Claude Code, add this to your `CLAUDE.md`:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
At the start of every session, run mcp__flair__bootstrap before responding.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
With the MCP server wired up (see the [integration section in README.md](../README.md#integration)), Claude Code runs bootstrap automatically on every new session.
|
|
131
|
+
|
|
132
|
+
## What's next
|
|
133
|
+
|
|
134
|
+
| You want to... | Go to |
|
|
135
|
+
|----------------|-------|
|
|
136
|
+
| Add more agents to the same instance | `flair agent add <id>` |
|
|
137
|
+
| Let one agent read another's memories | `flair grant <from> <to>` ([docs/auth.md](auth.md)) |
|
|
138
|
+
| Import memories from agentic-stack / Mem0 / etc. | [docs/bridges.md](bridges.md) |
|
|
139
|
+
| Sync memories across machines | [docs/federation.md](federation.md) |
|
|
140
|
+
| Integrate with OpenClaw, Claude Code, Cursor | [README.md#integration](../README.md#integration) |
|
|
141
|
+
| Fix something that isn't working | [docs/troubleshooting.md](troubleshooting.md) |
|
|
142
|
+
| Upgrade to a new version | `flair upgrade --restart` or [docs/upgrade.md](upgrade.md) |
|
|
143
|
+
|
|
144
|
+
## If you change your mind
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
flair stop # stop the service (keeps data)
|
|
148
|
+
flair restart # restart
|
|
149
|
+
flair uninstall # remove the service (keeps data + keys)
|
|
150
|
+
flair uninstall --purge # remove everything including data and keys
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
All reversible. Your memories aren't locked in.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Releasing Flair
|
|
2
|
+
|
|
3
|
+
Flair publishes eight workspace packages to npm under `@tpsdev-ai/*`. Releases are
|
|
4
|
+
**tokenless** and **staged**: CI authenticates to npm with a short-lived OIDC token
|
|
5
|
+
(no `NPM_TOKEN` lives anywhere) and submits each package to npm's **staging** area.
|
|
6
|
+
A maintainer then approves the staged tarballs on npmjs.com with 2FA to make them live.
|
|
7
|
+
|
|
8
|
+
> `flair-bench` is version-bumped and tagged in lockstep with the other 7, but stages
|
|
9
|
+
> in its own step in CI (allowed to fail) until its one-time bootstrap is done — see
|
|
10
|
+
> [flair-bench bootstrap](#flair-bench-bootstrap-one-time) below.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
merge release PR ──▶ push tag v0.11.0 ──▶ CI stages all packages ──▶ npm staging
|
|
14
|
+
│
|
|
15
|
+
maintainer reviews + approves (2FA)
|
|
16
|
+
▼
|
|
17
|
+
live on npm
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Pushing a `vX.Y.Z` tag triggers the release. This replaces the old "run
|
|
21
|
+
`release.sh --publish` from a laptop logged into npm" flow. Nothing publishes without
|
|
22
|
+
a human 2FA approval, and every package ships with a provenance attestation (public
|
|
23
|
+
repo → verifiable build origin). The person who tags the release does **not** need npm
|
|
24
|
+
credentials or `Actions: write` — only repo push access; the only privileged step is
|
|
25
|
+
the maintainer's 2FA approval.
|
|
26
|
+
|
|
27
|
+
## Cutting a release
|
|
28
|
+
|
|
29
|
+
### Phase 1 — open the release PR
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# promote ## Unreleased to the new version in CHANGELOG.md first, then:
|
|
33
|
+
./scripts/release.sh 0.11.0
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This bumps every workspace package to the version, aligns internal deps, refreshes
|
|
37
|
+
`bun.lock`, builds, tests, and opens a `release: v0.11.0` PR. Review and merge it
|
|
38
|
+
(CI green + K&S approval) the same as any other PR.
|
|
39
|
+
|
|
40
|
+
### Phase 2 — tag the release
|
|
41
|
+
|
|
42
|
+
After the release PR is merged to `main`, push the version tag:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
git checkout main && git pull
|
|
46
|
+
git tag v0.11.0 && git push origin v0.11.0
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The tag push triggers the [`release-publish`](../.github/workflows/release-publish.yml)
|
|
50
|
+
workflow, which:
|
|
51
|
+
|
|
52
|
+
1. Resolves the version from the tag and validates it as semver.
|
|
53
|
+
2. Verifies the tagged commit is an ancestor of `main` (a tag can't ship un-merged code).
|
|
54
|
+
3. Verifies all 7 `package.json` files are at that version.
|
|
55
|
+
4. Builds every package.
|
|
56
|
+
5. Runs `npm stage publish` for each package in dependency order (flair-client first).
|
|
57
|
+
|
|
58
|
+
It authenticates via OIDC — no secrets, and it does **not** create or move any tag (the
|
|
59
|
+
tag you pushed is the trigger). Watch the run; when it's green, the packages are staged
|
|
60
|
+
but **not yet live**.
|
|
61
|
+
|
|
62
|
+
In parallel — and **independent of the npm staging approval** — a `github-release` job
|
|
63
|
+
auto-cuts a [GitHub release](https://github.com/tpsdev-ai/flair/releases) for the tag,
|
|
64
|
+
using the matching `## [X.Y.Z]` section of `CHANGELOG.md` as the release notes (extracted
|
|
65
|
+
by `scripts/changelog-extract.mjs`). It is idempotent: re-running the workflow or
|
|
66
|
+
re-pushing the tag updates the existing release rather than failing. The GitHub release
|
|
67
|
+
documents the tagged commit immediately; it does not wait on the npm 2FA gate. If the
|
|
68
|
+
CHANGELOG has no section for the version, this job fails loudly rather than cutting an
|
|
69
|
+
empty release — so always promote `## [Unreleased]` to `## [X.Y.Z]` in the release PR.
|
|
70
|
+
|
|
71
|
+
> `workflow_dispatch` with a `version` input remains as a manual fallback (needs
|
|
72
|
+
> `Actions: write`), but the tag push is the normal path.
|
|
73
|
+
|
|
74
|
+
### Phase 3 — approve the staged packages
|
|
75
|
+
|
|
76
|
+
Go to **[npmjs.com → tpsdev-ai → Staged Packages](https://www.npmjs.com/settings/tpsdev-ai/staging)**,
|
|
77
|
+
review each staged tarball, and approve with 2FA. Or from a machine logged into npm:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm stage list # show staged packages + their stage-ids
|
|
81
|
+
npm stage view <stage-id> # inspect one
|
|
82
|
+
npm stage approve <stage-id> # 2FA prompt; package goes live
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
There are seven lockstep-staged packages, so seven approvals (the web UI lists them on
|
|
86
|
+
one page). Approve in dependency order if installing immediately — flair-client before
|
|
87
|
+
its dependents — though staging does not itself resolve dependencies. `flair-bench`
|
|
88
|
+
stages separately and only appears here once its bootstrap (below) is done.
|
|
89
|
+
|
|
90
|
+
Verify when done:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npm view @tpsdev-ai/flair version # should report the new version
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## One-time setup
|
|
97
|
+
|
|
98
|
+
These are configured once and reused for every release.
|
|
99
|
+
|
|
100
|
+
### npm trusted publisher (per package)
|
|
101
|
+
|
|
102
|
+
For **each** of the seven packages, on npmjs.com → the package → **Settings → Trusted
|
|
103
|
+
Publisher → Add**:
|
|
104
|
+
|
|
105
|
+
| Field | Value |
|
|
106
|
+
| --------------- | --------------------------- |
|
|
107
|
+
| Provider | GitHub Actions |
|
|
108
|
+
| Organization | `tpsdev-ai` |
|
|
109
|
+
| Repository | `flair` |
|
|
110
|
+
| Workflow | `release-publish.yml` |
|
|
111
|
+
| Environment | `release` |
|
|
112
|
+
| Allowed actions | **`npm stage publish` only** |
|
|
113
|
+
|
|
114
|
+
Leave `npm publish` **unchecked** under allowed actions. This structurally prevents the
|
|
115
|
+
CI/OIDC identity from publishing anything live directly — the only path to live is the
|
|
116
|
+
human 2FA approval of a staged package.
|
|
117
|
+
|
|
118
|
+
Packages: `flair-client`, `flair-mcp`, `flair`, `openclaw-flair`, `pi-flair`,
|
|
119
|
+
`n8n-nodes-flair`, `langgraph-flair`.
|
|
120
|
+
|
|
121
|
+
> A package must already exist on npm before a trusted publisher can be added — all
|
|
122
|
+
> seven already do. This account-level config can only be done by an npm org owner.
|
|
123
|
+
> `flair-bench` doesn't exist on npm yet (verified via `npm view @tpsdev-ai/flair-bench`
|
|
124
|
+
> → 404 as of 2026-07-13) so it can't have a Trusted Publisher yet either — see below.
|
|
125
|
+
|
|
126
|
+
### `flair-bench` bootstrap (one-time)
|
|
127
|
+
|
|
128
|
+
`flair-bench` (added 2026-07-12, flair#702) is wired into the version-bump/tag flow
|
|
129
|
+
(`scripts/release.sh`, `release-publish.yml`'s version-check) alongside the other 7, but
|
|
130
|
+
`npm stage publish` categorically requires the package already exist on the npm registry
|
|
131
|
+
(`npm help stage`: "Package must exist"), and a Trusted Publisher can only be registered
|
|
132
|
+
for a package that already exists — chicken-and-egg for a brand-new package. Until an npm
|
|
133
|
+
org owner does this once, the workflow's dedicated "Stage-publish flair-bench" step is
|
|
134
|
+
expected to fail (it's `continue-on-error: true` so it doesn't block the other 7):
|
|
135
|
+
|
|
136
|
+
1. From a machine logged into npm with 2FA: `cd packages/flair-bench && npm run build &&
|
|
137
|
+
npm publish --access public` — one normal (non-staged) publish to create the package
|
|
138
|
+
on the registry. Any valid semver works; the very next lockstep release will bump it
|
|
139
|
+
to match the other 7 automatically (it's in `scripts/release.sh`'s `PACKAGES` array).
|
|
140
|
+
2. Add the Trusted Publisher for `@tpsdev-ai/flair-bench` using the same table as the
|
|
141
|
+
other 7 above (org=`tpsdev-ai`, repo=`flair`, workflow=`release-publish.yml`,
|
|
142
|
+
environment=`release`, allowed=`npm stage publish` only).
|
|
143
|
+
3. Remove `continue-on-error: true` from the "Stage-publish flair-bench" step in
|
|
144
|
+
`release-publish.yml` once a tag push has staged it successfully.
|
|
145
|
+
|
|
146
|
+
### GitHub `release` environment
|
|
147
|
+
|
|
148
|
+
A repository environment named `release` scopes the OIDC trust. It has **no required
|
|
149
|
+
reviewers** — the human gate is the npm staging approval, not a GitHub deployment
|
|
150
|
+
review. Because the release is triggered by a tag push, its deployment policy must allow
|
|
151
|
+
**`v*` tags** (Settings → Environments → `release` → Deployment branches and tags →
|
|
152
|
+
Selected branches and tags → add tag rule `v*`).
|
|
153
|
+
|
|
154
|
+
### Approver 2FA
|
|
155
|
+
|
|
156
|
+
The maintainer who approves staged packages must have 2FA enabled on their npm account.
|
|
157
|
+
|
|
158
|
+
## If something goes wrong
|
|
159
|
+
|
|
160
|
+
- **A staged package looks wrong** — reject it on npmjs.com instead of approving; it
|
|
161
|
+
never goes live. Fix forward on `main` and cut a new patch version.
|
|
162
|
+
- **Re-run the stage for the same version** — delete and re-push the tag
|
|
163
|
+
(`git push origin :v0.11.0` then `git tag -f v0.11.0 && git push origin v0.11.0`).
|
|
164
|
+
The tag push re-triggers the workflow.
|
|
165
|
+
- **Break-glass (CI down):** `./scripts/release.sh X.Y.Z --publish` still works from a
|
|
166
|
+
machine logged into npm. Prefer the staged flow; this bypasses the staging gate.
|
|
167
|
+
|
|
168
|
+
## Requirements
|
|
169
|
+
|
|
170
|
+
- npm CLI **≥ 11.15.0** (`npm stage`) and **≥ 11.5.1** (OIDC) — the workflow upgrades
|
|
171
|
+
npm itself; local approvers need a recent npm.
|
|
172
|
+
- Node **≥ 22.14**.
|
|
173
|
+
- Trusted publishing runs on GitHub-hosted runners only (no self-hosted support yet).
|