Skip to content

feat(memos-local-openclaw): add hub sharing, dual-instance isolation, and viewer/docs improvements#1320

Closed
tangbotony wants to merge 92 commits intoMemTensor:mainfrom
tangbotony:native_memos
Closed

feat(memos-local-openclaw): add hub sharing, dual-instance isolation, and viewer/docs improvements#1320
tangbotony wants to merge 92 commits intoMemTensor:mainfrom
tangbotony:native_memos

Conversation

@tangbotony
Copy link
Contributor

Description

This PR brings the native_memos branch into main with a major upgrade to the memos-local-openclaw plugin, focused on team sharing, dual-instance isolation, viewer usability, recall quality, and documentation completeness.

It solves several practical issues that appeared during real-world local OpenClaw usage, especially when running multiple instances on the same machine:

  • team sharing state transitions were fragile across join/leave/role-switch flows
  • Hub/Viewer ports and session state could conflict in dual-instance setups
  • admin and member notifications were incomplete or unclear
  • Viewer polling and sharing UX had refresh/state consistency issues
  • documentation and landing pages did not fully explain the Hub/Client architecture, multi-instance deployment, and collaboration workflow

Implementation approach:

  • added and hardened the Hub/Client sharing architecture, including Hub auth, client connector flow, server-side status management, admin operations, and notification handling
  • improved dual-instance isolation by refining runtime/config behavior around gateway-derived ports, sharing state cleanup, and local-vs-hub behavior boundaries
  • enhanced recall quality with origin tracking, Hub result filtering, and local/hybrid search improvements
  • improved Viewer UX and stability across sharing setup, admin workflows, polling, notifications, and collaboration-related UI
  • added and updated automated test coverage for hub server, viewer sharing, connector logic, storage, integration, and skill runtime flows
  • expanded README, Team Sharing guide, docs site, troubleshooting docs, and landing pages to better document collaboration workflows and multi-OpenClaw capabilities

Relevant dependencies / requirements:

  • no new mandatory external product dependency for end users beyond existing model/provider configuration
  • local runtime still depends on better-sqlite3 native bindings being built for the active Node.js version
  • optional telemetry and model-provider related configuration continue to follow the existing plugin setup

Related Issue (Required): Fixes #1319

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (does not change functionality, e.g. code style improvements, linting)
  • Documentation update

How Has This Been Tested?

The change was validated through a combination of targeted automated coverage added in this branch and manual end-to-end verification of multi-instance local OpenClaw scenarios.

Test areas covered in this branch include:

  • Hub server and authentication behavior
  • viewer sharing flows and config handling
  • client connector and sharing state transitions
  • storage and integration flows
  • skill runtime and sharing-related scenarios

Manual reproduction / verification steps:

  1. Start two local OpenClaw instances with isolated OPENCLAW_CONFIG_PATH, OPENCLAW_STATE_DIR, and workspace directories.
  2. Install and enable memos-local-openclaw in both instances.
  3. Configure one instance as Hub and another as Client.
  4. Verify gateway, viewer, and Hub startup behavior, including port isolation and no cross-instance conflict.
  5. Submit a join request from the Client, approve it from the Hub, and verify status updates and notifications.
  6. Test admin operations including promote, demote, remove member, and self-removal prevention.
  7. Test client leave / disable / role-switch behavior and verify state cleanup and reconnect behavior.
  8. Verify Viewer live updates do not cause unnecessary full refreshes or scroll-position loss.
  9. Open the updated docs / landing pages and confirm installation instructions, Team Sharing content, and collaboration visuals are displayed correctly.

Suggested test environment:

  • OS: macOS

  • Runtime: local OpenClaw dual-instance setup

  • Plugin: memos-local-openclaw

  • Database: SQLite / better-sqlite3

  • Unit Test

  • Test Script Or Test Steps (please provide)

  • Pipeline Automated API Test (please provide)

Checklist

  • I have performed a self-review of my own code | 我已自行检查了自己的代码
  • I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释
  • I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常
  • I have created related documentation issue/PR in MemOS-Docs (if applicable) | 我已在 MemOS-Docs 中创建了相关的文档 issue/PR(如果适用)
  • I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用)
  • I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人

Reviewer Checklist

jiaqian added 30 commits March 8, 2026 12:01
# Conflicts:
#	apps/memos-local-openclaw/tests/integration.test.ts
…licitly

- createMemorySearchTool now accepts optional store and ctx parameters
  instead of accessing private members via (engine as any)
- Add missing worker.flush() call in root index.ts stop handler
- Fix shutdown-lifecycle test mocks for new module dependencies

Made-with: Cursor
Prevents memory exhaustion from oversized request bodies. Returns 413
status code when the limit is exceeded.

Made-with: Cursor
Centralized auth + rate limit check for all authenticated endpoints.
- 60 req/min default, 30 req/min for search endpoints
- Returns 429 with retryAfterMs when exceeded
- Refactored handle() to authenticate once at the top

Made-with: Cursor
Add getHubGroupById, deleteHubGroup, and listHubGroupMembers to support
the existing Hub server group management API endpoints.

Made-with: Cursor
- Viewer server: add proxy endpoints for group CRUD, member management,
  and user listing (all forwarded to Hub API)
- Hub server: add GET /admin/users endpoint for listing active users
- Viewer UI: wire up "Manage Groups" button with group/member panel
  (already had the JS functions, now connected via server routes)

Made-with: Cursor
- Add local_shared_tasks table to track which tasks have been shared
- task_share/task_unshare now mark/unmark tasks in local tracking table
- After each agent_end, automatically sync new chunks for shared tasks
  to the Hub without requiring manual re-share

Made-with: Cursor
- Add upsertHubEmbedding/getHubEmbedding/getAllHubEmbeddings to SqliteStore
- Hub server accepts optional embedder; embeds shared chunks async on receive
- Hub search now merges FTS and vector results via RRF (k=60) when embedder
  is available, falling back to FTS-only otherwise
- Pass embedder instance to HubServer from root index.ts

Made-with: Cursor
- config.ts: inject provider:"openclaw" when hostEmbedding/hostCompletion
  capabilities are enabled but no explicit provider is configured, so the
  fallback priority chain (user config → openclaw → local/rule) works correctly
- openclaw-api.ts: rename class to OpenClawAPIClient and add explicit
  `implements OpenClawAPI` to avoid confusion with the interface in types.ts
- ingest/providers/index.ts: rewrite all 5 openclaw summarizer methods with
  high-quality prompts aligned with openai.ts (language preservation, structured
  JSON output for filter/dedup), reuse parseFilterResult/parseDedupResult
- viewer/server.ts: pass openclawAPI to Summarizer in migration code path
- openai.ts: export parseFilterResult for reuse

Made-with: Cursor
- memory_search/skill_search: read agentId from context (3rd arg)
  instead of params, matching the OpenClaw Plugin SDK calling convention
- memory_timeline: add owner filtering so agents cannot access
  other agents' private chunks via timeline traversal
- memory_get: add owner filtering so agents cannot read other
  agents' private chunks directly
- memory_search: include ref and summary in details.hits for
  downstream tools (timeline/get) that need the full ChunkRef
- service.stop(): reorder to flush worker before telemetry shutdown,
  ensuring data persistence completes before auxiliary services stop

Made-with: Cursor
jiachengzhen and others added 27 commits March 20, 2026 03:13
…credentials externalization

- Fix owner filter in serveMemories/serveStats: shared memories (owner='public')
  were excluded because session_key LIKE 'agent:main:%' never matched.
  Changed to simply include all public memories alongside agent-owned ones.
- Add toast notifications for retry-connection in all states (loading/fail/error)
  so sidebar clicks also get user feedback.
- Remove hardcoded ARMS telemetry credentials from source code.
  Credentials are now loaded at runtime from telemetry.credentials.json
  (generated by CI from GitHub Secrets) or MEMOS_ARMS_* env vars.
  If neither is available, telemetry is silently disabled.

Made-with: Cursor
…re atomicity

Disable "team" scope option in the sharing modal when hub connection is
not active, preventing users from triggering a doomed request. On the
backend, reorder scope handlers (memory, task, skill) so the hub remote
call executes before any local state mutation — if the hub request fails,
local data stays unchanged, avoiding inconsistency.

Made-with: Cursor
The migrate/scan endpoint only counted sessions under agents/main/,
while the actual import traverses agents/*/sessions/ for all configured
agents. This caused a mismatch between the previewed message count and
the import progress total.

Made-with: Cursor
Show the number of distinct agents instead of time span in the overview
stat cards. The data is already available from the owners array returned
by the stats API.

Made-with: Cursor
…ltering for Hub results, and skill embedding

- Add SearchHit.origin field (local/local-shared/hub-memory/hub-remote) to track result source
- RecallEngine sets origin based on chunk owner and hubmem: prefix
- memory_search: Hub remote results now pass through summarizer.filterRelevant LLM filtering
- Hub skill publish generates embedding async via embedSkillAsync for vector search
- Hub /api/v1/hub/skills search endpoint adds vector search + RRF fusion
- Add getVisibleHubSkillEmbeddings() to sqlite storage layer
- rawCandidates and auto-recall logs include origin field
- Viewer log recall-items display origin badges (本机共享/团队缓存/团队)
- AI output annotates each result with origin label
- Handle removed user re-join on Hub (reset to pending)
- Detect 401 in getHubStatus for deleted user cleanup

Made-with: Cursor
…serve client hub connection on disable

- Check both hostname and port when detecting self-join to avoid blocking different-port Hub on same machine
- Preserve client hub connection when sharing is disabled (instead of clearing it) for seamless re-enable
- Trigger auto-join when re-enabling sharing as client, not only on initial role switch

Made-with: Cursor
… sharing UX

- Fix embedding model consistency: Client mode no longer stores hub_memories
  locally or searches them with local embedder. Remote data stays remote,
  searched via Hub API only. Hub mode retains local hub_memories search
  since embeddings are generated by the same model.
- Add user notifications for approve/reject: Hub server now creates
  notifications for users when their membership is approved or rejected.
- Fix sharing UI onboarding: Settings page auto-switches to Hub tab when
  sharing is unconfigured, showing the setup guide card.
- Fix scope selector visibility: Memory/task/skill scope selectors now
  appear when hub is connected, auto-refresh data on first connection.
- Fix hub group management: Add hub_groups/hub_group_members tables and
  CRUD methods, enforce group-based search permissions.
- Fix chunker type system: Support code_block, error_stack, list, command
  chunk kinds beyond paragraph.
- Fix test stability: Mock LLM in task-processor test, adapt viewer-sharing
  tests to pending-approval flow, fix viewer-ui function call.

Made-with: Cursor
…ove notification and admin panel refresh

- Fix 401 misdiagnosis: token expiry was incorrectly treated as "removed" status.
  Now queries registration-status for real state and auto-renews token if active.
- Add membership_approved/rejected notification types with i18n support
- Reconnect SSE and load notifications immediately on pending→active transition
- Shorten client pending poll interval from 10s to 5s
- Add user.status to admin fingerprint to catch status changes
- Force admin data refresh on view switch and after approve/reject/remove/role-change
- Add notifPollImmediate for instant notification check on new SSE connections

Made-with: Cursor
…uto-upgrade, and sharing UX fixes

- Auto-recall: add hubFallback() to search remote Hub when local yields no/insufficient results (3-layer fallback)
- memory_search: auto-upgrade scope from "local" to "all" when sharing is enabled
- config: parse client nickname field for join requests
- hub/server: sync userManager.approveUser on registration-status token renewal
- storage: tasks query includes shared public tasks for original owner visibility
- viewer: role switch clears stale panels, rejected/removed show retry button, admin tab visibility control, adminToggleRole refreshes all panels, memory scope persists in localStorage

Made-with: Cursor
…ment, and admin notifications

- Hub port auto-derivation (gatewayPort + 11) to avoid port conflicts in multi-instance setups
- Hub port retry on EADDRINUSE (up to 3 retries)
- Role change notifications (role_promoted / role_demoted) sent to affected users
- Withdraw-pending API for canceling pending join requests when switching roles
- Complete client connection cleanup (clearClientHubConnection) on role switch
- Frontend toast guards: pending→connected/rejected only fire for client role
- Resource notification display: localized titles with resource name as detail
- Self-removal prevention in admin user management panel
- Faster restart overlay (waitDown max 8 attempts instead of 60)
- Config path resolution via OPENCLAW_CONFIG_PATH / OPENCLAW_STATE_DIR

Made-with: Cursor
…s all docs and landing pages

- README: expand Team Sharing section with capabilities table, multi-instance deployment, Viewer panel details
- HUB-SHARING-GUIDE: add admin features, notifications table, multi-instance deployment, port auto-derivation
- www/index.html: add Team Sharing section with Hub-Client architecture demo, admin controls, nav link, update tool count to 17
- docs/index.html: add Team Sharing sidebar group, feature card, full setup/admin/multi-instance/notification docs
- openclaw.plugin.json: update description to include team sharing and collaboration tools

Made-with: Cursor
…platform tabs & one-liner install

- www/index.html: add macOS/Linux + Windows tab switcher for hero terminal and Quick Start install section; update install description to match openmem.net
- README.md: simplify install to one-liner curl/powershell commands matching openmem.net; add Windows PowerShell install; update homepage links

Made-with: Cursor
…to Team Sharing section

Replace text-only code blocks with a full SVG architecture diagram showing:
- Hub server with team members (online/offline/pending states)
- Three Client instances (Alice connected, Bob pending, Charlie offline)
- Data flow arrows (task_share, skill_pull) between instances
- Shared data badges (tasks, memories, skills counts)
- Per-client views (local private vs team shared data)
- Port auto-derivation info box
- OpenClaw mascot icons on each instance

Made-with: Cursor
…ction

- Add animated SVG showing Hub + 3 Client instances with data flow particles
- Each instance has OpenClaw mascot, role label, memory counts, and operations
- Animated connection lines and flowing data particles between instances
- "...N" indicator showing unlimited scalability
- Update Hero tagline to emphasize multi-instance collaboration

Made-with: Cursor
…inal & add architecture SVG to docs pages

- Move multi-OpenClaw collaboration SVG from below install terminal to above it in Hero section
- Add Hub-Client architecture diagram to docs/index.html and www/docs/index.html team sharing section
- Use distinct gradient ID namespaces (hg*/ts*/dg*) to avoid SVG ID conflicts across pages

Made-with: Cursor
…t hub_memories recall

- Add team_shared_chunks table + upsert/get/delete; clear in deleteAll
- Client: after Hub memories/share, persist metadata only; Hub role keeps upsertHubMemory
- Viewer: merge team_shared_chunks into memory list sharing map; getHubMemoryForChunk reads both
- Unshare paths delete team_shared_chunks; shareMemoryToHub/unshareMemoryFromHub aligned in index.ts
- capture: strip MiniMax <final> tags from captured text
- hub: sync bootstrapAdminToken on rename (self + admin)
- viewer html: admin preview/collapsed message fade mask 88%
- chore: version 1.0.4-beta.19

Made-with: Cursor
…mory on Hub

- Hub: resource_removed notification includes JSON message with memoryId + sourceChunkId
- Viewer: POST /api/sharing/sync-hub-removal clears team_shared_chunks + local hub_memories row
- html: sync from notifications before non-silent loadMemories

Made-with: Cursor
…dge), never hub_memories/recall

Made-with: Cursor
When a memory is re-shared to team after an admin removal, old
resource_removed notifications would incorrectly clear the new
team_shared_chunks badge on every page refresh. Now handleSyncHubRemoval
compares the notification's memoryId against the current hub_memory_id
and skips deletion when they differ (stale notification).

Bump to 1.0.4-beta.21.

Made-with: Cursor
macos-13 runner is deprecated. Use macos-15 (ARM64) and rebuild
better-sqlite3 under Rosetta 2 via arch -x86_64 to produce the
x64 native binary.

Made-with: Cursor
The plugin runs as ESM (type: module) but telemetry.ts relied on
__dirname which is undefined in ESM. Credentials file existed on disk
but was never found, silently disabling all telemetry since day one.

Now accepts pluginDir from index.ts (resolved via import.meta.url)
and uses it as primary search path for telemetry.credentials.json.

Made-with: Cursor
@tangbotony tangbotony closed this Mar 23, 2026
CaralHsi added a commit that referenced this pull request Mar 23, 2026
… isolation, and viewer improvements (#1321)

## Description

This PR brings the `native_memos` branch into `main` with a major
upgrade to the `memos-local-openclaw` plugin, focused on team sharing,
dual-instance isolation, viewer usability, recall quality, and
documentation completeness.

It solves several practical issues that appeared during real-world local
OpenClaw usage, especially when running multiple instances on the same
machine:
- team sharing state transitions were fragile across
join/leave/role-switch flows
- Hub/Viewer ports and session state could conflict in dual-instance
setups
- admin and member notifications were incomplete or unclear
- Viewer polling and sharing UX had refresh/state consistency issues
- documentation and landing pages did not fully explain the Hub/Client
architecture, multi-instance deployment, and collaboration workflow

Implementation approach:
- added and hardened the Hub/Client sharing architecture, including Hub
auth, client connector flow, server-side status management, admin
operations, and notification handling
- improved dual-instance isolation by refining runtime/config behavior
around gateway-derived ports, sharing state cleanup, and local-vs-hub
behavior boundaries
- enhanced recall quality with origin tracking, Hub result filtering,
and local/hybrid search improvements
- improved Viewer UX and stability across sharing setup, admin
workflows, polling, notifications, and collaboration-related UI
- added and updated automated test coverage for hub server, viewer
sharing, connector logic, storage, integration, and skill runtime flows
- expanded README, Team Sharing guide, docs site, troubleshooting docs,
and landing pages to better document collaboration workflows and
multi-OpenClaw capabilities

Relevant dependencies / requirements:
- no new mandatory external product dependency for end users beyond
existing model/provider configuration
- local runtime still depends on `better-sqlite3` native bindings being
built for the active Node.js version
- optional telemetry and model-provider related configuration continue
to follow the existing plugin setup

Related Issue (Required): Fixes #1320

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [x] Refactor (does not change functionality, e.g. code style
improvements, linting)
- [x] Documentation update

## How Has This Been Tested?

The change was validated through a combination of targeted automated
coverage added in this branch and manual end-to-end verification of
multi-instance local OpenClaw scenarios.

Test areas covered in this branch include:
- Hub server and authentication behavior
- viewer sharing flows and config handling
- client connector and sharing state transitions
- storage and integration flows
- skill runtime and sharing-related scenarios

Manual reproduction / verification steps:
1. Start two local OpenClaw instances with isolated
`OPENCLAW_CONFIG_PATH`, `OPENCLAW_STATE_DIR`, and workspace directories.
2. Install and enable `memos-local-openclaw` in both instances.
3. Configure one instance as Hub and another as Client.
4. Verify gateway, viewer, and Hub startup behavior, including port
isolation and no cross-instance conflict.
5. Submit a join request from the Client, approve it from the Hub, and
verify status updates and notifications.
6. Test admin operations including promote, demote, remove member, and
self-removal prevention.
7. Test client leave / disable / role-switch behavior and verify state
cleanup and reconnect behavior.
8. Verify Viewer live updates do not cause unnecessary full refreshes or
scroll-position loss.
9. Open the updated docs / landing pages and confirm installation
instructions, Team Sharing content, and collaboration visuals are
displayed correctly.

Suggested test environment:
- OS: macOS
- Runtime: local OpenClaw dual-instance setup
- Plugin: `memos-local-openclaw`
- Database: SQLite / `better-sqlite3`

- [ ] Unit Test
- [x] Test Script Or Test Steps (please provide)
- [ ] Pipeline Automated API Test (please provide)

## Checklist

- [x] I have performed a self-review of my own code | 我已自行检查了自己的代码
- [x] I have commented my code in hard-to-understand areas |
我已在难以理解的地方对代码进行了注释
- [x] I have added tests that prove my fix is effective or that my
feature works | 我已添加测试以证明我的修复有效或功能正常
- [x] I have created related documentation issue/PR in
[MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) |
我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档
issue/PR(如果适用)
- [x] I have linked the issue to this PR (if applicable) | 我已将 issue
链接到此 PR(如果适用)
- [x] I have mentioned the person who will review this PR | 我已提及将审查此 PR
的人

## Reviewer Checklist
- [x] closes #1320 
- [x] Made sure Checks passed
- [x] Tests have been provided
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.

feat(memos-local-openclaw): support robust multi-OpenClaw sharing and dual-instance isolation

1 participant