---
title: "Team Knowledge Sharing: Access Tokens, Approvals, and Data Scopes"
description: Separate current cloud tokens from proposed member permissions; test read operations and batch approval on fixtures and define recovery responsibilities.
image: "https://zengliangyi.com/og/blog/en/team-knowledge-sharing-plan.png"
---

Team sharing has two boundaries: what content is approved to leave a personal device, and which principals may perform which operations on a shared instance. ChatCrystal’s cloud mode already has token authentication and normalized remote import. The pinned commit does not create separate member accounts or project-level read/write roles. Distributing one shared token does not create permission isolation.

## Current cloud capabilities

[server/src/runtime/cloud.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/runtime/cloud.ts) enables cloud mode through CHATCRYSTAL_CLOUD_MODE=true or a nonempty CHATCRYSTAL_API_TOKEN. [server/src/routes/setup.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/routes/setup.ts) installs Bearer-token checks for protected API routes. Health, setup status/completion, and auth verify are public exceptions; setup, verification, and token rotation have their own checks. The rotate route verifies currentToken in its request body, so not every route is guarded only by Bearer authentication. [server/src/services/auth.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/auth.ts) supports an environment token or a scrypt-stored single token and failed-attempt controls. The API rotates only a persisted token; environment tokens must be changed in the deployment environment. This is not multiple accounts, individual revocation, or RBAC.

[server/src/routes/import.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/routes/import.ts) disables server-side local scans in cloud mode and provides ingest. [server/src/cli/commands/import.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/cli/commands/import.ts) parses on a device holding source histories and uploads a normalized payload; noninteractive use requires explicit –yes. [server/src/runtime/watcherPolicy.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/runtime/watcherPolicy.ts) prevents cloud-mode watching. Neither automatic scanning of everyone’s desktop from a shared host nor a complete absence of remote import matches current behavior. Multiple clients can submit; concurrency pressure, isolation, and conflict recovery are not thereby tested.

The seven MCP tools use the same API connection through a client; see [MCP protocol boundaries](/en/blog/mcp-protocol-boundaries/). Tool names do not identify the team’s dataset or establish member permissions for a gateway.

## Define the trust boundary before choosing a layout

| Layout | Boundary retained | Additional work |

| --- | --- | --- |

| Personal libraries plus reviewed readable exports | Private histories remain on their owner’s device first | Export versions, redaction, provenance, updates |

| Shared instance within one trusted group | Current single-token access | Holder capabilities, rotation impact, concurrent recovery |

| Shared instance behind an identity gateway | External member/role policy can be defined | Complete method/path tests, direct-access prevention, gateway maintenance and audit |

| Separate instances for different trust groups | Data and credentials stay separate | Multi-instance updates and retrieval strategy |

These are deployment designs, not built-in team UI features or measured member-count and memory recommendations. tag, project_key, and scope describe retrieval or knowledge semantics, not token permission partitions. Manual global memory versus automatic project memory cannot promise that a member cannot read another project.

## Review content first and define reads by operation

Source histories may include paths, code, credentials, or unreviewed conclusions. Obtain the owner’s approval, define shareable scope, redact, and record provenance before uploading. Automatic summaries do not guarantee redaction. Server ingest is a data entry point; command confirmation is not organizational approval.

GET-only access blocks read-like operations such as `POST /api/memory/recall`, while potentially exposing sensitive configuration GETs. Define roles against exact methods and paths, then test actual client workflows. Prevent direct access to the shared-token backend at the network layer. The following checks a **proposed gateway policy**, not ChatCrystal authentication. Roles are parameters; there is no identity authentication, HTTP proxy, real redactor, import, or backend.

Save this as team.mjs under Node 24 and run `node team.mjs`.



```js
import   assert   from   'node:assert/strict'  ;  
  
  // Proposed gateway policy; this is not ChatCrystal's token hook.  
  const   rules   =   new   Map  ([  
    [  'reader'  ,   new   Set  ([  'POST /api/memory/recall'  ,   'GET /api/notes'  ])],  
    [  'importer'  ,   new   Set  ([  'POST /api/import/ingest'  ])],  
  ]);  
  function   authorize  (  role  ,   method  ,   rawPath  ,   target  ,   approvedTarget  ) {  
    assert.  equal  (target, approvedTarget);  
    const   url   =   new   URL  (rawPath,   'https://gateway.invalid'  );  
    if   (url.pathname.  includes  (  '%'  )   ||   url.pathname.  includes  (  '..'  ))   throw   new   Error  (  'ambiguous path'  );  
    if   (  !  rules.  get  (role)?.  has  (  `${  method  } ${  url  .  pathname  }`  ))   throw   new   Error  (  'denied'  );  
  }  
  const   target   =   'reviewed-instance-a'  ;  
  let   stored   =   [];  
  function   ingest  (  role  ,   items  ) {  
    authorize  (role,   'POST'  ,   '/api/import/ingest'  , target, target);  
    for   (  const   item   of   items) {  
      if   (item.approval   !==   'approved'   ||   item.classification   !==   'team-shareable'  )  
        throw   new   Error  (  'unapproved input'  );  
      if   (  /  secret  |  password  |  token  /  i  .  test  (item.content))   throw   new   Error  (  'redaction required'  );  
    }  
    stored.  push  (  ...  items.  map  (({   id  ,   content   })   =>   ({ id, content })));  
  }  
  authorize  (  'reader'  ,   'POST'  ,   '/api/memory/recall'  , target, target);  
  assert.  throws  (()   =>   authorize  (  'reader'  ,   'POST'  ,   '/api/import/ingest'  , target, target),   /  denied  /  );  
  assert.  throws  (()   =>   authorize  (  'reader'  ,   'GET'  ,   '/api/notes'  ,   'other-instance'  , target));  
  assert.  throws  (()   =>   authorize  (  'reader'  ,   'DELETE'  ,   '/api/notes/1'  , target, target),   /  denied  /  );  
  assert.  throws  (()   =>   authorize  (  'reader'  ,   'POST'  ,   '/api/queue/cancel'  , target, target),   /  denied  /  );  
  assert.  throws  (()   =>   authorize  (  'reader'  ,   'GET'  ,   '/api/config'  , target, target),   /  denied  /  );  
  assert.  throws  (()   =>   authorize  (  'unknown'  ,   'GET'  ,   '/api/notes'  , target, target),   /  denied  /  );  
  const   approved   =   {  
    id:   'reviewed-1'  ,  
    content:   'use a scoped transaction'  ,  
    approval:   'approved'  ,  
    classification:   'team-shareable'  ,  
  };  
  ingest  (  'importer'  , [approved]);  
  assert.  equal  (stored.  length  ,   1  );  
  assert.  throws  (  
    ()   =>   ingest  (  'importer'  , [approved, {   ...  approved, id:   'private-2'  , approval:   'pending'   }]),  
    /  unapproved  /  
  );  
  assert.  equal  (stored.  length  ,   1  );  
  assert.  throws  (  
    ()   =>   ingest  (  'importer'  , [{   ...  approved, content:   'password=example'   }]),  
    /  redaction  /  
  );  
  assert.  equal  (stored.  length  ,   1  );  
  console.  log  (  'proposed gateway roles and whole-batch review gate pass on fixtures'  );
```



## Permission and approval checks need rejection fixtures

Remove rule matching: the reader-ingest rejection assertion must fail. Move stored.push before reviewing all inputs: the pending-content batch pollutes synthetic storage and the count assertion must fail. Restore and run again. Keyword checks only reject the example; they are not dependable redaction or sensitive-data detection. URL/method rules are not a complete secure proxy implementation.

Before deployment, separately test missing/wrong tokens, old tokens after rotation, reader recall and denied writes, unapproved payloads, the wrong instance, gateway bypass, and retrieval after restore. Receipts in [server/src/services/memory/writeback.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/memory/writeback.ts) and quality feedback in [server/src/services/experience/reviews.ts](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/experience/reviews.ts) serve business purposes; neither is a complete per-member operation audit. A shared token cannot reliably identify the person acting. If external systems own identity, audit, and content approval, record their owners and retention policy in the deployment agreement.

## Synchronization and backup cannot copy an active database blindly

Do not point multiple desktops at one active chatcrystal.db or overwrite a running library through file synchronization. sql.js operates in memory and exports data; vectra-index is another dataset. See [WASM persistence](/en/blog/sqljs-wasm-persistence/) and [vector-index boundaries](/en/blog/vectra-search-internals/). Stop all writers or take a consistent snapshot, copy the agreed data directory, and verify recovery in isolation. Active source-tool SQLite also needs main-database/WAL consistency; copying one state.vscdb alone does not establish a complete backup.

Sharing does not require centralizing every history. Test approved imports, provenance, retrieval, rejection, and recovery for the same task before choosing what enters a shared library. See the [CLI knowledge workflow](/en/blog/cli-knowledge-workflow/) for automation steps.

Share:

##  Related Posts

[##  Turning AI Coding Chats into Engineering Notes: Review and Reuse

Audit source and length denominators, false accepts and rejects, and empty samples; separate current filtering, summaries, and measured reuse.          曾亮懿       October 7, 2026      5 min read

#ChatCrystal

#Knowledge management

#Evaluation](/en/blog/conversation-knowledge-retrospective)    [##  Local AI Knowledge Base Setup: Install, Ingest, and Search

Verify installation, the local service, both model configurations, import, summarization, and search with the actual ChatCrystal 0.6.1 CLI.          曾亮懿       October 3, 2026      4 min read

#ChatCrystal

#Node.js

#Knowledge management](/en/blog/chatcrystal-getting-started)    [##  Parsing Codex, Trae, and Copilot Chat Logs: 3 Storage Formats

Check source directories, event extraction, and snapshot boundaries in ChatCrystal, then verify each adapter against a conversation you know.          曾亮懿       October 3, 2026      4 min read

#ChatCrystal

#Data parsing

#Knowledge management](/en/blog/codex-trae-copilot-import)

##  From writing to code

Explore ChatCrystal, developer tools and daily learning notes on my GitHub. Questions about the implementation are welcome.

[Visit my GitHub](https://github.com/ZengLiangYi)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ZengLiangYi Blog",
  "alternateName": [
    "Zeng Liangyi",
    "ZengLiangYi",
    "zengliangyi.com"
  ],
  "url": "https://zengliangyi.com",
  "description": "曾亮懿的个人网站。记录 AI Native 探索、开发者工具与全栈产品实践。"
}
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "Team Knowledge Sharing: Access Tokens, Approvals, and Data Scopes",
  "description": "Separate current cloud tokens from proposed member permissions; test read operations and batch approval on fixtures and define recovery responsibilities.",
  "url": "https://zengliangyi.com/en/blog/team-knowledge-sharing-plan/",
  "image": "https://zengliangyi.com/images/blog/team-knowledge-sharing-plan.svg",
  "datePublished": "2026-10-07T00:00:00.000Z",
  "dateModified": "2026-10-23T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "曾亮懿",
    "url": "https://zengliangyi.com/en/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "ZengLiangYi Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://zengliangyi.com/favicon-96x96.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://zengliangyi.com/en/blog/team-knowledge-sharing-plan/"
  }
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "Home",
      "item": "https://zengliangyi.com/en"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "Blog",
      "item": "https://zengliangyi.com/en/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "Team Knowledge Sharing: Access Tokens, Approvals, and Data Scopes",
      "item": "https://zengliangyi.com/en/blog/team-knowledge-sharing-plan/"
    }
  ]
}
```
