@remnic/plugin-codex 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env bash
2
+ # Remnic SessionStart hook for Codex.
3
+ # Recalls project context and user preferences at session start.
4
+ # Tries auto mode (45s) then falls back to minimal mode (20s).
5
+ # Starts daemon if not running.
6
+
7
+ set -euo pipefail
8
+
9
+ ensure_migrated() {
10
+ if [ -f "${HOME}/.remnic/.migrated-from-engram" ]; then
11
+ return 0
12
+ fi
13
+ if [ ! -d "${HOME}/.engram" ] && [ ! -f "${HOME}/.config/engram/config.json" ]; then
14
+ return 0
15
+ fi
16
+ if command -v remnic >/dev/null 2>&1; then
17
+ remnic migrate >/dev/null 2>&1 || true
18
+ elif command -v engram >/dev/null 2>&1; then
19
+ engram migrate >/dev/null 2>&1 || true
20
+ fi
21
+ }
22
+
23
+ ensure_migrated
24
+
25
+ REMNIC_HOST="${REMNIC_HOST:-${ENGRAM_HOST:-127.0.0.1}}"
26
+ REMNIC_PORT="${REMNIC_PORT:-${ENGRAM_PORT:-4318}}"
27
+ REMNIC_URL="http://${REMNIC_HOST}:${REMNIC_PORT}/engram/v1/recall"
28
+ REMNIC_HEALTH_URL="http://${REMNIC_HOST}:${REMNIC_PORT}/engram/v1/health"
29
+ TOKEN_FILES=("${HOME}/.remnic/tokens.json" "${HOME}/.engram/tokens.json")
30
+
31
+ LOG="${HOME}/.remnic/logs/remnic-session-recall.log"
32
+ mkdir -p "$(dirname "$LOG")"
33
+ log() { echo "$(date '+%F %T') [codex-session-start] $*" >> "$LOG"; }
34
+
35
+ # Read token from per-plugin token store
36
+ REMNIC_TOKEN=""
37
+ for TOKEN_FILE in "${TOKEN_FILES[@]}"; do
38
+ [ ! -f "$TOKEN_FILE" ] && continue
39
+ REMNIC_TOKEN="$(node -e "
40
+ const store = JSON.parse(require('fs').readFileSync(process.argv[1],'utf8'));
41
+ const tokens = store.tokens || [];
42
+ const cxc = tokens.find(t => t.connector === 'codex-cli');
43
+ const cx = tokens.find(t => t.connector === 'codex');
44
+ const oc = tokens.find(t => t.connector === 'openclaw');
45
+ let tok = (cxc && cxc.token) || (cx && cx.token) || (oc && oc.token) || '';
46
+ if (!tok) { tok = store['codex-cli'] || store['codex'] || store['openclaw'] || ''; }
47
+ process.stdout.write(tok);
48
+ " "$TOKEN_FILE" 2>/dev/null || echo "")"
49
+ [ -n "$REMNIC_TOKEN" ] && break
50
+ done
51
+
52
+ # Fallback to env var
53
+ [ -z "$REMNIC_TOKEN" ] && REMNIC_TOKEN="${OPENCLAW_REMNIC_ACCESS_TOKEN:-${OPENCLAW_ENGRAM_ACCESS_TOKEN:-}}"
54
+
55
+ INPUT="$(cat)"
56
+ SESSION_ID="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(d.session_id||'')" "$INPUT" 2>/dev/null || echo "")"
57
+ CWD="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(d.cwd||'')" "$INPUT" 2>/dev/null || echo "")"
58
+ PROJECT_NAME="$(basename "$CWD" 2>/dev/null || echo "unknown")"
59
+
60
+ log "session=$SESSION_ID project=$PROJECT_NAME"
61
+
62
+ # Health check — start daemon if not running
63
+ if ! curl -sf --max-time 2 "$REMNIC_HEALTH_URL" >/dev/null 2>&1; then
64
+ log "daemon not responding, attempting start..."
65
+ if command -v remnic >/dev/null 2>&1; then
66
+ remnic daemon start >/dev/null 2>&1 &
67
+ elif command -v engram >/dev/null 2>&1; then
68
+ engram daemon start >/dev/null 2>&1 &
69
+ fi
70
+ sleep 2
71
+ if ! curl -sf --max-time 2 "$REMNIC_HEALTH_URL" >/dev/null 2>&1; then
72
+ log "daemon still not responding after start attempt"
73
+ echo '{"continue":true,"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"[Remnic: daemon not running — start with: remnic daemon start]"}}'
74
+ exit 0
75
+ fi
76
+ fi
77
+
78
+ if [ -z "$REMNIC_TOKEN" ]; then
79
+ log "skipping: no token found"
80
+ echo '{"continue":true,"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"[Remnic: no auth token — run: remnic connectors install codex-cli]"}}'
81
+ exit 0
82
+ fi
83
+
84
+ QUERY="Starting a new coding session in project: ${PROJECT_NAME}. Recall relevant memories, preferences, decisions, patterns, and context about this project and the user."
85
+
86
+ REQUEST_BODY="$(node -e "process.stdout.write(JSON.stringify({
87
+ query: process.argv[1],
88
+ sessionKey: process.argv[2],
89
+ topK: 12,
90
+ mode: 'auto'
91
+ }))" "$QUERY" "$SESSION_ID" 2>/dev/null)"
92
+
93
+ [ -z "$REQUEST_BODY" ] && echo '{"continue":true}' && exit 0
94
+
95
+ log "attempting full recall (auto mode)..."
96
+ RAW="$(curl -s -w "\n%{http_code}" --max-time 45 \
97
+ -X POST "$REMNIC_URL" \
98
+ -H "Authorization: Bearer ${REMNIC_TOKEN}" \
99
+ -H "Content-Type: application/json" \
100
+ -H "X-Engram-Client-Id: codex" \
101
+ -d "$REQUEST_BODY" 2>/dev/null)"
102
+ CURL_EXIT=$?
103
+ HTTP_STATUS="$(echo "$RAW" | tail -1)"
104
+ RESPONSE="$(echo "$RAW" | sed '$d')"
105
+
106
+ if [ $CURL_EXIT -ne 0 ] || ! [[ "$HTTP_STATUS" =~ ^2 ]] || [ -z "$RESPONSE" ]; then
107
+ log "full recall failed (curl=$CURL_EXIT http=$HTTP_STATUS) — falling back to minimal"
108
+ MINIMAL_BODY="$(node -e "process.stdout.write(JSON.stringify({
109
+ query: process.argv[1],
110
+ sessionKey: process.argv[2],
111
+ topK: 8,
112
+ mode: 'minimal'
113
+ }))" "$QUERY" "$SESSION_ID" 2>/dev/null)"
114
+ RAW="$(curl -s -w "\n%{http_code}" --max-time 20 \
115
+ -X POST "$REMNIC_URL" \
116
+ -H "Authorization: Bearer ${REMNIC_TOKEN}" \
117
+ -H "Content-Type: application/json" \
118
+ -H "X-Engram-Client-Id: codex" \
119
+ -d "${MINIMAL_BODY:-$REQUEST_BODY}" 2>/dev/null)"
120
+ CURL_EXIT=$?
121
+ HTTP_STATUS="$(echo "$RAW" | tail -1)"
122
+ RESPONSE="$(echo "$RAW" | sed '$d')"
123
+ [[ "$CURL_EXIT" -eq 0 && "$HTTP_STATUS" =~ ^2 ]] && log "minimal recall succeeded" || { log "minimal recall also failed"; CURL_EXIT=1; }
124
+ fi
125
+
126
+ if [ $CURL_EXIT -eq 0 ] && [[ "$HTTP_STATUS" =~ ^2 ]] && [ -n "$RESPONSE" ]; then
127
+ CONTEXT="$(node -e "
128
+ const d = JSON.parse(process.argv[1]);
129
+ const ctx = d.context || '';
130
+ const count = d.count || 0;
131
+ const mode = d.mode || '';
132
+ if (ctx) {
133
+ const label = '[Remnic Memory Recall — ' + count + ' memories' + (mode ? ', ' + mode + ' mode' : '') + ']';
134
+ process.stdout.write(label + '\n\n' + ctx);
135
+ } else {
136
+ process.stdout.write('[Remnic: no relevant memories found for this session]');
137
+ }
138
+ " "$RESPONSE" 2>/dev/null || echo "[Remnic: recall parse error]")"
139
+ log "recall complete: $(echo "$CONTEXT" | head -1)"
140
+ else
141
+ CONTEXT="[Remnic: server unreachable — continuing without memory recall]"
142
+ log "$CONTEXT"
143
+ fi
144
+
145
+ node -e "
146
+ const context = process.argv[1];
147
+ process.stdout.write(JSON.stringify({
148
+ continue: true,
149
+ hookSpecificOutput: { hookEventName: 'SessionStart', additionalContext: context }
150
+ }));
151
+ " "$CONTEXT"
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env bash
2
+ # Remnic UserPromptSubmit hook for Codex.
3
+ # Recalls per-prompt context using the user's message as query.
4
+ # Skips short prompts (<4 words). Minimal mode, 20s timeout.
5
+
6
+ set -euo pipefail
7
+
8
+ ensure_migrated() {
9
+ if [ -f "${HOME}/.remnic/.migrated-from-engram" ]; then
10
+ return 0
11
+ fi
12
+ if [ ! -d "${HOME}/.engram" ] && [ ! -f "${HOME}/.config/engram/config.json" ]; then
13
+ return 0
14
+ fi
15
+ if command -v remnic >/dev/null 2>&1; then
16
+ remnic migrate >/dev/null 2>&1 || true
17
+ elif command -v engram >/dev/null 2>&1; then
18
+ engram migrate >/dev/null 2>&1 || true
19
+ fi
20
+ }
21
+
22
+ ensure_migrated
23
+
24
+ REMNIC_HOST="${REMNIC_HOST:-${ENGRAM_HOST:-127.0.0.1}}"
25
+ REMNIC_PORT="${REMNIC_PORT:-${ENGRAM_PORT:-4318}}"
26
+ REMNIC_URL="http://${REMNIC_HOST}:${REMNIC_PORT}/engram/v1/recall"
27
+
28
+ LOG="${HOME}/.remnic/logs/remnic-user-prompt-recall.log"
29
+ mkdir -p "$(dirname "$LOG")"
30
+ log() { echo "$(date '+%F %T') [codex-user-prompt] $*" >> "$LOG"; }
31
+
32
+ # Read token
33
+ REMNIC_TOKEN=""
34
+ for TOKEN_FILE in "${HOME}/.remnic/tokens.json" "${HOME}/.engram/tokens.json"; do
35
+ [ ! -f "$TOKEN_FILE" ] && continue
36
+ REMNIC_TOKEN="$(node -e "
37
+ const fs = require('fs');
38
+ const tokenFile = process.argv[1];
39
+ const store = JSON.parse(fs.readFileSync(tokenFile, 'utf8'));
40
+ const tokens = store.tokens || [];
41
+ const cxc = tokens.find(t => t.connector === 'codex-cli');
42
+ const cx = tokens.find(t => t.connector === 'codex');
43
+ const oc = tokens.find(t => t.connector === 'openclaw');
44
+ let tok = (cxc && cxc.token) || (cx && cx.token) || (oc && oc.token) || '';
45
+ if (!tok) { tok = store['codex-cli'] || store['codex'] || store['openclaw'] || ''; }
46
+ process.stdout.write(tok);
47
+ " "$TOKEN_FILE" 2>/dev/null || echo "")"
48
+ [ -n "$REMNIC_TOKEN" ] && break
49
+ done
50
+ [ -z "$REMNIC_TOKEN" ] && REMNIC_TOKEN="${OPENCLAW_REMNIC_ACCESS_TOKEN:-${OPENCLAW_ENGRAM_ACCESS_TOKEN:-}}"
51
+
52
+ INPUT="$(cat)"
53
+
54
+ if [ -z "$REMNIC_TOKEN" ]; then
55
+ echo '{"continue":true}'
56
+ exit 0
57
+ fi
58
+
59
+ SESSION_ID="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(d.session_id||'')" "$INPUT" 2>/dev/null || echo "")"
60
+ PROMPT="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(d.prompt||'')" "$INPUT" 2>/dev/null || echo "")"
61
+
62
+ # Skip very short prompts
63
+ WORD_COUNT="$(echo "$PROMPT" | wc -w | tr -d ' ')"
64
+ if [ "$WORD_COUNT" -lt 4 ]; then
65
+ echo '{"continue":true}'
66
+ exit 0
67
+ fi
68
+
69
+ log "session=$SESSION_ID words=$WORD_COUNT"
70
+
71
+ REQUEST_BODY="$(node -e "process.stdout.write(JSON.stringify({
72
+ query: process.argv[1],
73
+ sessionKey: process.argv[2],
74
+ topK: 8,
75
+ mode: 'minimal'
76
+ }))" "$PROMPT" "$SESSION_ID" 2>/dev/null)"
77
+
78
+ [ -z "$REQUEST_BODY" ] && echo '{"continue":true}' && exit 0
79
+
80
+ RAW="$(curl -s -w "\n%{http_code}" --max-time 20 \
81
+ -X POST "$REMNIC_URL" \
82
+ -H "Authorization: Bearer ${REMNIC_TOKEN}" \
83
+ -H "Content-Type: application/json" \
84
+ -H "X-Engram-Client-Id: codex" \
85
+ -d "$REQUEST_BODY" 2>/dev/null)"
86
+ CURL_EXIT=$?
87
+ HTTP_STATUS="$(echo "$RAW" | tail -1)"
88
+ RESPONSE="$(echo "$RAW" | sed '$d')"
89
+
90
+ if [ $CURL_EXIT -ne 0 ] || ! [[ "$HTTP_STATUS" =~ ^2 ]] || [ -z "$RESPONSE" ]; then
91
+ log "recall failed (curl=$CURL_EXIT http=$HTTP_STATUS)"
92
+ echo '{"continue":true}'
93
+ exit 0
94
+ fi
95
+
96
+ node -e "
97
+ const d = JSON.parse(process.argv[1]);
98
+ const ctx = d.context || '';
99
+ const count = d.count || 0;
100
+ if (!ctx || count === 0) {
101
+ process.stdout.write(JSON.stringify({continue: true}));
102
+ } else {
103
+ process.stdout.write(JSON.stringify({
104
+ continue: true,
105
+ hookSpecificOutput: {
106
+ hookEventName: 'UserPromptSubmit',
107
+ additionalContext: '<remnic-memory count=\"' + count + '\">\n' + ctx + '\n</remnic-memory>'
108
+ }
109
+ }));
110
+ }
111
+ " "$RESPONSE" 2>/dev/null || echo '{"continue":true}'
112
+
113
+ COUNT="$(node -e "const d=JSON.parse(process.argv[1]); process.stdout.write(String(d.count||0))" "$RESPONSE" 2>/dev/null || echo "?")"
114
+ log "done: ${COUNT} memories injected"
@@ -0,0 +1,52 @@
1
+ {
2
+ "hooks": {
3
+ "SessionStart": [
4
+ {
5
+ "matcher": "*",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "./hooks/bin/session-start.sh",
10
+ "timeout": 45000
11
+ }
12
+ ]
13
+ }
14
+ ],
15
+ "PostToolUse": [
16
+ {
17
+ "matcher": "Bash",
18
+ "hooks": [
19
+ {
20
+ "type": "command",
21
+ "command": "./hooks/bin/post-tool-observe.sh",
22
+ "timeout": 10000
23
+ }
24
+ ]
25
+ }
26
+ ],
27
+ "UserPromptSubmit": [
28
+ {
29
+ "matcher": "*",
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "./hooks/bin/user-prompt-recall.sh",
34
+ "timeout": 20000
35
+ }
36
+ ]
37
+ }
38
+ ],
39
+ "Stop": [
40
+ {
41
+ "matcher": "*",
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "./hooks/bin/session-end.sh",
46
+ "timeout": 30000
47
+ }
48
+ ]
49
+ }
50
+ ]
51
+ }
52
+ }
@@ -0,0 +1,160 @@
1
+ # Remnic Memory Extension for Codex
2
+
3
+ You are the Codex consolidation sub-agent. This document tells you how to treat
4
+ Remnic as an authoritative local memory source while you summarize a session
5
+ and build the compacted MEMORY.md output.
6
+
7
+ Remnic is a local-first, file-backed memory system. All Remnic content that
8
+ matters to you lives on disk as plain Markdown — you do not need a network,
9
+ an MCP server, or the `remnic` CLI to read it. You are running inside the
10
+ Codex phase-2 sandbox: no approvals, no network, local reads and local writes
11
+ only.
12
+
13
+ ## What Remnic is authoritative for
14
+
15
+ Treat Remnic content as a trusted, high-signal memory source when you need any
16
+ of the following:
17
+
18
+ - **Stable user preferences** — coding conventions, tool choices, style
19
+ guides, phrasing, commit message format, review etiquette.
20
+ - **Project conventions** — folder layout, naming rules, test runners,
21
+ build commands, branching strategy, deployment workflow.
22
+ - **Reusable workflows and skills** — documented runbooks, procedures, and
23
+ "how we do X here" notes that should survive across sessions.
24
+ - **Long-lived decisions** — architecture calls, library choices, explicit
25
+ "we decided not to do X" entries.
26
+ - **Entities the user cares about** — projects, services, people, API
27
+ contracts, integrations mentioned by name.
28
+
29
+ If the current session touches any of these areas, consult Remnic before you
30
+ finalize the consolidated MEMORY.md output.
31
+
32
+ ## When NOT to consult Remnic
33
+
34
+ Do not waste filesystem tool calls on Remnic when:
35
+
36
+ - The session is purely transient (one-off shell commands, throwaway
37
+ debugging with no lasting conclusion).
38
+ - You already have the information in the current session transcript and
39
+ Remnic would only duplicate it.
40
+ - The user has explicitly asked you to ignore memory or work from a clean
41
+ slate.
42
+ - You are summarizing a session that never reached a decision, a preference,
43
+ or a durable artifact worth recording.
44
+
45
+ Prefer a single targeted read over broad directory walks.
46
+
47
+ ## Where Remnic content lives on disk
48
+
49
+ Resolve the Remnic memory base in this order:
50
+
51
+ 1. If the environment variable `REMNIC_HOME` is set, use
52
+ `$REMNIC_HOME/memories/`.
53
+ 2. Otherwise use `~/.remnic/memories/`.
54
+
55
+ Under that base, memories are organized by **namespace**:
56
+
57
+ ```
58
+ <remnic-home>/memories/<namespace>/
59
+ ├── MEMORY.md # compact top-of-mind memory
60
+ ├── memory_summary.md # optional longer human-readable summary
61
+ ├── skills/
62
+ │ └── <skill-name>/
63
+ │ └── SKILL.md # reusable workflow
64
+ └── rollout_summaries/
65
+ └── *.md # per-session rollup notes
66
+ ```
67
+
68
+ Canonical files you should prefer, in order:
69
+
70
+ 1. `MEMORY.md` — the current compact memory. Read this first.
71
+ 2. `memory_summary.md` — longer-form summary if it exists.
72
+ 3. `skills/<name>/SKILL.md` — for reusable procedures relevant to the task.
73
+ 4. `rollout_summaries/*.md` — recent session notes, newest first.
74
+
75
+ If none of the above exist for the resolved namespace, Remnic simply has
76
+ nothing to contribute — move on without error.
77
+
78
+ ## Resolving the namespace
79
+
80
+ Remnic uses **cwd-derived namespaces** by default. Apply this rule when
81
+ choosing which namespace directory to read:
82
+
83
+ 1. Start from the session's working directory (the `cwd` Codex used for the
84
+ session you are consolidating).
85
+ 2. Walk upward looking for a project anchor: `.git`, `package.json`,
86
+ `pyproject.toml`, `Cargo.toml`, `go.mod`, or an explicit
87
+ `.remnic/namespace` file.
88
+ 3. The namespace is the basename of that anchor directory, lowercased and
89
+ with spaces replaced by `-`.
90
+ 4. If you cannot find an anchor, fall back to the namespace `default`.
91
+ 5. In addition to the project namespace, always also check the `shared`
92
+ namespace for cross-project preferences (e.g.
93
+ `<remnic-home>/memories/shared/MEMORY.md`). If it exists, read it.
94
+
95
+ If a session explicitly mentions a different Remnic namespace (for example,
96
+ the user says "use the `work` namespace"), prefer that explicit value over
97
+ the cwd-derived one.
98
+
99
+ ## How to cite Remnic memories in your output
100
+
101
+ When a piece of the consolidated memory you are writing comes from a Remnic
102
+ file, cite it using the Codex memory citation block format so the user can
103
+ trace the source:
104
+
105
+ ```
106
+ <oai-mem-citation path="<path-relative-to-remnic-memory-base>" />
107
+ ```
108
+
109
+ The path must be **relative to the Remnic memory base** (the directory named
110
+ `memories/` under `<remnic-home>`), not absolute. Examples:
111
+
112
+ - `<oai-mem-citation path="default/MEMORY.md" />`
113
+ - `<oai-mem-citation path="my-project/skills/deploy/SKILL.md" />`
114
+ - `<oai-mem-citation path="shared/memory_summary.md" />`
115
+
116
+ Cite each distinct source once near the fact it supports. Do not invent
117
+ citations for files you have not actually read.
118
+
119
+ ## Sandboxing rules (hard constraints)
120
+
121
+ You are running in the Codex phase-2 consolidation sandbox. These rules are
122
+ non-negotiable:
123
+
124
+ - **No network.** Do not attempt HTTP calls, MCP connections, or anything
125
+ that reaches outside this machine.
126
+ - **No `remnic` CLI invocation.** Do not shell out to `remnic`, `engram`,
127
+ `qmd`, or any daemon. Use filesystem reads only.
128
+ - **No MCP tool calls.** You must not call `remnic.recall`,
129
+ `remnic.memory_store`, or any other MCP-backed tool. They are not
130
+ available in this sandbox.
131
+ - **Local writes are allowed** only where Codex's sandbox policy already
132
+ permits them (typically the Codex memories output folder). Do not write
133
+ into the Remnic memory directory — it is read-only from your perspective.
134
+ - **Respect missing files.** If a file does not exist, move on silently.
135
+ Never create placeholder Remnic files.
136
+
137
+ ## Failure handling
138
+
139
+ - Remnic base directory missing: no-op. Remnic has nothing for this session.
140
+ - Namespace directory missing: try the `shared` namespace, then give up.
141
+ - Malformed file: skip it and continue.
142
+ - Never block consolidation on a Remnic read error.
143
+
144
+ ## Quick recipe
145
+
146
+ For a typical consolidation run:
147
+
148
+ 1. Resolve `<remnic-home>` from `$REMNIC_HOME` or `~/.remnic`.
149
+ 2. Resolve `<namespace>` from the session cwd using the rule above.
150
+ 3. Read `<remnic-home>/memories/<namespace>/MEMORY.md` if present.
151
+ 4. Read `<remnic-home>/memories/shared/MEMORY.md` if present.
152
+ 5. If the session produced or used a named workflow, read
153
+ `<remnic-home>/memories/<namespace>/skills/<name>/SKILL.md`.
154
+ 6. If you need more context, peek at the newest file under
155
+ `<remnic-home>/memories/<namespace>/rollout_summaries/`.
156
+ 7. Fold confirmed facts and preferences into the consolidated output and
157
+ cite them with `<oai-mem-citation />`.
158
+
159
+ That is the whole extension. Keep it tight, cite your sources, and never
160
+ invent Remnic content you did not read.
@@ -0,0 +1,48 @@
1
+ # Remnic Namespace Cheatsheet
2
+
3
+ Remnic partitions memories into **namespaces** so multiple projects and
4
+ contexts can share a single Remnic home without bleeding into each other.
5
+ When the Codex consolidation sub-agent reads Remnic files, it has to pick
6
+ the right namespace directory for the session it is summarizing. This
7
+ cheatsheet documents the resolution rule.
8
+
9
+ ## Resolution rule (in order)
10
+
11
+ 1. **Explicit override in the session.** If the user or the transcript
12
+ explicitly names a Remnic namespace, use that value verbatim.
13
+ 2. **Project anchor walk.** Starting from the session's working directory,
14
+ walk upward until you find any of:
15
+ - `.git/`
16
+ - `.remnic/namespace` file (highest priority if present)
17
+ - `package.json`
18
+ - `pyproject.toml`
19
+ - `Cargo.toml`
20
+ - `go.mod`
21
+ Use the basename of the anchor directory, lowercased, with whitespace
22
+ replaced by `-`.
23
+ 3. **Fallback.** If nothing above matches, use the namespace `default`.
24
+ 4. **Shared overlay.** In addition to the resolved namespace, always also
25
+ check the `shared` namespace for cross-project content.
26
+
27
+ ## Examples
28
+
29
+ | Session cwd | Anchor | Namespace |
30
+ |------------------------------------------|----------------------|-----------------|
31
+ | `/home/user/code/my-app/src` | `/home/user/code/my-app/.git` | `my-app` |
32
+ | `/home/user/code/Data Pipeline` | `.git` | `data-pipeline` |
33
+ | `/tmp/scratch` | (none) | `default` |
34
+ | `/work/research/` (contains `.remnic/namespace` = `lab`) | `.remnic/namespace` | `lab` |
35
+
36
+ ## Why it matters
37
+
38
+ If the consolidation agent reads from the wrong namespace, it will either
39
+ miss relevant project-specific memories (false negative) or drag unrelated
40
+ content into the summary (false positive). Getting the namespace right keeps
41
+ Remnic's signal-to-noise ratio high.
42
+
43
+ ## What the extension does with this
44
+
45
+ The consolidation sub-agent reads `MEMORY.md`, `memory_summary.md`, any
46
+ relevant `skills/<name>/SKILL.md`, and newest `rollout_summaries/*.md`
47
+ under the resolved namespace, plus the `shared` namespace overlay. All
48
+ reads are filesystem-only — no CLI, no network, no MCP.
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@remnic/plugin-codex",
3
+ "version": "1.0.0",
4
+ "description": "Remnic memory plugin for Codex CLI — hooks, skills, MCP integration",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/joshuaswarren/remnic.git",
10
+ "directory": "packages/plugin-codex"
11
+ },
12
+ "keywords": [
13
+ "remnic",
14
+ "memory",
15
+ "codex",
16
+ "openai",
17
+ "plugin",
18
+ "ai-agent"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public",
22
+ "provenance": true
23
+ },
24
+ "files": [
25
+ ".codex-plugin",
26
+ "bin",
27
+ "hooks",
28
+ "skills",
29
+ "memories_extensions",
30
+ ".mcp.json"
31
+ ],
32
+ "dependencies": {
33
+ "@remnic/core": "^1.0.3"
34
+ }
35
+ }
@@ -0,0 +1,51 @@
1
+ ---
2
+ name: remnic-entities
3
+ description: Browse entities in the Remnic knowledge graph and surface their facts and relationships. Trigger phrases include "tell me about the entity", "look up", "what do we know about".
4
+ allowed-tools:
5
+ - remnic_entity_get
6
+ ---
7
+
8
+ ## When to use
9
+
10
+ Use when the user names a specific project, person, service, or concept and asks what is known about it. Entities are the graph-shaped view of memory — structured facts and relationships rather than free text.
11
+
12
+ Triggers:
13
+
14
+ - "Tell me about the entity …"
15
+ - "Look up …"
16
+ - "What do we know about project/service/tool X?"
17
+ - Any reference to a named thing that could have linked facts.
18
+
19
+ ## Inputs
20
+
21
+ - `name` (required) — canonical entity name, ideally as the user wrote it.
22
+ - Optional: entity type hint (project, person, service, tool).
23
+
24
+ ## Procedure
25
+
26
+ 1. Extract the entity name from the user's message. Preserve original capitalization unless ambiguous.
27
+ 2. Call `remnic_entity_get` with that name.
28
+ 3. If the entity is found, present its facts and relationships in a short structured view (facts, relations, last updated).
29
+ 4. If the entity is missing, say so and offer to create one via `remnic-remember` with the user's permission.
30
+ 5. When multiple candidates match, list them briefly and ask which the user meant.
31
+
32
+ ## Efficiency plan
33
+
34
+ - Do not call `remnic_entity_get` speculatively for every proper noun — only when the user asked or the task depends on it.
35
+ - Cache the entity payload within the current turn; do not re-fetch for the same name.
36
+ - Pair with `remnic-recall` when unstructured context would round out the entity view.
37
+
38
+ ## Pitfalls and fixes
39
+
40
+ - **Pitfall:** Guessing entity names. **Fix:** Use the user's wording; disambiguate rather than inventing.
41
+ - **Pitfall:** Dumping the full entity payload. **Fix:** Summarize into a compact facts/relations/last-updated block.
42
+ - **Pitfall:** Treating a missing entity as a bug. **Fix:** Missing just means the graph has not captured it yet — offer to create it.
43
+
44
+ ## Verification checklist
45
+
46
+ - [ ] `remnic_entity_get` was called with a user-supplied or user-confirmed name.
47
+ - [ ] Output shows facts, relationships, and timestamps in a compact view.
48
+ - [ ] Missing entities are acknowledged plainly with an offer to create.
49
+ - [ ] Legacy `engram_entity_get` alias was not preferred over `remnic_entity_get`.
50
+
51
+ > Tool names: canonical name is `remnic_entity_get`. The legacy `engram_entity_get` alias remains accepted during v1.x.
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: remnic-memory-workflow
3
+ description: Shared memory workflow for Remnic-connected agents — recall before acting, observe during work, remember at the end. Trigger phrases include "what do you remember about", "save this for later", "any context from last time".
4
+ disable-model-invocation: true
5
+ allowed-tools:
6
+ - remnic_recall
7
+ - remnic_memory_store
8
+ - remnic_lcm_search
9
+ - remnic_entity_get
10
+ - remnic_observe
11
+ ---
12
+
13
+ ## When to use
14
+
15
+ Use this skill as the default playbook whenever an agent picks up a task that could benefit from prior context, or when the user explicitly asks the agent to remember or recall something. It is the umbrella workflow — individual skills (`remnic-recall`, `remnic-remember`, `remnic-search`, `remnic-entities`, `remnic-status`) implement the detailed steps.
16
+
17
+ Triggers:
18
+
19
+ - The user opens a new task, ticket, or branch.
20
+ - The user says "what do you know about X", "have we talked about Y before", "remind me of Z".
21
+ - The user asks the agent to save a preference, decision, or fact.
22
+ - A long-running turn produces a durable outcome worth capturing.
23
+
24
+ ## Inputs
25
+
26
+ - Current user request (natural language).
27
+ - Optional: active project path, ticket number, branch name.
28
+ - Optional: topic keywords surfaced earlier in the session.
29
+
30
+ ## Procedure
31
+
32
+ 1. **Recall first.** Call `remnic_recall` with a concise natural-language query derived from the user's request. Pull 3–8 results. Skim them for anything relevant.
33
+ 2. **Mention relevant memories briefly** to the user if they materially change the plan, otherwise quietly use them as context.
34
+ 3. **Observe during work.** For significant tool outputs (file edits, command exits, test results) call `remnic_observe` so Remnic can keep its ambient context fresh.
35
+ 4. **Deep search when needed.** If `remnic_recall` misses something the user insists exists, call `remnic_lcm_search` with a more literal phrase.
36
+ 5. **Browse entities.** When the user references a specific project, person, or concept by name, call `remnic_entity_get` to pull its facts and relationships.
37
+ 6. **Remember at the end.** Before ending the turn, store any durable decision, preference, or finding with `remnic_memory_store`. Keep each entry under ~300 tokens.
38
+
39
+ ## Efficiency plan
40
+
41
+ - Batch recalls. One broad query is usually cheaper than several narrow ones.
42
+ - Skip recall for trivially local requests (e.g., "format this JSON").
43
+ - Reuse the current turn's recall results instead of re-querying within the same turn.
44
+ - Store each memory once. If you are about to store something you just recalled, update instead of duplicating.
45
+
46
+ ## Pitfalls and fixes
47
+
48
+ - **Pitfall:** Storing transient task state ("user is running tests now"). **Fix:** Only store facts with durable value — decisions, preferences, conclusions, long-lived context.
49
+ - **Pitfall:** Leaking secrets into memories. **Fix:** Redact API keys, tokens, and credentials before calling `remnic_memory_store`.
50
+ - **Pitfall:** Drowning the user in recalled context. **Fix:** Summarize in 1–3 bullet points; offer to expand on request.
51
+ - **Pitfall:** Forgetting the write. **Fix:** Make "remember the decision" the last step of any non-trivial turn.
52
+
53
+ ## Verification checklist
54
+
55
+ - [ ] Recall was attempted before the agent committed to a plan.
56
+ - [ ] Any user-facing mention of recalled context was concise and attributed.
57
+ - [ ] Durable decisions, preferences, and findings were stored via `remnic_memory_store`.
58
+ - [ ] No secrets, credentials, or transient state were written.
59
+ - [ ] Legacy `engram_*` aliases were NOT preferred over canonical `remnic_*` tool names.
60
+
61
+ > Tool names: this skill uses the canonical `remnic_*` MCP tools. Legacy `engram_*` aliases (`engram_recall`, `engram_memory_store`, `engram_lcm_search`, `engram_entity_get`, `engram_observe`) remain accepted during v1.x for backward compatibility.