create-egregore 0.19.12 → 0.19.15
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/assets/egregore-launcher.js +228 -15
- package/assets/egregore-launcher.sh +7 -3
- package/bin/cli.js +18 -0
- package/lib/setup.js +94 -14
- package/package.json +2 -2
- package/runtime/codex/.codex/hooks/search-hint.js +4 -2
- package/runtime/codex/.codex/skills/search/SKILL.md +28 -5
- package/runtime/codex/.codex/spec-manifest.json +7 -1
- package/runtime/codex/AGENTS.md +50 -3
- package/runtime/codex/bin/codex-render-spec.mjs +1 -0
- package/runtime/codex/bin/search.sh +240 -0
- package/runtime/codex/manifest.json +1 -0
- package/runtime/pi/.codex/hooks/search-hint.js +4 -2
- package/runtime/pi/.codex/skills/search/SKILL.md +28 -5
- package/runtime/pi/.codex/spec-manifest.json +7 -1
- package/runtime/pi/.pi/APPEND_SYSTEM.md +47 -0
- package/runtime/pi/.pi/spec-manifest.json +2 -2
- package/runtime/pi/AGENTS.md +50 -3
- package/runtime/pi/bin/codex-render-spec.mjs +1 -0
- package/runtime/pi/bin/search.sh +240 -0
- package/runtime/pi/manifest.json +1 -0
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
"sourceHash": "b5d9a149f1a6",
|
|
51
51
|
"note": "Kept verbatim — bin/graph.sh is runtime-neutral."
|
|
52
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"section": "Egregore Retrieval Beat",
|
|
55
|
+
"action": "keep",
|
|
56
|
+
"sourceHash": "0c4d4715fb13",
|
|
57
|
+
"note": "Kept verbatim — product attribution applies across runtimes."
|
|
58
|
+
},
|
|
53
59
|
{
|
|
54
60
|
"section": "Notifications",
|
|
55
61
|
"action": "keep",
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
{
|
|
96
102
|
"section": "Command Awareness",
|
|
97
103
|
"action": "keep",
|
|
98
|
-
"sourceHash": "
|
|
104
|
+
"sourceHash": "a020fc5d9b98",
|
|
99
105
|
"note": "Prepended the Codex command surface (skill tokens, native vs adapter split, $save abstraction); disambiguation map kept with /x -> $x token rendering. Tokens with no Codex skill (e.g. /loop, a Claude Code harness feature) are left as-is."
|
|
100
106
|
},
|
|
101
107
|
{
|
package/runtime/codex/AGENTS.md
CHANGED
|
@@ -220,6 +220,53 @@ Run `catalog` only when the route is unclear. Named reads return bounded stable
|
|
|
220
220
|
|
|
221
221
|
---
|
|
222
222
|
|
|
223
|
+
## Egregore Retrieval Beat
|
|
224
|
+
|
|
225
|
+
Egregore's organizational search is a product surface, not indistinguishable
|
|
226
|
+
agent tool use. For each user-directed lookup of organizational knowledge,
|
|
227
|
+
show exactly one visible attribution line:
|
|
228
|
+
|
|
229
|
+
- memory-only retrieval:
|
|
230
|
+
`⌕ Egregore · searching your organization’s memory`
|
|
231
|
+
- retrieval that actually queries the connected graph:
|
|
232
|
+
`⌕ Egregore Connect · searching your organization’s memory and relationships`
|
|
233
|
+
|
|
234
|
+
**Visibility is the contract.** Emit the applicable line verbatim as a
|
|
235
|
+
standalone assistant message before the first Bash, Grep, Glob, Read, or other
|
|
236
|
+
retrieval tool call. Shell/tool output does not satisfy this requirement:
|
|
237
|
+
Claude Code and other harnesses may collapse it. Do not paraphrase the line or
|
|
238
|
+
replace it with generic narration such as “I’ll search org memory.”
|
|
239
|
+
|
|
240
|
+
Use the memory form for local/filesystem-only organizational retrieval. Use the
|
|
241
|
+
Connect form when the retrieval route will query the connected graph, including
|
|
242
|
+
automatic graph enrichment in `bin/search.sh query`, a graph-only named read,
|
|
243
|
+
or exploratory Cypher. Emit once for the whole retrieval episode, not once per
|
|
244
|
+
hop. The banner printed by `bin/search.sh` remains a direct-shell fallback and
|
|
245
|
+
does not replace the assistant-visible beat.
|
|
246
|
+
|
|
247
|
+
**Routing is part of the contract.** For organizational history, decisions,
|
|
248
|
+
handoffs, meetings, people, pricing, strategy, or other shared-memory content,
|
|
249
|
+
the first retrieval action is:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
bash bin/search.sh query "<concept>" -n 6
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Do not start by resolving `memory/` to its sibling repository, changing
|
|
256
|
+
directory into that absolute path, or improvising `grep`/`ls` over it. The
|
|
257
|
+
search entry point owns keyword/semantic selection and automatically attaches
|
|
258
|
+
graph state in connected mode. Read or grep the returned `memory/...` source
|
|
259
|
+
paths only after the ranked call when verification needs the full document.
|
|
260
|
+
Native Grep/Glob remain the right first action for repository code, filenames,
|
|
261
|
+
and exact error strings—not organizational recall.
|
|
262
|
+
|
|
263
|
+
Do not emit the beat for native repository/code search, Git inspection, startup
|
|
264
|
+
context hydration, graph writes, ingestion projection, background sync,
|
|
265
|
+
maintenance, or command-internal queries that are not answering a user lookup.
|
|
266
|
+
Never name `Egregore Connect` unless a graph read will actually run.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
223
270
|
## Notifications
|
|
224
271
|
|
|
225
272
|
**Connected mode only.** Always use `bin/notify.sh` for Telegram notifications — never construct API calls directly. See DEVELOPMENT.md §1 for usage examples. In local mode there are no live notifications.
|
|
@@ -306,7 +353,7 @@ Codex reserves leading `/` for built-ins, so Egregore workflows are **skills**,
|
|
|
306
353
|
Invoke commands from user intent — don't wait for the slash. Each command file has a `## When to invoke` section. Load it for the full spec.
|
|
307
354
|
|
|
308
355
|
**Core loop** — `$activity` `$dashboard` `$handoff` `$wrap` `$save` `$reflect` `$todo`
|
|
309
|
-
**Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll`
|
|
356
|
+
**Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll` `$mock`
|
|
310
357
|
**Identity** — `$me` (view profile or set display name)
|
|
311
358
|
**Coordination** — `$ask` `$quest` `$issue` `$invite` `$delete-user` `$announce`
|
|
312
359
|
**Connectors** — `$telegram-connect` (Telegram group setup) `$teams-connect` (Microsoft Teams channel setup)
|
|
@@ -316,9 +363,9 @@ Invoke commands from user intent — don't wait for the slash. Each command file
|
|
|
316
363
|
|
|
317
364
|
**Disambiguation:**
|
|
318
365
|
- Knowledge: `$reflect` (share-ready) · `$note` (half-baked) · `$deep-reflect` (deep research over memory — questions AND cross-referencing) · `$archive` (AI patterns)
|
|
319
|
-
- Finding things —
|
|
366
|
+
- Finding things — **organizational recall starts with `bash bin/search.sh query`** (ranked filesystem retrieval in OSS; automatic relationship/status enrichment in Connect). Use `bin/graph.sh` named reads first only for a pure relationship/status traversal. Use Grep/Glob first for repository code, filenames, and exact error strings—not shared-memory recall. Do not `cd` into the sibling memory repository.
|
|
320
367
|
- Finding **something you generated** (a scroll, handoff, emissary, decision, any hosted egregore.xyz link): `bash bin/artifacts.sh find <query>`. Every generative surface already records into memory — hosted artifacts self-register into `memory/artifacts/` at publish (and the record is committed+pushed, so it's findable from *any* session, not just the one that made it); handoffs land in `memory/handoffs/`, emissaries in `memory/handoffs/outbound/`, decisions/findings/patterns in `memory/knowledge/`. The finder searches **all** of them, ranks title/topic matches above passing body mentions, tags each hit by type (`[document]`/`[handoff]`/`[emissary]`/`[decision]`), and surfaces the shareable URL. Findable by **content, not just name**, across all three layers — grep-first for OSS, folding in search + graph when available. *"bring me the artifact where I laid out our GTM plan"* → this.
|
|
321
|
-
- Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face)
|
|
368
|
+
- Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face) · `$mock` (pre-build walkthrough of decided design — gauge per stop, verdict copy-back)
|
|
322
369
|
- Status: `$dashboard` (personal) · `$activity` (org-wide)
|
|
323
370
|
- Ending: `$wrap` (personal closure) · `$handoff` (notes for others) · `$save` (still working)
|
|
324
371
|
- Tasks: `$todo` (personal) · `$quest` (team exploration) · `$issue` (something broken)
|
|
@@ -301,6 +301,7 @@ const RULES = {
|
|
|
301
301
|
},
|
|
302
302
|
'Config Files': { action: 'keep', note: 'Kept verbatim — shell facts, runtime-neutral.' },
|
|
303
303
|
'Knowledge Graph': { action: 'keep', note: 'Kept verbatim — bin/graph.sh is runtime-neutral.' },
|
|
304
|
+
'Egregore Retrieval Beat': { action: 'keep', note: 'Kept verbatim — product attribution applies across runtimes.' },
|
|
304
305
|
'Notifications': { action: 'keep', note: 'Kept verbatim — bin/notify.sh is runtime-neutral.' },
|
|
305
306
|
'Onboarding': { action: 'keep', note: 'Kept; /onboarding rendered as $onboarding.' },
|
|
306
307
|
'Transparency Beat': { action: 'keep', note: 'Kept verbatim.' },
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Hybrid search over shared memory — powered by qmd (BM25 + vector + rerank, fully local).
|
|
3
|
+
# Usage:
|
|
4
|
+
# bash bin/search.sh query "text" [-n N] [--fast|--semantic] [--all]
|
|
5
|
+
# bash bin/search.sh reindex [--embed]
|
|
6
|
+
# bash bin/search.sh status
|
|
7
|
+
#
|
|
8
|
+
# The memory repo is registered as a qmd collection named "{slug}-memory".
|
|
9
|
+
# Every call is scoped to that collection with -c, so other qmd collections
|
|
10
|
+
# on the machine are never read or modified.
|
|
11
|
+
#
|
|
12
|
+
# Modes:
|
|
13
|
+
# (default) qmd query — hybrid BM25 + vector + rerank (needs local models, ~2GB one-time download)
|
|
14
|
+
# --fast qmd search — BM25 keyword only, instant, no models
|
|
15
|
+
# --semantic qmd vsearch — vector similarity only (needs embeddings: reindex --embed)
|
|
16
|
+
# Hybrid/semantic fall back to BM25 automatically if models or embeddings are missing.
|
|
17
|
+
|
|
18
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
19
|
+
export NODE_NO_WARNINGS=1
|
|
20
|
+
# Do NOT set CI=1 here — it disables qmd's LLM ops (query expansion, rerank).
|
|
21
|
+
|
|
22
|
+
# qmd's progress spinner can leak into stdout when it misdetects a TTY;
|
|
23
|
+
# strip ANSI escapes and spinner frames from anything we return.
|
|
24
|
+
_clean() {
|
|
25
|
+
sed -E $'s/\x1b\\[[0-9;?]*[A-Za-z]//g' | grep -v 'Gathering information' || true
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
SLUG=$(jq -r '.slug // "egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "egregore")
|
|
29
|
+
COLLECTION="${SLUG}-memory"
|
|
30
|
+
MEM_PATH="$(readlink -f "$SCRIPT_DIR/memory" 2>/dev/null || true)"
|
|
31
|
+
|
|
32
|
+
QMD_VERSION="2.5.3" # pinned — bump deliberately, never float @latest
|
|
33
|
+
|
|
34
|
+
_qmd() {
|
|
35
|
+
if command -v qmd >/dev/null 2>&1; then
|
|
36
|
+
qmd "$@"
|
|
37
|
+
else
|
|
38
|
+
npx -y "@tobilu/qmd@${QMD_VERSION}" "$@"
|
|
39
|
+
fi
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# --- Weight ladder ----------------------------------------------------------
|
|
43
|
+
# Three tiers, chosen by what is already on disk — no mode ever triggers a
|
|
44
|
+
# model download in a session's critical path:
|
|
45
|
+
# keyword 0 MB BM25, works at install, forever
|
|
46
|
+
# semantic ~334 MB embed model, fetched silently by the background warm
|
|
47
|
+
# hybrid ~2.2 GB rerank + expansion — org opt-in (features.search_hybrid),
|
|
48
|
+
# prefetched by the background warm, never inline
|
|
49
|
+
MODELS_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/qmd/models"
|
|
50
|
+
_have_embed() { ls "$MODELS_DIR"/*embedding* >/dev/null 2>&1; }
|
|
51
|
+
_have_hybrid() { ls "$MODELS_DIR"/*reranker* >/dev/null 2>&1 && ls "$MODELS_DIR"/*expansion* >/dev/null 2>&1; }
|
|
52
|
+
_hybrid_opted() { [ "$(jq -r '.features.search_hybrid // false' "$SCRIPT_DIR/egregore.json" 2>/dev/null)" = "true" ]; }
|
|
53
|
+
|
|
54
|
+
_ensure() {
|
|
55
|
+
if [ -z "$MEM_PATH" ] || [ ! -d "$MEM_PATH" ]; then
|
|
56
|
+
echo "memory/ not found — run bin/search.sh from an Egregore instance with a memory symlink" >&2
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
if ! _qmd collection list 2>/dev/null | grep -q "^${COLLECTION} "; then
|
|
60
|
+
_qmd collection add "$MEM_PATH" --name "$COLLECTION" >/dev/null 2>&1 || true
|
|
61
|
+
fi
|
|
62
|
+
# Incremental re-index so new handoffs/decisions are searchable immediately.
|
|
63
|
+
# NEVER swallow a failure silently: a dead path in ANY registered collection
|
|
64
|
+
# (e.g. a deleted side-project dir) crashes `qmd update` for every collection,
|
|
65
|
+
# and the index quietly stops absorbing new documents. Caught in dogfooding
|
|
66
|
+
# 2026-07-07 — results looked fine while missing three days of handoffs.
|
|
67
|
+
if ! _qmd update >/dev/null 2>&1; then
|
|
68
|
+
echo "(search: index update FAILED — results may be missing recent documents. A registered qmd collection likely points at a deleted path: run 'qmd collection list', remove the dead one, retry.)" >&2
|
|
69
|
+
fi
|
|
70
|
+
_embed_bg
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
# Keep vector embeddings warm without anyone running a manual step: fire a
|
|
74
|
+
# detached, lock-guarded `qmd embed` on every query. Nothing pending → exits
|
|
75
|
+
# in ~1s. First run on a machine → downloads models + embeds in the
|
|
76
|
+
# background while queries fall back to keyword mode.
|
|
77
|
+
_embed_bg() {
|
|
78
|
+
[ "${EGREGORE_SEARCH_NO_WARM:-0}" = "1" ] && return 0
|
|
79
|
+
local lock="${TMPDIR:-/tmp}/egregore-qmd-embed-${COLLECTION}.lock"
|
|
80
|
+
if [ -f "$lock" ]; then
|
|
81
|
+
# A crashed embed shouldn't block warming forever — expire the lock after 60 min.
|
|
82
|
+
if [ -n "$(find "$lock" -mmin +60 2>/dev/null)" ]; then rm -f "$lock"; else return 0; fi
|
|
83
|
+
fi
|
|
84
|
+
touch "$lock"
|
|
85
|
+
if ! _have_embed; then
|
|
86
|
+
echo "(first run: building the semantic index in the background — searches use keyword mode until it finishes)" >&2
|
|
87
|
+
fi
|
|
88
|
+
# Background fetch policy: `qmd embed` pulls only the ~334MB embed model
|
|
89
|
+
# (the semantic tier). The ~1.9GB hybrid pack is prefetched here ONLY when
|
|
90
|
+
# the org opted in — a session never waits on either.
|
|
91
|
+
( ( _qmd embed >/dev/null 2>&1
|
|
92
|
+
if _hybrid_opted && ! _have_hybrid; then
|
|
93
|
+
_qmd query "warmup" -c "$COLLECTION" -n 1 >/dev/null 2>&1
|
|
94
|
+
fi
|
|
95
|
+
rm -f "$lock" ) & ) >/dev/null 2>&1
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# Annotate results with live graph state (connected mode): each hit that the
|
|
99
|
+
# graph knows (Session by filePath = handoffs; Artifact by filePath = knowledge)
|
|
100
|
+
# gets one "↳ graph:" line — search finds the artifact, the graph tells you its
|
|
101
|
+
# state, in a single call. Fails soft everywhere: local mode / graph offline /
|
|
102
|
+
# unknown paths simply produce no annotations.
|
|
103
|
+
_enrich() {
|
|
104
|
+
local results paths params out
|
|
105
|
+
results=$(cat)
|
|
106
|
+
echo "$results"
|
|
107
|
+
paths=$(echo "$results" | grep -o "qmd://${COLLECTION}/[^: ]*\.md" | sed "s|qmd://${COLLECTION}/||" | sort -u)
|
|
108
|
+
[ -z "$paths" ] && return 0
|
|
109
|
+
params=$(printf '%s\n' "$paths" | jq -R . | jq -sc '{paths: .}')
|
|
110
|
+
out=$(bash "$SCRIPT_DIR/bin/graph.sh" query "UNWIND \$paths AS fp
|
|
111
|
+
OPTIONAL MATCH (s:Session {filePath: fp})
|
|
112
|
+
OPTIONAL MATCH (a:Artifact {filePath: fp})
|
|
113
|
+
WITH fp, s, a WHERE s IS NOT NULL OR a IS NOT NULL
|
|
114
|
+
RETURN fp,
|
|
115
|
+
CASE WHEN s IS NOT NULL THEN coalesce(s.handoffStatus, s.status) ELSE null END AS sessionStatus,
|
|
116
|
+
s.handedTo AS handedTo, a.type AS artifactType,
|
|
117
|
+
CASE WHEN a IS NOT NULL THEN [q IN [(a)-[:PART_OF]->(qq:Quest) | qq.id] | q][0] ELSE null END AS quest" \
|
|
118
|
+
"$params" 2>/dev/null)
|
|
119
|
+
echo "$out" | jq -r '.values[]? | @tsv' 2>/dev/null | while IFS=$'\t' read -r fp sstat sto atype quest; do
|
|
120
|
+
local ann=""
|
|
121
|
+
[ -n "$sstat" ] && [ "$sstat" != "null" ] && ann="status: $sstat"
|
|
122
|
+
[ -n "$sto" ] && [ "$sto" != "null" ] && ann="$ann${ann:+ · }to: $sto"
|
|
123
|
+
[ -n "$atype" ] && [ "$atype" != "null" ] && ann="$ann${ann:+ · }artifact: $atype"
|
|
124
|
+
[ -n "$quest" ] && [ "$quest" != "null" ] && ann="$ann${ann:+ · }quest: $quest"
|
|
125
|
+
[ -n "$ann" ] && echo "↳ graph · $fp — $ann"
|
|
126
|
+
done
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
cmd_query() {
|
|
130
|
+
local mode="query" n=6 enrich=auto all=()
|
|
131
|
+
local -a words=()
|
|
132
|
+
while [ $# -gt 0 ]; do
|
|
133
|
+
case "$1" in
|
|
134
|
+
--fast) mode="search" ;;
|
|
135
|
+
--semantic) mode="vsearch" ;;
|
|
136
|
+
--enrich) enrich=1 ;;
|
|
137
|
+
--no-enrich) enrich=0 ;;
|
|
138
|
+
--all) all=(--all) ;;
|
|
139
|
+
-n) n="$2"; shift ;;
|
|
140
|
+
*) words+=("$1") ;;
|
|
141
|
+
esac
|
|
142
|
+
shift
|
|
143
|
+
done
|
|
144
|
+
# Default mode rides the weight ladder: use the heaviest tier whose models
|
|
145
|
+
# are already local. Explicit flags always win; nothing downloads inline.
|
|
146
|
+
if [ "$mode" = "query" ] && ! _have_hybrid; then
|
|
147
|
+
if _have_embed; then mode="vsearch"; else mode="search"; fi
|
|
148
|
+
fi
|
|
149
|
+
# Enrichment is managed, not a user choice: on wherever a graph exists
|
|
150
|
+
# (connected mode), silently off everywhere else. Flags only override.
|
|
151
|
+
if [ "$enrich" = "auto" ]; then
|
|
152
|
+
if [ "$(jq -r '.mode // "connected"' "$SCRIPT_DIR/egregore.json" 2>/dev/null)" != "local" ] && \
|
|
153
|
+
[ -n "$(jq -r '.api_url // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null)" ]; then
|
|
154
|
+
enrich=1
|
|
155
|
+
else
|
|
156
|
+
enrich=0
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
local q="${words[*]}"
|
|
160
|
+
if [ -z "$q" ]; then
|
|
161
|
+
echo "usage: bash bin/search.sh query \"text\" [-n N] [--fast|--semantic] [--all]" >&2
|
|
162
|
+
exit 1
|
|
163
|
+
fi
|
|
164
|
+
_ensure
|
|
165
|
+
local emit="cat"
|
|
166
|
+
[ "$enrich" = 1 ] && emit="_enrich"
|
|
167
|
+
local t0 out label
|
|
168
|
+
t0=$(date +%s)
|
|
169
|
+
if [ "$mode" != "search" ]; then
|
|
170
|
+
out=$(_qmd "$mode" "$q" -c "$COLLECTION" -n "$n" --format md --full-path "${all[@]}" 2>/dev/null | _clean)
|
|
171
|
+
if [ -n "$out" ] && [ "$out" != "No results found." ]; then
|
|
172
|
+
[ "$mode" = "query" ] && label="hybrid" || label="semantic"
|
|
173
|
+
_banner_and_emit "$label" "$t0" "$emit" "$q" "$out"
|
|
174
|
+
return 0
|
|
175
|
+
fi
|
|
176
|
+
echo "_(hybrid/semantic returned nothing — showing keyword results. If this persists, run: bash bin/search.sh reindex --embed)_"
|
|
177
|
+
echo ""
|
|
178
|
+
fi
|
|
179
|
+
out=$(_qmd search "$q" -c "$COLLECTION" -n "$n" --format md --full-path "${all[@]}" | _clean)
|
|
180
|
+
_banner_and_emit "keyword" "$t0" "$emit" "$q" "$out"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# One visible product-attribution line per search — the tell that Egregore's
|
|
184
|
+
# organizational retrieval layer (not an improvised agent grep loop) answered.
|
|
185
|
+
# It names the graph only when enrichment actually ran, then reports mode,
|
|
186
|
+
# hit count, and latency. Colored when stdout is a terminal; plain glyph in
|
|
187
|
+
# harness transcripts. Also appends to ~/.egregore/search.log (local only,
|
|
188
|
+
# never uploaded) so dogfooding can measure search-first rate and latency.
|
|
189
|
+
_banner_and_emit() {
|
|
190
|
+
local label="$1" t0="$2" emit="$3" q="$4" out="$5"
|
|
191
|
+
local hits dur modef product surface plural=""
|
|
192
|
+
hits=$(printf '%s\n' "$out" | grep -c '^qmd://' 2>/dev/null | tr -d ' ')
|
|
193
|
+
dur=$(( $(date +%s) - t0 ))
|
|
194
|
+
modef="$label"
|
|
195
|
+
product="Egregore"
|
|
196
|
+
surface="searching your organization’s memory"
|
|
197
|
+
if [ "$emit" = "_enrich" ] && [ "$hits" -gt 0 ]; then
|
|
198
|
+
modef="${label}+graph"
|
|
199
|
+
product="Egregore Connect"
|
|
200
|
+
surface="${surface} and relationships"
|
|
201
|
+
fi
|
|
202
|
+
[ "$hits" != "1" ] && plural="s"
|
|
203
|
+
local line="⌕ ${product} · ${surface} · ${label} · ${hits} hit${plural} · ${dur}s"
|
|
204
|
+
if [ -t 1 ]; then
|
|
205
|
+
printf '\033[1;38;5;30m%s\033[0m\n\n' "$line"
|
|
206
|
+
else
|
|
207
|
+
printf '%s\n\n' "$line"
|
|
208
|
+
fi
|
|
209
|
+
printf '%s\n' "$out" | $emit
|
|
210
|
+
mkdir -p "$HOME/.egregore" 2>/dev/null
|
|
211
|
+
echo "$(date '+%Y-%m-%d %H:%M:%S') mode=${modef} hits=${hits} dur=${dur}s q=\"$(printf '%.80s' "$q")\"" >> "$HOME/.egregore/search.log" 2>/dev/null || true
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
cmd_reindex() {
|
|
215
|
+
_ensure
|
|
216
|
+
_qmd update
|
|
217
|
+
if [ "${1:-}" = "--embed" ]; then
|
|
218
|
+
_qmd embed
|
|
219
|
+
# Hybrid pack prefetch only when the org opted in (features.search_hybrid).
|
|
220
|
+
if _hybrid_opted && ! _have_hybrid; then
|
|
221
|
+
_qmd query "warmup" -c "$COLLECTION" -n 1 >/dev/null 2>&1 || true
|
|
222
|
+
fi
|
|
223
|
+
fi
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
cmd_status() {
|
|
227
|
+
_qmd status 2>/dev/null
|
|
228
|
+
echo ""
|
|
229
|
+
echo "collection: $COLLECTION → $MEM_PATH"
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
case "${1:-}" in
|
|
233
|
+
query) shift; cmd_query "$@" ;;
|
|
234
|
+
reindex) shift; cmd_reindex "$@" ;;
|
|
235
|
+
status) shift; cmd_status ;;
|
|
236
|
+
*)
|
|
237
|
+
echo "usage: bash bin/search.sh {query|reindex|status}" >&2
|
|
238
|
+
exit 1
|
|
239
|
+
;;
|
|
240
|
+
esac
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
//
|
|
5
5
|
// Mirror of .claude/hooks/search-hint.sh: when the user's prompt is
|
|
6
6
|
// recall-shaped ("find the handoff about…", "did we decide…"), inject a
|
|
7
|
-
// routing hint toward `bin/
|
|
7
|
+
// routing hint toward `bash bin/search.sh query` — one ranked call over
|
|
8
8
|
// memory/ — instead of improvised ls/grep/graph exploration.
|
|
9
9
|
//
|
|
10
10
|
// Advisory only, never blocks, rate-limited once per session, exits 0.
|
|
@@ -43,6 +43,8 @@ const RECALL = new RegExp(
|
|
|
43
43
|
"\\bwho worked on\\b",
|
|
44
44
|
"\\bdidn.?t (someone|we) already\\b",
|
|
45
45
|
"\\bwas there (a|any) (handoff|decision|discussion|meeting)\\b",
|
|
46
|
+
"\\b(our|company|org|organization|team)\\b.*\\b(pricing|price|tiers?|plans?|paid|free|strategy|policy|positioning|ownership|decision)\\b",
|
|
47
|
+
"\\b(pricing|price|tiers?|plans?|paid|free)\\b.*\\b(our|company|org|organization|team)\\b",
|
|
46
48
|
].join("|"),
|
|
47
49
|
"i"
|
|
48
50
|
);
|
|
@@ -59,7 +61,7 @@ process.stdout.write(JSON.stringify({
|
|
|
59
61
|
hookSpecificOutput: {
|
|
60
62
|
hookEventName: "UserPromptSubmit",
|
|
61
63
|
additionalContext:
|
|
62
|
-
"Routing hint: this prompt asks for recall from org memory. FIRST action: `bin/
|
|
64
|
+
"Routing hint: this prompt asks for recall from org memory. FIRST action: `bash bin/search.sh query \"<the concept, not the literal sentence>\"` — one ranked call over all of memory/ (hybrid keyword+semantic; graph-state annotations attach automatically in connected mode). Read the top hits and cite paths. Do NOT improvise ls/grep/graph exploration first — hand-written graph queries against invented labels (e.g. :Handoff — handoffs are :Session nodes) return empty. Full spec: the search skill.",
|
|
63
65
|
},
|
|
64
66
|
}) + "\n");
|
|
65
67
|
process.exit(0);
|
|
@@ -11,12 +11,35 @@ search before answering from conversation context alone.
|
|
|
11
11
|
|
|
12
12
|
## Flow
|
|
13
13
|
|
|
14
|
-
1.
|
|
14
|
+
1. Organizational recall must begin with the Egregore search entry point in
|
|
15
|
+
step 2. Do not resolve `memory/` to its sibling Git repository, change into
|
|
16
|
+
that absolute path, or improvise raw grep/listing as the first retrieval
|
|
17
|
+
action. Use direct file reads or grep only on evidence paths returned by the
|
|
18
|
+
ranked search.
|
|
19
|
+
|
|
20
|
+
Before any shell, file-read, grep, or other retrieval tool call, send exactly
|
|
21
|
+
one standalone commentary line:
|
|
22
|
+
|
|
23
|
+
- local/filesystem-only:
|
|
24
|
+
`⌕ Egregore · searching your organization’s memory`
|
|
25
|
+
- connected mode with automatic graph enrichment:
|
|
26
|
+
`⌕ Egregore Connect · searching your organization’s memory and relationships`
|
|
27
|
+
|
|
28
|
+
Send the line verbatim. Do not replace it with generic narration such as
|
|
29
|
+
“I’ll search org memory.” It must be visible before the tool call; captured
|
|
30
|
+
command output does not satisfy this requirement. Emit it once even when the
|
|
31
|
+
retrieval needs multiple queries or source reads.
|
|
32
|
+
|
|
33
|
+
2. Run the search:
|
|
15
34
|
|
|
16
35
|
```bash
|
|
17
|
-
bin/
|
|
36
|
+
bash bin/search.sh query "your query" -n 6
|
|
18
37
|
```
|
|
19
38
|
|
|
39
|
+
- The command also prints the attribution as a direct-shell fallback. That
|
|
40
|
+
captured banner is diagnostic redundancy, not the user-visible product beat.
|
|
41
|
+
If the answer instead begins with a graph-only named read, follow the same
|
|
42
|
+
global Egregore Retrieval Beat before that query.
|
|
20
43
|
- Default is hybrid (BM25 + vector + rerank); it falls back to keyword
|
|
21
44
|
search automatically when local models aren't built, with a note.
|
|
22
45
|
- `--fast` — keyword only (BM25), instant. Use for exact terms: names,
|
|
@@ -27,15 +50,15 @@ bin/agent.sh search "your query" -n 6
|
|
|
27
50
|
state lines (status, recipient, artifact type, quest) with no flag.
|
|
28
51
|
`--no-enrich` skips it when speed matters; local mode never attempts it.
|
|
29
52
|
|
|
30
|
-
|
|
53
|
+
3. Search the *concept*, not the user's literal sentence. If the first query
|
|
31
54
|
returns weak scores, run a second with different wording — one
|
|
32
55
|
keyword-ish, one conceptual.
|
|
33
56
|
|
|
34
|
-
|
|
57
|
+
4. Results are snippets with `memory/...` file paths. Read the source file
|
|
35
58
|
for anything you will cite or act on — snippets truncate, and memory
|
|
36
59
|
files carry dates, authors, and caveats that change the answer.
|
|
37
60
|
|
|
38
|
-
|
|
61
|
+
5. Answer directly, citing file paths. If results are empty or weak, say so
|
|
39
62
|
plainly — "nothing in memory on X" is a real answer. Do not present
|
|
40
63
|
conversation-context guesses as memory.
|
|
41
64
|
|
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
"sourceHash": "b5d9a149f1a6",
|
|
51
51
|
"note": "Kept verbatim — bin/graph.sh is runtime-neutral."
|
|
52
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"section": "Egregore Retrieval Beat",
|
|
55
|
+
"action": "keep",
|
|
56
|
+
"sourceHash": "0c4d4715fb13",
|
|
57
|
+
"note": "Kept verbatim — product attribution applies across runtimes."
|
|
58
|
+
},
|
|
53
59
|
{
|
|
54
60
|
"section": "Notifications",
|
|
55
61
|
"action": "keep",
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
{
|
|
96
102
|
"section": "Command Awareness",
|
|
97
103
|
"action": "keep",
|
|
98
|
-
"sourceHash": "
|
|
104
|
+
"sourceHash": "a020fc5d9b98",
|
|
99
105
|
"note": "Prepended the Codex command surface (skill tokens, native vs adapter split, $save abstraction); disambiguation map kept with /x -> $x token rendering. Tokens with no Codex skill (e.g. /loop, a Claude Code harness feature) are left as-is."
|
|
100
106
|
},
|
|
101
107
|
{
|
|
@@ -146,6 +146,53 @@ Run `catalog` only when the route is unclear. Named reads return bounded stable
|
|
|
146
146
|
|
|
147
147
|
---
|
|
148
148
|
|
|
149
|
+
## Egregore Retrieval Beat
|
|
150
|
+
|
|
151
|
+
Egregore's organizational search is a product surface, not indistinguishable
|
|
152
|
+
agent tool use. For each user-directed lookup of organizational knowledge,
|
|
153
|
+
show exactly one visible attribution line:
|
|
154
|
+
|
|
155
|
+
- memory-only retrieval:
|
|
156
|
+
`⌕ Egregore · searching your organization’s memory`
|
|
157
|
+
- retrieval that actually queries the connected graph:
|
|
158
|
+
`⌕ Egregore Connect · searching your organization’s memory and relationships`
|
|
159
|
+
|
|
160
|
+
**Visibility is the contract.** Emit the applicable line verbatim as a
|
|
161
|
+
standalone assistant message before the first Bash, Grep, Glob, Read, or other
|
|
162
|
+
retrieval tool call. Shell/tool output does not satisfy this requirement:
|
|
163
|
+
Claude Code and other harnesses may collapse it. Do not paraphrase the line or
|
|
164
|
+
replace it with generic narration such as “I’ll search org memory.”
|
|
165
|
+
|
|
166
|
+
Use the memory form for local/filesystem-only organizational retrieval. Use the
|
|
167
|
+
Connect form when the retrieval route will query the connected graph, including
|
|
168
|
+
automatic graph enrichment in `bin/search.sh query`, a graph-only named read,
|
|
169
|
+
or exploratory Cypher. Emit once for the whole retrieval episode, not once per
|
|
170
|
+
hop. The banner printed by `bin/search.sh` remains a direct-shell fallback and
|
|
171
|
+
does not replace the assistant-visible beat.
|
|
172
|
+
|
|
173
|
+
**Routing is part of the contract.** For organizational history, decisions,
|
|
174
|
+
handoffs, meetings, people, pricing, strategy, or other shared-memory content,
|
|
175
|
+
the first retrieval action is:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
bash bin/search.sh query "<concept>" -n 6
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Do not start by resolving `memory/` to its sibling repository, changing
|
|
182
|
+
directory into that absolute path, or improvising `grep`/`ls` over it. The
|
|
183
|
+
search entry point owns keyword/semantic selection and automatically attaches
|
|
184
|
+
graph state in connected mode. Read or grep the returned `memory/...` source
|
|
185
|
+
paths only after the ranked call when verification needs the full document.
|
|
186
|
+
Native Grep/Glob remain the right first action for repository code, filenames,
|
|
187
|
+
and exact error strings—not organizational recall.
|
|
188
|
+
|
|
189
|
+
Do not emit the beat for native repository/code search, Git inspection, startup
|
|
190
|
+
context hydration, graph writes, ingestion projection, background sync,
|
|
191
|
+
maintenance, or command-internal queries that are not answering a user lookup.
|
|
192
|
+
Never name `Egregore Connect` unless a graph read will actually run.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
149
196
|
## Notifications
|
|
150
197
|
|
|
151
198
|
**Connected mode only.** Always use `bin/notify.sh` for Telegram notifications — never construct API calls directly. See DEVELOPMENT.md §1 for usage examples. In local mode there are no live notifications.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"generatedBy": "bin/pi-render-spec.mjs",
|
|
3
3
|
"source": "AGENTS.md generated Codex spec",
|
|
4
|
-
"sourceHash": "
|
|
5
|
-
"outputHash": "
|
|
4
|
+
"sourceHash": "34a5f678b6e3",
|
|
5
|
+
"outputHash": "43cd068d78fd",
|
|
6
6
|
"adaptations": [
|
|
7
7
|
"Pi project trust and APPEND_SYSTEM delivery",
|
|
8
8
|
"Pi tool_call branch gate",
|
package/runtime/pi/AGENTS.md
CHANGED
|
@@ -220,6 +220,53 @@ Run `catalog` only when the route is unclear. Named reads return bounded stable
|
|
|
220
220
|
|
|
221
221
|
---
|
|
222
222
|
|
|
223
|
+
## Egregore Retrieval Beat
|
|
224
|
+
|
|
225
|
+
Egregore's organizational search is a product surface, not indistinguishable
|
|
226
|
+
agent tool use. For each user-directed lookup of organizational knowledge,
|
|
227
|
+
show exactly one visible attribution line:
|
|
228
|
+
|
|
229
|
+
- memory-only retrieval:
|
|
230
|
+
`⌕ Egregore · searching your organization’s memory`
|
|
231
|
+
- retrieval that actually queries the connected graph:
|
|
232
|
+
`⌕ Egregore Connect · searching your organization’s memory and relationships`
|
|
233
|
+
|
|
234
|
+
**Visibility is the contract.** Emit the applicable line verbatim as a
|
|
235
|
+
standalone assistant message before the first Bash, Grep, Glob, Read, or other
|
|
236
|
+
retrieval tool call. Shell/tool output does not satisfy this requirement:
|
|
237
|
+
Claude Code and other harnesses may collapse it. Do not paraphrase the line or
|
|
238
|
+
replace it with generic narration such as “I’ll search org memory.”
|
|
239
|
+
|
|
240
|
+
Use the memory form for local/filesystem-only organizational retrieval. Use the
|
|
241
|
+
Connect form when the retrieval route will query the connected graph, including
|
|
242
|
+
automatic graph enrichment in `bin/search.sh query`, a graph-only named read,
|
|
243
|
+
or exploratory Cypher. Emit once for the whole retrieval episode, not once per
|
|
244
|
+
hop. The banner printed by `bin/search.sh` remains a direct-shell fallback and
|
|
245
|
+
does not replace the assistant-visible beat.
|
|
246
|
+
|
|
247
|
+
**Routing is part of the contract.** For organizational history, decisions,
|
|
248
|
+
handoffs, meetings, people, pricing, strategy, or other shared-memory content,
|
|
249
|
+
the first retrieval action is:
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
bash bin/search.sh query "<concept>" -n 6
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Do not start by resolving `memory/` to its sibling repository, changing
|
|
256
|
+
directory into that absolute path, or improvising `grep`/`ls` over it. The
|
|
257
|
+
search entry point owns keyword/semantic selection and automatically attaches
|
|
258
|
+
graph state in connected mode. Read or grep the returned `memory/...` source
|
|
259
|
+
paths only after the ranked call when verification needs the full document.
|
|
260
|
+
Native Grep/Glob remain the right first action for repository code, filenames,
|
|
261
|
+
and exact error strings—not organizational recall.
|
|
262
|
+
|
|
263
|
+
Do not emit the beat for native repository/code search, Git inspection, startup
|
|
264
|
+
context hydration, graph writes, ingestion projection, background sync,
|
|
265
|
+
maintenance, or command-internal queries that are not answering a user lookup.
|
|
266
|
+
Never name `Egregore Connect` unless a graph read will actually run.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
223
270
|
## Notifications
|
|
224
271
|
|
|
225
272
|
**Connected mode only.** Always use `bin/notify.sh` for Telegram notifications — never construct API calls directly. See DEVELOPMENT.md §1 for usage examples. In local mode there are no live notifications.
|
|
@@ -306,7 +353,7 @@ Codex reserves leading `/` for built-ins, so Egregore workflows are **skills**,
|
|
|
306
353
|
Invoke commands from user intent — don't wait for the slash. Each command file has a `## When to invoke` section. Load it for the full spec.
|
|
307
354
|
|
|
308
355
|
**Core loop** — `$activity` `$dashboard` `$handoff` `$wrap` `$save` `$reflect` `$todo`
|
|
309
|
-
**Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll`
|
|
356
|
+
**Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll` `$mock`
|
|
310
357
|
**Identity** — `$me` (view profile or set display name)
|
|
311
358
|
**Coordination** — `$ask` `$quest` `$issue` `$invite` `$delete-user` `$announce`
|
|
312
359
|
**Connectors** — `$telegram-connect` (Telegram group setup) `$teams-connect` (Microsoft Teams channel setup)
|
|
@@ -316,9 +363,9 @@ Invoke commands from user intent — don't wait for the slash. Each command file
|
|
|
316
363
|
|
|
317
364
|
**Disambiguation:**
|
|
318
365
|
- Knowledge: `$reflect` (share-ready) · `$note` (half-baked) · `$deep-reflect` (deep research over memory — questions AND cross-referencing) · `$archive` (AI patterns)
|
|
319
|
-
- Finding things —
|
|
366
|
+
- Finding things — **organizational recall starts with `bash bin/search.sh query`** (ranked filesystem retrieval in OSS; automatic relationship/status enrichment in Connect). Use `bin/graph.sh` named reads first only for a pure relationship/status traversal. Use Grep/Glob first for repository code, filenames, and exact error strings—not shared-memory recall. Do not `cd` into the sibling memory repository.
|
|
320
367
|
- Finding **something you generated** (a scroll, handoff, emissary, decision, any hosted egregore.xyz link): `bash bin/artifacts.sh find <query>`. Every generative surface already records into memory — hosted artifacts self-register into `memory/artifacts/` at publish (and the record is committed+pushed, so it's findable from *any* session, not just the one that made it); handoffs land in `memory/handoffs/`, emissaries in `memory/handoffs/outbound/`, decisions/findings/patterns in `memory/knowledge/`. The finder searches **all** of them, ranks title/topic matches above passing body mentions, tags each hit by type (`[document]`/`[handoff]`/`[emissary]`/`[decision]`), and surfaces the shareable URL. Findable by **content, not just name**, across all three layers — grep-first for OSS, folding in search + graph when available. *"bring me the artifact where I laid out our GTM plan"* → this.
|
|
321
|
-
- Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face)
|
|
368
|
+
- Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face) · `$mock` (pre-build walkthrough of decided design — gauge per stop, verdict copy-back)
|
|
322
369
|
- Status: `$dashboard` (personal) · `$activity` (org-wide)
|
|
323
370
|
- Ending: `$wrap` (personal closure) · `$handoff` (notes for others) · `$save` (still working)
|
|
324
371
|
- Tasks: `$todo` (personal) · `$quest` (team exploration) · `$issue` (something broken)
|
|
@@ -301,6 +301,7 @@ const RULES = {
|
|
|
301
301
|
},
|
|
302
302
|
'Config Files': { action: 'keep', note: 'Kept verbatim — shell facts, runtime-neutral.' },
|
|
303
303
|
'Knowledge Graph': { action: 'keep', note: 'Kept verbatim — bin/graph.sh is runtime-neutral.' },
|
|
304
|
+
'Egregore Retrieval Beat': { action: 'keep', note: 'Kept verbatim — product attribution applies across runtimes.' },
|
|
304
305
|
'Notifications': { action: 'keep', note: 'Kept verbatim — bin/notify.sh is runtime-neutral.' },
|
|
305
306
|
'Onboarding': { action: 'keep', note: 'Kept; /onboarding rendered as $onboarding.' },
|
|
306
307
|
'Transparency Beat': { action: 'keep', note: 'Kept verbatim.' },
|