Skip to content

feat(paperclip): add user-scoped memory isolation for GDPR compliance#1561

Closed
amirhmoradi wants to merge 8 commits into
vectorize-io:mainfrom
odience-network:main
Closed

feat(paperclip): add user-scoped memory isolation for GDPR compliance#1561
amirhmoradi wants to merge 8 commits into
vectorize-io:mainfrom
odience-network:main

Conversation

@amirhmoradi

Copy link
Copy Markdown
Contributor
  • Add userId parameter to BankContext for per-user memory isolation
  • Extend bankGranularity to support 'user' option for isolating memories by user
  • Add resolveUserIdFromActiveIssue() to extract user email from active issue
  • Add 'issues.read' capability to permissions for accessing active issue data
  • Update all bank ID derivations to include user ID when granularity includes 'user'
  • Update manifest description to mention GDPR compliance when user option is enabled

This allows agents to maintain user-scoped memory in multi-user scenarios,
ensuring that personal/scoped conversations don't leak between users.

amirhmoradi and others added 2 commits May 9, 2026 23:39
- Add userId parameter to BankContext for per-user memory isolation
- Extend bankGranularity to support 'user' option for isolating memories by user
- Add resolveUserIdFromActiveIssue() to extract user email from active issue
- Add 'issues.read' capability to permissions for accessing active issue data
- Update all bank ID derivations to include user ID when granularity includes 'user'
- Update manifest description to mention GDPR compliance when user option is enabled

This allows agents to maintain user-scoped memory in multi-user scenarios,
ensuring that personal/scoped conversations don't leak between users.
feat(paperclip): add user-scoped memory isolation
@benfrank241

Copy link
Copy Markdown
Member

Thanks @amirhmoradi, direction is right, per-user isolation in paperclip is a real gap worth fixing. but i pulled the branch and npm run typecheck fails with 4 errors:
src/worker.ts(89,57): TS2345: Property 'getActive' is missing in type 'PluginIssuesClient'
src/worker.ts(133,57): same
src/worker.ts(172,59): same
src/worker.ts(224,59): same

ctx.issues.getActive() doesn't exist in @paperclipai/plugin-sdk. I checked the pinned ^2026.403.0, the latest stable 2026.428.0, and the latest canary 2026.511.0-canary.8.

Paperclip-Paperclip and others added 6 commits May 12, 2026 00:11
…ve() method

The getActive() method does not exist in the Paperclip plugin SDK. Instead,
use ctx.issues.list() to retrieve the agent's issues, then extract the user
email from the first (most active) issue's originId field.

This fixes the TypeScript compilation errors reported in the PR review.
The previous fix still had the wrong type signature. The actual SDK
PluginIssuesClient.list() requires a {companyId, ...} input object.

Changes:
- Import PluginContext type from @paperclipai/plugin-sdk
- resolveUserIdFromActiveIssue now takes (ctx: PluginContext, companyId, agentId, config)
- Calls ctx.issues.list({ companyId, assigneeAgentId: agentId, status: 'in_progress', limit: 1 })
  to find the agent's currently active issue
- All 4 call sites updated to pass companyId and agentId from their respective contexts

Verified: npm run typecheck passes with zero errors.
@benfrank241

Copy link
Copy Markdown
Member

thanks for updating. one quick check: when an agent has more than one in-progress issue, this picks an arbitrary one (whatever list orders first). is that acceptable for paperclip's model, or should the helper pin to a specific id?

@benfrank241

Copy link
Copy Markdown
Member

@amirhmoradi thanks for the original work here — per-user isolation in paperclip is a real feature we wanted, and your PR is what kicked it off.

closing this one because it's picked up merge conflicts and the design question about multi-issue ordering (my comment from may 12) was never resolved. we've taken the concept and landed it in #1761 with a different approach: instead of ctx.issues.list() (which picks an arbitrary issue), we extract the user from the specific issue already in context for each event handler.

you're credited in both the commit and the PR description. appreciate the contribution — if you spot anything off in #1761, feel free to comment there.

@amirhmoradi

Copy link
Copy Markdown
Contributor Author

@amirhmoradi thanks for the original work here — per-user isolation in paperclip is a real feature we wanted, and your PR is what kicked it off.

closing this one because it's picked up merge conflicts and the design question about multi-issue ordering (my comment from may 12) was never resolved. we've taken the concept and landed it in #1761 with a different approach: instead of ctx.issues.list() (which picks an arbitrary issue), we extract the user from the specific issue already in context for each event handler.

you're credited in both the commit and the PR description. appreciate the contribution — if you spot anything off in #1761, feel free to comment there.

Thanks a lot for your message and the push towards a better implementation. 🙏

benfrank241 added a commit that referenced this pull request May 26, 2026
…1761)

* feat(paperclip): add per-user memory isolation via bankGranularity

Add 'user' as a bankGranularity option so each user gets their own
isolated memory bank. User identity is extracted from the specific
issue being worked on (via originId email or creatorEmail), not from
an arbitrary issue list query.

- bank.ts: add userId to BankContext, extractUserFromIssue() helper
- worker.ts: pass userId through all 4 bank-derivation sites, cache
  userId in plugin state so tool calls derive the same bank ID
- manifest.ts: add 'user' to bankGranularity enum
- tests: 6 new tests covering derivation, extraction, and integration

Inspired by #1561 — thanks @amirhmoradi for the original concept and
initial implementation.

* feat(paperclip): add bankId/dynamicBankId for static shared banks

Add bankId and dynamicBankId config fields matching the pattern used
by openclaw, claude-code, and opencode. When bankId is set and
dynamicBankId is not true, all agents share the same bank — useful
for multi-agent cohorts that need collaborative memory.

- bank.ts: static override check before dynamic derivation
- manifest.ts: add dynamicBankId (boolean) and bankId (string) fields
- worker.ts: add fields to PluginConfig type
- tests: 5 new tests (static override, trimming, whitespace fallthrough,
  dynamicBankId=true bypass, integration routing)

Inspired by #1589 — thanks @SeBru1 for the original concept.
Closes #1589.

* test(paperclip): add edge-case tests for bank feature interactions

19 additional tests covering:
- Feature interaction: static bankId vs user granularity precedence
- Static bankId edge cases: special chars, tabs/newlines, empty string
- Dynamic derivation edge cases: empty granularity, user-only, duplicates
- extractUserFromIssue: null fields, empty strings, multiple emails

* style(paperclip): fix lint formatting drift
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.

3 participants