feat(cloud): allow excluding user prompts from Cloud replication while keeping sessions and observations
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- go, sqlite
- Domain
- databases, distributed-systems
Research direction
Start by reading internal/sync/sync.go around Cloud mutation enqueueing and prompt application, then trace autosync in internal/cloud/autosync/manager.go and the existing Git content selection in internal/sync/git_export_content.go. Check the related behavior and tests for mutation accounting, tombstones, and the provenance preflight. Done means Cloud push and pull can exclude prompts while local prompt features and other entities continue to work, with the stated edge cases covered and Cloud documentation updated.
Written by the indexing model from the issue text.
Description
Existing Issue Search
- I searched existing issues and will add evidence to a canonical tracker when applicable.
Closest related work, none of which duplicates this request:
- #201 —
security(sync): make Git-based memory sync safer by default, especially for prompts(closed). This is the accepted precedent: the privacy framing was accepted and the mitigation shipped for local Git sync only. - #2172 —
feat(vault): add named encrypted vaults and private Cloud sync(open,status:needs-review). A different solution to a different problem; see "Why this is not #2172" below. - #2288 —
refactor(sync): separate Git export content selection from publication(closed). Relevant implementation surface.
🔍 Observed Consequence
Engram treats prompt privacy as a safety default on one of its two replication paths, but not the other.
For Git, prompts are excluded by default and require an explicit engram sync --include-prompts opt-in. For Engram Cloud, the same data is replicated unconditionally: the cloud export returns before the Git content-selection step, prompt payloads travel as sync mutations, autosync pushes every pending mutation including prompts, and the Git opt-in flag is actively rejected in cloud mode.
The consequences for a team on a self-hosted Cloud server:
- Every raw prompt a developer types reaches the shared server, where it is a first-class synced entity and is browsable by the team through prompt pages, prompt detail, paginated lists, and a prompt column inside session detail.
- There is no way to express "share what I curated, not what I typed". Observations are deliberately saved and structured. Prompts are captured automatically, unread, at the moment of typing.
- The captured prompt stream is not clean by the project's own record: synthetic and extension-injected turns have repeatedly been stored as user prompts (#1673, #1674, #2234), and capture activity has needed explicit tightening before (#310). Replicating that stream by default shares noise with a team, not memory.
- The only lever available today is lossy: disabling prompt capture also removes prompts from local context and compaction recovery, which is exactly the material a developer wants to keep for themselves.
💡 Desired Outcome
A developer on a shared Cloud server can keep their prompts on their own machine while still sharing everything else with the team.
Successful outcome:
- I set a Cloud client preference once, and from then on my prompts are not replicated to the shared server.
- My sessions, observations, relations and project metadata continue to sync exactly as they do today.
- My prompts still work locally: capture, search, and context/compaction recovery are unaffected.
- Symmetrically, I do not silently acquire teammates' prompts either.
- I understand exactly what this does and does not protect: it is a sharing policy, not encryption, not redaction, and not retroactive.
I understand this is not a request to change Git behavior, which already has the safer default.
📦 Affected Area
Sync (multi-instance)
Secondary: CLI (commands, flags), Documentation. No Store, MCP or TUI behavior change is requested; local reads must remain identical.
Release Context
main branch. Not release-specific; source observations are from the current tree at the time of filing and should be re-checked before implementation.
🔄 Workarounds and Constraints
Tried today: capture_prompt: false on mem_save, and not installing the host prompt hook. Both stop prompts from being stored locally too, which is the trade-off this issue asks to remove — they conflate "do not replicate" with "do not remember".
Constraints observed:
- The obvious insertion point already exists: entity-aware content selection was deliberately separated from publication in #2288, and the Git filter is a single localized step the Cloud path never reaches.
- Adding this must not change frozen chunk formats, remote canonicalization or materialization for the default path.
- #686 already showed how a malformed prompt mutation can wedge Cloud push for all projects; #837 showed prompt deletes being dropped during cloud chunk materialization. Any gate here must fail safe without breaking sessions and observations, and without losing deletion propagation.
📎 Additional Context
Why the existing boundary does not cover this case
The maintainers' resolution of #201 was deliberate, not an oversight: the shipped contract scoped prompt exclusion to local Git sync and explicitly left Cloud and standalone engram export unchanged. This issue is not a request to reopen #201, its defaults, or its tombstone model. It asks to extend an already-accepted policy to the other replication path for the same data — the one teams actually share.
The #201 reasoning was about Git history (durable, replicated, hard to clean). The same reasoning applies to a shared Cloud server with different mechanics: replicated, browsable by the team, and outside the author's control once pushed.
Why this is not #2172
#2172 answers a different threat model: protect work from the backend itself, using separately encrypted vaults with a key lifecycle, browser decryption and no plaintext fallback. It remains status:needs-review with the cryptographic backend, key derivation, representation and recovery semantics still unqualified, which is the correct place for that scrutiny.
This proposal is entity-scoped sharing policy inside the ordinary Cloud path:
| #2172 (vaults) | this issue | |
|---|---|---|
| Protects against | the operator / backend / account compromise | teammates browsing shared memory |
| Mechanism | separate encrypted storage + keys | do not replicate an entity type |
| New cryptography | yes | none |
| New storage format | yes | none |
| Claimed confidentiality | design objective, unqualified | explicitly not claimed |
Both can coexist. A team that wants vaults still needs a way to say "my prompts are not team knowledge at all", and a team that will never adopt vaults still has this problem.
Current behavior (source evidence)
| Fact | Source |
|---|---|
| Cloud export takes the mutation-backed branch and never reaches Git content selection | internal/sync/sync.go:527-532 |
| Git prompt exclusion lives only in the Git chunk builder | internal/sync/git_export_content.go:28-33 |
| Core API rejects the Git opt-in in cloud mode | internal/sync/sync.go:462-464 |
| Same rejection at CLI preflight, before effects | cmd/engram/main.go:2291, cmd/engram/main.go:2307-2308 |
| Prompts travel as full-payload sync mutations | internal/sync/sync.go:2043-2046 |
| Autosync pushes prompt mutations with everything else | internal/cloud/autosync/manager.go:756, internal/cloud/autosync/manager.go:779 |
| Autosync config has no prompt-scoped field | internal/cloud/autosync/manager.go:199-210 |
engram cloud config persists only endpoint and token |
cmd/engram/cloud.go:968-974 |
| Documented position: Cloud keeps its existing prompt behavior | DOCS.md:1945, docs/codebase/sync-and-cloud.md:33 |
| Git wording worth mirroring positively | DOCS.md:1932, DOCS.md:1938-1941 |
| Existing Cloud policy is project-level only | docs/engram-cloud/quickstart.md:196-200 |
| Prompt gating in autosync today is authorization, not exclusion | internal/cloud/autosync/manager.go:809-841 |
| Prompts are optional in local context/compaction output | internal/store/store.go:6578-6585, :6611, :6721-6726 |
| Prompt tombstones carry identity and metadata, not content | DOCS.md:1932, internal/store/store.go:11025-11026 |
These line numbers are from a read-only investigation of the current tree; treat them as pointers, not guarantees.
Proposed design contract (v1)
Following the shape the maintainers used for #201, the contract before any implementation:
- Boundary. Client-side Cloud only, at the point
SyncEntityPromptmutations are enqueued for transport. No server behavior change is required for v1. A server-enforced policy for teams that want it admin-guaranteed can be a follow-up. - Default. Opt-out: existing deployments keep today's behavior unless the preference is set. Whether the eventual default should mirror Git's safer default is a separate product decision and is explicitly not decided here.
- Local data. Nothing local is deleted, altered or suppressed. Capture,
/prompts/search,mem_search_promptsand local context keep working. - Bidirectional. The preference gates both enqueue (push) and prompt apply-on-pull, so a preserving machine neither publishes nor silently acquires teammates' prompts. Splitting pull into a later stage is possible but should be an explicit decision, not an implicit default.
- Tombstones. A prompt that was never published has no deletion to propagate, so with the preference off no prompt tombstone should be enqueued either. For prompts published before the preference was enabled, v1 must state plainly that deletion propagation stops, and purging already-replicated prompts is a separate decision. It is not secure erasure, and should not be described as one.
- Integrity and accounting. Reuse the discipline #201 required: counts and identifiers derive from what is actually replicated, and re-enabling prompt sync must neither silently skip older prompts nor resurrect deleted ones. The #201 contract already flagged the analogous watermark hazard for the Git path (
filterNewDatacomparing promptCreatedAtagainst the watermark,internal/sync/sync.go:2177); the Cloud journal model differs, but the same class of bug must be excluded and pinned by a test. - Failure behavior. The preference must not make sync fail. In particular the per-prompt provenance preflight must not start erroring because prompts are absent from a batch; sessions and observations must keep pushing.
- Degraded surfaces, documented. With prompts excluded and none published,
/prompts/search,mem_search_prompts, the dashboard prompt pages and prompt column, andengram cloud attest-prompt-sourcehave nothing to show or attest. That is expected behavior, not an error state, and belongs in the docs rather than being left as an empty-page surprise. - Docs parity.
docs/engram-cloud/currently states only the negative ("retains its existing prompt behavior"). It needs the positive statement, mirroring Git's wording: prompts stay local unless you intentionally share them, plus what that choice does not protect.
Proposed acceptance checks
- With
sync-prompts=off, a session containing both prompts and observations replicates its observation content and produces no prompt entity on the server. - Local reads are unaffected: prompts remain locally searchable and still appear in local context/compaction output.
- Sessions, observations, relations and project metadata replicate identically with the preference on and off.
- Re-enabling publishes eligible existing prompts without duplicating already-synced ones and without skipping prompts older than the current watermark.
- No prompt tombstone is enqueued while the preference is off, and enabling it later does not resurrect deleted prompts.
- The provenance preflight does not fail for a batch containing no prompt entities.
- Documented degraded surfaces behave as documented: empty results, not errors.
- Existing Git behavior, defaults and the
--include-promptscontract are unchanged.
Non-goals
- Not encryption, not a vault, not #2172, and not a change to the Cloud threat model. A server operator and anyone with server or database access still sees everything replicated.
- Not a replacement for, or change to, #201's Git defaults.
- Not retroactive: this does not erase prompts already replicated.
- Not per-prompt curation, redaction, or a review step before replication.
- Not a server-admin enforcement mechanism in v1.
Scale
The change is a scoped preference plus one gate at the mutation enqueue/apply boundary, with tests and docs. It is deliberately smaller than #2172 and independent of it, so it can be reviewed without waiting on the cryptographic design.
- Dominant language
- Go
- Stars
- 7.1k
- Forks
- 729
- Avg merge
- 11h 47m
- Merged PRs (30d)
- 284
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Gentleman-Programming/engram
-
status:needs-review
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Gentleman-Programming/engram#2065 · 1 comment ·
Maintainers usually reply within 1 day
-
status:needs-review
Difficulty 1/5 Under an hour Newbie friendliness 25/100
Gentleman-Programming/engram#2330 · 1 comment ·
Maintainers usually reply within 1 day
-
status:needs-review
Difficulty 4/5 3-5 days Newbie friendliness 48/100
Gentleman-Programming/engram#2315 ·
Maintainers usually reply within 1 day
-
question(test): stable request storage for existing EINTR scenariosPossibly taken @dnlrsls claimed this 1 day ago. Openstatus:needs-review type:question
Gentleman-Programming/engram#2291 · 1 assignee ·
Maintainers usually reply within 1 day
-
status:needs-review type:bug
Difficulty 4/5 3-5 days Newbie friendliness 38/100
Gentleman-Programming/engram#2278 · 2 comments ·
Maintainers usually reply within 1 day
All issues in Gentleman-Programming/engram
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
router-for-me/CLIProxyAPI#7330 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
bug os:ios
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
hajimehoshi/ebiten#4039 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 9 days