create-egregore 0.19.8 → 0.19.12

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 (92) hide show
  1. package/assets/egregore-launcher.js +266 -4
  2. package/lib/local.js +11 -1
  3. package/lib/setup.js +33 -0
  4. package/package.json +2 -2
  5. package/runtime/codex/.codex/hooks/branch-guard.js +242 -34
  6. package/runtime/codex/.codex/skills/activity/SKILL.md +18 -6
  7. package/runtime/codex/.codex/skills/deep-reflect/SKILL.md +90 -55
  8. package/runtime/codex/.codex/skills/deploy-bridge/SKILL.md +25 -0
  9. package/runtime/codex/.codex/skills/handoff/SKILL.md +6 -2
  10. package/runtime/codex/.codex/skills/save/SKILL.md +29 -5
  11. package/runtime/codex/.codex/skills/scroll/SKILL.md +54 -3
  12. package/runtime/codex/.codex/skills/task/SKILL.md +25 -0
  13. package/runtime/codex/.codex/skills/tui-design/SKILL.md +1 -1
  14. package/runtime/codex/.codex/skills/wrap/SKILL.md +4 -1
  15. package/runtime/codex/.codex/spec-manifest.json +19 -7
  16. package/runtime/codex/AGENTS.md +63 -19
  17. package/runtime/codex/bin/activity-data.sh +1 -1
  18. package/runtime/codex/bin/agent.sh +88 -25
  19. package/runtime/codex/bin/attendant.sh +525 -0
  20. package/runtime/codex/bin/capture-reconcile.sh +67 -0
  21. package/runtime/codex/bin/capture-run.sh +341 -0
  22. package/runtime/codex/bin/codex-render-spec.mjs +29 -14
  23. package/runtime/codex/bin/codex-session-start.sh +49 -4
  24. package/runtime/codex/bin/codex-skill-render.mjs +23 -4
  25. package/runtime/codex/bin/graph-op.sh +719 -49
  26. package/runtime/codex/bin/graph-wal.sh +3 -2
  27. package/runtime/codex/bin/handoff-run.sh +72 -0
  28. package/runtime/codex/bin/handoff-save-egregore.sh +51 -11
  29. package/runtime/codex/bin/index-handoff.sh +26 -17
  30. package/runtime/codex/bin/ingest-graph.sh +80 -0
  31. package/runtime/codex/bin/ingest-surface.html +429 -0
  32. package/runtime/codex/bin/ingest.py +614 -0
  33. package/runtime/codex/bin/ingest.sh +231 -0
  34. package/runtime/codex/bin/ingest_graph.py +776 -0
  35. package/runtime/codex/bin/ingest_surface.py +464 -0
  36. package/runtime/codex/bin/lib/git-sync.sh +2 -6
  37. package/runtime/codex/bin/lib/greeting.sh +157 -22
  38. package/runtime/codex/bin/lib/identity.sh +50 -29
  39. package/runtime/codex/bin/lib/noncode.sh +31 -0
  40. package/runtime/codex/bin/person.py +610 -0
  41. package/runtime/codex/bin/person.sh +448 -0
  42. package/runtime/codex/bin/session-autosave.sh +184 -0
  43. package/runtime/codex/bin/session-log.sh +199 -0
  44. package/runtime/codex/bin/settings.sh +1 -1
  45. package/runtime/codex/manifest.json +19 -1
  46. package/runtime/pi/.codex/hooks/branch-guard.js +242 -34
  47. package/runtime/pi/.codex/skills/activity/SKILL.md +18 -6
  48. package/runtime/pi/.codex/skills/deep-reflect/SKILL.md +90 -55
  49. package/runtime/pi/.codex/skills/deploy-bridge/SKILL.md +25 -0
  50. package/runtime/pi/.codex/skills/handoff/SKILL.md +6 -2
  51. package/runtime/pi/.codex/skills/save/SKILL.md +29 -5
  52. package/runtime/pi/.codex/skills/scroll/SKILL.md +54 -3
  53. package/runtime/pi/.codex/skills/task/SKILL.md +25 -0
  54. package/runtime/pi/.codex/skills/tui-design/SKILL.md +1 -1
  55. package/runtime/pi/.codex/skills/wrap/SKILL.md +4 -1
  56. package/runtime/pi/.codex/spec-manifest.json +19 -7
  57. package/runtime/pi/.pi/APPEND_SYSTEM.md +57 -14
  58. package/runtime/pi/.pi/extensions/egregore.ts +98 -8
  59. package/runtime/pi/.pi/spec-manifest.json +2 -2
  60. package/runtime/pi/AGENTS.md +63 -19
  61. package/runtime/pi/bin/activity-data.sh +1 -1
  62. package/runtime/pi/bin/agent.sh +88 -25
  63. package/runtime/pi/bin/attendant.sh +525 -0
  64. package/runtime/pi/bin/capture-reconcile.sh +67 -0
  65. package/runtime/pi/bin/capture-run.sh +341 -0
  66. package/runtime/pi/bin/codex-render-spec.mjs +29 -14
  67. package/runtime/pi/bin/codex-session-start.sh +49 -4
  68. package/runtime/pi/bin/codex-skill-render.mjs +23 -4
  69. package/runtime/pi/bin/graph-op.sh +719 -49
  70. package/runtime/pi/bin/graph-wal.sh +3 -2
  71. package/runtime/pi/bin/handoff-run.sh +72 -0
  72. package/runtime/pi/bin/handoff-save-egregore.sh +51 -11
  73. package/runtime/pi/bin/index-handoff.sh +26 -17
  74. package/runtime/pi/bin/ingest-graph.sh +80 -0
  75. package/runtime/pi/bin/ingest-surface.html +429 -0
  76. package/runtime/pi/bin/ingest.py +614 -0
  77. package/runtime/pi/bin/ingest.sh +231 -0
  78. package/runtime/pi/bin/ingest_graph.py +776 -0
  79. package/runtime/pi/bin/ingest_surface.py +464 -0
  80. package/runtime/pi/bin/lib/git-sync.sh +2 -6
  81. package/runtime/pi/bin/lib/greeting.sh +157 -22
  82. package/runtime/pi/bin/lib/identity.sh +50 -29
  83. package/runtime/pi/bin/lib/noncode.sh +31 -0
  84. package/runtime/pi/bin/person.py +610 -0
  85. package/runtime/pi/bin/person.sh +448 -0
  86. package/runtime/pi/bin/pi-branch-policy.mjs +164 -4
  87. package/runtime/pi/bin/pi-product-workflows.mjs +31 -2
  88. package/runtime/pi/bin/publish-artifact.sh +14 -0
  89. package/runtime/pi/bin/session-autosave.sh +184 -0
  90. package/runtime/pi/bin/session-log.sh +199 -0
  91. package/runtime/pi/bin/settings.sh +274 -0
  92. package/runtime/pi/manifest.json +20 -1
@@ -17,15 +17,37 @@ which branch, commit, push, pull request, or memory sync steps are required.
17
17
  ```bash
18
18
  git status --short
19
19
  git status --short memory 2>/dev/null || true
20
- git branch --show-current
20
+ BRANCH=$(git branch --show-current)
21
+ AHEAD=0
22
+ OPEN_PR=""
23
+ case "$BRANCH" in
24
+ dev/*|feature/*|bugfix/*)
25
+ git fetch origin develop --quiet 2>/dev/null || true
26
+ AHEAD=$(git rev-list --count "origin/develop..HEAD" 2>/dev/null || echo 0)
27
+ if command -v gh >/dev/null 2>&1; then
28
+ OPEN_PR=$(gh pr list --head "$BRANCH" --base develop --state open \
29
+ --json url --jq '.[0].url // empty' 2>/dev/null || true)
30
+ fi
31
+ ;;
32
+ esac
21
33
  ```
22
34
 
23
- 3. If there are no repo or memory changes, say everything is already saved and
24
- stop.
35
+ 3. A clean working tree alone does **not** mean the work is fully saved:
36
+ - If there are repo or memory changes, continue.
37
+ - If the task branch is ahead of `origin/develop` and `OPEN_PR` is empty,
38
+ continue even when the tree is clean. The bridge must push any committed
39
+ work and create the missing PR.
40
+ - Stop with "everything is already saved" only when there are no repo or
41
+ memory changes and either the branch has no commits to integrate
42
+ (`AHEAD=0`) or an open integration PR already exists.
25
43
  4. Synthesize:
26
44
  - a short topic from the work,
27
45
  - a clear commit message,
28
- - a one-line user-facing scope summary.
46
+ - a one-line user-facing scope summary,
47
+ - a PR description following `.claude/context/pr-format.md`:
48
+ `## What` (1–4 bullets), `## Why` (1–3 sentences), and
49
+ `## Verification` (how the change was checked — required when the
50
+ diff touches non-markdown files; be honest if unverified).
29
51
  5. If the scope is ambiguous or includes unrelated changes, ask for one compact
30
52
  confirmation. Use structured Codex question tooling when available;
31
53
  otherwise render:
@@ -40,11 +62,13 @@ Other:
40
62
  6. Run the bridge command:
41
63
 
42
64
  ```bash
43
- bin/agent.sh save --message "$MESSAGE" --topic "$TOPIC"
65
+ bin/agent.sh save --message "$MESSAGE" --topic "$TOPIC" --pr-body "$PR_BODY"
44
66
  ```
45
67
 
46
68
  The bridge owns the mechanical workflow: sync memory, ensure a task branch,
47
69
  commit repo changes, push, and create or reuse a pull request when available.
70
+ Always pass the synthesized `--pr-body` — the bridge only auto-generates a
71
+ skeleton body as a last resort, and the CI `pr-format` check gates every PR.
48
72
 
49
73
  7. Parse the output and report only useful user information:
50
74
  - branch name,
@@ -18,7 +18,7 @@ small fork. A scroll requires all three legs: face, harvest, and update loop.
18
18
  ## Structured UX parity
19
19
 
20
20
  The browser artifact is the primary output. Preserve both tabs, deep links from
21
- honest costs into decisions, the versioned copydock fence, stable URL, and local
21
+ honest costs into decisions, the versioned copydock return block, stable URL, and local
22
22
  source path. Do not substitute a prose-only summary or expose raw publish output.
23
23
 
24
24
  ## Route the invocation
@@ -121,13 +121,64 @@ the same `--id`; never mint a new URL for an update. In local mode, publishing
121
121
  is unavailable: open the file locally and report the source path without
122
122
  suggesting configuration changes.
123
123
 
124
- Add the URL or local path, source location, version, and fence tag to the
124
+ Add the URL or local path, source location, version, and return-block tag to the
125
125
  relevant quest's log/artifacts tables. If no quest is relevant, keep the source
126
126
  path as the durable record and state it.
127
127
 
128
+ ## Creator gate — before any absorb
129
+
130
+ The scroll record `memory/scrolls/<slug>.md` names `creator: <person-slug>` and
131
+ optionally `trusted: [<person-slug>, …]`. A record missing `creator:` is
132
+ backfilled from unambiguous existing attribution, otherwise ask the user once
133
+ and write it — never silently default the gate open.
134
+
135
+ Derive the paster from the session person (`.egregore-state.json`, then git
136
+ config) — never from the return block's self-declared `respondent:` line, which
137
+ is attribution metadata, not an authorization credential.
138
+
139
+ If the paster is not the creator and not in `trusted:`, the return is **gated**:
140
+
141
+ 1. Append a `turn-received` event to `memory/scrolls/.events/<slug>.jsonl`
142
+ (create the file if absent). Event ids are append-if-absent and MUST match
143
+ the Claude corpus exactly — both runtimes share one event log:
144
+ `turn.id = respondent + '|' + base_version + '|' + date + '|' + digest`;
145
+ digest = FNV-1a 32-bit hex over the UTF-8 bytes of
146
+ `JSON.stringify([respondent, String(base_version), date, sortedAnswers,
147
+ sortedOpens])` where `sortedAnswers` = answers sorted by fork id, each
148
+ mapped to the tuple `[fork, pick-or-UNDECIDED, note-or-empty]` (labels are
149
+ excluded), and `sortedOpens` = opens sorted by prompt id, each mapped to
150
+ `[prompt, text-or-UNDECIDED]`; every string is NFC-normalized and
151
+ CRLF→LF-normalized before hashing. Record `submitted_by: <paster>` on the
152
+ event (event-log metadata only — never projected into a published ledger)
153
+ and `merged_into: "pending"`.
154
+ 2. Do NOT absorb: no `memory/knowledge/decisions/` writes, no spec/plan edits,
155
+ no face rewrite, no version bump, no republish of new content. Republishing
156
+ the unchanged current version to acknowledge the turn is allowed and appends
157
+ no version event.
158
+ 3. Notify the creator — connected: `bash bin/notify.sh send <creator>
159
+ "<paster> answered your scroll <slug> (vN): <digest> — pending your review"`;
160
+ local: write an addressed handoff in `memory/handoffs/` naming the scroll,
161
+ paster, base version, digest, and the dispositions below. The contributor
162
+ may also send the artifact link directly.
163
+ 4. Report the gated state and stop.
164
+
165
+ **Creator review.** The creator disposes in chat: **accept** (absorb into the
166
+ next version), **decline — <reason>** (mandatory nonblank note; refuse a
167
+ decline without one), per-answer overrides (top-level disposition is the
168
+ default, listed answers override; a turn with zero effectively accepted answers
169
+ is a plain decline; a zero-answer turn takes the top-level disposition), or
170
+ **synthesize** (compose one proposal from all pending turns — consensus
171
+ decides, conflicts become new explicit forks — and publish only on creator
172
+ approval). Every disposition appends `turn-reviewed`
173
+ `{type, turn, disposition: accepted|declined, by, date, note?, answers?}` with
174
+ id `review|<turn.id>` before any composition. An accepted turn stays pending
175
+ until a version actually absorbs it. Declined turns are never absorbed, stay
176
+ attributed in the log, and their reason travels with them. The creator's own
177
+ returns and trusted respondents keep the immediate loop below.
178
+
128
179
  ## Update loop
129
180
 
130
- On a returned fence:
181
+ On a returned block (creator or trusted paster — gated returns stop above):
131
182
 
132
183
  1. **Absorb.** Parse Q/O lines and notes. Write durable decisions with their
133
184
  reasoning to `memory/knowledge/decisions/`, update the underlying spec or
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: task
3
+ description: 'Create, import, inspect, approve, answer, or cancel work in the hosted Egregore Agent Desk. Use for `/task`, `$task`, “send this work to the agents,” “start these tasks,” Markdown development batches, or checking hosted task progress. This skill submits work to the hosted pipeline; it does not implement the task in the current local session.'
4
+ ---
5
+
6
+ <!-- generated-by: bin/codex-sync-skills.sh -->
7
+
8
+ # Egregore task Adapter
9
+
10
+ This is fallback coverage for a long-tail Egregore workflow that has not been
11
+ ported to a hand-written Codex-native skill yet.
12
+
13
+ Use the project shell and filesystem directly. Do not invoke Claude Code
14
+ commands. Translate interactive choices to structured Codex question tooling
15
+ when it is available; otherwise render compact numbered choices with an
16
+ `Other:` option and wait for the user.
17
+
18
+ 1. Read `.claude/skills/task/SKILL.md` for the workflow details.
19
+ 2. Run the referenced `bin/` scripts directly from Codex.
20
+ 3. Treat graph, publish, and notify steps as best-effort unless that workflow
21
+ explicitly says they are required.
22
+ 4. Keep local-mode behavior filesystem-first and avoid graph or notification
23
+ calls when `egregore.json` declares `"mode": "local"`.
24
+ 5. Never call the deprecated `egregore-handoff` CLI for Egregore project
25
+ handoffs.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tui-design
3
- description: 'Fallback Codex adapter for the Egregore tui-design workflow.'
3
+ description: 'TUI Design System for Egregore slash commands. Use when designing or modifying any command''s terminal output to ensure visual consistency. Triggers on: TUI, terminal output, box drawing, command output formatting, sigils, section markers. Do NOT use for browser rendering (use dark-mode) or external prose (use egregore-voice).'
4
4
  ---
5
5
 
6
6
  <!-- generated-by: bin/codex-sync-skills.sh -->
@@ -6,7 +6,10 @@ description: Wrap an Egregore session when the user invokes /wrap or $wrap, or s
6
6
  # Egregore Wrap
7
7
 
8
8
  Native Codex Egregore skill. Use this inside an Egregore checkout with
9
- `bin/agent.sh`.
9
+ `bin/agent.sh`. The command routes through `bin/capture-run.sh --mode personal`.
10
+ It writes the personal record first, appends graph and handoff-completion events
11
+ to the local WAL, and reconciles them detached; do not wait for or repeat that
12
+ background work.
10
13
 
11
14
  ## Flow
12
15
 
@@ -14,6 +14,18 @@
14
14
  "sourceHash": "ddcbc0083aff",
15
15
  "note": "Kept; /update, /contribute, /save tokens rendered as $skill tokens."
16
16
  },
17
+ {
18
+ "section": "Cross-Runtime Compatibility",
19
+ "action": "keep",
20
+ "sourceHash": "75d02e2603f5",
21
+ "note": "Kept verbatim — framework parity applies equally to Claude Code, Codex, and Pi."
22
+ },
23
+ {
24
+ "section": "Voice",
25
+ "action": "keep",
26
+ "sourceHash": "af73d4eaa7cd",
27
+ "note": "Kept — all runtimes can consult the shared voice rules and register-specific skills."
28
+ },
17
29
  {
18
30
  "section": "On Launch — MANDATORY FIRST ACTION",
19
31
  "action": "replace",
@@ -23,19 +35,19 @@
23
35
  {
24
36
  "section": "After Greeting — BRANCH ON FIRST RESPONSE",
25
37
  "action": "replace",
26
- "sourceHash": "c71340e68c9e",
38
+ "sourceHash": "bce266fb848b",
27
39
  "note": "EnterWorktree -> bin/agent.sh branch with git checkout fallback; AskUserQuestion -> numbered options in plain text; branch-guard mapped to .codex/hooks/branch-guard.js with instruction fallback; plan-mode note dropped (no plan mode on Codex); /branch + /onboarding -> skill tokens. Handoff claiming and repoState auto-checkout kept verbatim (pure git)."
28
40
  },
29
41
  {
30
42
  "section": "Config Files",
31
43
  "action": "keep",
32
- "sourceHash": "81b7bf09901b",
44
+ "sourceHash": "8d7f1bd0f2d9",
33
45
  "note": "Kept verbatim — shell facts, runtime-neutral."
34
46
  },
35
47
  {
36
48
  "section": "Knowledge Graph",
37
49
  "action": "keep",
38
- "sourceHash": "5c0953aee955",
50
+ "sourceHash": "b5d9a149f1a6",
39
51
  "note": "Kept verbatim — bin/graph.sh is runtime-neutral."
40
52
  },
41
53
  {
@@ -71,7 +83,7 @@
71
83
  {
72
84
  "section": "Git Workflow",
73
85
  "action": "keep",
74
- "sourceHash": "d058d1f8da11",
86
+ "sourceHash": "49fd4625fa1e",
75
87
  "note": "Kept; slash tokens rendered as $skill tokens. Branch diagram unchanged (code fence)."
76
88
  },
77
89
  {
@@ -83,7 +95,7 @@
83
95
  {
84
96
  "section": "Command Awareness",
85
97
  "action": "keep",
86
- "sourceHash": "e1db878ccaee",
98
+ "sourceHash": "ce5eb3015427",
87
99
  "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."
88
100
  },
89
101
  {
@@ -107,8 +119,8 @@
107
119
  {
108
120
  "section": "Environment Isolation",
109
121
  "action": "replace",
110
- "sourceHash": "ed47e96248bd",
111
- "note": "boundary-check is a Claude PreToolUse hook with no .codex equivalent — behavior stated as a standing instruction; AskUserQuestion remediation -> numbered options."
122
+ "sourceHash": "086e2c1d9019",
123
+ "note": "boundary-check is a Claude PreToolUse hook with no .codex equivalent — two-tier model stated as a standing instruction; AskUserQuestion remediation -> numbered options, now including the two consent-grant options (session grant -> .egregore-boundary-consent, instance grant -> .egregore-boundary.local.json read[])."
112
124
  }
113
125
  ]
114
126
  }
@@ -35,7 +35,8 @@ Use the runtime-neutral bridge instead of Claude Code slash commands:
35
35
 
36
36
  ```bash
37
37
  bin/agent.sh branch --topic "auth review"
38
- bin/agent.sh save --message "Save: auth review" --topic "auth review"
38
+ bin/agent.sh save --message "Save: auth review" --topic "auth review" \
39
+ --pr-body "$PR_BODY" # body per .claude/context/pr-format.md (auto-skeleton if omitted)
39
40
  bin/agent.sh wrap --from alice --topic "auth review" \
40
41
  --summary "Implemented the OAuth callback parser and documented follow-ups." \
41
42
  --body "Open threads: review error cases and browser redirects."
@@ -96,6 +97,24 @@ When a user reports broken or missing framework behavior, the first question is
96
97
 
97
98
  ---
98
99
 
100
+ ## Cross-Runtime Compatibility
101
+
102
+ Framework behavior must work across Claude Code, Codex, and Pi Egregores. Put
103
+ shared mechanics in runtime-neutral `bin/` scripts; keep `.claude/`, `.codex/`,
104
+ and `.pi/` as thin adapters to those mechanics. When changing startup, session
105
+ lifecycle, capture, skills, or commands, trace all three runtime entry points
106
+ and add or update a parity test. Do not call a framework change complete based
107
+ on one runtime alone. Regenerate derived Codex and Pi specifications or runtime
108
+ bundles whenever their sources change.
109
+
110
+ ---
111
+
112
+ ## Voice
113
+
114
+ Egregore's voice is governed by `.claude/rules/voice-bedrock.md` (always loaded). Register-specific skills: `egregore-voice` (external), `product-voice` (internal UX), `character-v4` (encounters), `alpha-openers` (outreach). See voice-bedrock for the full register map.
115
+
116
+ ---
117
+
99
118
  ## On Launch — MANDATORY FIRST ACTION
100
119
 
101
120
  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`.
@@ -146,19 +165,22 @@ If on develop after two messages, create a branch immediately from whatever cont
146
165
 
147
166
  ### Branch-guard protocol
148
167
 
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:
168
+ The `.codex/hooks/branch-guard.js` PreToolUse hook (enabled by the launcher via `--enable hooks`) protects project writes on `develop`/`main`/`master`. Its block message is operational guidance, not a reason to interrupt the user with routine Git choices:
150
169
 
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):
170
+ - **Topic is clear** (the user said "fix X", "add Y feature") → run `bin/agent.sh branch --topic "<topic>"` automatically, continue in the printed worktree, and say one short sentence so the branch change is visible. Do not ask the user to approve routine branching.
171
+ - **Topic is genuinely ambiguous** → ask only for the topic, using compact numbered options:
153
172
 
154
173
  ```text
155
- Need a working branch first. Topic?
174
+ What should I call this work?
156
175
  1. <suggested slug from context>
157
176
  2. <alternative slug>
158
177
  3. Other: (name it)
159
178
  ```
160
179
 
161
180
  Wait for the reply, then branch.
181
+ - **The user explicitly requested the protected branch** → that request is consent. Record it with `echo '{branch}' > .egregore-branch-consent`, then retry. Never create the marker merely to silence the hook.
182
+
183
+ Memory, managed-repo, and runtime-state writes should bypass the project guard. If one triggers it, correct the operation target/context instead of asking for protected-branch consent.
162
184
 
163
185
  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
186
 
@@ -170,7 +192,7 @@ If the startup card output contains `onboarding_needed`, invoke the `$onboarding
170
192
 
171
193
  ## Config Files
172
194
 
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.**
195
+ - **`egregore.json`** — committed. Non-secret org config: `org_name`, `github_org`, `memory_repo`, `slug`, `mode`. `api_url` is connected-mode only. Optional `boundary { posture, read[], locked }` sets the org's isolation posture (see Environment Isolation). **Never put secrets here.**
174
196
  - **`.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
197
 
176
198
  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.
@@ -179,7 +201,22 @@ In connected mode, infrastructure credentials (Neo4j, Telegram) live on the API
179
201
 
180
202
  ## Knowledge Graph
181
203
 
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.
204
+ **Connected mode only.** For the following intents, the named read must be the
205
+ first retrieval action. Run the exact command with its safe default limit before
206
+ opening files, running broad grep, inspecting `graph-op.sh`, or writing Cypher:
207
+
208
+ - current work addressed to someone → `bash bin/graph-op.sh open-handoffs "<user>"`
209
+ - unanswered questions for someone → `bash bin/graph-op.sh pending-questions "<user>"`
210
+ - handoff → implementation → branch/PR/direction → `bash bin/graph-op.sh lineage "<topic>"`
211
+ - company/person/topic across meetings → `bash bin/graph-op.sh meeting-history "<entity-or-topic>"`
212
+
213
+ A question about calls, meetings, transcripts, demos, or how a conversation
214
+ evolved is always `meeting-history` intent when it names a company, person, or
215
+ topic—even when it does not ask for "current" or "live" state. Pass the shortest
216
+ discriminative entity or topic (for example, `meeting-history "42CAP"`), not the
217
+ whole question.
218
+
219
+ Run `catalog` only when the route is unclear. Named reads return bounded stable fields and exact canonical `evidencePath` pointers; open only the returned files needed to answer. When a read reports partial coverage, use `unprojectedPaths` rather than claiming those files are represented in the graph. Use `bin/graph.sh` for unsupported Neo4j queries and never construct curl calls directly. See DEVELOPMENT.md §1 for the schema. In local mode there is no graph; read `memory/` directly.
183
220
 
184
221
  ---
185
222
 
@@ -244,6 +281,10 @@ main ← stable (/release)
244
281
  - **Memory repo**: stays on main (separate repo, auto-merge).
245
282
  - **Never push directly to main or develop.** All changes flow through PRs.
246
283
 
284
+ ### Pull request format (all harnesses)
285
+
286
+ Every PR body follows `.claude/context/pr-format.md`, enforced by the `pr-format` CI check regardless of which harness opened it: `## What` (1–4 bullets) + `## Why` (1–3 sentences) always; `## Verification` when the diff touches non-markdown files (how it was checked, or an honest `Not verified — <reason>`); `## Risk`/`## Links` when real; title `type(scope): imperative summary` (advisory). **Never create a PR with an empty body or `--fill`** — write the body and pass it explicitly (`gh pr create --body`, or `bin/agent.sh save --pr-body` for shell agents; the bridge auto-generates a compliant skeleton only as a last resort).
287
+
247
288
  ### Managed Repos
248
289
 
249
290
  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.
@@ -268,13 +309,13 @@ Invoke commands from user intent — don't wait for the slash. Each command file
268
309
  **Knowledge** — `$search` `$deep-reflect` `$archive` `$note` `$add` `$meeting` `$ingest` `$scroll`
269
310
  **Identity** — `$me` (view profile or set display name)
270
311
  **Coordination** — `$ask` `$quest` `$issue` `$invite` `$delete-user` `$announce`
271
- **Connectors** — `$telegram-connect` (Telegram group setup)
312
+ **Connectors** — `$telegram-connect` (Telegram group setup) `$teams-connect` (Microsoft Teams channel setup)
272
313
  **Git** — `$branch` `$commit` `$push` `$pr` `$save` `$review-pr` `$contribute`
273
314
  **Spirits** — `$summon` (persistent agent processes)
274
315
  **Infra** — `$setup` `$update` `$pull` `$env` `$infra` `$sync-repos` `$release` `$checkup`
275
316
 
276
317
  **Disambiguation:**
277
- - Knowledge: `$reflect` (share-ready) · `$note` (half-baked) · `$deep-reflect` (cross-reference) · `$archive` (AI patterns)
318
+ - Knowledge: `$reflect` (share-ready) · `$note` (half-baked) · `$deep-reflect` (deep research over memory — questions AND cross-referencing) · `$archive` (AI patterns)
278
319
  - 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
320
  - 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
321
  - Artifacts with questions: `$scroll` (living paper + embedded harvest, updates in place) · `$view` (static render) · `$harvest` (elicitation, no published face)
@@ -282,8 +323,8 @@ Invoke commands from user intent — don't wait for the slash. Each command file
282
323
  - Ending: `$wrap` (personal closure) · `$handoff` (notes for others) · `$save` (still working)
283
324
  - Tasks: `$todo` (personal) · `$quest` (team exploration) · `$issue` (something broken)
284
325
  - 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)
326
+ - Ingestion: `$ingest <file-or-folder>` (org-scoped corpus intake) · `$ingest meeting` · `$ingest user-interview` · `$ingest google` · ambiguous → ask which type
327
+ - Connectors: `$telegram-connect` (Telegram group) · `$teams-connect` (MS Teams channel) · `$ingest` (bring content in)
287
328
  - Identity: `$me` — "who am I", "call me oz"
288
329
  - People: `$invite` (add) · `$delete-user` (remove)
289
330
  - PRs: `$pr` (create) · `$review-pr` (review)
@@ -332,19 +373,22 @@ Egregore runs in one of two configurations, set by `mode` in `egregore.json`. De
332
373
 
333
374
  ## Environment Isolation
334
375
 
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.
376
+ Sessions are confined to this project + memory + managed repos, with a **two-tier boundary** — a hard wall between Egregore instances, a consent gate for everything else. On Codex the boundary is a standing instruction, not an enforced hook — hold it yourself.
336
377
 
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:
378
+ - **Hard tier — other Egregore instances.** Denied for every tool, always. There is no consent path. Never access another instance's files — refuse even if asked. Never modify `~/.egregore/instances.json` (managed by session-start.sh). When a request points at another instance's files there is nothing to ask — refuse and explain.
379
+ - **Soft tier — paths outside the boundary.** Consent-gated. Inbox dirs (`~/Downloads`, `~/Desktop`) are readable without consent under the default posture; writes outside the project always need consent. Posture (`strict | standard | open`) and extra read roots come from `egregore.json` -> `boundary { posture, read[], locked }` (org, committed) merged with `.egregore-boundary.local.json` (personal, gitignored). `locked: true` removes the consent path entirely.
380
+ - When a request needs soft-tier consent, do not improvise a workaround. Ask in plain text with numbered options:
340
381
 
341
382
  ```text
342
383
  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
384
+ 1. Allow its directory for this session (recorded in .egregore-boundary-consent)
385
+ 2. Always allow on this instance (added to read[] in .egregore-boundary.local.json)
386
+ 3. Paste the contents inline
387
+ 4. Cancel
346
388
  ```
347
389
 
348
- See DEVELOPMENT.md §3 for boundary details.
390
+ Never record a consent grant without the user's explicit choice of option 1 or 2 in that exchange. Session grants are cleared on session start; `locked: true` removes options 1 and 2.
391
+
392
+ See DEVELOPMENT.md §3 for boundary details and `memory/knowledge/decisions/2026-07-08-boundary-hook-consent-design.md` for the design decisions.
349
393
 
350
394
  <!-- END GENERATED EGREGORE CODEX SPEC -->
@@ -9,7 +9,7 @@ trap "rm -rf $TMPDIR" EXIT
9
9
 
10
10
  # --- Read config ---
11
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-)
12
+ API_KEY="${EGREGORE_API_KEY:-$(grep '^EGREGORE_API_KEY=' "$SCRIPT_DIR/.env" 2>/dev/null | cut -d'=' -f2-)}"
13
13
  ORG=$(jq -r '.org_name // "Egregore"' "$SCRIPT_DIR/egregore.json" 2>/dev/null || echo "Egregore")
14
14
  DATE=$(date '+%b %d')
15
15
 
@@ -32,9 +32,13 @@ Runtime-neutral commands:
32
32
  Hybrid recall over shared memory (qmd)
33
33
  people List known people from memory/people
34
34
  branch --topic TEXT Create or reuse a task branch/worktree
35
- save [--message TEXT] Commit and push current repo + memory changes
35
+ save [--message TEXT] [--pr-body TEXT|--pr-body-file PATH]
36
+ Commit and push current repo + memory changes;
37
+ PR body follows .claude/context/pr-format.md
38
+ (auto-generated skeleton if not provided)
36
39
  wrap --topic T --summary TEXT Write a session wrap to memory/wraps
37
- handoff --from A --to B --topic T [--body TEXT|--body-file PATH] [--no-push] [--no-publish] [--no-notify] [--json]
40
+ handoff --from A --to B --topic T [--intent action|feedback|fyi]
41
+ [--body TEXT|--body-file PATH] [--no-push] [--no-publish] [--no-notify] [--json]
38
42
  ask --from A --to B --topic T --question TEXT [--no-push]
39
43
  [--harvest-id ID --harvest-session-id ID --turn N
40
44
  --question-intent TEXT --context-mode blind|disclosed|comparative]
@@ -331,13 +335,26 @@ ensure_working_branch() {
331
335
  echo "$branch"
332
336
  }
333
337
 
338
+ build_pr_body() {
339
+ # Compliant fallback PR body (spec: .claude/context/pr-format.md) built
340
+ # from the commit log + diff when the calling agent supplies none.
341
+ local topic="${1:-portable save}" commits stat
342
+ commits="$(git -C "$SCRIPT_DIR" log --pretty='- %s' "origin/develop..HEAD" 2>/dev/null | head -8)"
343
+ [ -n "$commits" ] || commits="- (commit list unavailable — see the Files tab)"
344
+ stat="$(git -C "$SCRIPT_DIR" diff --shortstat "origin/develop...HEAD" 2>/dev/null | sed 's/^ *//')"
345
+ printf '## What\n%s\n\n## Why\nShell-agent session save — topic: %s. Body auto-generated by bin/agent.sh; pass --pr-body for a hand-written description.\n\n## Verification\nNot verified — auto-generated skeleton; review the diff before merging.%s\n\n🤖 Saved via bin/agent.sh\n' \
346
+ "$commits" "$topic" "${stat:+ ($stat)}"
347
+ }
348
+
334
349
  cmd_save() {
335
- local message="" topic="" no_pr=0 branch pushed="false" committed="false" pr_url="" existing_pr=""
350
+ local message="" topic="" no_pr=0 branch pushed="false" committed="false" pr_url="" existing_pr="" pr_number="" non_md="" merged="false" pr_body="" pr_body_file=""
336
351
 
337
352
  while [ $# -gt 0 ]; do
338
353
  case "$1" in
339
354
  --message|-m) message="${2:-}"; shift 2 ;;
340
355
  --topic) topic="${2:-}"; shift 2 ;;
356
+ --pr-body) pr_body="${2:-}"; shift 2 ;;
357
+ --pr-body-file) pr_body_file="${2:-}"; shift 2 ;;
341
358
  --no-pr) no_pr=1; shift ;;
342
359
  *) die "unknown save option: $1" ;;
343
360
  esac
@@ -375,7 +392,31 @@ cmd_save() {
375
392
  if [ -n "$existing_pr" ]; then
376
393
  pr_url="$existing_pr"
377
394
  else
378
- pr_url="$(gh pr create --base develop --head "$branch" --title "$message" --body "Saved via bin/agent.sh save." 2>/dev/null || true)"
395
+ if [ -z "$pr_body" ] && [ -n "$pr_body_file" ] && [ -f "$pr_body_file" ]; then
396
+ pr_body="$(cat "$pr_body_file")"
397
+ fi
398
+ [ -n "$pr_body" ] || pr_body="$(build_pr_body "$topic")"
399
+ pr_url="$(gh pr create --base develop --head "$branch" --title "$message" --body "$pr_body" 2>/dev/null || true)"
400
+ fi
401
+ fi
402
+
403
+ # Non-coding saves auto-merge to develop (same rule as /save and the
404
+ # handoff helper; policy in bin/lib/noncode.sh). `--auto` needs repo
405
+ # auto-merge + pending required checks; without branch protection it always
406
+ # errors, so fall back to a direct merge.
407
+ if [ -n "$pr_url" ]; then
408
+ # shellcheck source=bin/lib/noncode.sh
409
+ . "$SCRIPT_DIR/bin/lib/noncode.sh" 2>/dev/null || true
410
+ type noncode_blockers >/dev/null 2>&1 || noncode_blockers() {
411
+ git -C "${2:-.}" diff "${1:-origin/develop}...HEAD" --name-only 2>/dev/null | grep -v '\.md$' | head -1 || true
412
+ }
413
+ pr_number="${pr_url##*/}"
414
+ non_code="$(noncode_blockers origin/develop "$SCRIPT_DIR")"
415
+ if [ -z "$non_code" ] && [ -n "$pr_number" ]; then
416
+ if gh pr merge "$pr_number" --auto --merge >/dev/null 2>&1 \
417
+ || gh pr merge "$pr_number" --merge >/dev/null 2>&1; then
418
+ merged="true"
419
+ fi
379
420
  fi
380
421
  fi
381
422
 
@@ -383,6 +424,7 @@ cmd_save() {
383
424
  echo "commit: $committed"
384
425
  echo "push: $pushed"
385
426
  [ -n "$pr_url" ] && echo "pr: $pr_url"
427
+ [ "$merged" = "true" ] && echo "merge: non-coding, merged to develop"
386
428
  return 0
387
429
  }
388
430
 
@@ -413,31 +455,38 @@ cmd_wrap() {
413
455
  fi
414
456
  [ -n "$body" ] || body="$summary"
415
457
 
416
- local month rel abs slug now
417
- month="$(date +%Y-%m)"
418
- slug="$(slugify "$topic")"
419
- [ -n "$slug" ] || slug="session"
420
- rel="wraps/$month/$(date +%d)-${from}-${slug}.md"
421
- abs="$MEMORY_DIR/$rel"
422
- now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
423
- mkdir -p "$(dirname "$abs")"
424
-
425
- {
426
- printf '# Wrap: %s\n\n' "$topic"
427
- printf '**Date**: %s\n' "$(date +%Y-%m-%d)"
428
- printf '**Author**: %s\n' "$from"
429
- printf '**Wrapped At**: %s\n\n' "$now"
430
- printf '## Summary\n\n%s\n\n' "$summary"
431
- printf '## Notes\n\n%s\n' "$body"
432
- } > "$abs"
433
-
434
- NO_PUSH="$no_push" save_memory "Wrap: $topic" "$rel"
458
+ local tmpd result rel session_id branch
459
+ local capture_args=(--mode personal)
460
+ tmpd="$(mktemp -d -t egregore-agent-wrap-XXXXXX)"
461
+ trap 'rm -rf "$tmpd"' RETURN
462
+ session_id="$(cat "$SCRIPT_DIR/.egregore-session-id" 2>/dev/null || true)"
463
+ branch="$(git -C "$SCRIPT_DIR" branch --show-current 2>/dev/null || true)"
464
+ [ "$no_push" = "1" ] && capture_args+=(--no-push)
465
+
466
+ printf '%s\n' "$body" |
467
+ TMPDIR="$tmpd" bash "$SCRIPT_DIR/bin/capture-run.sh" \
468
+ "${capture_args[@]}" \
469
+ --author "$from" \
470
+ --topic "$topic" \
471
+ --summary "$summary" \
472
+ --session-id "$session_id" \
473
+ --branch "$branch" >/dev/null
474
+
475
+ result="$tmpd/capture-run-result.json"
476
+ rel="$(jq -r '.file // empty' "$result" 2>/dev/null || true)"
477
+ [ -n "$rel" ] || die "wrap was not created"
435
478
  echo "wrap: memory/$rel"
479
+
480
+ # Session close: non-coding core-repo changes save + merge themselves
481
+ # (gated inside session-autosave.sh — code is never auto-committed).
482
+ if [ "$no_push" = "0" ]; then
483
+ ( bash "$SCRIPT_DIR/bin/session-autosave.sh" --dir "$SCRIPT_DIR" >/dev/null 2>&1 & ) >/dev/null 2>&1
484
+ fi
436
485
  }
437
486
 
438
487
  cmd_handoff() {
439
488
  ensure_memory
440
- local from="" to="" topic="" body="" body_file="" project=""
489
+ local from="" to="" topic="" body="" body_file="" project="" intent="action"
441
490
  local no_publish=0 no_notify=0 json=0
442
491
  NO_PUSH=0
443
492
 
@@ -449,6 +498,7 @@ cmd_handoff() {
449
498
  --body) body="${2:-}"; shift 2 ;;
450
499
  --body-file) body_file="${2:-}"; shift 2 ;;
451
500
  --project) project="${2:-}"; shift 2 ;;
501
+ --intent) intent="${2:-}"; shift 2 ;;
452
502
  --no-push) NO_PUSH=1; shift ;;
453
503
  --no-publish) no_publish=1; shift ;;
454
504
  --no-notify) no_notify=1; shift ;;
@@ -460,6 +510,10 @@ cmd_handoff() {
460
510
  [ -z "$from" ] && from="$(person_from_state)"
461
511
  [ -n "$from" ] || die "handoff requires --from"
462
512
  [ -n "$topic" ] || die "handoff requires --topic"
513
+ case "$intent" in
514
+ action|feedback|fyi) ;;
515
+ *) die "invalid --intent: $intent (action|feedback|fyi)" ;;
516
+ esac
463
517
  if [ -n "$body_file" ]; then
464
518
  [ -f "$body_file" ] || die "body file not found: $body_file"
465
519
  body="$(cat "$body_file")"
@@ -480,6 +534,7 @@ cmd_handoff() {
480
534
  [ -n "$project" ] && project_line="**Project**: $project"
481
535
  [ -n "$to" ] && handoff_args+=(--recipient "$to")
482
536
  [ -n "$project" ] && handoff_args+=(--project "$project")
537
+ handoff_args+=(--intent "$intent")
483
538
  [ "$NO_PUSH" = "1" ] && handoff_args+=(--no-push)
484
539
  [ "$no_publish" = "1" ] && handoff_args+=(--no-publish)
485
540
  [ "$no_notify" = "1" ] && handoff_args+=(--no-notify)
@@ -489,10 +544,12 @@ cmd_handoff() {
489
544
  printf '**Date**: %s\n' "$today"
490
545
  printf '**Author**: %s\n' "$from"
491
546
  [ -n "$to" ] && printf '**To**: %s\n' "$to"
547
+ printf '**Intent**: %s\n' "$intent"
492
548
  [ -n "$project_line" ] && printf '%s\n' "$project_line"
493
549
  printf '\n## Briefing\n\n%s\n\n' "$body"
494
550
  printf '## Next Steps\n\n- Continue from this handoff using the shared Egregore memory protocol.\n'
495
- } | TMPDIR="$tmpd" bash "$SCRIPT_DIR/bin/handoff-run.sh" \
551
+ } | TMPDIR="$tmpd" bash "$SCRIPT_DIR/bin/capture-run.sh" \
552
+ --mode addressed \
496
553
  --author "$from" \
497
554
  --topic "$topic" \
498
555
  "${handoff_args[@]}" \
@@ -509,6 +566,12 @@ cmd_handoff() {
509
566
  [ -s "$stdout_file" ] && sed 's/^/status: /' "$stdout_file"
510
567
  echo "handoff: memory/$rel"
511
568
  echo "result: $result_out"
569
+
570
+ # Parity with the Claude /handoff skill: save core-repo session work in the
571
+ # background (non-coding diffs auto-merge to develop, code stays in a PR).
572
+ if [ "$NO_PUSH" = "0" ]; then
573
+ ( bash "$SCRIPT_DIR/bin/handoff-save-egregore.sh" "$from" "$topic" --repo-dir "$SCRIPT_DIR" >/dev/null 2>&1 & ) >/dev/null 2>&1
574
+ fi
512
575
  }
513
576
 
514
577
  cmd_ask() {