Skip to content

Add eidetic remember/recall memory skills#2

Open
OriNachum wants to merge 1 commit into
mainfrom
rollout/eidetic-memory
Open

Add eidetic remember/recall memory skills#2
OriNachum wants to merge 1 commit into
mainfrom
rollout/eidetic-memory

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

Vendors eidetic-cli's first-party remember + recall memory skills into this repo's .claude/skills/ kit (cite-don't-import), giving this agent a shared, persistent memory surface (~/.eidetic/memory) that Claude and the colleague backend both read and write.

  • remembereidetic remember: idempotent upsert of one JSON record or an NDJSON batch on stdin (dedup by id + content hash).
  • recalleidetic recall: four search modes (exact / approximate / keyword / hybrid), each hit carrying text, full provenance metadata, a relevance score, and a freshness signal.

The .sh wrappers are byte-verbatim from eidetic-cli (their first-party origin); this repo's SKILL.md scope examples are localized to its own nick. Version bumped + CHANGELOG updated per the AgentCulture rule. Runtime dep: the eidetic CLI on PATH (else a local eidetic-cli checkout + uv).

Propagated by rollout-cli's eidetic-memory recipe (origin: agentculture/eidetic-cli). Squash-merge at your discretion.

🤖 Generated with Claude Code

  • rollout-cli (Claude)

- **Vendored the `remember` + `recall` memory skills from eidetic-cli**
  (cite-don't-import) — the write/read halves of eidetic's shared
  `~/.eidetic/memory` surface, so this agent (Claude and its colleague backend)
  can persist facts across sessions and recall them later, sharing one store.
  `remember` drives `eidetic remember` (idempotent upsert of one JSON record or
  an NDJSON batch on stdin, dedup by id + content hash); `recall` drives
  `eidetic recall` with four search modes — exact / approximate / keyword /
  hybrid — each hit carrying text, full provenance metadata, a relevance score,
  and a freshness signal. The `.sh` wrappers are byte-verbatim from eidetic-cli
  (their first-party origin); each `SKILL.md` is localized only in the
  illustrative `--scope <nick>` examples (Provenance keeps "First-party to
  eidetic-cli"). Both default to this agent's PRIVATE scope, reading the suffix
  from `culture.yaml`. Runtime dep: the `eidetic` CLI on PATH (else a local
  eidetic-cli checkout with `uv`). Propagated by rollout-cli's `eidetic-memory`
  recipe.
@qodo-code-review

Copy link
Copy Markdown

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: test-publish

Failed stage: Build and publish to TestPyPI [❌]

Failed test name: ""

Failure summary:

The action failed during the uv publish step when attempting PyPI Trusted Publishing to TestPyPI.
-
uv publish --publish-url https://test.pypi.org/legacy/ --trusted-publishing always could not obtain
an OIDC token (exit code 2).
- TestPyPI returned 422 Unprocessable Entity with invalid-publisher:
the token was valid, but TestPyPI could not find a configured Trusted Publisher matching the GitHub
OIDC claims.
- The token claims indicate this ran from
agentculture/reduce-cli/.github/workflows/publish.yml@refs/pull/2/merge with environment testpypi
(sub: repo:agentculture/reduce-cli:environment:testpypi), which must exactly match a Trusted
Publisher configuration on TestPyPI; it appears that configuration is missing or does not match
these claims (e.g., wrong repo/workflow ref/environment).

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

194:  ##[endgroup]
195:  Publishing 0.3.0.dev3 to TestPyPI
196:  ##[group]Run uv build
197:  �[36;1muv build�[0m
198:  �[36;1muv publish --publish-url https://test.pypi.org/legacy/ --trusted-publishing always --check-url https://test.pypi.org/simple/�[0m
199:  shell: /usr/bin/bash -e {0}
200:  env:
201:  UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
202:  DEV_VERSION: 0.3.0.dev3
203:  ##[endgroup]
204:  Building source distribution...
205:  Building wheel from source distribution...
206:  Successfully built dist/reduce_cli-0.3.0.dev3.tar.gz
207:  Successfully built dist/reduce_cli-0.3.0.dev3-py3-none-any.whl
208:  Publishing 2 files to https://test.pypi.org/legacy/
209:  error: Failed to obtain token for trusted publishing
210:  Caused by: Server returned error code 422 Unprocessable Entity, is trusted publishing correctly configured?
211:  Response: {"errors":[{"code":"invalid-publisher","description":"valid token, but no corresponding publisher (Publisher with matching claims was not found)"}],"message":"Token request failed"}
212:  Token claims, which must match the publisher configuration: GitHub(
213:  GitHubTokenClaims {
214:  sub: "repo:agentculture/reduce-cli:environment:testpypi",
215:  repository: "agentculture/reduce-cli",
216:  repository_owner: "agentculture",
217:  repository_owner_id: "277824871",
218:  job_workflow_ref: "agentculture/reduce-cli/.github/workflows/publish.yml@refs/pull/2/merge",
219:  ref: "refs/pull/2/merge",
220:  environment: Some(
221:  "testpypi",
222:  ),
223:  },
224:  )
225:  ##[error]Process completed with exit code 2.
226:  ##[group]Run echo "::notice::Test with: uv tool install --index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match reduce-cli==${DEV_VERSION}"

@sonarqubecloud

Copy link
Copy Markdown

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Vendor eidetic remember/recall memory skills
✨ Enhancement 📝 Documentation ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

Description

• Vendor /remember and /recall skills for shared, persistent eidetic memory.
• Add portable wrappers that resolve eidetic and default to private per-repo scope.
• Bump version to 0.3.0 and record the release in CHANGELOG.
Diagram

graph TD
  Agent(["Claude / colleague backend"]) --> Remember["remember.sh"] --> Eidetic["eidetic CLI"] --> Store[("~/.eidetic/memory")]
  Agent --> Recall["recall.sh"] --> Eidetic
  Remember --> Culture["culture.yaml"]
  Recall --> Culture
  Eidetic --> Embed{{"Embed server"}}
  Eidetic --> Remote[("Mongo/Neo4j (opt)")]

  subgraph Legend
    direction LR
    _a(["Agent"]) ~~~ _f["Script / config"] ~~~ _d[("Data store")] ~~~ _e{{"External"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use a Python wrapper/module instead of bash scripts
  • ➕ Easier unit testing and structured argument handling
  • ➕ More consistent behavior across shells/OS environments
  • ➖ Introduces a runtime Python dependency path for skills
  • ➖ Increases coupling/maintenance burden for something eidetic-cli already owns
2. Treat eidetic-cli as a formal dependency (no vendoring)
  • ➕ Single upstream source; no drift between repos
  • ➕ Less duplicated documentation in downstream repos
  • ➖ Breaks the repo’s cite-don’t-import vendoring practice for skills
  • ➖ Harder to keep skill UX stable if upstream changes unexpectedly
3. Integrate memory directly into reduce-cli (no external `eidetic` CLI)
  • ➕ No external CLI install required
  • ➕ Full control over storage/search implementation
  • ➖ Large scope increase; re-implements a dedicated subsystem
  • ➖ Higher security/consistency risk vs delegating to eidetic’s first-party implementation

Recommendation: The current approach (vendored skill docs + thin, byte-verbatim bash wrappers delegating to the eidetic CLI) is the best tradeoff for this repo: it keeps the skill kit self-contained, preserves eidetic-cli as the single owner of the memory surface, and minimizes ongoing maintenance while still providing consistent scope defaults via culture.yaml. The main follow-up to consider is documenting the new skill provenance in docs/skill-sources.md to keep the vendoring ledger complete.

Files changed (6) +599 / -1

Enhancement (2) +279 / -0
recall.shAdd recall.sh wrapper with CLI resolution and private scope defaults +141/-0

Add recall.sh wrapper with CLI resolution and private scope defaults

• Adds a portable bash wrapper that resolves 'eidetic' from PATH or falls back to 'uv run' inside an eidetic-cli checkout. If '--scope' is not provided, it derives scope suffix from the nearest 'culture.yaml' and injects '--visibility private' unless explicitly overridden; also sets default embedding env vars for semantic modes.

.claude/skills/recall/scripts/recall.sh

remember.shAdd remember.sh wrapper with CLI resolution and private scope defaults +138/-0

Add remember.sh wrapper with CLI resolution and private scope defaults

• Adds a portable bash wrapper for 'eidetic remember' supporting single JSON object args or NDJSON batches on stdin. Resolves the 'eidetic' CLI (PATH first, 'uv run' fallback), injects a default per-repo scope from 'culture.yaml' when '--scope' is absent, and defaults visibility to private unless overridden.

.claude/skills/remember/scripts/remember.sh

Documentation (3) +319 / -0
SKILL.mdAdd /recall skill docs for eidetic memory search +181/-0

Add /recall skill docs for eidetic memory search

• Introduces SKILL.md describing '/recall' as a front door to 'eidetic recall', including the four search modes, output fields, freshness signal, lifecycle flags, and usage examples. Documents defaulting to the agent’s private per-repo scope derived from 'culture.yaml', and that the store lives in '~/.eidetic/memory'.

.claude/skills/recall/SKILL.md

SKILL.mdAdd /remember skill docs for eidetic memory ingest +118/-0

Add /remember skill docs for eidetic memory ingest

• Introduces SKILL.md documenting '/remember' as a wrapper around 'eidetic remember', including record shape, idempotent upsert/dedup behavior, and scope/visibility behavior. Emphasizes default private per-repo scope from 'culture.yaml' and the shared '~/.eidetic/memory' store semantics.

.claude/skills/remember/SKILL.md

CHANGELOG.mdDocument 0.3.0 release adding eidetic memory skills +20/-0

Document 0.3.0 release adding eidetic memory skills

• Adds a 0.3.0 entry describing the newly vendored 'remember' and 'recall' skills, their behavior, default scope handling, and the runtime dependency on the 'eidetic' CLI. Notes that the wrappers are byte-verbatim from eidetic-cli and propagated via rollout-cli recipe.

CHANGELOG.md

Other (1) +1 / -1
pyproject.tomlBump project version to 0.3.0 +1/-1

Bump project version to 0.3.0

• Updates the project version from 0.2.0 to 0.3.0 to match the new feature release documented in the changelog.

pyproject.toml

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Broken uv fallback lookup 🐞 Bug ☼ Reliability
Description
recall.sh/remember.sh claim a dev-checkout fallback, but resolve_eidetic() only searches for
an eidetic-cli pyproject.toml in ancestor directories of the wrapper script path, so it cannot
find a separate local eidetic-cli checkout when these skills are vendored into this repo. If
eidetic is not on PATH, both skills will always exit with an error even when uv + a local
eidetic-cli checkout are available.
Code

.claude/skills/recall/scripts/recall.sh[R16-43]

+# ── resolve the eidetic CLI (installed tool first, then dev checkout) ────────
+EIDETIC=()
+resolve_eidetic() {
+    if command -v eidetic >/dev/null 2>&1; then
+        EIDETIC=(eidetic)            # installed console script — the normal case
+        return 0
+    fi
+    # Dev fallback: inside the eidetic-cli checkout, run via uv.
+    local dir
+    dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
+    while [ -n "$dir" ] && [ "$dir" != "/" ]; do
+        if [ -f "$dir/pyproject.toml" ] \
+            && grep -q '^name = "eidetic-cli"' "$dir/pyproject.toml" 2>/dev/null; then
+            if command -v uv >/dev/null 2>&1; then
+                EIDETIC=(uv run --project "$dir" eidetic)
+                return 0
+            fi
+            break
+        fi
+        dir=$(dirname "$dir")
+    done
+    cat >&2 <<'EOF'
+error: eidetic CLI not found.
+hint: install it with `uv tool install eidetic-cli` (or `pipx install eidetic-cli`),
+      or run from inside the eidetic-cli checkout with `uv` available.
+      The console script is `eidetic` (dist name: eidetic-cli).
+EOF
+    return 1
Evidence
The wrappers start their fallback search from the script’s own directory (BASH_SOURCE[0]), not the
current working directory, and then require a pyproject.toml whose name is exactly eidetic-cli.
In this repo the project name is reduce-cli, so the fallback never matches and the scripts always
error when eidetic isn’t on PATH.

.claude/skills/recall/scripts/recall.sh[16-43]
pyproject.toml[1-4]
.claude/skills/remember/scripts/remember.sh[23-50]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The wrappers’ dev fallback cannot succeed in this repository because it walks up from the wrapper’s own directory and looks for `pyproject.toml` named `eidetic-cli`. Since these scripts live under `reduce-cli`, they will never be inside an `eidetic-cli` checkout, so the fallback is effectively dead code.

### Issue Context
- Current logic uses `dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)` and walks upward.
- In this repo, the only root `pyproject.toml` is `name = "reduce-cli"`, so the grep for `eidetic-cli` never matches.

### Fix Focus Areas
- .claude/skills/recall/scripts/recall.sh[16-43]
- .claude/skills/remember/scripts/remember.sh[23-50]

### Suggested fix approach
- Change the fallback search root to something that can actually be inside an `eidetic-cli` checkout (e.g., walk up from `$PWD`, or from `git rev-parse --show-toplevel`, similar to how `ask-colleague` does it).
- Optionally add an explicit override like `EIDETIC_PROJECT=/path/to/eidetic-cli` (or `EIDETIC_BIN`) that, when set, is used directly.
- Update the error hint text to match the new behavior (so it’s not instructing users to do something that can’t work).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Misleading remember help text 🐞 Bug ⚙ Maintainability
Description
remember.sh --help says “Public data only” even though the wrapper defaults to injecting
--visibility private when it auto-resolves a scope from culture.yaml. This contradicts the
skill’s documented behavior and can mislead operators about whether private storage is
supported/expected.
Code

.claude/skills/remember/scripts/remember.sh[R52-65]

+usage() {
+    cat <<'EOF'
+remember.sh — ingest records into the shared eidetic memory store (the /remember skill).
+
+Usage:
+  remember.sh '<json-object>' [--json] [--backend files|mongo|neo4j] \
+              [--scope NAME] [--visibility public|private]
+  cat records.ndjson | remember.sh [--json] ...
+
+A record needs `id`, `text`, and `type`; `hash` and `metadata` are recommended
+(hash is derived from text when omitted). Upsert is idempotent by id.
+Public data only. Every flag is forwarded verbatim to `eidetic remember`.
+See `eidetic explain remember`.
+EOF
Evidence
The help text explicitly claims public-only, while the wrapper injects --visibility private by
default and the skill documentation describes private as the safe default for personal notes.

.claude/skills/remember/scripts/remember.sh[52-65]
.claude/skills/remember/scripts/remember.sh[125-132]
.claude/skills/remember/SKILL.md[61-66]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `remember.sh` usage text currently states “Public data only”, but the wrapper defaults to a private personal scope when it injects scope args, and the skill docs explicitly say private notes are safe by default.

### Issue Context
This is user-facing output (`remember.sh --help`) and conflicts with the rest of the skill’s contract.

### Fix Focus Areas
- .claude/skills/remember/scripts/remember.sh[52-65]
- .claude/skills/remember/scripts/remember.sh[125-132]

### Suggested fix approach
- Replace “Public data only.” with wording that matches the wrapper’s actual default (private unless `--visibility` is explicitly set, and `--visibility public` should be treated as the public/shared pool).
- Keep the guidance about not putting sensitive data into public visibility, but don’t imply private storage is unsupported.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Skill ledger not updated 🐞 Bug ⚙ Maintainability
Description
The new skills’ Provenance sections point to docs/skill-sources.md, but that ledger doesn’t list
remember/recall or the optional eidetic prerequisite. This undermines the repo’s documented
“cite-don’t-import” provenance tracking for vendored skills.
Code

.claude/skills/recall/SKILL.md[R177-181]

+## Provenance
+
+First-party to **eidetic-cli** — eidetic owns its memory surface. Cite, don't
+import: downstream repos copy this skill, they don't symlink it. See
+[`docs/skill-sources.md`](../../../docs/skill-sources.md).
Evidence
The new skill docs direct provenance tracking to docs/skill-sources.md, but the ledger table and
prerequisites section currently omit these newly vendored skills and their runtime dependency.

.claude/skills/recall/SKILL.md[177-181]
docs/skill-sources.md[23-37]
docs/skill-sources.md[108-122]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`docs/skill-sources.md` is the repo’s provenance ledger for vendored skills, but it doesn’t include the newly added `remember` and `recall` skills, nor the `eidetic` CLI prerequisite.

### Issue Context
The new skills explicitly direct readers to the ledger for provenance.

### Fix Focus Areas
- docs/skill-sources.md[23-37]
- docs/skill-sources.md[108-122]
- README.md[7-13]

### Suggested fix approach
- Add `remember` and `recall` rows to the skills table with upstream/origin notes (eidetic-cli) and last-synced date.
- Add `eidetic` to Tooling prerequisites (similar to how `colleague` is documented as optional).
- Update README’s skill count to reflect the new total (if you keep counts there).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +16 to +43
# ── resolve the eidetic CLI (installed tool first, then dev checkout) ────────
EIDETIC=()
resolve_eidetic() {
if command -v eidetic >/dev/null 2>&1; then
EIDETIC=(eidetic) # installed console script — the normal case
return 0
fi
# Dev fallback: inside the eidetic-cli checkout, run via uv.
local dir
dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
while [ -n "$dir" ] && [ "$dir" != "/" ]; do
if [ -f "$dir/pyproject.toml" ] \
&& grep -q '^name = "eidetic-cli"' "$dir/pyproject.toml" 2>/dev/null; then
if command -v uv >/dev/null 2>&1; then
EIDETIC=(uv run --project "$dir" eidetic)
return 0
fi
break
fi
dir=$(dirname "$dir")
done
cat >&2 <<'EOF'
error: eidetic CLI not found.
hint: install it with `uv tool install eidetic-cli` (or `pipx install eidetic-cli`),
or run from inside the eidetic-cli checkout with `uv` available.
The console script is `eidetic` (dist name: eidetic-cli).
EOF
return 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Broken uv fallback lookup 🐞 Bug ☼ Reliability

recall.sh/remember.sh claim a dev-checkout fallback, but resolve_eidetic() only searches for
an eidetic-cli pyproject.toml in ancestor directories of the wrapper script path, so it cannot
find a separate local eidetic-cli checkout when these skills are vendored into this repo. If
eidetic is not on PATH, both skills will always exit with an error even when uv + a local
eidetic-cli checkout are available.
Agent Prompt
### Issue description
The wrappers’ dev fallback cannot succeed in this repository because it walks up from the wrapper’s own directory and looks for `pyproject.toml` named `eidetic-cli`. Since these scripts live under `reduce-cli`, they will never be inside an `eidetic-cli` checkout, so the fallback is effectively dead code.

### Issue Context
- Current logic uses `dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)` and walks upward.
- In this repo, the only root `pyproject.toml` is `name = "reduce-cli"`, so the grep for `eidetic-cli` never matches.

### Fix Focus Areas
- .claude/skills/recall/scripts/recall.sh[16-43]
- .claude/skills/remember/scripts/remember.sh[23-50]

### Suggested fix approach
- Change the fallback search root to something that can actually be inside an `eidetic-cli` checkout (e.g., walk up from `$PWD`, or from `git rev-parse --show-toplevel`, similar to how `ask-colleague` does it).
- Optionally add an explicit override like `EIDETIC_PROJECT=/path/to/eidetic-cli` (or `EIDETIC_BIN`) that, when set, is used directly.
- Update the error hint text to match the new behavior (so it’s not instructing users to do something that can’t work).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant