rollout-cli 0.6.0__tar.gz → 0.7.0__tar.gz

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 (133) hide show
  1. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/recall/SKILL.md +13 -9
  2. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/recall/scripts/recall.sh +45 -22
  3. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/remember/SKILL.md +8 -5
  4. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/remember/scripts/remember.sh +50 -22
  5. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/CHANGELOG.md +18 -1
  6. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/CLAUDE.md +28 -0
  7. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/PKG-INFO +1 -1
  8. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/docs/skill-sources.md +6 -0
  9. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/pyproject.toml +1 -1
  10. rollout_cli-0.7.0/recipes/eidetic-memory/README.md +161 -0
  11. rollout_cli-0.7.0/recipes/eidetic-memory/apply.sh +118 -0
  12. rollout_cli-0.7.0/recipes/eidetic-memory/check.sh +46 -0
  13. rollout_cli-0.7.0/recipes/eidetic-memory/files/CLAUDE.snippet.tmpl +25 -0
  14. rollout_cli-0.7.0/recipes/eidetic-memory/files/SKILL.md.recall.tmpl +185 -0
  15. rollout_cli-0.7.0/recipes/eidetic-memory/files/SKILL.md.remember.tmpl +121 -0
  16. rollout_cli-0.7.0/recipes/eidetic-memory/files/scripts/recall.sh +164 -0
  17. rollout_cli-0.7.0/recipes/eidetic-memory/files/scripts/remember.sh +166 -0
  18. rollout_cli-0.7.0/recipes/eidetic-memory/manifest.toml +51 -0
  19. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/devex_pr.py +18 -8
  20. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_devex_pr.py +23 -5
  21. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/uv.lock +1 -1
  22. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/agent-config/SKILL.md +0 -0
  23. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/agent-config/data/backend-fingerprints.yaml +0 -0
  24. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/agent-config/scripts/show.sh +0 -0
  25. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/ask-colleague/SKILL.md +0 -0
  26. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/ask-colleague/prompts/explore.md +0 -0
  27. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/ask-colleague/prompts/review.md +0 -0
  28. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/ask-colleague/prompts/write.md +0 -0
  29. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/ask-colleague/scripts/ask-colleague.sh +0 -0
  30. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/assign-to-workforce/SKILL.md +0 -0
  31. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh +0 -0
  32. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/SKILL.md +0 -0
  33. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/scripts/_resolve-nick.sh +0 -0
  34. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/scripts/portability-lint.sh +0 -0
  35. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/scripts/pr-reply.sh +0 -0
  36. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/scripts/pr-status.sh +0 -0
  37. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/cicd/scripts/workflow.sh +0 -0
  38. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/SKILL.md +0 -0
  39. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/fetch-issues.sh +0 -0
  40. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/mesh-message.sh +0 -0
  41. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/post-comment.sh +0 -0
  42. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/post-issue.sh +0 -0
  43. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/templates/skill-new-brief.md +0 -0
  44. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/communicate/scripts/templates/skill-update-brief.md +0 -0
  45. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/doc-test-alignment/SKILL.md +0 -0
  46. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/doc-test-alignment/scripts/check.sh +0 -0
  47. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/mass-update/SKILL.md +0 -0
  48. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/mass-update/scripts/mass-update.sh +0 -0
  49. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/pypi-maintainer/SKILL.md +0 -0
  50. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/pypi-maintainer/scripts/switch-source.sh +0 -0
  51. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/run-tests/SKILL.md +0 -0
  52. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/run-tests/scripts/test.sh +0 -0
  53. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/sonarclaude/SKILL.md +0 -0
  54. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/sonarclaude/scripts/sonar.sh +0 -0
  55. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/spec-to-plan/SKILL.md +0 -0
  56. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/spec-to-plan/scripts/spec-to-plan.sh +0 -0
  57. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/think/SKILL.md +0 -0
  58. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/think/scripts/think.sh +0 -0
  59. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/version-bump/SKILL.md +0 -0
  60. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills/version-bump/scripts/bump.py +0 -0
  61. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.claude/skills.local.yaml.example +0 -0
  62. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.devague/frames/mass-update-now-clones-each-target-repo-into-a-git.json +0 -0
  63. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.devague/frames/rollout-cli-ships-rollout-define-an-org-wide-chang.json +0 -0
  64. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.devague/plans/mass-update-now-clones-each-target-repo-into-a-git.json +0 -0
  65. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.devague/plans/rollout-cli-ships-rollout-define-an-org-wide-chang.json +0 -0
  66. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.flake8 +0 -0
  67. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.github/workflows/publish.yml +0 -0
  68. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.github/workflows/tests.yml +0 -0
  69. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.gitignore +0 -0
  70. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/.markdownlint-cli2.yaml +0 -0
  71. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/AGENTS.colleague.md +0 -0
  72. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/LICENSE +0 -0
  73. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/README.md +0 -0
  74. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/culture.yaml +0 -0
  75. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/docs/plans/2026-06-06-rollout-cli-ships-rollout-define-an-org-wide-chang.md +0 -0
  76. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/docs/plans/2026-06-12-mass-update-now-clones-each-target-repo-into-a-git.md +0 -0
  77. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/docs/specs/2026-06-06-rollout-cli-ships-rollout-define-an-org-wide-chang.md +0 -0
  78. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/docs/specs/2026-06-12-mass-update-now-clones-each-target-repo-into-a-git.md +0 -0
  79. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/apache-relicense/apply.sh +0 -0
  80. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/apache-relicense/check.sh +0 -0
  81. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/apache-relicense/files/LICENSE +0 -0
  82. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/apache-relicense/manifest.toml +0 -0
  83. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/README.md +0 -0
  84. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/apply.sh +0 -0
  85. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/check.sh +0 -0
  86. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/files/SKILL.md.tmpl +0 -0
  87. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/files/prompts/explore.md +0 -0
  88. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/files/prompts/review.md +0 -0
  89. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/files/prompts/write.md +0 -0
  90. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/files/scripts/ask-colleague.sh +0 -0
  91. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/recipes/ask-colleague-revendor/manifest.toml +0 -0
  92. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/__init__.py +0 -0
  93. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/__main__.py +0 -0
  94. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/__init__.py +0 -0
  95. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/__init__.py +0 -0
  96. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/apply.py +0 -0
  97. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/cli.py +0 -0
  98. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/doctor.py +0 -0
  99. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/explain.py +0 -0
  100. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/learn.py +0 -0
  101. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/overview.py +0 -0
  102. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/plan.py +0 -0
  103. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_commands/whoami.py +0 -0
  104. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_errors.py +0 -0
  105. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/cli/_output.py +0 -0
  106. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/__init__.py +0 -0
  107. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/bump.py +0 -0
  108. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/gitops.py +0 -0
  109. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/orchestrate.py +0 -0
  110. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/preflight.py +0 -0
  111. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/recipe.py +0 -0
  112. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/report.py +0 -0
  113. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/core/targets.py +0 -0
  114. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/explain/__init__.py +0 -0
  115. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/rollout/explain/catalog.py +0 -0
  116. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/sonar-project.properties +0 -0
  117. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/__init__.py +0 -0
  118. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_apache_relicense.py +0 -0
  119. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_apply_cmd.py +0 -0
  120. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_bump.py +0 -0
  121. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_cli.py +0 -0
  122. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_cli_introspection.py +0 -0
  123. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_cli_wiring.py +0 -0
  124. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_e2e_apache_relicense.py +0 -0
  125. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_explain_catalog.py +0 -0
  126. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_gitops.py +0 -0
  127. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_mass_update.py +0 -0
  128. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_orchestrate.py +0 -0
  129. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_plan_cmd.py +0 -0
  130. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_preflight.py +0 -0
  131. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_recipe.py +0 -0
  132. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_report.py +0 -0
  133. {rollout_cli-0.6.0 → rollout_cli-0.7.0}/tests/test_targets.py +0 -0
@@ -9,13 +9,17 @@ description: >
9
9
  text, full metadata, a relevance `score`, and a freshness `signal`. Recall
10
10
  passively reinforces matched records (bumps last_recall + recall_count).
11
11
  Shadowed and archived records are excluded by default; use
12
- --include-shadowed / --include-archived to retrieve them. The store lives at
13
- ~/.eidetic/memory (a home-dir path outside any git worktree); the wrapper
14
- defaults queries to this agent's PERSONAL, PRIVATE scope (`--scope rollout-cli
15
- --visibility private`, suffix read from culture.yaml) matching where
16
- /remember writes so a no-flag recall returns this agent's own private records
17
- plus the shared public pool, and Claude and the colleague backend recall each
18
- other's memories because both resolve the same suffix via this skill. Use
12
+ --include-shadowed / --include-archived to retrieve them. The store uses
13
+ visibility-aware routing: PUBLIC records inside a git repo go to
14
+ <repo-root>/.eidetic/memory (committed, team-shared); PRIVATE records, or any
15
+ record outside a git repo, go to $HOME/.eidetic/memory (never committed). An
16
+ explicit EIDETIC_DATA_DIR wins and short-circuits to that single dir. Recall
17
+ reads both stores and merges. The wrapper defaults queries to this agent's
18
+ PERSONAL, PRIVATE scope (`--scope rollout-cli --visibility private`, suffix
19
+ read from culture.yaml) — matching where /remember writes — so a no-flag
20
+ recall returns this agent's own private records plus the shared public pool,
21
+ and Claude and the colleague backend recall each other's memories because both
22
+ resolve the same suffix via this skill. Use
19
23
  when the user says "recall", "what do we know about X", "search memory",
20
24
  "have we seen X before", "look it up in memory", "eidetic recall", or before
21
25
  answering from scratch when prior context may already be stored. Pairs with
@@ -31,7 +35,7 @@ surface; the write half is the sibling **/remember** skill.
31
35
 
32
36
  The point of a *shared* store is that memory is a **team faculty**, not a
33
37
  per-agent silo: a record Claude wrote is recallable by the colleague backend
34
- (and vice versa), because both resolve the same `~/.eidetic/memory` path.
38
+ (and vice versa), because both resolve the same `$HOME/.eidetic/memory` path.
35
39
 
36
40
  ## How to run
37
41
 
@@ -168,7 +172,7 @@ bash .claude/skills/recall/scripts/recall.sh "power" --include-archived --includ
168
172
  matches. `approximate` keeps every candidate ranked by raw cosine, so it can
169
173
  return low/near-zero scores when the store is small — lower `--top-k` to trim.
170
174
  A `--min-score` threshold is a tracked follow-up.
171
- - **Sharing scope = one OS user.** The default store is `~/.eidetic/memory`, so
175
+ - **Sharing scope = one OS user.** The default store is `$HOME/.eidetic/memory`, so
172
176
  every agent/process running as the *same* OS user shares it (that is the point —
173
177
  Claude + colleague). It is not isolated between OS users by anything but file
174
178
  permissions; keep genuinely private data in a `--visibility private` scope and
@@ -6,10 +6,11 @@
6
6
  # forwards every flag verbatim — so `recall.sh "<query>" --mode hybrid --json`
7
7
  # is exactly `eidetic recall "<query>" --mode hybrid --json`.
8
8
  #
9
- # The store is the files backend at ~/.eidetic/memory by default — a home-dir
10
- # path OUTSIDE any git worktree, so Claude and the colleague backend (which runs
11
- # in throwaway worktrees) read the SAME memories. Set EIDETIC_DATA_DIR to opt out
12
- # of sharing; set EIDETIC_MONGO_URI / NEO4J_URI + --backend for a server store.
9
+ # The store is the files backend. Default location resolves per-operation:
10
+ # PUBLIC records inside a git repo <repo-root>/.eidetic/memory (committed,
11
+ # team-shared); PRIVATE records, or any record outside a git repo
12
+ # $HOME/.eidetic/memory (never committed). Recall reads both stores and merges.
13
+ # An explicit EIDETIC_DATA_DIR wins and short-circuits to that single dir.
13
14
 
14
15
  set -euo pipefail
15
16
 
@@ -34,12 +35,10 @@ resolve_eidetic() {
34
35
  fi
35
36
  dir=$(dirname "$dir")
36
37
  done
37
- cat >&2 <<'EOF'
38
- error: eidetic CLI not found.
39
- hint: install it with `uv tool install eidetic-cli` (or `pipx install eidetic-cli`),
40
- or run from inside the eidetic-cli checkout with `uv` available.
41
- The console script is `eidetic` (dist name: eidetic-cli).
42
- EOF
38
+ # In a vendored copy there is no eidetic-cli checkout to fall back to, so the
39
+ # only honest remedy is to install the CLI. One `error:` + one `hint:` line.
40
+ printf 'error: eidetic CLI not found.\n' >&2
41
+ printf 'hint: install it with: uv tool install eidetic-cli (or pipx install eidetic-cli); the console script is eidetic.\n' >&2
43
42
  return 1
44
43
  }
45
44
 
@@ -65,15 +64,22 @@ EOF
65
64
  }
66
65
 
67
66
  case "${1:-}" in
68
- -h | --help | help | "")
67
+ -h | --help)
69
68
  usage
70
69
  exit 0
71
70
  ;;
71
+ "")
72
+ # A missing query is a usage error, not success. The bareword `help` is
73
+ # a legitimate search term, so it is intentionally NOT a usage alias.
74
+ printf 'error: no query given.\n' >&2
75
+ printf 'hint: recall.sh "<query>" [--mode ...] [--json]; run recall.sh --help for usage.\n' >&2
76
+ exit 1
77
+ ;;
72
78
  esac
73
79
 
74
80
  resolve_eidetic || exit 2
75
81
 
76
- # ── default to this agent's PERSONAL, PRIVATE scope (culture.yaml `suffix`) ──
82
+ # ── default to this agent's PERSONAL scope, PUBLIC visibility (culture.yaml `suffix`) ──
77
83
  # Query this agent's OWN personal scope by default, matching where /remember
78
84
  # writes, instead of the global `default` scope shared by every project on this
79
85
  # host. We read the `suffix` from the nearest culture.yaml (walking up from this
@@ -82,15 +88,16 @@ resolve_eidetic || exit 2
82
88
  # backend (running in a worktree of this same repo) resolves the same suffix,
83
89
  # keeping the Claude↔colleague shared-memory story intact.
84
90
  #
85
- # The personal scope is PRIVATE by default to match /remember: in eidetic's model
86
- # a private record is served only to a recall in the SAME scope (`can_serve`), so
87
- # querying with --scope <suffix> --visibility private is what retrieves those
88
- # isolated records (a public/default recall can't see them). Scope and visibility
89
- # are paired — the private default applies only when we inject the resolved scope,
91
+ # Visibility defaults to PUBLIC (a recipe-level policy override of eidetic's
92
+ # upstream private default see the POLICY OVERRIDE comment below) to match
93
+ # /remember, so a plain recall queries the in-repo public pool at
94
+ # <repo>/.eidetic/memory that /remember writes to. Scope and visibility are
95
+ # paired — the public default applies only when we inject the resolved scope,
90
96
  # and only if the caller didn't pass --visibility (so an explicit
91
- # `--visibility public` still wins). An explicit --scope on the command line takes
92
- # over steering entirely; a wheel install with no culture.yaml falls back to the
93
- # plain CLI default (`default`/`public`).
97
+ # `--visibility private` still wins, also surfacing this agent's private $HOME
98
+ # notes). An explicit --scope on the command line takes over steering entirely; a
99
+ # wheel install with no culture.yaml falls back to the plain CLI default
100
+ # (`default`/`public`).
94
101
  resolve_scope() {
95
102
  local dir suffix=""
96
103
  dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
@@ -100,9 +107,12 @@ resolve_scope() {
100
107
  # inline `# comment` or trailing space can't bleed into the scope),
101
108
  # then strip surrounding quotes only — matching the canonical parser
102
109
  # in .claude/skills/cicd/scripts/_resolve-nick.sh.
110
+ # `|| true`: under `set -o pipefail`, `head -n1` closing the pipe
111
+ # early can SIGPIPE `sed`, making the substitution non-zero and
112
+ # aborting the script. An empty parse must yield "" here, not exit.
103
113
  suffix=$(sed -n \
104
114
  's/^[[:space:]]*-\{0,1\}[[:space:]]*suffix:[[:space:]]*\([^[:space:]]*\).*/\1/p' \
105
- "$dir/culture.yaml" | head -n1 | tr -d "\"'")
115
+ "$dir/culture.yaml" | head -n1 | tr -d "\"'" || true)
106
116
  break
107
117
  fi
108
118
  dir=$(dirname "$dir")
@@ -127,7 +137,20 @@ if ! has_flag --scope "$@"; then
127
137
  EIDETIC_SCOPE=$(resolve_scope)
128
138
  if [ -n "$EIDETIC_SCOPE" ]; then
129
139
  SCOPE_ARGS+=(--scope "$EIDETIC_SCOPE")
130
- has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility private)
140
+ # rollout-cli eidetic-memory recipe POLICY OVERRIDE (not eidetic's
141
+ # upstream private default): default to PUBLIC, so a plain recall queries
142
+ # the in-repo public pool (<repo>/.eidetic/memory) this repo writes to.
143
+ # Pass --visibility private to also surface this agent's private ($HOME)
144
+ # notes. The two-store read model reads both dirs regardless.
145
+ has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility public)
146
+ elif ! has_flag --visibility "$@"; then
147
+ # No suffix AND no explicit --visibility: the query runs against
148
+ # eidetic's own default (scope=default, visibility=public), not this
149
+ # agent's private personal scope — so an empty result isn't silently
150
+ # misread. Warn on stderr (stdout stays clean for --json). Warn ONLY
151
+ # here: an explicit --scope (outer guard) or --visibility (this guard) is
152
+ # a deliberate choice, honored verbatim, so either flag silences this.
153
+ printf 'warning: no culture.yaml suffix resolved; querying the public default scope rather than a private personal scope. Pass --scope or --visibility to target deliberately.\n' >&2
131
154
  fi
132
155
  fi
133
156
 
@@ -8,10 +8,13 @@ description: >
8
8
  dedups by content hash) — re-remembering updates in place, never duplicates.
9
9
  Stamps a `created` date on every record at ingest time. Accepts `supersedes`
10
10
  (id of the record this one replaces, for within-scope shadowing via `sweep`)
11
- and `links` (list of related-memory ids). The store lives at
12
- ~/.eidetic/memory (a home-dir path outside any git worktree), and the wrapper
13
- defaults records to this agent's PERSONAL, PRIVATE scope (`--scope rollout-cli
14
- --visibility private`, suffix read from culture.yaml) so they don't leak to a
11
+ and `links` (list of related-memory ids). The store uses visibility-aware
12
+ routing: PUBLIC records inside a git repo go to <repo-root>/.eidetic/memory
13
+ (committed, team-shared); PRIVATE records, or any record outside a git repo,
14
+ go to $HOME/.eidetic/memory (never committed). An explicit EIDETIC_DATA_DIR
15
+ wins and short-circuits to that single dir. The wrapper defaults records to
16
+ this agent's PERSONAL, PRIVATE scope (`--scope rollout-cli --visibility
17
+ private`, suffix read from culture.yaml) so they don't leak to a
15
18
  default/other-scope recall — Claude and the colleague backend still share them
16
19
  because both resolve the same suffix via this skill. Pass `--visibility public`
17
20
  to contribute to the shared public pool instead. Use when the user says
@@ -25,7 +28,7 @@ description: >
25
28
  `remember` drives **`eidetic remember`**, the write half of the memory surface
26
29
  (the read half is the sibling **/recall** skill). Records you store here are
27
30
  recallable later by *any* agent on this machine — Claude or the colleague
28
- backend — because the default store is one shared `~/.eidetic/memory` path.
31
+ backend — because the default store is one shared `$HOME/.eidetic/memory` path.
29
32
 
30
33
  ## How to run
31
34
 
@@ -12,10 +12,11 @@
12
12
  # Upsert is idempotent by id (and dedups by content hash): re-remembering the
13
13
  # same record updates it in place, never duplicates.
14
14
  #
15
- # The store is the files backend at ~/.eidetic/memory by default — a home-dir
16
- # path OUTSIDE any git worktree, so a record Claude remembers is recallable by
17
- # the colleague backend (which runs in throwaway worktrees), and vice versa.
18
- # Set EIDETIC_DATA_DIR to opt out of sharing; use --backend mongo|neo4j (with
15
+ # The store is the files backend. Default location resolves per-operation:
16
+ # PUBLIC records inside a git repo <repo-root>/.eidetic/memory (committed,
17
+ # team-shared); PRIVATE records, or any record outside a git repo
18
+ # $HOME/.eidetic/memory (never committed). An explicit EIDETIC_DATA_DIR still
19
+ # wins and short-circuits to that single dir. Use --backend mongo|neo4j (with
19
20
  # EIDETIC_MONGO_URI / NEO4J_URI) for a server-backed shared store.
20
21
 
21
22
  set -euo pipefail
@@ -40,12 +41,10 @@ resolve_eidetic() {
40
41
  fi
41
42
  dir=$(dirname "$dir")
42
43
  done
43
- cat >&2 <<'EOF'
44
- error: eidetic CLI not found.
45
- hint: install it with `uv tool install eidetic-cli` (or `pipx install eidetic-cli`),
46
- or run from inside the eidetic-cli checkout with `uv` available.
47
- The console script is `eidetic` (dist name: eidetic-cli).
48
- EOF
44
+ # In a vendored copy there is no eidetic-cli checkout to fall back to, so the
45
+ # only honest remedy is to install the CLI. One `error:` + one `hint:` line.
46
+ printf 'error: eidetic CLI not found.\n' >&2
47
+ printf 'hint: install it with: uv tool install eidetic-cli (or pipx install eidetic-cli); the console script is eidetic.\n' >&2
49
48
  return 1
50
49
  }
51
50
 
@@ -60,7 +59,10 @@ Usage:
60
59
 
61
60
  A record needs `id`, `text`, and `type`; `hash` and `metadata` are recommended
62
61
  (hash is derived from text when omitted). Upsert is idempotent by id.
63
- Public data only. Every flag is forwarded verbatim to `eidetic remember`.
62
+ Records default to this agent's PUBLIC personal scope (--scope from the
63
+ culture.yaml suffix), committed in-repo at <repo>/.eidetic/memory; pass
64
+ --visibility private to keep a record in $HOME (uncommitted). Every flag is
65
+ forwarded verbatim to `eidetic remember`.
64
66
  See `eidetic explain remember`.
65
67
  EOF
66
68
  }
@@ -72,9 +74,19 @@ case "${1:-}" in
72
74
  ;;
73
75
  esac
74
76
 
77
+ # No record argument AND stdin is an interactive terminal → `eidetic remember`
78
+ # would block forever waiting for NDJSON. Show usage instead of hanging. A piped
79
+ # or redirected stdin (`cat records.ndjson | remember.sh`) is not a TTY and
80
+ # proceeds to the batch path normally.
81
+ if [ "$#" -eq 0 ] && [ -t 0 ]; then
82
+ usage >&2
83
+ printf 'hint: pass a JSON record as an argument, or pipe NDJSON on stdin.\n' >&2
84
+ exit 1
85
+ fi
86
+
75
87
  resolve_eidetic || exit 2
76
88
 
77
- # ── default to this agent's PERSONAL, PRIVATE scope (culture.yaml `suffix`) ──
89
+ # ── default to this agent's PERSONAL scope, PUBLIC visibility (culture.yaml `suffix`) ──
78
90
  # A record this agent remembers should land in its OWN personal scope, not the
79
91
  # global `default` scope shared by every project on this host. We read the
80
92
  # `suffix` from the nearest culture.yaml (walking up from this script), so the
@@ -83,14 +95,15 @@ resolve_eidetic || exit 2
83
95
  # (running in a worktree of this same repo) resolves the same suffix, keeping
84
96
  # the Claude↔colleague shared-memory story intact.
85
97
  #
86
- # The personal scope is PRIVATE by default: in eidetic's model only a private
87
- # record is isolated to its scope (`can_serve`), so private is what actually
88
- # keeps these records from leaking to a default/other-scope recall. Scope and
89
- # visibility are paired — the private default applies only when we inject the
90
- # resolved scope, and only if the caller didn't pass --visibility (so an
91
- # explicit `--visibility public` still wins). An explicit --scope on the command
92
- # line takes over steering entirely; a wheel install with no culture.yaml falls
93
- # back to the plain CLI default (`default`/`public`).
98
+ # Visibility defaults to PUBLIC (a recipe-level policy override of eidetic's
99
+ # upstream private default see the POLICY OVERRIDE comment below), so a plain
100
+ # remember lands in the in-repo, committed, team- and mesh-shared pool at
101
+ # <repo>/.eidetic/memory. Scope and visibility are paired — the public default
102
+ # applies only when we inject the resolved scope, and only if the caller didn't
103
+ # pass --visibility (so an explicit `--visibility private` still wins, keeping
104
+ # the record in $HOME / uncommitted). An explicit --scope on the command line
105
+ # takes over steering entirely; a wheel install with no culture.yaml falls back
106
+ # to the plain CLI default (`default`/`public`).
94
107
  resolve_scope() {
95
108
  local dir suffix=""
96
109
  dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
@@ -100,9 +113,12 @@ resolve_scope() {
100
113
  # inline `# comment` or trailing space can't bleed into the scope),
101
114
  # then strip surrounding quotes only — matching the canonical parser
102
115
  # in .claude/skills/cicd/scripts/_resolve-nick.sh.
116
+ # `|| true`: under `set -o pipefail`, `head -n1` closing the pipe
117
+ # early can SIGPIPE `sed`, making the substitution non-zero and
118
+ # aborting the script. An empty parse must yield "" here, not exit.
103
119
  suffix=$(sed -n \
104
120
  's/^[[:space:]]*-\{0,1\}[[:space:]]*suffix:[[:space:]]*\([^[:space:]]*\).*/\1/p' \
105
- "$dir/culture.yaml" | head -n1 | tr -d "\"'")
121
+ "$dir/culture.yaml" | head -n1 | tr -d "\"'" || true)
106
122
  break
107
123
  fi
108
124
  dir=$(dirname "$dir")
@@ -127,7 +143,19 @@ if ! has_flag --scope "$@"; then
127
143
  EIDETIC_SCOPE=$(resolve_scope)
128
144
  if [ -n "$EIDETIC_SCOPE" ]; then
129
145
  SCOPE_ARGS+=(--scope "$EIDETIC_SCOPE")
130
- has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility private)
146
+ # rollout-cli eidetic-memory recipe POLICY OVERRIDE (not eidetic's
147
+ # upstream private default): default to PUBLIC so a plain remember lands
148
+ # in <repo>/.eidetic/memory — committed, team- and mesh-shared. Pass
149
+ # --visibility private to keep a record in $HOME (uncommitted).
150
+ has_flag --visibility "$@" || SCOPE_ARGS+=(--visibility public)
151
+ elif ! has_flag --visibility "$@"; then
152
+ # No suffix AND no explicit --visibility: the record falls back to
153
+ # eidetic's own default (scope=default, visibility=public). Don't let an
154
+ # expected-private record go public silently — warn on stderr (stdout
155
+ # stays clean for --json). Warn ONLY here: an explicit --scope (outer
156
+ # guard) or --visibility (this guard) means the caller chose deliberately
157
+ # and is honored verbatim, so either flag silences this.
158
+ printf 'warning: no culture.yaml suffix resolved; this record falls back to the public default scope. Pass --scope or --visibility to place it deliberately.\n' >&2
131
159
  fi
132
160
  fi
133
161
 
@@ -5,11 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/). This project
6
6
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.0] - 2026-06-23
9
+
10
+ ### Added
11
+
12
+ - `eidetic-memory` rollout recipe (`recipes/eidetic-memory/`) — propagates the eidetic-origin `remember` + `recall` skills to every AgentCulture repo with a `.claude/skills/` kit, and adds them fresh where absent. `apply.sh` drops both wrappers verbatim and, on a fresh add, localizes each SKILL.md’s illustrative `--scope <nick>` example to the target’s `culture.yaml` suffix (else repo basename); `check.sh` skips repos lacking a quoted-semver `pyproject.toml`, a `CHANGELOG.md`, or a skills kit. The engine bumps the target version + prepends a CHANGELOG entry (so the org-wide version-check passes) and opens one PR per repo. README carries the 57-repo downstream-consumer ledger + reconciliation procedure.
13
+ - `eidetic-memory` now also wires a memory-discipline **"Conventions and workflow"** section into each target’s `CLAUDE.md` (`files/CLAUDE.snippet.tmpl`) — a per-task *recall-before / remember-after* convention with the scope reference localized to the target’s nick (`__REPO_NICK__`), so the vendored skills are actually used, not just present. The section frames each repo’s memory as **in-repo and public** (records resolve to `<repo-root>/.eidetic/memory`, committed and team/mesh-shared), matching the wrappers’ public default. Inserted idempotently on a marker phrase: slotted under an existing `## Conventions and workflow` heading when one exists, else appended (the file is created if the repo has none). `check.sh` now requires the section present (alongside byte-matching wrappers) before classifying a repo `done`; `manifest.toml` declares `CLAUDE.md` in `touched_files`.
14
+
15
+ ### Changed
16
+
17
+ - Refreshed the `eidetic-memory` recipe’s bundled `remember` / `recall` wrappers — and rollout-cli’s own vendored copies — from **eidetic-cli 0.10.0** (cite-don’t-import), picking up eidetic’s **project-local store default**: PUBLIC records inside a git repo resolve to `<repo-root>/.eidetic/memory` (committed, team-shared), PRIVATE records (or any record outside a repo) go to `$HOME/.eidetic/memory` (uncommitted), `EIDETIC_DATA_DIR` still wins, and recall reads both stores and merges. Also carries the 0.9.3 hardening (interactive-stdin guard, `help` as a search term, SIGPIPE-safe suffix parsing). **Recipe-level policy override** (the wrappers are no longer byte-verbatim): the injected default visibility is flipped from eidetic’s `private` to **`public`** (one line + a `POLICY OVERRIDE` comment in each wrapper), so a plain `/remember` keeps memory in-repo at `./.eidetic/memory`; the reconciliation procedure re-applies this `sed` after each `cp` from origin. rollout-cli’s own `CLAUDE.md` + skill copies dogfood the change.
18
+
19
+ ### Fixed
20
+
21
+ - `rollout/core/devex_pr.py` `open_pr` now **requires** `gh`. The engine opens a PR for a freshly-cloned sibling (an arbitrary repo + branch) from rollout-cli’s own cwd, which only `gh pr create --repo --head --base` can target; `devex pr open` operates on the current checkout and rejects those flags, so it silently failed to open PRs whenever it was on PATH. The earlier "prefer gh, fall back to devex" selection was internally inconsistent — the devex fallback built a command devex would reject (Qodo review). `open_pr` now selects `gh` unconditionally and raises a clear `PrError` (pointing at `https://cli.github.com`) when `gh` is absent, instead of falling through to a broken devex invocation. `build_pr_command`’s pure `tool="devex"` branch is retained (still unit-tested); only the runtime selection is gh-only.
22
+ - `recipes/eidetic-memory/check.sh` version preflight is now end-anchored (`…"$`), matching `rollout/core/bump.py`’s `_LINE_RE` exactly (Qodo review). The old grep accepted `version = "1.2.3" # comment` (or trailing whitespace), so `plan` could classify a repo `ok`/`done` and then `apply` would fail at the version-bump step; preflight is now a strict subset of what the bumper accepts.
23
+ - `eidetic-memory` wrappers (`remember.sh` / `recall.sh`, bundled + rollout-cli’s own copies): corrected stale header/usage comments that still described a **private** default after the policy flip to public (Qodo review) — the code already injected `--visibility public` and warned on a suffixless fallback, but the prose said "PRIVATE by default", contradicting the behavior. Comment-only; no behavior change.
24
+
8
25
  ## [0.6.0] - 2026-06-23
9
26
 
10
27
  ### Added
11
28
 
12
- - remember / recall skills — vendored directly from eidetic-cli (cite-don't-import), the write/read halves of eidetic's shared ~/.eidetic/memory surface. `remember` wraps `eidetic remember` (idempotent JSON object or NDJSON-batch upsert by id); `recall` wraps `eidetic recall` with four search modes (exact / approximate / keyword / hybrid). The `.sh` wrappers are byte-verbatim; each SKILL.md is localized only in the illustrative `--scope rollout-cli` scope examples (Provenance keeps "First-party to eidetic-cli"). docs/skill-sources.md gains the two provenance rows (origin = eidetic-cli, vendored direct, not via guildmaster). Runtime dep: the `eidetic` CLI on PATH (else a local eidetic-cli checkout + uv).
29
+ - remember / recall skills — vendored directly from eidetic-cli (cite-don't-import), the write/read halves of eidetic's shared `$HOME/.eidetic/memory` surface. `remember` wraps `eidetic remember` (idempotent JSON object or NDJSON-batch upsert by id); `recall` wraps `eidetic recall` with four search modes (exact / approximate / keyword / hybrid). The `.sh` wrappers are byte-verbatim; each SKILL.md is localized only in the illustrative `--scope rollout-cli` scope examples (Provenance keeps "First-party to eidetic-cli"). docs/skill-sources.md gains the two provenance rows (origin = eidetic-cli, vendored direct, not via guildmaster). Runtime dep: the `eidetic` CLI on PATH (else a local eidetic-cli checkout + uv).
13
30
 
14
31
  ## [0.5.1] - 2026-06-18
15
32
 
@@ -81,3 +81,31 @@ check whether the *target file path* is already ignored —
81
81
  Note: `devex`'s own self-heal (`devex overview`/`devex init`) bootstraps `.devex/`
82
82
  only — it will **not** restore an `.agex/.gitignore`, so for `.agex` repos the
83
83
  file must be supplied verbatim.
84
+
85
+ ## Conventions and workflow
86
+
87
+ **Memory discipline — recall before, remember after.** This repo keeps its
88
+ eidetic memory **in-repo and public**: records resolve to
89
+ `<repo-root>/.eidetic/memory` — committed, and shared with the team and mesh
90
+ peers (the `claude` and `colleague` backends both read the same `rollout-cli`
91
+ scope), so memory travels with the repo, not a private home-dir store. Make it
92
+ a per-task habit:
93
+
94
+ - **`/recall` before you start.** Search the store for the area you're about
95
+ to touch — prior decisions, gotchas, "have we done this before?" — so you
96
+ build on what's already known instead of re-deriving it. Do this before
97
+ non-trivial tasks, not just when asked.
98
+ - **`/remember` when something worth keeping surfaces.** A non-obvious
99
+ decision and its rationale, a constraint, a fix and *why* it was needed, a
100
+ gotcha that cost time, a fact the next session would otherwise re-learn.
101
+ Capture it as it happens, not at the end when it's faded.
102
+
103
+ A plain `/remember` lands the note in `./.eidetic/memory` in this repo — no
104
+ flag needed (the wrappers here default to `--visibility public`; in-repo
105
+ routing needs `eidetic >= 0.10.0`, older CLIs keep records in `$HOME`). Keep
106
+ something out of the committed store only by passing `--visibility private`
107
+ (routes to `$HOME/.eidetic/memory`, never committed); `/recall` reads both
108
+ stores and merges. Don't store what the repo already records (code structure,
109
+ git history, what's already in this file or `CHANGELOG.md`) — store what you'd
110
+ have to re-derive. These are the `recall`/`remember` skills (`.claude/skills/`),
111
+ backed by the `eidetic` store.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rollout-cli
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Cross-repo propagation workflow built on refactor-cli — apply a transformation across many repos at once.
5
5
  Project-URL: Homepage, https://github.com/agentculture/rollout-cli
6
6
  Project-URL: Issues, https://github.com/agentculture/rollout-cli/issues
@@ -115,6 +115,12 @@ ledger of who those consumers are — is owned by the
115
115
  [`ask-colleague-revendor`](../recipes/ask-colleague-revendor/README.md) rollout
116
116
  recipe (rollout-cli#3).
117
117
 
118
+ Likewise, broadcasting the eidetic-origin `remember` / `recall` skills **out to
119
+ the AgentCulture mesh** — and the ledger of which repos consume them — is owned
120
+ by the [`eidetic-memory`](../recipes/eidetic-memory/README.md) rollout recipe.
121
+ Re-vendor *this* repo's own copy from `../eidetic-cli` directly (the `.sh`
122
+ wrappers verbatim; localize only the illustrative `--scope rollout-cli` examples).
123
+
118
124
  ## Tooling prerequisites
119
125
 
120
126
  - **`devex`** (>=0.21) on PATH — `cicd` delegates the PR lifecycle to `devex pr`.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "rollout-cli"
3
- version = "0.6.0"
3
+ version = "0.7.0"
4
4
  description = "Cross-repo propagation workflow built on refactor-cli — apply a transformation across many repos at once."
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -0,0 +1,161 @@
1
+ # eidetic-memory
2
+
3
+ Propagate eidetic-cli's first-party **`remember`** + **`recall`** memory skills
4
+ to every AgentCulture repo that vendors a `.claude/skills/` kit — add them fresh
5
+ wherever they are absent, refresh the wrappers wherever they are stale — and wire
6
+ a per-task **memory-discipline convention** into each repo's `CLAUDE.md` so the
7
+ skills are actually used, not just present.
8
+
9
+ `remember` / `recall` are first-party to **eidetic-cli** (it owns its memory
10
+ surface); downstream repos vendor them **cite-don't-import**. eidetic-cli's own
11
+ skill ledger anticipated this broadcast: *"Broadcast to the mesh via
12
+ steward/guildmaster is for later, if other agents want it."* This recipe is that
13
+ broadcast, driven through rollout-cli (the propagation tool) rather than forced
14
+ into the origin repo.
15
+
16
+ ## What it does
17
+
18
+ For each target repo, `apply.sh` lays down both skills:
19
+
20
+ - **`scripts/<skill>.sh`** — always overwritten from the bundled snapshot. The
21
+ wrapper resolves the `eidetic` CLI (`PATH` first, else `uv run` from a
22
+ checkout) and reads the `suffix` from `culture.yaml` at runtime, so the same
23
+ bytes are correct in every consumer. The snapshot is eidetic-cli **0.10.0**
24
+ verbatim **except one documented recipe-level policy override**: the injected
25
+ default visibility is flipped from eidetic's `private` to **`public`** (a
26
+ single line in each wrapper, plus a `POLICY OVERRIDE` comment). With
27
+ eidetic 0.10.0's project-local store, a PUBLIC record inside a git repo
28
+ resolves to `<repo-root>/.eidetic/memory` (committed, team-shared) while a
29
+ PRIVATE one goes to `$HOME/.eidetic/memory` (uncommitted) — so defaulting to
30
+ public means a plain `/remember` keeps memory **in the repo**. Pass
31
+ `--visibility private` to opt a record back out to `$HOME`.
32
+ - **`SKILL.md`** — written **only when absent** (fresh add), substituting the
33
+ target's nick (`culture.yaml` `suffix`, else repo basename) into the
34
+ illustrative `--scope <nick>` examples via the `__REPO_NICK__` token in
35
+ `files/SKILL.md.<skill>.tmpl`. An existing `SKILL.md` is never clobbered (a
36
+ downstream may have localized or diverged it). The Provenance line always
37
+ cites **"First-party to eidetic-cli"**.
38
+
39
+ Then, once, into `CLAUDE.md`:
40
+
41
+ - **Memory-discipline section** — a "Conventions and workflow" block
42
+ (*recall-before / remember-after*) rendered from `files/CLAUDE.snippet.tmpl`
43
+ with the same `__REPO_NICK__` nick substituted into the scope reference.
44
+ Inserted **only when its marker is absent** (idempotent): slotted under an
45
+ existing `## Conventions and workflow` heading when the repo already has one,
46
+ otherwise appended as a fresh section (and `CLAUDE.md` is created if the repo
47
+ has none). This makes the skills load-bearing — the agent is told to `/recall`
48
+ before non-trivial work and `/remember` what it would otherwise re-derive.
49
+
50
+ `apply` also bumps the target's version (`minor`) and prepends a CHANGELOG entry
51
+ — required because AgentCulture's org-wide CI rule fails any PR that does not
52
+ bump the version. `check.sh` classifies a repo `done` (both wrappers byte-match
53
+ the snapshot **and** `CLAUDE.md` already carries the section), `ok`
54
+ (wrapper missing/stale or section absent → apply), or `needs-attention` (no
55
+ quoted-semver `pyproject.toml`, no `CHANGELOG.md`, or no `.claude/skills/` kit).
56
+
57
+ ## Run it
58
+
59
+ Operate on **fresh clones** in a scratch base dir (never live agent checkouts):
60
+
61
+ ```bash
62
+ # Dry-run classification across consumers (zero outward effect):
63
+ uv run rollout plan eidetic-memory --repos <slugs> --base <clones-dir>
64
+
65
+ # Apply — branch, lay down skills, bump version, open one PR per repo
66
+ # (the operator squash-merges; rollout never merges):
67
+ uv run rollout apply eidetic-memory --repos <slugs> --base <clones-dir> --yes
68
+ ```
69
+
70
+ ## Downstream-consumer ledger
71
+
72
+ Origin: **eidetic-cli** (`agentculture/eidetic-cli`,
73
+ `.claude/skills/{remember,recall}/`). Consumers = every non-archived
74
+ AgentCulture repo with a `.claude/skills/` kit + a version-bumpable
75
+ `pyproject.toml`, discovered 2026-06-23 (57 repos):
76
+
77
+ ```text
78
+ agenda agentculture-cli agentfront agentirc agent-lifecycle agtag
79
+ amazing-hand-cli antoine appsec arm101-cli arxivist auntiepypi climate-cli
80
+ cloudai-cli code-lens-cli coherence-cli colleague culture cultureagent
81
+ culture-agent-template culture-core cultureflare culture-tools data-refinery-cli
82
+ devague devex dgx-spark-cli discord-bot-cli dominion-breaker ec2bedrock-cli
83
+ ec2-cli ghafi grant guildmaster identity-cli irc-lens jetson jetson-ai-lab-cli
84
+ katvan knowledgebase-cli lecodeur lobes-cli office-agent operator-cli prove-cli
85
+ qodo-cli reachy-mini-cli reachy-mini-mcp reduce-cli refactor-cli reterminal-cli
86
+ rtx-spark-cli steward telek tensor-cli tipalti unsloth-cli
87
+ ```
88
+
89
+ Excluded as non-targets (no `.claude/skills/` kit): `antigravityd`, `codexd`,
90
+ `kirod`, `landing-page`. `eidetic-cli` is the origin (already has them);
91
+ `rollout-cli` is self (carries its own localized copy + this recipe).
92
+
93
+ Eight consumers have **no `culture.yaml` suffix** (`agentirc`, `cultureagent`,
94
+ `cultureflare`, `ghafi`, `grant`, `irc-lens`, `office-agent`, `tipalti`) — their
95
+ fresh-add `SKILL.md` falls back to the repo basename in the scope example; the
96
+ wrapper itself falls back to the CLI default scope at runtime, so they still
97
+ work. Keep this table current when a consumer is added or dropped.
98
+
99
+ ## Reconciliation procedure (when eidetic-cli changes a wrapper)
100
+
101
+ 1. Refresh the snapshot from the origin checkout, then **re-apply the
102
+ public-default policy override** (the wrappers are origin-verbatim *except*
103
+ that one line — `cp` re-introduces eidetic's `private`, so the `sed` must
104
+ flip it back to `public`):
105
+
106
+ ```bash
107
+ O=../eidetic-cli/.claude/skills
108
+ D=recipes/eidetic-memory/files/scripts
109
+ cp "$O/remember/scripts/remember.sh" "$D/"
110
+ cp "$O/recall/scripts/recall.sh" "$D/"
111
+ # POLICY OVERRIDE: default visibility private -> public (keeps memory in-repo).
112
+ # Re-add the POLICY OVERRIDE comment by hand if a future eidetic release moves
113
+ # the line; the marker to find is `SCOPE_ARGS+=(--visibility private)`.
114
+ sed -i 's/SCOPE_ARGS+=(--visibility private)/SCOPE_ARGS+=(--visibility public)/' \
115
+ "$D/remember.sh" "$D/recall.sh"
116
+ # SKILL.md templates — re-tokenize the illustrative scope examples:
117
+ sed -e 's/--scope eidetic-cli/--scope __REPO_NICK__/g' \
118
+ -e 's/(here, `eidetic-cli`)/(here, `__REPO_NICK__`)/g' \
119
+ "$O/remember/SKILL.md" > recipes/eidetic-memory/files/SKILL.md.remember.tmpl
120
+ sed -e 's/--scope eidetic-cli/--scope __REPO_NICK__/g' \
121
+ "$O/recall/SKILL.md" > recipes/eidetic-memory/files/SKILL.md.recall.tmpl
122
+ ```
123
+
124
+ Note: the vendored `SKILL.md` text still describes eidetic's upstream
125
+ `private` default (it is documentation from the origin). The operative
126
+ override to `public` lives in the wrapper + the `CLAUDE.md` convention this
127
+ recipe writes; keep those two authoritative.
128
+
129
+ 2. Dry-run, then apply (see "Run it"). The wrapper is always re-vendored; an
130
+ existing downstream `SKILL.md` is left untouched, so a doc-only upstream
131
+ change must be re-broadcast deliberately (delete the downstream `SKILL.md`
132
+ first, or extend `apply.sh`).
133
+
134
+ The `CLAUDE.md` memory-discipline section (`files/CLAUDE.snippet.tmpl`) is
135
+ rollout-cli-authored, **not** vendored from eidetic-cli, so a wrapper refresh
136
+ does not touch it. It is gated on its marker phrase the same way: once a target
137
+ carries the section, a re-apply leaves it alone; to re-broadcast an edited
138
+ snippet, remove the marker line downstream first.
139
+
140
+ ## Re-broadcasting: the work-branch collision
141
+
142
+ The engine names the work branch `rollout/<recipe-name>` — for this recipe,
143
+ `rollout/eidetic-memory` — and the `apply` CLI has **no `--branch` flag**. So a
144
+ *second* broadcast collides with the first round's branch wherever it still
145
+ exists (merged-but-not-deleted, or an open round-1 PR): the push is rejected and
146
+ that repo lands a `needs-attention` row. Deleting sibling branches in bulk is
147
+ also (rightly) refused by the agent's safety classifier. The clean fix is a
148
+ **fresh, unique branch name** per round — drive the engine directly:
149
+
150
+ ```python
151
+ # round-2 used branch="rollout/eidetic-memory-0.10" over fresh clones:
152
+ orchestrate.apply_one(clone_path, rec, branch="rollout/eidetic-memory-0.10",
153
+ repo_slug=slug, date=today, pr_opener=opener)
154
+ ```
155
+
156
+ A unique branch never collides and deletes nothing. (Round-2, 2026-06-24, opened
157
+ 57/57 this way; `colleague`'s still-open round-1 PR became a harmless duplicate
158
+ to close.)
159
+
160
+ Refs: eidetic-cli skill ledger (`docs/skill-sources.md`), rollout-cli
161
+ `docs/skill-sources.md` (provenance rows for `remember` / `recall`).