Repository navigation
Workspace memory for AI clients (Enterprise) - #1152
Merged
Merged
Conversation
Generating skills deleted every pending skill in its scope, including Agent Skills Finder suggestions awaiting approval and manual pending ones. Skills now record their source (manual, llm, finder) and generation only replaces its own pending llm suggestions. activeSkillsText also filters by organization, and the skill endpoints validate their bodies with DTOs. Intent capture was one switch for the whole workspace. Admins can now set each member to inherit, on or off (also in bulk, optionally erasing the intents already captured), and members can opt themselves out. Only contributing callers get the _intent parameter; callers without a member identity never contribute. Changes are logged as LEARNING_CHANGED.
Every applied skill was pasted into the initialize instructions, a skill could only hold a 2,000-character rule, and edits overwrote it. - skills_list / skill_get on /mcp/:serverId when the caller sees an applied skill, scoped to the server's organization and the caller's visible connectors; each skill is also offered as an MCP prompt. - Per-server skills_delivery: auto (full text up to 6,000 characters, else an index), inline or index. The migration pins servers already above the threshold to inline so nothing changes until an admin opts in. - Optional body (markdown, up to 20,000 characters) served by skill_get only; the Skills Finder can file one. - Edits keep the previous content in kg_skill_versions; skill_get and prompts count uses. Consolidate leaves skills with a procedure alone. - AI Skills page shows procedure, version, usage and history; the MCP server page gets the delivery setting.
AI clients can save facts, preferences and notes and find them again in
any client connected to a server of the workspace: personal memory per
member (readable only by that member) and a company memory.
- memory_items with a generated tsvector ('simple') and GIN index;
organization_members.memory_access (inherit, none, read, personal,
contribute) with a workspace default.
- memory_search / memory_save / memory_forget on /mcp/:serverId only,
offered by the caller's level; results are labelled as data, not
instructions. Company memory from AI clients waits for approval unless
the workspace switch is set to automatic.
- Secrets are refused; size limits per item, member and workspace.
Admins can erase a member's personal memory without reading it;
removing a membership deletes it. Access, settings and erasures are
logged as security events.
- Licence gate in ee/licensing (EditionService.hasMemory): an active
Enterprise licence of the workspace (Cloud) or instance (self-hosted);
not the trial or transition period. The code itself is AGPL.
- Memory page (my memory, company memory, review, settings), Memory
column and bulk actions on Settings > Users, docs/memory.md.
This was referenced Oct 19, 2026
Closed
10 tasks done
Contributor
Author
|
Update after review (19 Oct): verified with a real model (gpt-4o-mini driving the MCP server as a chat client) and two independent security reviews. Fixes are in the PRs they belong to:
Merge the stack in order (#1146 → #1149 → #1152 → #1154 → #1158) and release them together. |
9 tasks done
…ai/workspace-memory
…ai/workspace-memory
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Workspace memory, see #1151. Builds on #1146 and #1149: until those are merged this PR also shows their commits; the changes here are in the last commit, "Add workspace memory for AI clients (Enterprise)".
AI clients can save facts, preferences and notes and find them again later, in any client connected to an MCP server of the workspace. Each member has a personal memory that only they can read, and the workspace has a company memory. Admins decide per member what their AI clients may do with it, and whether company memory proposed by AI clients needs approval.
Memory is available with an Enterprise licence on Cloud and self-hosted. It is gated like single sign-on: the code is AGPL, only the licence check (
EditionService.hasMemory/assertMemory) lives inee/licensing. Thatee/change was decided by the maintainer for this feature.Changes
memory_items(organization, scopepersonal|organization, owner, kindfact|preference|note, content up to 2,000 characters, tags, statusactive|pending|rejected, source, author, approver) with a generatedtsvectorcolumn (simpleconfiguration, no stemming, so German, Italian and English behave alike) and a GIN index.organization_members.memory_access:inherit(default) |none|read|personal|contribute. Workspace settings inorg_settings: default access (initiallypersonal) and the write mode for company memory from AI clients (approvalby default, orauto).EditionService.hasMemory(organizationId): an active, unexpired licence with planenterprise. Cloud reads the workspace's licence; self-hosted reads the workspace's or the instance's key. The Business plan, the trial and the transition period do not include it. Cached 60 s per workspace because the MCP endpoint checks it on every request. Without it the routes answeredition_requiredand no memory tool is offered; stored data is kept./mcp/:serverIdonly; the shared/mcptoolset is unchanged), offered by the caller's level in the server's organization:read:memory_search(query?, scope?, limit?), full text ranked by relevance, falling back to a substring match for partial words and codes.personal: alsomemory_save(personal) andmemory_forget(own personal items only).contribute:memory_savealso offersscope: "organization", pending or active depending on the workspace switch.password:/token=patterns, private keys) is refused. Limits: 10 tags per item, 1,000 personal items per member and workspace, 20,000 items per workspace.MEMORY_ACCESS_CHANGED(one row per member),MEMORY_SETTINGS_CHANGED,MEMORY_ERASED./api/memory):status,items(list, create, edit, delete),items/:id/approveanditems/:id/reject(admin, editor),settings(admin),members/access(admin, up to 500),members/:userId/personal(admin, erase). All DTO-validated.docs/memory.md, linked fromdocs/guides.md.Cloud and self-hosted behave the same; the only difference is where the licence is read (workspace licence on Cloud, workspace or instance key on self-hosted).
Type
Testing
Commands and results:
packages/backend:npx prisma generate,npx tsc --noEmit -p tsconfig.json: no errorspackages/backend:npm run lint: 0 errors (existing warnings only); eslint --fix rewrites of untouched files were revertedpackages/backend:npx jest: 677 suites passed, 4 skipped; 20464 tests passed, 1496 skippedpackages/frontend:npx tsc --noEmit -p tsconfig.json: no errors; eslint on the changed files: no new findingsprisma migrate deployon an empty scratch database, thenprisma migrate diffagainst the schema: empty (the generated column and GIN index are declared in the schema, so later migrations do not try to drop them).New unit tests: licence rules (Enterprise yes; Business, Team, inactive, expired, trial, transition no; per-workspace lookup), access resolution (no licence, no user, non-member, deactivated, inherit, explicit), save rules (levels, approval vs automatic, curator, secrets, limits, tags), search scope (organization filter, personal only for the owner, read level, full text then fallback, rank order), ownership (forget, someone else's personal item is not found even for an admin, curators only for company items), erase, access changes, membership removal, and the MCP endpoint (tools per level, organization scope only from contribute, arguments scoped to the server's organization, data labelling).
Manual end-to-end on a local backend (scratch database, MCP API key, JSON-RPC over
/mcp/:serverId):/api/memory/statusreportslicensed: false, item routes return 403edition_required, no memory tool is listed.personallists search, save and forget;memory_savehas noscope; a preference was saved; a token-like text was refused.contribute: a company item was saved as pending, did not appear in search, was approved via the API, then found by full text ("stammkunde"), by a partial word ("framew", fallback) and by English words ("Italian tables").memory_forgetof the member's item returns not found; the member still sees it. A viewer cannot change access (403). The admin erased the member's personal memory (1 item) without reading it.MEMORY_ACCESS_CHANGED,MEMORY_ERASED,MEMORY_SETTINGS_CHANGEDwith from/to.Checklist
npx jest)Related Issues
Fixes #1151
Depends on #1146, #1149