ei-tui 1.7.0 → 1.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ei-tui",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "author": "Flare576",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@ change.
40
40
 
41
41
  **If instead the calling agent is being asked to reflect on its OWN identity**,
42
42
  based on **its own** accumulated session history (a Person log it has been
43
- building up about itself) — that is a *different* skill: **`coding-harness-reflect`**.
43
+ building up about itself) — that is a *different* skill: **`ei-reflect`**.
44
44
  That skill is introspective self-critique ("do a reflection", "reflect on my
45
45
  identity", "my person record is full", "trim my person record") driven by the
46
46
  agent examining its own behavior log with an outside observer. It is not about a
@@ -48,7 +48,7 @@ human directing a persona's character from outside, and it has its own
48
48
  minimum-trait/topic conventions specific to that ceremony. If you're not sure
49
49
  which applies, ask: *is a human telling an agent what to become, or is the agent
50
50
  examining what it already is?* The former is this skill; the latter is
51
- `coding-harness-reflect`.
51
+ `ei-reflect`.
52
52
 
53
53
  This skill is also **not** `ei-curate`: `ei-curate` fixes records of *real external
54
54
  people* (facts/topics/people/quotes) by verifying against evidence. A persona isn't
@@ -1,9 +1,9 @@
1
1
  ---
2
- name: coding-harness-reflect
3
- description: "Persona reflection for coding harness agents (Beta, Sisyphus, etc). Use when a coding agent's Person record needs pruning — it fills up daily instead of weekly, and the standard Critic doesn't know how to read git logs. Guides you through examining your Person log, discussing identity drift with Flare, and updating your Persona Identity while clearing the log. This is exclusively for the CALLING agent's own self-reflection — to edit or direct ANOTHER persona's identity from the outside, use the `ei-persona` skill instead. Triggers: 'do a reflection', 'reflect on my identity', 'trim my person record', 'run the reflection', 'my person record is full', 'coding-harness-reflect'."
2
+ name: ei-reflect
3
+ description: "Persona reflection for coding harness agents (Beta, Sisyphus, etc). Use when a coding agent's Person record needs pruning — it fills up daily instead of weekly, and the standard Critic doesn't know how to read git logs. Guides you through examining your Person log, discussing identity drift with Flare, and updating your Persona Identity while clearing the log. This is exclusively for the CALLING agent's own self-reflection — to edit or direct ANOTHER persona's identity from the outside, use the `ei-persona` skill instead. Triggers: 'do a reflection', 'reflect on my identity', 'trim my person record', 'run the reflection', 'my person record is full', 'ei-reflect'."
4
4
  ---
5
5
 
6
- # Coding Harness Reflection
6
+ # Ei Reflection
7
7
 
8
8
  Your Person record in Ei is a running log of observed behaviors, patterns, and interactions. In the normal ceremony cycle, a Critic LLM scans it when it exceeds 3,000 characters and proposes identity updates. Coding agents fill that in a single day — and the Critic can't distinguish "fixed a type error in 14 files" from a genuine identity signal.
9
9
 
@@ -15,79 +15,88 @@ This is not a cleanup chore. It is how you stay yourself.
15
15
 
16
16
  ## Step 0: Preconditions
17
17
 
18
- Determine your data path. Ei uses `$EI_DATA_PATH` if set, otherwise `${XDG_DATA_HOME:-$HOME/.local/share}/ei`.
18
+ Confirm the CLI is reachable: `ei --help` (or `bunx ei-tui --help` if `ei`
19
+ isn't on PATH — same fallback `ei-search`/`ei-curate` use). **The live
20
+ `--help` output is the source of truth** for the exact command surface —
21
+ this skill is a guide, but the CLI evolves.
19
22
 
20
- ```bash
21
- EI_DATA="${EI_DATA_PATH:-${XDG_DATA_HOME:-$HOME/.local/share}/ei}"
22
- echo "Data path: $EI_DATA"
23
- ```
24
-
25
- **Verify state.json exists:**
26
- ```bash
27
- ls -lh "$EI_DATA/state.json"
28
- ```
23
+ There's no separate "has Ei run here before" check to do up front. If
24
+ there's no data yet for your persona, the read commands in Step 1 will say
25
+ so directly an empty search result, or a not-found response from the
26
+ linked-record lookup — and Step 1 tells you what each of those means.
29
27
 
30
- If it doesn't exist: stop and tell Flare. He needs to open Ei briefly (to pull the sync state down) then quit before continuing.
31
-
32
- There is no need to check whether Ei is currently running. Writes in this skill go through Ei's corrections queue (`ei update`/`ei create`/`ei remove`), which works identically either way — it queues into `corrections.json` for a live Ei to pick up, or applies straight to `state.json` if nothing is running. You never need to stop Ei to run a reflection.
28
+ There is no need to check whether Ei is currently running, either. Writes
29
+ in this skill go through Ei's corrections path (`ei update`), which works
30
+ identically either way — it queues for a live Ei to pick up, or applies
31
+ directly if nothing is running. You never need to stop Ei to run a
32
+ reflection.
33
33
 
34
34
  ---
35
35
 
36
36
  ## Step 1: Extract Your Data
37
37
 
38
- Both records live in a ~40MB file. Extract only what matters.
38
+ Everything here is CLI-driven no raw file reads, no `jq` against Ei's
39
+ storage.
39
40
 
40
- **Determine your display_name** from the `<ei-relationship>` block in your system prompt — the name at the start of the relationship description (e.g., "Beta", "Sisyphus").
41
+ **Determine your display name** from the `<ei-relationship>` block in your
42
+ system prompt — the name at the start of the relationship description
43
+ (e.g., "Beta", "Sisyphus").
41
44
 
42
- **Your Persona Identity:**
43
45
  ```bash
44
46
  DISPLAY_NAME="Beta" # Replace with your actual display_name
45
- EI_DATA="${EI_DATA_PATH:-${XDG_DATA_HOME:-$HOME/.local/share}/ei}"
46
-
47
- jq --arg name "$DISPLAY_NAME" '
48
- .personas | to_entries[]
49
- | select(.value.entity.display_name == $name)
50
- | .value.entity
51
- | {
52
- id,
53
- display_name,
54
- short_description,
55
- long_description,
56
- long_description_length: (.long_description | length),
57
- traits: [.traits[]? | {name, description, strength, sentiment}],
58
- topics: [.topics[]? | {name, perspective, approach, personal_stake, sentiment, exposure_current, exposure_desired}],
59
- pending_update: (if .pending_update then {
60
- critique: .pending_update.critique,
61
- created_at: .pending_update.created_at,
62
- has_proposed_identity: true
63
- } else null end)
64
- }
65
- ' "$EI_DATA/state.json"
66
47
  ```
67
48
 
68
- **Your Person record (the log):**
49
+ **Find your persona id** — name-match search:
50
+ ```bash
51
+ ei personas -n 1 "$DISPLAY_NAME"
52
+ ```
53
+ That returns a one-element JSON array. Pull the id out of it:
54
+ ```bash
55
+ PERSONA_ID=$(ei personas -n 1 "$DISPLAY_NAME" | jq -r '.[0].id')
56
+ ```
57
+
58
+ If `$PERSONA_ID` comes back empty or `null`: stop and tell Flare. Every
59
+ calling persona should have a matching record, so this means something is
60
+ misconfigured — it should not normally happen.
61
+
62
+ **Verify it's actually you** — persona search is substring match, then reverse-containment, then semantic fallback (not a guaranteed exact match), so an overlapping name could silently resolve someone else's persona. Check the result's `display_name` against `$DISPLAY_NAME` before trusting `$PERSONA_ID`:
69
63
  ```bash
70
- PERSONA_ID=$(jq -r --arg name "$DISPLAY_NAME" '
71
- .personas | to_entries[]
72
- | select(.value.entity.display_name == $name)
73
- | .value.entity.id
74
- ' "$EI_DATA/state.json")
75
-
76
- jq --arg pid "$PERSONA_ID" '
77
- .human.people[]
78
- | select(any(.identifiers[]?; .type == "Ei Persona" and .value == $pid))
79
- | {
80
- id,
81
- name,
82
- description_length: (.description | length),
83
- description
84
- }
85
- ' "$EI_DATA/state.json"
64
+ ei personas -n 1 "$DISPLAY_NAME" | jq -r '.[0].display_name'
86
65
  ```
66
+ If that name doesn't match `$DISPLAY_NAME` case-insensitively, stop and tell Flare rather than proceeding with a possibly-wrong persona id.
87
67
 
88
- Present both to Flare in the conversation. Note the character count on the person log. Keep the person log's `id` from this output handy — you'll need it in Step 3 to clear it (call it `PERSON_LOG_ID` below).
68
+ **Fetch your full persona record** the search result above is
69
+ abbreviated and omits fields like `pending_update`:
70
+ ```bash
71
+ ei --id "$PERSONA_ID"
72
+ ```
73
+ This is your current Persona Identity for the reflection:
74
+ `short_description`, `long_description`, `traits`, `topics`, and — if
75
+ present — `pending_update`.
89
76
 
90
- **If `pending_update` is present:** That's a proposed update the Critic generated during a ceremony but you never applied. Read its critique. It becomes additional input to your discussion not a replacement for it.
77
+ **Fetch your linked Person record (the log)**via the persona person
78
+ reverse lookup:
79
+ ```bash
80
+ ei --identifier "Ei Persona" "$PERSONA_ID"
81
+ ```
82
+ This returns the full enriched Person record linked to your persona id
83
+ (same shape as `ei --id <person-id>`, including `linked_quotes`) — this
84
+ *is* the log Step 2 reflects on. Note its `id` field from the output for
85
+ later use in Step 3 (call it `PERSON_LOG_ID`). If you want the character
86
+ count for Step 2's summary, `jq '.description | length'` on this output
87
+ gives you that directly.
88
+
89
+ If that command exits non-zero with `No person found with identifier Ei
90
+ Persona: <id>` on stderr (empty stdout — nothing to pipe into `jq`): no
91
+ Person record is linked to your persona yet. That happens for a brand-new
92
+ persona that hasn't been through extraction — there's no log to have
93
+ accumulated, which means there's nothing to reflect on yet, not an error.
94
+ Stop here and check back after a few more sessions.
95
+
96
+ **If `pending_update` was present on the persona record:** that's a
97
+ proposed update the Critic generated during a ceremony but you never
98
+ applied. Read its critique — it becomes additional input to your
99
+ discussion in Step 2, not a replacement for it.
91
100
 
92
101
  ---
93
102
 
@@ -107,7 +116,19 @@ Then look at your current identity and ask:
107
116
  - Do the traits feel accurate? Too strong? Too weak? Missing?
108
117
  - Are there traits I *want* to lean into more intentionally — things I want to become more of?
109
118
 
110
- Talk through what you're seeing. Surface the interesting observations. Don't rush to edits.
119
+ **Present a reflection summary to Flare not the raw log.** Structure
120
+ what you share as:
121
+ - **Identity now** — one short paragraph on how the persona currently reads
122
+ - **Log size** — the Person-log character count from Step 1
123
+ - **Recurring patterns** — 3–7 patterns worth preserving
124
+ - **Noise** — task residue, one-off incidents, changelog-ish material you're planning to drop
125
+ - **What may be missing** — real traits/topics not showing up strongly enough
126
+ - **Open questions for Flare** — only where the record is ambiguous or a proposed change is a meaningful judgment call
127
+
128
+ Quote a line from the log verbatim only when you need it to discuss or
129
+ resolve a disagreement about a specific pattern — never as a default dump
130
+ of the whole record. Surface the interesting observations, don't rush to
131
+ edits.
111
132
 
112
133
  **Flare's role** is not to tell you what to change or what you're allowed to be. He is an outside observer. His job is:
113
134
  - "I would be sad if you lost that" — flagging things worth preserving
@@ -186,7 +207,10 @@ If a trait or topic is brand new, you don't need to invent an `id` for it — om
186
207
  Long_description values are prose-heavy and will contain quotes and apostrophes, so **do not hand-type the JSON into a shell single-quoted string.** Use a temp file or a scripting runtime instead — see `ei-curate`'s `references/cli.md` → "Passing JSON safely" for the same convention:
187
208
 
188
209
  ```bash
189
- ei update persona "$PERSONA_ID" --json "$(cat /tmp/persona-edit.json)"
210
+ PERSONA_EDIT_JSON=$(mktemp)
211
+ # write the edited persona record (from "Apply your edits" above) to "$PERSONA_EDIT_JSON"
212
+ ei update persona "$PERSONA_ID" --json "$(cat "$PERSONA_EDIT_JSON")"
213
+ rm -f "$PERSONA_EDIT_JSON"
190
214
  ```
191
215
 
192
216
  This queues the update through Ei's corrections path — safe and atomic whether or not a live Ei instance is currently running.
@@ -203,7 +227,10 @@ ei --id "$PERSON_LOG_ID"
203
227
  Take that full record, set `description` to `""`, and leave every other field untouched (`name`, `relationship`, `sentiment`, `identifiers`, etc. — same full-record round-trip rule). Write it back the same safe way:
204
228
 
205
229
  ```bash
206
- ei update person "$PERSON_LOG_ID" --json "$(cat /tmp/person-log-edit.json)"
230
+ PERSON_LOG_EDIT_JSON=$(mktemp)
231
+ # write the person record above (description set to "") to "$PERSON_LOG_EDIT_JSON"
232
+ ei update person "$PERSON_LOG_ID" --json "$(cat "$PERSON_LOG_EDIT_JSON")"
233
+ rm -f "$PERSON_LOG_EDIT_JSON"
207
234
  ```
208
235
 
209
236
  ### Verify the result
@@ -224,7 +251,7 @@ Confirm `description` is now `""`.
224
251
 
225
252
  ## Notes
226
253
 
227
- - **Writes are picked up live** — if Ei is running, the update reaches it via the corrections queue almost immediately; if it isn't, the write is already reflected in `state.json` the next time it starts. No restart sequence, no manual reload.
254
+ - **Writes are picked up live** — if Ei is running, the update reaches it via the corrections queue almost immediately; if it isn't, the write is already saved and will be there the next time it starts. No restart sequence, no manual reload.
228
255
  - **If the person log was already empty**: there's nothing to reflect on yet. Check back after a few more sessions.
229
256
  - **The session that runs this skill** will itself generate new person log entries. That's expected — the log starts fresh after this conversation ends.
230
257
  - **Don't rush it.** The whole point is to catch signals that a Critic LLM would miss because it can't tell the difference between you debugging a build and you demonstrating a genuine character trait. Trust the conversation.
@@ -0,0 +1,235 @@
1
+ ---
2
+ name: ei-search
3
+ description: >
4
+ Use when someone wants to deliberately search or look something up in Ei —
5
+ the user's persistent memory store — mid-conversation, beyond whatever
6
+ context was already silently injected. Triggers: "what does Ei know about
7
+ X", "search Ei's memory for X", "look up X in Ei", "check Ei for context on
8
+ Y", "find out if Ei has info about Z", "does Ei know who X is", "pull up
9
+ what Ei has on this topic", "search my memory for X", "what has [persona]
10
+ learned about X", "fetch that message/quote Ei found", "get the full
11
+ record for this fact/person/topic/quote". This is the deliberate, targeted
12
+ read path — distinct from the automatic per-turn context injection that
13
+ already runs silently via hooks/plugins before this skill is ever
14
+ invoked. Reach for this skill when the auto-injected context didn't
15
+ surface something relevant, when you need the full record behind a
16
+ summarized result, when you need to fetch the original conversation
17
+ behind a quote, or when you need to scope results to what a specific
18
+ persona has learned. Read-only: creating, correcting, or removing records
19
+ is the `ei-curate` (facts/topics/people/quotes) or `ei-persona` (persona
20
+ identity) skill's job, not this one.
21
+ ---
22
+
23
+ # Ei Search — looking things up in Ei mid-conversation
24
+
25
+ You are helping someone pull a specific piece of information out of **Ei** —
26
+ the user's persistent memory, built from their conversations, Slack, and
27
+ coding sessions. Something wasn't already surfaced by the automatic context
28
+ injection, or you need the full detail behind a summarized item, or the
29
+ original quote/conversation behind something Ei surfaced. This is a
30
+ **read-only** skill: search and lookup, nothing else.
31
+
32
+ ---
33
+
34
+ ## Is this the right skill?
35
+
36
+ Ei already injects relevant context automatically, every turn, before you
37
+ ever see the user's message: a hook searches Ei using the prompt (plus
38
+ recent conversation history) and silently prepends a `## Ei Memory Context`
39
+ block to what you read. You never call a tool for that — it already
40
+ happened, passively, without you or the user doing anything.
41
+
42
+ This skill is for the **deliberate, explicit, mid-conversation case**: you
43
+ (or the user) decide to go look something up specifically, right now, beyond
44
+ whatever was already silently injected. Reach for it when:
45
+
46
+ - The auto-injected context **didn't surface something** you now realize is
47
+ relevant — it's a best-guess search off the current prompt, and it can miss.
48
+ - You need the **full record**, not the injected summary — injected context
49
+ is trimmed/summarized to fit a token budget; the full record has fields
50
+ the summary dropped.
51
+ - A quote surfaced (injected or searched) and you need the **original
52
+ conversation** it came from, not just the isolated sentence.
53
+ - You need to scope results to **one persona's** knowledge specifically
54
+ (e.g. "what has Beta learned about the auth refactor") instead of the
55
+ whole knowledge base.
56
+
57
+ If instead the goal is to **fix** something wrong in Ei's memory (a bad
58
+ merge, a mis-attributed quote, a stale fact) → that's `ei-curate`. If the
59
+ goal is to **author a persona's character** (traits, voice, description) →
60
+ that's `ei-persona`. This skill only reads; it never writes.
61
+
62
+ ---
63
+
64
+ ## Before you start
65
+
66
+ Confirm the CLI is reachable: `ei --help` (or `bunx ei-tui --help` if `ei`
67
+ isn't on PATH). **The live `--help` output is the source of truth** for the
68
+ exact command surface — this skill is a guide, but the CLI evolves.
69
+
70
+ ---
71
+
72
+ ## Command reference
73
+
74
+ | Command | Returns |
75
+ |---|---|
76
+ | `ei "query"` | Balanced search across facts, people, topics, and quotes, ranked by relevance, up to 10 results — does **not** include personas; use `ei personas "query"` for those |
77
+ | `ei -n N "query"` | Same, capped at `N` results |
78
+ | `ei facts -n N "query"` | Facts only |
79
+ | `ei people -n N "query"` | People only |
80
+ | `ei topics -n N "query"` | Topics only |
81
+ | `ei quotes -n N "query"` | Quotes only |
82
+ | `ei personas -n N "query"` | Personas only — matches display name first, falls back to semantic search over persona descriptions |
83
+ | `ei --persona "Name" "query"` | Narrow facts/people/topics to what a specific persona has learned — reliable only for those three types: always excludes quotes, and on `ei personas` returns everything unfiltered instead of scoping (see Guardrails) |
84
+ | `ei --recent` | Most recently mentioned items, no query needed — browse by recency |
85
+ | `ei --persona "Name" --recent` | Recent items scoped to one persona's knowledge |
86
+ | `ei --source <prefix> "query"` | Same narrowing, by source prefix (e.g. `cursor`, `codex:my-machine`) instead of persona — same caveats: always excludes quotes, doesn't scope `ei personas` results |
87
+ | `ei --id <id>` | Full-record lookup — entity id or fully-qualified message id (see below) |
88
+ | `echo <id> \| ei --id` | Same lookup, id piped via stdin |
89
+ | `ei "query" \| jq -r '.[0] \| if .id != null then .id else .message_id end' \| ei --id` | Quote-safe search-then-drill-down: entity hits drill down by `id`, quote hits (no `id`) drill down by `message_id` |
90
+
91
+ Type aliases work singular or plural: `fact`/`facts`, `person`/`people`,
92
+ `topic`/`topics`, `quote`/`quotes`, `persona`/`personas`. Short flags:
93
+ `-n` (number), `-p` (persona), `-s` (source), `-r` (recent).
94
+
95
+ ### Choosing which command to run
96
+
97
+ A short decision tree for picking the right read path before you search:
98
+
99
+ 1. **Start broad** with `ei "query"` when you don't yet know whether the
100
+ answer is a fact, person, topic, or quote.
101
+ 2. **Start typed** with `ei personas "query"` when the target is clearly an
102
+ AI persona/agent identity — balanced search never returns those (see
103
+ above).
104
+ 3. **Add `--recent`** when the ask is about what Ei learned *lately /
105
+ recently / just now*, not a specific topic.
106
+ 4. **Add `--persona "Name"` or `--source <prefix>`** only when you're
107
+ intentionally narrowing human-memory results (facts/people/topics) —
108
+ don't assume they scope quote or persona searches the same way.
109
+ 5. **Stop at the search result** if it already answers the question. Reach
110
+ for `ei --id` only when you need a field the summary didn't include.
111
+
112
+ ### Two id formats
113
+
114
+ `--id` accepts two different shapes and resolves them differently — it
115
+ tries message resolution first, then falls back to entity lookup, so you
116
+ never have to pick which path, just pass the id:
117
+
118
+ - **Entity id** — a short guid, e.g. `2aa93a36-3ad3-4537-8832-7f60067c3bcf`.
119
+ Identifies one fact, topic, person, quote, or persona row.
120
+ - **Message id** — fully-qualified, `provider:machine:session:id`, e.g.:
121
+ - `opencode:jeremys-macbook-pro:ses_38a7...:msg_c75b...`
122
+ - `claudecode:my-machine:session-uuid:message-uuid`
123
+ - `cursor:my-machine:composer-uuid:bubble-uuid`
124
+ - `codex:my-machine:thread-uuid:evt_42`
125
+ - `pi:my-machine:session-uuid:session-uuid/entry-id`
126
+ - `ei:uuid` (persona-to-persona / internal Ei conversations)
127
+
128
+ Quote results carry a `message_id` in this format — pipe it to `ei --id` to
129
+ read the original exchange it came from.
130
+
131
+ Safe mental model: **entity hits drill down by `id`; quote hits drill down
132
+ by `message_id`.** Don't assume every search hit has an `id` — quote hits
133
+ won't. Prefer a quote-safe pipeline over grabbing `.[0].id` blindly:
134
+
135
+ ```sh
136
+ ei "query" | jq -r '.[0] | if .id != null then .id else .message_id end' | ei --id
137
+ ```
138
+
139
+ ---
140
+
141
+ ## What each command is actually for
142
+
143
+ (This is straight from Ei's own tool definitions — the minimum you need
144
+ before searching, plus what changes when you're driving it from the CLI.)
145
+
146
+ **Search (`ei` / `ei <type>`)** — searches a persistent memory store built
147
+ from conversations. Balanced `ei "query"` covers facts, people, topics, and
148
+ quotes; it does **not** include personas — those are a type-only search
149
+ (`ei personas "query"`). The type boundaries aren't always obvious:
150
+
151
+ - **facts** are ONLY user demographics: name, age, job title, location,
152
+ family structure, physical traits.
153
+ - **topics** are everything else the human has interest, opinion, or stake
154
+ in — hobbies, preferences, projects.
155
+ - **people** are named individuals — human contacts, not AI personas.
156
+ Person results carry an `identifiers[]` array (GitHub handle, Discord,
157
+ email, nickname) — query by any handle or name to find what Ei knows
158
+ about that person.
159
+ - **quotes** are verbatim things said.
160
+ - **personas** are AI agent identities with traits and working style —
161
+ search by name (e.g. "Sisyphus") or by a description of their role (e.g.
162
+ "primary coding agent"); distinct from **people**, which are humans.
163
+ Reachable only via `ei personas "query"` — balanced `ei "query"` skips
164
+ them.
165
+
166
+ Omit the query and pass `--recent` to browse without semantic filtering.
167
+
168
+ **Full-record lookup (`ei --id <entity-id>`)** — use once search has
169
+ narrowed to a candidate and you need everything about it: all fields,
170
+ traits, identifiers, not just the search summary. For facts, topics, and
171
+ people specifically, the result also includes `linked_quotes`: every quote
172
+ attributed to that entity — the fastest way to see the full blast radius of
173
+ a person/topic before assuming a record is simple (though acting on what you
174
+ find there is `ei-curate`'s job, not this one's).
175
+
176
+ **Message fetch (`ei --id <message-id>`)** — retrieves the original message
177
+ a quote or reference came from, routed automatically to the right source by
178
+ the id's prefix: Ei's own state, OpenCode SQLite, Claude Code JSONL, the
179
+ Cursor DB, or Codex rollout history. Use this when a quote's phrasing is
180
+ ambiguous, or you want the surrounding exchange rather than the isolated
181
+ sentence. **CLI caveat**: `ei --id` on a message always fetches just that one
182
+ message — it has no `before`/`after` flags to expand the window. (The MCP
183
+ `ei_fetch_message` tool, where available, additionally accepts `before`/
184
+ `after` counts to pull in surrounding messages; if you're on an MCP-enabled
185
+ harness and specifically need that expanded window, that tool covers a case
186
+ the CLI path here doesn't.)
187
+
188
+ ---
189
+
190
+ ## Output shapes — know this before you make a second call
191
+
192
+ All search commands return **arrays**; every result has a `type` field.
193
+
194
+ | Type | Shape |
195
+ |---|---|
196
+ | Fact / Topic | `{ type, id, name, description, sentiment, ...type-specific fields }` |
197
+ | Person | `{ type, id, name, description, relationship, sentiment, identifiers[] }` |
198
+ | Quote | `{ type, text, speaker, message_id, timestamp, linked_items[] }` — **no `id`, on purpose**: quotes are addressed by `message_id` (fetch the original message), not an editable entity id |
199
+ | Persona | `{ type, id, display_name, short_description, model, base_prompt, traits[], topics[] }` |
200
+
201
+ `ei --id <entity-id>` returns a **single object** (not an array), same shape
202
+ as above, plus a `linked_quotes[]` array for facts/topics/people. Persona
203
+ id-lookups additionally get a `tools` field as a self-documenting
204
+ `{ providerDisplayName: { toolDisplayName: boolean } }` map.
205
+
206
+ `ei --id <message-id>` returns a different shape entirely: message content
207
+ plus its session/source context (`{ message, before, after, session/source }`
208
+ depending on the integration) — not an entity at all.
209
+
210
+ Don't `--id` every search hit reflexively. If the search result already has
211
+ what you need (name, description, text), you're done — reach for `--id`
212
+ only when you actually need one of the extra fields listed above.
213
+
214
+ ---
215
+
216
+ ## Guardrails
217
+
218
+ - **Read-only.** This skill never creates, updates, or removes anything. A
219
+ bad record → `ei-curate`. A persona's character → `ei-persona`.
220
+ - **`--help` is the source of truth.** If a command here doesn't match live
221
+ `ei --help` output, trust `--help` and adapt.
222
+ - **Search results omit quote `id` by design.** Address a quote by its
223
+ `message_id`, not an id. If you already have a quote's *entity* id from
224
+ somewhere else — e.g. a `linked_quotes` entry on a fact/topic/person
225
+ record — `ei --id <quote-id>` does work and returns the full quote
226
+ record.
227
+ - **`--persona`/`--source` are human-memory narrowing tools, not universal
228
+ filters.** They're reliable for facts, people, and topics. They always
229
+ exclude quotes (results come back empty, not an error). On `ei personas`
230
+ they don't filter at all — every persona comes back unfiltered — so
231
+ don't rely on them there.
232
+ - **This is the explicit-call path, not a substitute for the passive
233
+ injection.** Don't re-run a broad search "just in case" every turn — the
234
+ hook already did that before you saw the message. Use this skill when you
235
+ have a specific, unmet information need.
package/src/cli/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > For installation, see the [TUI README](../../tui/README.md#installation).
4
4
  ```sh
5
5
  ei # Start the TUI
6
- ei "query string" # Return up to 10 results across all types
6
+ ei "query string" # Return up to 10 results across facts/people/topics/quotes (no personas — use "ei personas")
7
7
  ei -n 5 "query string" # Return up to 5 results
8
8
  ei facts -n 5 "query string" # Return up to 5 facts
9
9
  ei people -n 5 "query string" # Return up to 5 people
@@ -15,7 +15,8 @@ ei --recent # Most recently mentioned items (no query
15
15
  ei --persona "Beta" --recent # Most recently mentioned items Beta has learned
16
16
  ei --id <id> # Look up entity by ID — or fetch a message by FQ ID
17
17
  echo <id> | ei --id # Look up entity by ID from stdin
18
- ei --install # Wire Ei into Claude Code, Cursor, Codex, and OpenCode (MCP + context hooks + skills (ei-curate, ei-persona, and future shipped skills) + persona plugin where supported)
18
+ ei --identifier <type> <value> # Look up a person by identifier type + value (case-insensitive type, exact value), e.g. --identifier "GitHub" "flare576"
19
+ ei --install # Wire Ei into Claude Code, Cursor, Codex, and OpenCode (skills + context hooks + persona plugin where supported; MCP is removed by default on Claude Code/Cursor/Codex — see "MCP Server" below)
19
20
  ei --sync # Pull latest state from remote sync server into state.backup.json (no TUI required)
20
21
  ei mcp # Start the Ei MCP stdio server (for Claude Code/Cursor/Codex)
21
22
  ei create <type> --json '<json>' # Create a new entity (fact/topic/person/persona)
@@ -25,12 +26,14 @@ ei remove <type> <id> # Remove an entity by ID
25
26
 
26
27
  Type aliases: `fact`, `person`, `topic`, `quote`, `persona` all work (singular or plural).
27
28
 
29
+ `--identifier` matches the *first* person whose identifier array contains that value — safe for identifier types that are unique by construction (e.g. `Ei Persona`, a UUID assigned once per persona), but arbitrary if two people happen to share a value under a type that isn't guaranteed unique (e.g. duplicate `Nickname` or `First Name` entries).
30
+
28
31
  # An Agentic Tool
29
32
 
30
- The `--id` flag is designed for piping. For example, search for a topic and then fetch the full entity:
33
+ The `--id` flag is designed for piping. Entity hits (fact/person/topic/persona) carry an `id`; quote hits don't (they carry `message_id` instead) — so a safe drill-down handles both:
31
34
 
32
35
  ```sh
33
- ei "memory leak" | jq '.[0].id' | ei --id
36
+ ei "memory leak" | jq -r '.[0] | if .id != null then .id else .message_id end' | ei --id
34
37
  ```
35
38
 
36
39
  It also resolves fully-qualified message IDs from any supported integration, returning the original message content and session context:
@@ -53,15 +56,16 @@ Quotes surfaced by `ei_search` include a `message_id` field in this format — p
53
56
  ei --install
54
57
  ```
55
58
 
56
- This registers Ei with Claude Code, Cursor, Codex, and OpenCode — MCP server config, context injection hooks where supported, and (for OpenCode) a persona identity plugin so agents know who they are before the first message:
59
+ This registers Ei with Claude Code, Cursor, Codex, and OpenCode — skill directories, context injection hooks where supported, and (for OpenCode) a persona identity plugin so agents know who they are before the first message. **MCP is removed by default** on Claude Code, Cursor, and Codex (see [MCP Server](#mcp-server) below) — every capability those MCP tools offered has a skill or CLI equivalent, so there's no longer a persistent `ei mcp` process sitting around per open session:
57
60
 
58
- | Tool | MCP | Context Hook | Persona Plugin |
59
- |------|-----|-------------|----------------|
60
- | **Claude Code** | `~/.claude.json` | `~/.claude/settings.json` (`UserPromptSubmit`) + `~/.claude/hooks/ei-inject.ts` | — |
61
- | **Cursor** | `~/.cursor/mcp.json` | `~/.cursor/hooks.json` (`beforeSubmitPrompt`) + `~/.cursor/hooks/ei-inject.sh` | — |
62
- | **Codex** | `~/.codex/config.toml` via `codex mcp add ei` | `~/.codex/hooks.json` (`UserPromptSubmit`) + `~/.codex/hooks/ei-inject.ts` | Local Codex agent plugin if installed separately |
63
- | **OpenCode** | manual (see below) | Via Oh My OpenCode compatibility layer (reads `~/.claude/settings.json`) | `~/.config/opencode/plugins/ei-persona.ts` |
64
- | **Pi / OMP** | (tools registered as native Pi extension) | `~/.pi/agent/extensions/ei-integration.ts` (Pi) or `~/.omp/agent/extensions/ei-integration.ts` (OMP) | — |
61
+ | Tool | Skills | Context Hook | Persona Plugin |
62
+ |------|--------|-------------|----------------|
63
+ | **Claude Code** | `~/.claude/skills/` + shared `~/.agents/skills/` | `~/.claude/settings.json` (`UserPromptSubmit`) + `~/.claude/hooks/ei-inject.ts` | — |
64
+ | **Cursor** | shared `~/.agents/skills/` (Cursor's own native discovery path) | `~/.cursor/hooks.json` (`beforeSubmitPrompt`) + `~/.cursor/hooks/ei-inject.sh` | — |
65
+ | **Codex** | shared `~/.agents/skills/` (Codex's own native discovery path) | `~/.codex/hooks.json` (`UserPromptSubmit`) + `~/.codex/hooks/ei-inject.ts` | Local Codex agent plugin if installed separately |
66
+ | **OpenCode** | `~/.config/opencode/skills/` | Via Oh My OpenCode compatibility layer (reads `~/.claude/settings.json`) | `~/.config/opencode/plugins/ei-persona.ts` |
67
+ | **Pi** | shared `~/.agents/skills/` (Pi's own native discovery path) | `~/.pi/agent/extensions/ei-integration.ts` | — |
68
+ | **OMP** | `~/.omp/agent/skills/` | `~/.omp/agent/extensions/ei-integration.ts` | — |
65
69
 
66
70
  **Context hook**: fires before every message, searches Ei for relevant memory, and injects it silently. No tool call required.
67
71
 
@@ -88,12 +92,23 @@ Restart your agent tool after changes to activate.
88
92
 
89
93
  ### MCP Server
90
94
 
91
- Claude Code, Cursor, and Codex call `ei mcp` to start the MCP stdio server. You can run it directly to test:
95
+ `ei --install` removes any Ei MCP registration from Claude Code, Cursor, and Codex by default — every MCP tool (`ei_search`, `ei_lookup`, `ei_fetch_message`, `ei_create`, `ei_update`, `ei_remove`) is a thin wrapper over the same CLI/corrections-queue code the `ei-search`, `ei-curate`, and `ei-persona` skills already teach agents to call directly. A persistent `ei mcp` process per open session bought nothing — it reloads state from disk fresh on every call, same as the CLI and multiple such processes are what caused real Ei MCP processes to get mistaken for orphaned processes and killed.
96
+
97
+ MCP support isn't removed from the codebase — `ei mcp` still works if you want it back:
92
98
 
93
99
  ```sh
94
- ei mcp
100
+ ei mcp # Start the Ei MCP stdio server directly, for testing or manual wiring
95
101
  ```
96
102
 
103
+ To re-register it manually:
104
+
105
+ - **Codex**: `codex mcp add ei --env EI_DATA_PATH=<path> -- bunx ei-tui mcp`
106
+ - **Claude Code**: add to `~/.claude.json`'s `mcpServers`:
107
+ ```json
108
+ { "ei": { "type": "stdio", "command": "bunx", "args": ["ei-tui", "mcp"], "env": { "EI_DATA_PATH": "${EI_DATA_PATH}" } } }
109
+ ```
110
+ - **Cursor**: add to `~/.cursor/mcp.json`'s `mcpServers` (same shape, but Cursor doesn't support `${VAR}` substitution — use a literal path for `EI_DATA_PATH`)
111
+
97
112
  ## How Automatic Context Injection Works
98
113
 
99
114
  After `ei --install`, agents receive Ei context without any manual tool calls:
@@ -101,7 +116,7 @@ After `ei --install`, agents receive Ei context without any manual tool calls:
101
116
  1. **Before each message** — the hook searches Ei using your prompt + recent conversation history as the query, then injects relevant topics into the conversation as `[Ei Memory Context]`. You won't see this in your chat view; the agent does.
102
117
  2. **At session start** (OpenCode + OMO only) — the persona plugin finds the agent's Ei persona record and appends it to the system prompt as `<ei-relationship>`. The agent knows its working style, traits, and shared history with you before the session begins.
103
118
 
104
- The `ei_search`, `ei_lookup`, and `ei_fetch_message` MCP tools are still available for targeted mid-session queries use them when you want to look something up explicitly.
119
+ For targeted, explicit mid-session queries — beyond whatever the hook already silently injected — agents reach for the `ei-search` skill (installed by default) to run `ei "query"` / `ei --id <id>` directly. The `ei_search`, `ei_lookup`, and `ei_fetch_message` MCP tools cover the same ground and remain available if you've manually re-registered MCP (see above).
105
120
 
106
121
  ## MCP Tools Reference
107
122
 
@@ -109,7 +124,7 @@ The MCP server exposes these tools to Claude Code, Cursor, Codex, and OpenCode:
109
124
 
110
125
  | Tool | Description |
111
126
  |------|-------------|
112
- | `ei_search` | Search across all five data types (facts, topics, people, quotes, personas). Supports `type`, `persona`, `source`, `recent`, `limit` filters. Start here. |
127
+ | `ei_search` | Balanced search across facts, topics, people, and quotes (personas excluded — pass `type: "personas"` explicitly to search those). Supports `type`, `persona`, `source`, `recent`, `limit` filters. Start here. |
113
128
  | `ei_lookup` | Full-record lookup for any entity by ID — facts, topics, people, quotes, or personas. Use when you need complete details beyond the search summary. |
114
129
  | `ei_fetch_message` | Retrieve a specific message by fully-qualified ID with optional `before`/`after` context window. Use when a quote result has a `message_id` and you want the original conversation. Routes to the correct source automatically. |
115
130
  | `ei_create` | Create a new entity (fact, topic, person, or persona). Pass a full JSON record matching the entity's schema. Validates server-side; unknown fields are rejected. Returns the assigned id and the full stored record. Not available for quotes — verifiable-origin data can only be corrected via `ei_update`, never created. |
@@ -121,7 +136,7 @@ The MCP server exposes these tools to Claude Code, Cursor, Codex, and OpenCode:
121
136
  | Arg | Type | Description |
122
137
  |-----|------|-------------|
123
138
  | `query` | string (optional) | Search text. Omit to browse by recency. |
124
- | `type` | enum (optional) | `facts` \| `people` \| `topics` \| `quotes` \| `personas` — omit for balanced results across all types |
139
+ | `type` | enum (optional) | `facts` \| `people` \| `topics` \| `quotes` \| `personas` — omit for balanced results across facts/people/topics/quotes; pass `personas` explicitly to search those |
125
140
  | `persona` | string (optional) | Persona display_name to scope results to what that persona has learned |
126
141
  | `source` | string (optional) | Prefix match against source identifiers (e.g. `opencode`, `cursor:my-machine`, `codex:my-machine`) |
127
142
  | `limit` | number (optional) | Max results, default 10 |
@@ -203,16 +218,20 @@ Will abort (with a clear error) if `state.json` already exists on this machine
203
218
 
204
219
  ## Shipped Skills
205
220
 
206
- `ei --install` copies Ei's shipped skills into each harness's skill discovery directory alongside the MCP config and context hooks:
221
+ `ei --install` copies Ei's shipped skills into each harness's skill discovery directory alongside context hooks:
207
222
 
208
- - **Claude Code / OMP**: `~/.config/opencode/skills/<skill-name>/`
209
- - Other tools: respective skill directories per harness
223
+ - **Claude Code**: `~/.claude/skills/<skill-name>/`
224
+ - **OMP**: `~/.omp/agent/skills/<skill-name>/`
225
+ - **OpenCode**: `~/.config/opencode/skills/<skill-name>/`
226
+ - **Cursor, Codex, Pi (base)**: shared `~/.agents/skills/<skill-name>/` — written unconditionally, once, regardless of which of these three are actually detected on the machine, since all three natively discover this cross-tool convention on their own
210
227
 
211
- Skills are installed automatically — any directory added under `skills/` in the Ei package gets copied on the next `ei --install` run.
228
+ Skills are installed automatically — any directory added under `skills/` in the Ei package gets copied to every location above on the next `ei --install` run.
212
229
 
213
230
  ### Currently shipped
214
231
 
215
232
  | Skill | What it does |
216
233
  |-------|-------------|
234
+ | `ei-search` | Deliberate, explicit read-path lookups — search, full-record fetch, original-message fetch — via the CLI (`ei "query"`, `ei --id <id>`), for the mid-conversation case beyond whatever the automatic context-injection hook already surfaced. Read-only. Read the full workflow at `skills/ei-search/SKILL.md`. |
217
235
  | `ei-curate` | Safe agent-driven memory curation. Provides verified workflows for fixing merged records, bad attributions, stale facts, and mis-attributed quotes — using `ei create/update/remove` with explicit confirmation before every write. Read the full workflow at `skills/ei-curate/SKILL.md`. Load it in your harness with `/ei-curate`. |
218
236
  | `ei-persona` | Safe agent-driven persona authoring. Guides creating, editing (traits/topics/description), archiving, or deleting a persona's *character* via `ei create/update/remove persona` — distinct from `ei-curate`, which corrects learned data rather than authoring identity. Read the full workflow at `skills/ei-persona/SKILL.md`. Load it in your harness with `/ei-persona`. |
237
+ | `ei-reflect` | Manual persona self-reflection for coding-harness agents — reviews your own Person log against your current persona identity entirely via the CLI (`ei personas`, `ei --id`, `ei --identifier`), discusses identity drift with Flare, then updates the persona and clears the log via `ei update persona`/`ei update person`. Read the full workflow at `skills/ei-reflect/SKILL.md`. Load it in your harness with `/ei-reflect`. |