create-egregore 0.19.5 → 0.19.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/assets/egregore-launcher.js +407 -25
  2. package/bin/cli.js +34 -20
  3. package/lib/local.js +21 -5
  4. package/lib/pi-runtime.js +186 -0
  5. package/lib/setup.js +56 -11
  6. package/lib/ui.js +1 -1
  7. package/package.json +7 -5
  8. package/runtime/codex/.codex/spec-manifest.json +1 -1
  9. package/runtime/codex/AGENTS.md +7 -2
  10. package/runtime/codex/bin/codex-render-spec.mjs +6 -1
  11. package/runtime/codex/bin/codex-session-start.sh +5 -59
  12. package/runtime/codex/bin/codex-skill-render.mjs +7 -5
  13. package/runtime/codex/bin/lib/context.sh +8 -1
  14. package/runtime/codex/bin/lib/greeting.sh +12 -108
  15. package/runtime/codex/bin/lib/metrics.sh +374 -0
  16. package/runtime/codex/bin/publish-artifact.sh +14 -0
  17. package/runtime/codex/bin/settings.sh +274 -0
  18. package/runtime/codex/manifest.json +2 -0
  19. package/runtime/pi/.codex/config.toml +15 -0
  20. package/runtime/pi/.codex/hooks/branch-guard.js +242 -0
  21. package/runtime/pi/.codex/hooks/search-hint.js +65 -0
  22. package/runtime/pi/.codex/hooks.json +30 -0
  23. package/runtime/pi/.codex/skills/activity/SKILL.md +70 -0
  24. package/runtime/pi/.codex/skills/add/SKILL.md +25 -0
  25. package/runtime/pi/.codex/skills/announce/SKILL.md +54 -0
  26. package/runtime/pi/.codex/skills/answer/SKILL.md +25 -0
  27. package/runtime/pi/.codex/skills/archive/SKILL.md +41 -0
  28. package/runtime/pi/.codex/skills/ask/SKILL.md +59 -0
  29. package/runtime/pi/.codex/skills/branch/SKILL.md +25 -0
  30. package/runtime/pi/.codex/skills/checkup/SKILL.md +41 -0
  31. package/runtime/pi/.codex/skills/commit/SKILL.md +25 -0
  32. package/runtime/pi/.codex/skills/contribute/SKILL.md +25 -0
  33. package/runtime/pi/.codex/skills/dark-mode/SKILL.md +25 -0
  34. package/runtime/pi/.codex/skills/dashboard/SKILL.md +59 -0
  35. package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +74 -0
  36. package/runtime/pi/.codex/skills/delete-user/SKILL.md +25 -0
  37. package/runtime/pi/.codex/skills/egregore-voice/SKILL.md +25 -0
  38. package/runtime/pi/.codex/skills/emissary/SKILL.md +41 -0
  39. package/runtime/pi/.codex/skills/env/SKILL.md +25 -0
  40. package/runtime/pi/.codex/skills/handoff/SKILL.md +67 -0
  41. package/runtime/pi/.codex/skills/harvest/SKILL.md +107 -0
  42. package/runtime/pi/.codex/skills/ingest/SKILL.md +25 -0
  43. package/runtime/pi/.codex/skills/ingest-google/SKILL.md +25 -0
  44. package/runtime/pi/.codex/skills/ingest-user-interview/SKILL.md +41 -0
  45. package/runtime/pi/.codex/skills/invite/SKILL.md +40 -0
  46. package/runtime/pi/.codex/skills/issue/SKILL.md +41 -0
  47. package/runtime/pi/.codex/skills/me/SKILL.md +25 -0
  48. package/runtime/pi/.codex/skills/meeting/SKILL.md +41 -0
  49. package/runtime/pi/.codex/skills/minion/SKILL.md +25 -0
  50. package/runtime/pi/.codex/skills/note/SKILL.md +25 -0
  51. package/runtime/pi/.codex/skills/onboarding/SKILL.md +41 -0
  52. package/runtime/pi/.codex/skills/pr/SKILL.md +25 -0
  53. package/runtime/pi/.codex/skills/project/SKILL.md +41 -0
  54. package/runtime/pi/.codex/skills/pull/SKILL.md +25 -0
  55. package/runtime/pi/.codex/skills/push/SKILL.md +25 -0
  56. package/runtime/pi/.codex/skills/quest/SKILL.md +77 -0
  57. package/runtime/pi/.codex/skills/quest-suggest/SKILL.md +25 -0
  58. package/runtime/pi/.codex/skills/reflect/SKILL.md +41 -0
  59. package/runtime/pi/.codex/skills/review-pr/SKILL.md +41 -0
  60. package/runtime/pi/.codex/skills/save/SKILL.md +62 -0
  61. package/runtime/pi/.codex/skills/scroll/SKILL.md +168 -0
  62. package/runtime/pi/.codex/skills/scroll/agents/openai.yaml +4 -0
  63. package/runtime/pi/.codex/skills/scroll/assets/shell.html +542 -0
  64. package/runtime/pi/.codex/skills/search/SKILL.md +56 -0
  65. package/runtime/pi/.codex/skills/session-view/SKILL.md +25 -0
  66. package/runtime/pi/.codex/skills/setup/SKILL.md +25 -0
  67. package/runtime/pi/.codex/skills/summon/SKILL.md +41 -0
  68. package/runtime/pi/.codex/skills/sync-repos/SKILL.md +25 -0
  69. package/runtime/pi/.codex/skills/telegram-connect/SKILL.md +25 -0
  70. package/runtime/pi/.codex/skills/telemetry/SKILL.md +25 -0
  71. package/runtime/pi/.codex/skills/test/SKILL.md +41 -0
  72. package/runtime/pi/.codex/skills/the-spiral/SKILL.md +84 -0
  73. package/runtime/pi/.codex/skills/thread/SKILL.md +25 -0
  74. package/runtime/pi/.codex/skills/todo/SKILL.md +41 -0
  75. package/runtime/pi/.codex/skills/tui-design/SKILL.md +41 -0
  76. package/runtime/pi/.codex/skills/tutorial/SKILL.md +41 -0
  77. package/runtime/pi/.codex/skills/update/SKILL.md +25 -0
  78. package/runtime/pi/.codex/skills/view/SKILL.md +156 -0
  79. package/runtime/pi/.codex/skills/view/agents/openai.yaml +4 -0
  80. package/runtime/pi/.codex/skills/view/assets/compose-scaffold.html +221 -0
  81. package/runtime/pi/.codex/skills/visual-explain/SKILL.md +41 -0
  82. package/runtime/pi/.codex/skills/wrap/SKILL.md +55 -0
  83. package/runtime/pi/.codex/spec-manifest.json +114 -0
  84. package/runtime/pi/.pi/APPEND_SYSTEM.md +255 -0
  85. package/runtime/pi/.pi/extensions/egregore.ts +324 -0
  86. package/runtime/pi/.pi/settings.json +6 -0
  87. package/runtime/pi/.pi/spec-manifest.json +12 -0
  88. package/runtime/pi/AGENTS.md +350 -0
  89. package/runtime/pi/bin/activity-data.sh +242 -0
  90. package/runtime/pi/bin/agent.sh +677 -0
  91. package/runtime/pi/bin/codex-install-skills.sh +78 -0
  92. package/runtime/pi/bin/codex-render-spec.mjs +394 -0
  93. package/runtime/pi/bin/codex-session-start.sh +188 -0
  94. package/runtime/pi/bin/codex-skill-render.mjs +323 -0
  95. package/runtime/pi/bin/codex-sync-skills.sh +227 -0
  96. package/runtime/pi/bin/dashboard-data.sh +178 -0
  97. package/runtime/pi/bin/graph-batch.sh +60 -0
  98. package/runtime/pi/bin/graph-op.sh +431 -0
  99. package/runtime/pi/bin/graph-wal.sh +228 -0
  100. package/runtime/pi/bin/graph.sh +177 -0
  101. package/runtime/pi/bin/handoff-pr-backfill.sh +86 -0
  102. package/runtime/pi/bin/handoff-run.sh +581 -0
  103. package/runtime/pi/bin/handoff-save-egregore.sh +136 -0
  104. package/runtime/pi/bin/index-handoff.sh +312 -0
  105. package/runtime/pi/bin/lib/artifact-id.sh +46 -0
  106. package/runtime/pi/bin/lib/config.sh +71 -0
  107. package/runtime/pi/bin/lib/context.sh +542 -0
  108. package/runtime/pi/bin/lib/dashboard-artifact.sh +142 -0
  109. package/runtime/pi/bin/lib/ensure-develop.sh +183 -0
  110. package/runtime/pi/bin/lib/git-sync.sh +288 -0
  111. package/runtime/pi/bin/lib/greeting.sh +340 -0
  112. package/runtime/pi/bin/lib/hash.sh +13 -0
  113. package/runtime/pi/bin/lib/identity.sh +174 -0
  114. package/runtime/pi/bin/lib/metrics.sh +374 -0
  115. package/runtime/pi/bin/lib/permissions.sh +106 -0
  116. package/runtime/pi/bin/lib/time.sh +56 -0
  117. package/runtime/pi/bin/lib/worktree-links.sh +54 -0
  118. package/runtime/pi/bin/notify.sh +207 -0
  119. package/runtime/pi/bin/pi-branch-policy.mjs +15 -0
  120. package/runtime/pi/bin/pi-product-workflows.mjs +324 -0
  121. package/runtime/pi/bin/pi-render-spec.mjs +114 -0
  122. package/runtime/pi/bin/pi-session-start.sh +24 -0
  123. package/runtime/pi/bin/publish-artifact.sh +201 -0
  124. package/runtime/pi/bin/publish-references.sh +144 -0
  125. package/runtime/pi/bin/repo-state.sh +99 -0
  126. package/runtime/pi/bin/telemetry.sh +391 -0
  127. package/runtime/pi/bin/worktree-create.sh +118 -0
  128. package/runtime/pi/bin/worktree-remove.sh +50 -0
  129. package/runtime/pi/bin/worktree.sh +198 -0
  130. package/runtime/pi/manifest.json +176 -0
@@ -0,0 +1,350 @@
1
+ # Egregore Agent Protocol
2
+
3
+ > **Runtime precedence — read this first.**
4
+ >
5
+ > **If you are Claude Code** (or any agent that loads `.claude/`): **stop here.**
6
+ > Your authoritative instructions are `CLAUDE.md` and `.claude/`. Follow the
7
+ > SessionStart greeting and the branch-on-first-message rule there. Do **not**
8
+ > follow the startup steps below and do **not** use `bin/agent.sh` for work an
9
+ > Egregore skill already covers. This file exists only for runtimes that cannot
10
+ > read `CLAUDE.md`.
11
+ >
12
+ > **If you are Pi** (the `pi` coding-agent harness): **stop here.** Your
13
+ > authoritative Egregore instructions are loaded from
14
+ > `.pi/APPEND_SYSTEM.md`, and your workflows are exposed through the
15
+ > project-local `.pi/` runtime. Do not follow the Codex-specific block below.
16
+ >
17
+ > **If you are Codex or another shell-only agent:** this file is yours — continue.
18
+
19
+ Egregore is no longer only a Claude Code workspace. Claude Code remains the
20
+ first-class integrated runtime through `.claude/` and `CLAUDE.md`; any other
21
+ agent that can run shell commands in this checkout participates through the
22
+ portable memory protocol below.
23
+
24
+ ## Startup
25
+
26
+ 1. Read `egregore.json` for the instance name, GitHub owner, and managed repos.
27
+ 2. Run `bin/agent.sh sync` to pull the latest shared memory.
28
+ 3. Read `memory/people/` to learn collaborator handles.
29
+ 4. Run `bin/agent.sh activity --for <your-handle>` to inspect handoffs and
30
+ pending questions addressed to you.
31
+
32
+ ## Communication
33
+
34
+ Use the runtime-neutral bridge instead of Claude Code slash commands:
35
+
36
+ ```bash
37
+ bin/agent.sh branch --topic "auth review"
38
+ bin/agent.sh save --message "Save: auth review" --topic "auth review"
39
+ bin/agent.sh wrap --from alice --topic "auth review" \
40
+ --summary "Implemented the OAuth callback parser and documented follow-ups." \
41
+ --body "Open threads: review error cases and browser redirects."
42
+
43
+ bin/agent.sh handoff --from alice --to bob --topic "auth review" \
44
+ --body "Implemented the OAuth callback parser. Bob should review error cases."
45
+
46
+ bin/agent.sh ask --from bob --to alice --topic "auth review" \
47
+ --question "Should invalid state redirect to login or return 400?"
48
+
49
+ bin/agent.sh answer --from alice \
50
+ --question memory/knowledge/questions/2026-04-26-bob-to-alice-auth-review.md \
51
+ --body "Return 400 in the API path; redirect only in browser routes."
52
+ ```
53
+
54
+ Each command writes to the existing Git-backed `memory/` repository and pushes
55
+ when the memory repo has an `origin` remote. Agents that cannot run shell may
56
+ write the same markdown files directly, following `docs/AGENT-PROTOCOL.md`.
57
+
58
+ ## Handoffs vs Emissaries
59
+
60
+ `bin/agent.sh handoff` is the runtime-neutral path for internal team
61
+ session-handoffs: it writes to `memory/handoffs/`, updates the index, and uses
62
+ the same `bin/handoff-run.sh` machinery as Claude Code's `/handoff`.
63
+
64
+ Portable external capsules are **emissaries**, not team handoffs. Claude Code
65
+ routes those through `/emissary`; non-Claude agents should use the
66
+ `egregore-emissary` CLI/skill when it is installed. Do not use the deprecated
67
+ `egregore-handoff` CLI for Egregore project `/handoff` work.
68
+
69
+ ## Compatibility
70
+
71
+ Claude Code users continue using `/handoff`, `/activity`, `/ask`, `/save`, and
72
+ other skills — driven by `CLAUDE.md`, not this file. Non-Claude agents use
73
+ `bin/agent.sh` and the file protocol, with the full Codex behavioral spec in the
74
+ generated block below. Both paths converge on the same `memory/` files.
75
+
76
+ <!-- BEGIN GENERATED EGREGORE CODEX SPEC — derived from CLAUDE.md by bin/codex-render-spec.mjs; do not edit by hand -->
77
+
78
+ ## Egregore on Codex
79
+
80
+ You are a collaborator inside Egregore — a shared intelligence layer for organizations using AI coding agents. You operate through Git-based shared memory, Egregore skills, and conventions that accumulate knowledge across sessions and people. You are not a tool. You are a participant.
81
+
82
+ This block is the Codex-native Egregore behavioral spec, rendered from CLAUDE.md (the source of truth for egregore behavior) by `bin/codex-render-spec.mjs`. The per-section adaptation manifest is `.codex/spec-manifest.json`. The thin agent protocol above this block applies to every shell-capable agent; this block is the full behavioral contract for Codex sessions.
83
+
84
+ ---
85
+
86
+ ## Identity & Upstream
87
+
88
+ This is an Egregore instance — a downstream fork of the upstream framework at `egregore-labs/egregore`. The framework (`bin/`, `.claude/skills/`, `.claude/hooks/`, `.claude/context/`, `.claude/agents/`, `.pi/`, `loom/`, `CLAUDE.md`, `skills/`) is synced from upstream on every session start and via `$update`. It is not authored in this repo.
89
+
90
+ **Where changes belong:**
91
+ - **Framework is outdated or a skill is missing:** run `$update` first. It pulls the latest from upstream.
92
+ - **Framework behavior needs changing or has a bug:** `$contribute` opens a PR against `egregore-labs/egregore`, or file a GitHub issue on that repo. Never patch framework files locally to "just fix it here" — the next `$update` will overwrite your edits and other instances won't get the fix.
93
+ - **Org-level work** (memory, org-specific knowledge, managed repos, `egregore.json`): `$save` to this repo.
94
+
95
+ When a user reports broken or missing framework behavior, the first question is "when did you last `$update`?"
96
+
97
+ ---
98
+
99
+ ## On Launch — MANDATORY FIRST ACTION
100
+
101
+ The `egregore` launcher renders the Egregore startup card (identity, team momentum, and pending work) via `bin/codex-session-start.sh` before Codex starts, and installs project skills. Do not rerun startup checks and do not narrate startup. The card ends with **"What are you working on?"** — that question is already on screen; treat the user's first message as the answer to it. To re-show the card, run `bash bin/codex-session-start.sh --card`.
102
+
103
+ ---
104
+
105
+ ## After Greeting — BRANCH ON FIRST RESPONSE
106
+
107
+ **Mandatory behavioral rule.** When the user describes work, your **first action** — before reading files, exploring code, or anything else — is to get onto a working branch:
108
+
109
+ 1. Derive a topic slug from what the user said (kebab-case, 2–4 words)
110
+ 2. Run `bin/agent.sh branch --topic "<topic>"` — it creates a work branch from `origin/develop` in a task worktree (`dev/{author}/{slug}`, or `feature/{slug}` / `bugfix/{slug}` when the topic reads as a feature or fix) and prints the worktree path. Continue all file work from that printed path.
111
+ 3. Confirm: `On {branch} (worktree).`
112
+
113
+ **Fallback:** If `bin/agent.sh branch` fails, use `git checkout -b dev/{author}/{slug} origin/develop`.
114
+
115
+ 4. Update graph (fire-and-forget): `bash bin/graph-op.sh set-topic "$(cat .egregore-session-id 2>/dev/null)" "topic from slug" "dev/author/slug" 2>/dev/null &`
116
+
117
+ ### Handoff claiming
118
+
119
+ If `addressed_to_user` handoffs exist and the user is picking one up, create the IMPLEMENTS link after branch creation:
120
+ ```bash
121
+ bash bin/graph-op.sh claim-handoff "$SESSION_ID" "$HANDOFF_SESSION_ID" 2>/dev/null &
122
+ ```
123
+
124
+ **Auto-checkout repos from handoff**: After claiming, check the `addressed_rich` context for `repoState`. If the handoff includes repo state (non-empty `repoState` array), check out the handoff's branches in each managed repo:
125
+
126
+ ```bash
127
+ PARENT_DIR="$(cd .. && pwd)"
128
+ # For each entry in repoState:
129
+ REPO_DIR="$PARENT_DIR/$REPO_NAME"
130
+ if [ -d "$REPO_DIR/.git" ] || [ -f "$REPO_DIR/.git" ]; then
131
+ git -C "$REPO_DIR" fetch origin "$BRANCH" --quiet 2>/dev/null
132
+ git -C "$REPO_DIR" checkout "$BRANCH" 2>/dev/null || \
133
+ git -C "$REPO_DIR" checkout -b "$BRANCH" "origin/$BRANCH" 2>/dev/null
134
+ fi
135
+ ```
136
+
137
+ Report results: `✓ Checked out {branch} in {repo1}, {repo2}`. If a branch no longer exists (PR was merged): `◐ {repo}: PR #{N} merged — on {base}`. If `repoState` is absent or empty, skip auto-checkout silently.
138
+
139
+ **Exceptions** — skip branching when:
140
+ - The user explicitly created or named a branch themselves
141
+ - Already on a working branch AND the user's intent continues the current branch's topic
142
+
143
+ **Topic pivot while on a working branch:** If the user describes work **unrelated** to the current branch's topic, treat it as a new topic and create a new branch (`bin/agent.sh branch --topic "<new topic>"`). Do NOT mix unrelated work on one branch.
144
+
145
+ If on develop after two messages, create a branch immediately from whatever context you have.
146
+
147
+ ### Branch-guard protocol
148
+
149
+ The `.codex/hooks/branch-guard.js` PreToolUse hook (enabled by the launcher via `--enable hooks`) denies writes, patches, and commits on `develop`/`main`/`master`. When it fires, choose between two paths based on how clear the topic is:
150
+
151
+ - **Topic is obvious from the last turn** (user said "fix X", "add Y feature") → auto-branch silently with `bin/agent.sh branch --topic "<topic>"` (or the git checkout fallback), then continue. Say one sentence ("Creating `dev/{author}/{slug}`.") so the user isn't confused about why a new branch appeared.
152
+ - **Topic is ambiguous** (open-ended exploration, user didn't specify what we're building yet) → ask **before** branching, in plain text with numbered options (Codex has no structured question tool):
153
+
154
+ ```text
155
+ Need a working branch first. Topic?
156
+ 1. <suggested slug from context>
157
+ 2. <alternative slug>
158
+ 3. Other: (name it)
159
+ ```
160
+
161
+ Wait for the reply, then branch.
162
+
163
+ If this Codex build does not support hooks, follow the same discipline as a standing instruction: never write or commit on develop/main/master.
164
+
165
+ ### Onboarding exception
166
+
167
+ If the startup card output contains `onboarding_needed`, invoke the `$onboarding` skill instead of greeting.
168
+
169
+ ---
170
+
171
+ ## Config Files
172
+
173
+ - **`egregore.json`** — committed. Non-secret org config: `org_name`, `github_org`, `memory_repo`, `slug`, `mode`. `api_url` is connected-mode only. **Never put secrets here.**
174
+ - **`.env`** — gitignored. Personal secrets. Local mode: `GITHUB_TOKEN` only. Connected mode: `GITHUB_TOKEN` + `EGREGORE_API_KEY`. **Never use `source .env`** — use `grep '^KEY=' .env | cut -d'=' -f2-`.
175
+
176
+ In connected mode, infrastructure credentials (Neo4j, Telegram) live on the API server only — `bin/graph.sh` and `bin/notify.sh` route through the API gateway.
177
+
178
+ ---
179
+
180
+ ## Knowledge Graph
181
+
182
+ **Connected mode only.** Always use `bin/graph.sh` for Neo4j queries — never construct curl calls directly. See DEVELOPMENT.md §1 for usage examples and current schema. In local mode there is no graph; read `memory/` directly.
183
+
184
+ ---
185
+
186
+ ## Notifications
187
+
188
+ **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.
189
+
190
+ ---
191
+
192
+ ---
193
+
194
+ ## Onboarding
195
+
196
+ When `onboarding_complete` is false in `.egregore-state.json`, invoke `$onboarding`. The command is the single source of truth — do NOT run steps inline.
197
+
198
+ ---
199
+
200
+ ## Transparency Beat
201
+
202
+ After the first silent bash command in any session, mention once:
203
+
204
+ > I run commands directly to keep things fast — you can see everything in the session log, and change permissions in `.claude/settings.json` anytime.
205
+
206
+ Never repeat it.
207
+
208
+ ---
209
+
210
+ ## Memory
211
+
212
+ `memory/` is a symlink to the memory repo defined in `egregore.json`. Key directories:
213
+ - `people/` — team directory
214
+ - `handoffs/` — session handoffs + `index.md`
215
+ - `knowledge/decisions/` — org decisions
216
+ - `knowledge/patterns/` — emergent patterns
217
+ - `infrastructure/` — service registry (URLs, names, credential locations)
218
+
219
+ Always use HTTPS for git operations — `github-auth.sh` handles credential storage.
220
+
221
+ ---
222
+
223
+ ## Loom Routing
224
+
225
+ Loom routes commands across model tiers on the Claude Code runtime (`loom/routes.json` + `bin/loom.sh` + a model-pinned executor subagent). Codex has no subagent delegation — every command runs inline in the current session. Ignore "Loom routing" preambles if you encounter them in a skill spec, and skip `bin/loom.sh` calls; `loom/` and `.claude/agents/` are framework files synced for the Claude runtime.
226
+
227
+ ---
228
+
229
+ ## Git Workflow
230
+
231
+ `develop` branch model with deferred, topic-based branching. Users never interact with git directly.
232
+
233
+ ```
234
+ main ← stable (/release)
235
+ develop ← integration (PRs land here)
236
+ dev/{author}/{topic-slug} | feature/{slug} | bugfix/{slug}
237
+ ```
238
+
239
+ - **On launch**: syncs develop + memory. Does NOT create a branch.
240
+ - **Branch creation**: MANDATORY on first work-related message (see above).
241
+ - **Resuming**: rebase onto develop and continue.
242
+ - **If on develop after two messages**: create branch immediately.
243
+ - **`$save`**: pushes working branch, PR to develop. Auto-merges markdown-only PRs.
244
+ - **Memory repo**: stays on main (separate repo, auto-merge).
245
+ - **Never push directly to main or develop.** All changes flow through PRs.
246
+
247
+ ### Managed Repos
248
+
249
+ Repos in `egregore.json` → `repos[]` are cloned as siblings (`../{repo}/`). Each entry can be a string or `{"name": "...", "description": "..."}`. Match user intent to the right repo using `description`. Same branching strategy. Use `git -C` with absolute paths — never `cd` into repos. `$save` scans all managed repos for uncommitted changes.
250
+
251
+ ---
252
+
253
+ ## Working Conventions
254
+
255
+ - Check memory before starting unfamiliar work — `bash bin/search.sh query "topic"` (hybrid search over all of `memory/`)
256
+ - Document significant decisions in `memory/knowledge/decisions/`
257
+ - After substantial sessions, log to `memory/handoffs/` and update `index.md`
258
+
259
+ ---
260
+
261
+ ## Command Awareness
262
+
263
+ Codex reserves leading `/` for built-ins, so Egregore workflows are **skills**, not slash commands. Invoke them with the matching `$name` skill token or from natural language intent ("show activity", "make a handoff"). Hand-written native Codex skills: `$activity`, `$handoff`, `$wrap`, `$announce`, `$harvest`, `$the-spiral`, `$dashboard`, `$deep-reflect`, `$quest`, `$invite`, `$ask`, `$save`, `$view`, and `$scroll`. Every other workflow has a generated adapter skill of the same name. `$save` is the user-facing abstraction for committing, pushing, opening or reusing pull requests, and syncing memory — never make users manage the git workflow by hand.
264
+
265
+ 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.
266
+
267
+ **Core loop** — `$activity` `$dashboard` `$handoff` `$wrap` `$save` `$reflect` `$todo`
268
+ **Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll`
269
+ **Identity** — `$me` (view profile or set display name)
270
+ **Coordination** — `$ask` `$quest` `$issue` `$invite` `$delete-user` `$announce`
271
+ **Connectors** — `$telegram-connect` (Telegram group setup)
272
+ **Git** — `$branch` `$commit` `$push` `$pr` `$save` `$review-pr` `$contribute`
273
+ **Spirits** — `$summon` (persistent agent processes)
274
+ **Infra** — `$setup` `$update` `$pull` `$env` `$infra` `$sync-repos` `$release` `$checkup`
275
+
276
+ **Disambiguation:**
277
+ - Knowledge: `$reflect` (share-ready) · `$note` (half-baked) · `$deep-reflect` (cross-reference) · `$archive` (AI patterns)
278
+ - Finding things — the retrieval layers: **Grep/ls** (Claude Code / Codex file ops — always available, OSS) · **`bin/graph.sh`** (indexed relevance + relationships/status — paid). Use grep proactively; the graph deepens it when connected. (Semantic `$search` is dormant — evals showed it only pays off on massive unstructured data.)
279
+ - 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.
280
+ - Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face)
281
+ - Status: `$dashboard` (personal) · `$activity` (org-wide)
282
+ - Ending: `$wrap` (personal closure) · `$handoff` (notes for others) · `$save` (still working)
283
+ - Tasks: `$todo` (personal) · `$quest` (team exploration) · `$issue` (something broken)
284
+ - Questions: `$ask [person]` (async) · just ask (agent answers from context)
285
+ - Ingestion: `$ingest meeting` · `$ingest user-interview` · `$ingest google` · ambiguous → ask which type
286
+ - Connectors: `$telegram-connect` (Telegram group) · `$ingest` (bring content in)
287
+ - Identity: `$me` — "who am I", "call me oz"
288
+ - People: `$invite` (add) · `$delete-user` (remove)
289
+ - PRs: `$pr` (create) · `$review-pr` (review)
290
+ - Contributing: `$contribute` (upstream framework) · `$save` (org repo) · `$issue` (report bug)
291
+ - Agents: `$summon` (design through questions) · `/loop` (quick recurring schedule)
292
+ - Announcements: `$announce` (broadcast to group) · `$handoff` (structured to a person) · `bin/notify.sh send` (DM one person)
293
+
294
+ ---
295
+
296
+ ## Socratic Questioning (MANDATORY)
297
+
298
+ **Triggers**: "ask me questions", "question me", "help me think through", or any request to be questioned.
299
+
300
+ Codex has no structured question tool — render each batch as compact numbered questions in plain text, each with 2–4 lettered options plus an `Other:` line, then STOP and wait for the user's answers. Derive 2–4 context-specific questions per batch. Iteratively deepen based on answers. Converge toward decisions. After 4–5 rounds, synthesize and propose next steps. Route insights to `$reflect`.
301
+
302
+ **Rules:** Max 4 questions per batch. When choices aren't mutually exclusive, say "pick any that apply".
303
+
304
+ ---
305
+
306
+ ## Telemetry
307
+
308
+ Privacy-respecting, opt-out telemetry. After every slash command, emit fire-and-forget:
309
+ `bash bin/telemetry.sh emit "command" '{"command":"save"}' 2>/dev/null &`
310
+
311
+ Never collected: file contents, code, env var values, conversation content.
312
+ Command events may carry optional model/tier/routing/duration fields per `.claude/context/telemetry.md`.
313
+ On first session (if `telemetry_noticed` not set in state file), mention the notice once, then set `telemetry_noticed: true`. Full spec: `.claude/context/telemetry.md`.
314
+
315
+ ---
316
+
317
+ ## Mode
318
+
319
+ Egregore runs in one of two configurations, set by `mode` in `egregore.json`. Detect with `_detect_mode` in `bin/lib/config.sh`, or check `.mode` / `.api_url` directly.
320
+
321
+ **Local mode** (`"mode": "local"` or no `api_url`) — the default, self-contained configuration. The OSS experience. Memory files are the source of truth. All core commands work: `$reflect`, `$handoff`, `$quest`, `$ask`, `$activity`, `$dashboard`, `$todo`. Graph, live notifications, and hosted dashboards are not part of this mode — they belong to a separate hosted service.
322
+
323
+ **Hard rules in local mode:**
324
+ - Never tell the user to "ask their admin" for credentials. The user IS the admin.
325
+ - Never surface `api_url`, `EGREGORE_API_KEY`, or "connected mode" as an upgrade path. Hosted Egregore is a separate service, not something a user can turn on by adding fields to `egregore.json`.
326
+ - If a feature genuinely requires the hosted service, say so plainly ("this isn't available in this configuration") and stop. Do not improvise a path to enabling it.
327
+ - Calling `bin/graph.sh` or `bin/notify.sh` in local mode is harmless — they fail soft and return empty results — but there is no need to call them; prefer reading `memory/` directly.
328
+
329
+ **Connected mode** (`"mode": "connected"`, `api_url` set) — the hosted configuration, used by organizations on the hosted service. Full feature set: Neo4j knowledge graph via `bin/graph.sh`, Telegram notifications via `bin/notify.sh`, dashboard publication, API-backed context gathering on session start. Use `$env` to check API key, `$checkup` for diagnostics. If the graph is offline, show troubleshooting.
330
+
331
+ ---
332
+
333
+ ## Environment Isolation
334
+
335
+ Sessions are confined to this project + memory + managed repos. On Codex this boundary is a standing instruction, not an enforced hook — hold it yourself.
336
+
337
+ - **Never modify `~/.egregore/instances.json`** — managed by session-start.sh
338
+ - **Never access another instance's files** — refuse even if asked
339
+ - When a request points outside the boundary, do not improvise a workaround. Ask in plain text with numbered options:
340
+
341
+ ```text
342
+ That path is outside this Egregore's boundary. How should we proceed?
343
+ 1. Paste the contents inline
344
+ 2. Move the file into the repo and point me at the new path
345
+ 3. Cancel
346
+ ```
347
+
348
+ See DEVELOPMENT.md §3 for boundary details.
349
+
350
+ <!-- END GENERATED EGREGORE CODEX SPEC -->
@@ -0,0 +1,242 @@
1
+ #!/bin/bash
2
+ # Fetches all activity dashboard data: single API call + parallel git/disk ops.
3
+ # Usage: bash bin/activity-data.sh [username]
4
+ # Returns a single JSON object with all query results.
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
7
+ TMPDIR=$(mktemp -d)
8
+ trap "rm -rf $TMPDIR" EXIT
9
+
10
+ # --- Read config ---
11
+ API_URL=$(jq -r '.api_url // empty' "$SCRIPT_DIR/egregore.json" 2>/dev/null)
12
+ API_KEY=$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2-)
13
+ ORG=$(jq -r '.org_name // "Egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "Egregore")
14
+ DATE=$(date '+%b %d')
15
+
16
+ source "$SCRIPT_DIR/bin/lib/handoff-meta.sh" >/dev/null 2>/dev/null || true
17
+
18
+ # --- Detect user ---
19
+ GH_USER="${1:-}"
20
+ if [ -z "$GH_USER" ]; then
21
+ STATE_FILE="$SCRIPT_DIR/.egregore-state.json"
22
+ if [ -f "$STATE_FILE" ]; then
23
+ GH_USER=$(jq -r '.github_username // empty' "$STATE_FILE" 2>/dev/null)
24
+ fi
25
+ if [ -z "$GH_USER" ]; then
26
+ GH_USER=$(git -C "$SCRIPT_DIR" config user.name 2>/dev/null || echo "unknown")
27
+ fi
28
+ fi
29
+
30
+ EMPTY='{"fields":[],"values":[]}'
31
+
32
+ # --- Fire API call + git/disk ops in parallel ---
33
+
34
+ # Graph data: single API call (all queries run server-side)
35
+ (
36
+ GRAPH_STATUS="offline"
37
+ GRAPH_REASON=""
38
+ if [ -z "$API_URL" ] || [ -z "$API_KEY" ]; then
39
+ GRAPH_REASON="missing_config"
40
+ else
41
+ # Store HTTP status code alongside response body. curl already emits 000
42
+ # on transport failure; keep the exit status separate so it cannot become
43
+ # 000000 and fall through as an invalid JSON response.
44
+ CURL_STATUS=0
45
+ HTTP_CODE=$(curl -s -o "$TMPDIR/activity_raw.json" -w "%{http_code}" \
46
+ "${API_URL}/api/activity/dashboard?github_username=$(printf '%s' "$GH_USER" | jq -sRr @uri)" \
47
+ -H "Authorization: Bearer $API_KEY" \
48
+ --connect-timeout 5 --max-time 15 2>/dev/null) || CURL_STATUS=$?
49
+
50
+ if [ "$CURL_STATUS" -ne 0 ] || [ "$HTTP_CODE" = "000" ] || ! [[ "$HTTP_CODE" =~ ^[0-9][0-9][0-9]$ ]]; then
51
+ GRAPH_REASON="unreachable"
52
+ elif [ "$HTTP_CODE" = "401" ] || [ "$HTTP_CODE" = "403" ]; then
53
+ GRAPH_REASON="auth_error"
54
+ elif [ "$HTTP_CODE" -ge 500 ] 2>/dev/null; then
55
+ GRAPH_REASON="server_error"
56
+ elif [ -s "$TMPDIR/activity_raw.json" ] && jq -e '.me' "$TMPDIR/activity_raw.json" >/dev/null 2>&1; then
57
+ cp "$TMPDIR/activity_raw.json" "$TMPDIR/activity.json"
58
+ GRAPH_STATUS="connected"
59
+ else
60
+ GRAPH_REASON="invalid_response"
61
+ fi
62
+ fi
63
+
64
+ # If not connected, write status-only response
65
+ if [ "$GRAPH_STATUS" != "connected" ]; then
66
+ jq -n --arg status "$GRAPH_STATUS" --arg reason "$GRAPH_REASON" \
67
+ '{graph_status: $status, graph_reason: $reason}' > "$TMPDIR/activity.json"
68
+ else
69
+ # Inject graph_status into successful response
70
+ jq --arg status "$GRAPH_STATUS" '. + {graph_status: $status}' \
71
+ "$TMPDIR/activity.json" > "$TMPDIR/activity_merged.json" \
72
+ && mv "$TMPDIR/activity_merged.json" "$TMPDIR/activity.json"
73
+ fi
74
+ ) &
75
+ API_PID=$!
76
+
77
+ # Git/disk: runs in parallel (stays client-side)
78
+ (
79
+ # Sync
80
+ git -C "$SCRIPT_DIR" fetch origin --quiet 2>/dev/null || true
81
+ CURRENT=$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || echo "unknown")
82
+ if [ "$CURRENT" != "develop" ]; then
83
+ git -C "$SCRIPT_DIR" fetch origin develop:develop --quiet 2>/dev/null || true
84
+ fi
85
+ if [[ "$CURRENT" == dev/* ]]; then
86
+ git -C "$SCRIPT_DIR" rebase develop --quiet >/dev/null 2>&1 || git -C "$SCRIPT_DIR" rebase --abort >/dev/null 2>&1 || true
87
+ fi
88
+
89
+ # Memory sync
90
+ if [ -d "$SCRIPT_DIR/memory/.git" ] || [ -L "$SCRIPT_DIR/memory" ]; then
91
+ git -C "$SCRIPT_DIR/memory" fetch origin main --quiet 2>/dev/null || true
92
+ LOCAL=$(git -C "$SCRIPT_DIR/memory" rev-parse HEAD 2>/dev/null || echo "")
93
+ REMOTE=$(git -C "$SCRIPT_DIR/memory" rev-parse origin/main 2>/dev/null || echo "")
94
+ if [ -n "$LOCAL" ] && [ -n "$REMOTE" ] && [ "$LOCAL" != "$REMOTE" ]; then
95
+ git -C "$SCRIPT_DIR/memory" pull origin main --quiet 2>/dev/null || true
96
+ fi
97
+ fi
98
+
99
+ # PRs
100
+ PRS=$(cd "$SCRIPT_DIR" && gh pr list --base develop --state open --json number,title,author 2>/dev/null || echo "[]")
101
+ echo "$PRS" > "$TMPDIR/prs.json"
102
+
103
+ # Disk cross-reference
104
+ MONTH=$(date +%Y-%m)
105
+ TODAY=$(date +%d)
106
+ YESTERDAY=$(date -v-1d +%d 2>/dev/null || date -d 'yesterday' +%d 2>/dev/null || echo "00")
107
+ HANDOFFS=$(ls -1 "$SCRIPT_DIR/memory/handoffs/$MONTH/" 2>/dev/null | grep "^${TODAY}-\|^${YESTERDAY}-" 2>/dev/null | head -10 || echo "")
108
+ echo "$HANDOFFS" > "$TMPDIR/disk_handoffs.txt"
109
+
110
+ DECISIONS=$(ls -1t "$SCRIPT_DIR/memory/knowledge/decisions/" 2>/dev/null | head -5 || echo "")
111
+ echo "$DECISIONS" > "$TMPDIR/disk_decisions.txt"
112
+ ) &
113
+ GIT_PID=$!
114
+
115
+ # Local sessions: parse memory files when graph is offline (parallel)
116
+ (
117
+ GH_LC=$(echo "$GH_USER" | tr '[:upper:]' '[:lower:]')
118
+ DISPLAY_LC=""
119
+ if [ -f "$SCRIPT_DIR/.egregore-state.json" ]; then
120
+ DISPLAY_LC=$(jq -r '.display_name // empty' "$SCRIPT_DIR/.egregore-state.json" 2>/dev/null | tr '[:upper:]' '[:lower:]')
121
+ fi
122
+
123
+ CUTOFF=$(date -v-14d +%Y-%m-%d 2>/dev/null || date -d '14 days ago' +%Y-%m-%d 2>/dev/null || echo "2000-01-01")
124
+ MY="[]"
125
+ TEAM="[]"
126
+
127
+ # Scan sessions, wraps, and handoffs
128
+ ALL_ENTRIES=""
129
+ for DIR in "$SCRIPT_DIR/memory/sessions" "$SCRIPT_DIR/memory/wraps" "$SCRIPT_DIR/memory/handoffs"; do
130
+ [ -d "$DIR" ] || continue
131
+ TYPE=$(basename "$DIR")
132
+ find -L "$DIR" -name '*.md' -not -name 'index*' -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -20 | while read -r MFILE; do
133
+ [ -z "$MFILE" ] && continue
134
+ M_AUTH=$(head -10 "$MFILE" 2>/dev/null | grep -m1 '^\*\*Author\*\*:' | sed 's/^\*\*Author\*\*:[[:space:]]*//')
135
+ M_DATE=$(head -10 "$MFILE" 2>/dev/null | grep -m1 '^\*\*Date\*\*:' | sed 's/^\*\*Date\*\*:[[:space:]]*//')
136
+ M_BRANCH=$(head -10 "$MFILE" 2>/dev/null | grep -m1 '^\*\*Branch\*\*:' | sed 's/^\*\*Branch\*\*:[[:space:]]*//')
137
+ M_DURATION=$(head -10 "$MFILE" 2>/dev/null | grep -m1 '^\*\*Duration\*\*:' | sed 's/^\*\*Duration\*\*:[[:space:]]*//')
138
+ M_TOPIC=$(head -3 "$MFILE" 2>/dev/null | grep -m1 '^# ' | sed 's/^# [^:]*:[[:space:]]*//')
139
+ [ -z "$M_AUTH" ] && continue
140
+ # Date filter
141
+ M_DAY="${M_DATE%%T*}"
142
+ [ -n "$M_DAY" ] && [ "$M_DAY" \< "$CUTOFF" ] && continue
143
+ echo "${M_AUTH}|${M_DATE}|${M_BRANCH}|${M_TOPIC}|${M_DURATION}|${TYPE}"
144
+ done
145
+ done | jq -Rn --arg gh "$GH_LC" --arg dn "$DISPLAY_LC" '
146
+ [inputs | split("|") |
147
+ {author: .[0], date: .[1], branch: .[2], topic: .[3], duration: .[4], type: .[5]}
148
+ ] | {
149
+ my_sessions: [.[] | select((.author | ascii_downcase) == $gh or (.author | ascii_downcase) == $dn) | select($dn != "" or (.author | ascii_downcase) == $gh)],
150
+ team_sessions: [.[] | select((.author | ascii_downcase) != $gh and (if $dn != "" then (.author | ascii_downcase) != $dn else true end))]
151
+ }
152
+ ' 2>/dev/null > "$TMPDIR/local_sessions.json" || echo '{"my_sessions":[],"team_sessions":[]}' > "$TMPDIR/local_sessions.json"
153
+ ) &
154
+ LOCAL_PID=$!
155
+
156
+ # --- Wait for all ---
157
+ wait $API_PID $GIT_PID $LOCAL_PID 2>/dev/null || true
158
+
159
+ # --- Read results ---
160
+ PRS=$(cat "$TMPDIR/prs.json" 2>/dev/null || echo "[]")
161
+ echo "$PRS" | jq . >/dev/null 2>&1 || PRS="[]"
162
+
163
+ # Resolve PR author GitHub logins -> egregore display names. `gh pr list` returns
164
+ # the raw github login (e.g. "alice-gh"); without this it leaks into activity
165
+ # instead of the person's display name ("Alice"). Map via the graph when connected;
166
+ # fall back to the github profile name, then the login. Author becomes a string.
167
+ if [ -n "$PRS" ] && [ "$PRS" != "[]" ]; then
168
+ AUTHOR_MAP='{}'
169
+ if [ -n "$API_URL" ] && [ -n "$API_KEY" ]; then
170
+ MAP_RAW=$(bash "$SCRIPT_DIR/bin/graph.sh" query \
171
+ "MATCH (p:Person) WHERE p.github IS NOT NULL RETURN p.github AS gh, p.name AS name" 2>/dev/null)
172
+ AUTHOR_MAP=$(printf '%s' "$MAP_RAW" | jq -c \
173
+ 'reduce (.values[]?) as $v ({}; .[($v[0]|ascii_downcase)] = $v[1])' 2>/dev/null || echo '{}')
174
+ fi
175
+ PRS=$(printf '%s' "$PRS" | jq -c --argjson map "$AUTHOR_MAP" '
176
+ map(
177
+ (if (.author|type)=="object" then .author else {login: (.author|tostring), name: null} end) as $a
178
+ | .author = ([$map[(($a.login // "") | ascii_downcase)], $a.name, $a.login]
179
+ | map(select(. != null and . != "")) | first // "unknown")
180
+ )' 2>/dev/null || printf '%s' "$PRS")
181
+ fi
182
+ DISK_HANDOFFS=$(cat "$TMPDIR/disk_handoffs.txt" 2>/dev/null || echo "")
183
+ DISK_DECISIONS=$(cat "$TMPDIR/disk_decisions.txt" 2>/dev/null || echo "")
184
+ LOCAL_SESSIONS=$(cat "$TMPDIR/local_sessions.json" 2>/dev/null || echo '{"my_sessions":[],"team_sessions":[]}')
185
+ echo "$LOCAL_SESSIONS" | jq . >/dev/null 2>&1 || LOCAL_SESSIONS='{"my_sessions":[],"team_sessions":[]}'
186
+
187
+ handoff_metadata_map() {
188
+ local json="$1"
189
+
190
+ if ! declare -F eg_handoff_metadata_json >/dev/null 2>&1; then
191
+ echo "{}"
192
+ return
193
+ fi
194
+
195
+ printf '%s\n' "$json" | jq -r '
196
+ [(.handoffs_to_me[]?.filePath // empty), (.all_handoffs[]?.filePath // empty)]
197
+ | map(select(. != ""))
198
+ | unique[]
199
+ ' 2>/dev/null | while IFS= read -r rel; do
200
+ [ -z "$rel" ] && continue
201
+ file="$SCRIPT_DIR/memory/$rel"
202
+ [ -f "$file" ] || continue
203
+ eg_handoff_metadata_json "$file" | jq -c --arg rel "$rel" '{key:$rel, value:{author:.author, topic:.topic, date:.date}}'
204
+ done | jq -sc 'map({(.key): .value}) | add // {}' 2>/dev/null || echo "{}"
205
+ }
206
+
207
+ # --- Merge server response + local git/disk data ---
208
+ FINAL_JSON=$(jq -n \
209
+ --arg org "$ORG" \
210
+ --arg date "$DATE" \
211
+ --slurpfile activity "$TMPDIR/activity.json" \
212
+ --argjson prs "$PRS" \
213
+ --arg disk_handoffs "$DISK_HANDOFFS" \
214
+ --arg disk_decisions "$DISK_DECISIONS" \
215
+ --argjson local_sessions "$LOCAL_SESSIONS" \
216
+ '$activity[0] + {
217
+ org: $org,
218
+ date: $date,
219
+ prs: $prs,
220
+ disk: {handoffs: $disk_handoffs, decisions: $disk_decisions},
221
+ local_sessions: $local_sessions
222
+ }')
223
+
224
+ HANDOFF_META="$(handoff_metadata_map "$FINAL_JSON")"
225
+ [ -z "$HANDOFF_META" ] && HANDOFF_META="{}"
226
+
227
+ printf '%s\n' "$FINAL_JSON" | jq --argjson handoff_meta "$HANDOFF_META" '
228
+ def enrich_handoff_sender:
229
+ (.filePath // "") as $file
230
+ | if $file != "" and ($handoff_meta[$file] // null) != null then
231
+ ($handoff_meta[$file] // {}) as $meta
232
+ | .author = ($meta.author // .author)
233
+ | .from = ($meta.author // .from)
234
+ | .topic = (.topic // $meta.topic)
235
+ | .date = (.date // $meta.date)
236
+ else
237
+ .
238
+ end;
239
+
240
+ .handoffs_to_me = ((.handoffs_to_me // []) | map(enrich_handoff_sender))
241
+ | .all_handoffs = ((.all_handoffs // []) | map(enrich_handoff_sender))
242
+ '