Files
yvgude--lean-ctx/docs/contracts/team-server-contract-v2.md
T
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

7.2 KiB
Raw Blame History

Team Server Contract v2

GitLab: #2331, #387, #388
Pillar: Context Delivery
Scope: workspaces, scopes, audit log, dot-path rewrite, hosted-storage quota, ROI webhook, managed connectors

v2 is additive over v1: every v1 guarantee holds unchanged. v2 adds the optional storageQuotaBytes and roiWebhookUrl config keys (the v1 file is frozen; this file is the live, stable surface).

Config (TeamServerConfig)

File is JSON.

  • host (string, required)
  • port (number, required)
  • defaultWorkspaceId (string, required)
  • workspaces (array, required; must include default workspace)
    • { id, label?, root }
  • tokens (array, required for serve)
    • { id, sha256Hex, scopes?, role? }
    • sha256Hex is lowercase hex SHA-256 of the plaintext token
    • scopes and/or role (see RBAC roles); a token must yield at least one effective scope
  • auditLogPath (path, required)
  • disableHostCheck (bool, default false)
  • allowedHosts (string[], default [])
  • maxBodyBytes (number, default 2097152)
  • maxConcurrency (number, default 32)
  • maxRps (number, default 50)
  • rateBurst (number, default 100)
  • requestTimeoutMs (number, default 30000)
  • statefulMode (bool, default false)
  • jsonResponse (bool, default true)
  • storageQuotaBytes (number, optional, v2 / GL #387) — hosted-storage quota; omitted ⇒ Team-tier 5 GiB default, LEANCTX_TEAM_STORAGE_QUOTA_BYTES overrides both
  • roiWebhookUrl (string, optional, v2 / GL #388) — https-only Slack/Discord/generic webhook; when set, the server posts a weekly team-ROI summary (once per ISO week, real reported numbers only; state in savings/roi_webhook_state.json). A non-https URL is a startup error.
  • connectors (array, optional, GL #281) — managed source syncs; each entry is a ConnectorConfig (see Managed Connectors). Omitted ⇒ the feature is off and the scheduler never starts.

Workspace selection

Workspace is selected deterministically via:

  1. Header x-leanctx-workspace (if present and valid)
  2. Otherwise defaultWorkspaceId

POST /v1/tools/call also accepts workspaceId in the JSON body (takes precedence over the header for that call).

Dot-path rewrite (rewrite_dot_paths)

For arguments keys path, target_directory, targetDirectory:

  • if value is "" or ".", it is rewritten to the workspace root path before executing the tool.

Scopes

Scope enforcement is tool/action-aware. Tokens must include required scopes for the requested tool.

Scope Grants Access To
search ctx_read, ctx_multi_read, ctx_smart_read, ctx_search, ctx_tree, ctx_outline, ctx_expand, ctx_delta, ctx_dedup, ctx_prefetch, ctx_preload, ctx_review, ctx_response, ctx_task, ctx_overview, ctx_pack, ctx_semantic_search, ctx_proof, ctx_verify
graph ctx_graph, ctx_impact, ctx_callgraph, ctx_refactor, ctx_routes, ctx_pack
artifacts ctx_artifacts, ctx_semantic_search with artifacts=true
index ctx_graph with action=index-build*, ctx_semantic_search with action=reindex
events GET /v1/events SSE stream
sessionMutations ctx_session (mutating: save, set_task, task, checkpoint, finding, decision, reset, import), ctx_handoff, ctx_workflow, ctx_share
knowledge ctx_knowledge (mutating: remember, feedback, remove, consolidate), ctx_knowledge_relations (mutating: relate, unrelate)
audit GET /v1/metrics, GET /v1/connectors, full-payload event access, audit log reads

Errors:

  • 401 unauthorized (missing/invalid token)
  • 403 scope_denied (token lacks required scopes)
  • 400 unknown_workspace

RBAC roles

A token's effective scopes are scopes role.scopes(). Roles (EPIC 13.2) are an ergonomic layer over scopes — assign a coarse role instead of hand-picking scopes. Enforcement is unchanged (the middleware evaluates effective scopes).

Role Effective scopes
viewer search
member search, graph, index, knowledge, events
admin all scopes
owner all scopes (org/billing authority is a hosted control-plane concern)

Roles are monotonic: viewer ⊆ member ⊆ admin = owner (server scopes). Create with lean-ctx team token create --role <viewer|member|admin|owner> (or --scopes <csv>, or both).

Additive / Team-Cloud plane only — never gates the local plane. SSO/SCIM, org-shared knowledge graph, and audit-retention dashboards build on this role model and are tracked on the commercial plane (EPIC 13.2).

Managed Connectors (#281)

A connector is a scheduled, in-process sync from an external source into a workspace's long-term stores (BM25 + graph + knowledge). Once a connector has run, ctx_semantic_search and ctx_knowledge surface the source's issues / PRs / pipelines to every seat — no per-call credential transport, no manual ctx_provider invocation.

ConnectorConfig

Each entry of connectors[] (camelCase JSON):

  • id (string, required) — stable, file-safe, unique within the instance.
  • provider (string, required) — gitlab | github.
  • resource (string, required) — gitlab issues|merge_requests|pipelines; github issues|pull_requests|actions.
  • project (string, optional) — group/project (GitLab) or owner/repo (GitHub).
  • host (string, optional) — GitLab host (default gitlab.com) or GitHub API base (default https://api.github.com).
  • state (string, optional) — provider state filter (e.g. opened).
  • limit (number, optional, default 50) — max items per sync.
  • intervalSecs (number, optional, default 3600) — sync cadence, clamped to a 300 s floor to protect external APIs.
  • secret (string, optional) — the provider credential. Plaintext only inside the private team.json (a control-plane-injected env var); it is never written to disk by the server and never returned by any endpoint.
  • workspaceId (string, optional) — target workspace; the instance default when omitted.
  • displayName (string, optional).
  • enabled (bool, default true).

Scheduler

A single background scheduler ticks once a minute, runs each due connector (now ≥ lastRun + effectiveInterval) on the blocking pool, and records the outcome per connector under <state_dir>/<id>.json (never the credential). When the hosted index is over quota (GL #282) ingestion pauses (never deletes, never gates reads); the connector records an error status and waits its interval before retrying.

GET /v1/connectors

Audit-scoped. Returns the secret-free roster + per-connector sync status (lastRunAt, lastStatus ok|error, lastError, lastItemCount, totalRuns, totalItems, hasSecret). The credential is never exposed.

Audit log (JSONL)

Audit log is JSONL; one object per line:

  • ts (RFC3339)
  • tokenId
  • workspaceId
  • tool
  • method
  • allowed (bool)
  • deniedReason (string|null)
  • argumentsMd5 (string; MD5 of canonicalized arguments JSON)

Raw arguments are never stored in the audit log.

Implementation

  • rust/src/http_server/team.rs
  • CLI dispatch: rust/src/cli/dispatch.rs (lean-ctx team ...)