-
-
Notifications
You must be signed in to change notification settings - Fork 119
Multi User Collaboration
CortexPrism v0.53.0 introduced multi-user collaboration with users, teams, API tokens, and resource scoping across the entire platform. Every agent, session, service, node, channel, and workspace config is now owned by a user and optionally scoped to a team.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Users │ │ Teams │ │ API Tokens │
│ PBKDF2 hash │◄──►│ join policies│◄──►│ SHA-256 hash │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────┐
│ RequestIdentity System │
│ extractIdentity() → user / instance / anonymous │
│ userId · username · teamIds · currentTeamId │
│ isInstanceAdmin · sessionId │
└─────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Authorization Guards │
│ requireInstanceAdmin · requireTeamAdmin │
│ requireTeamMember · requireResourceOwner │
└─────────────────────────────────────────────────────┘
Users are stored in the users table (migration 044) with PBKDF2 password hashing. Each user has:
| Field | Description |
|---|---|
id |
usr_<uuid> — unique user identifier |
username |
Unique login name |
password_hash |
PBKDF2-SHA-256 derived key (200,000 iterations) |
password_salt |
16-byte random salt |
display_name |
Optional human-readable name |
email |
Optional email address |
disabled_at |
Timestamp if user is disabled (soft-delete) |
Passwords are hashed using PBKDF2 with SHA-256, 200,000 iterations, and a 16-byte random salt. Verification uses constant-time comparison to prevent timing attacks. Password complexity requires at least 8 characters with at least 2 of: lowercase, uppercase, numbers, symbols.
The first user created during initial setup is automatically assigned as the instance admin.
Instance admins are tracked in the config table under the key instance_admins as a JSON array
of user IDs. Instance admins bypass all resource ownership and team membership checks.
The Users page (src/server/ui/js/28_users.ts) provides:
- User list with create/disable/enable actions (instance admin only)
- Username, email, and disabled status display
cortex users list # List all users (instance admin)
cortex users create <username> <password> # Create a user (instance admin)
cortex users disable <userId> # Disable a user (instance admin)
cortex users enable <userId> # Re-enable a disabled user (instance admin)Teams are stored in the teams table with join policies. The team_memberships join table assigns
users to teams with admin or member roles.
| Table | Purpose |
|---|---|
teams |
Team identity: id, name, join_policy, created_at
|
team_memberships |
User-team assignments: user_id, team_id, role (admin/member) |
| Method | Path | Description |
|---|---|---|
GET |
/api/teams |
List teams (filtered to user's teams) |
POST |
/api/teams |
Create a team (instance admin) |
GET |
/api/teams/:id |
Get team details |
PATCH |
/api/teams/:id |
Update team (team admin or instance admin) |
DELETE |
/api/teams/:id |
Delete team (instance admin) |
GET |
/api/teams/:id/members |
List team members |
POST |
/api/teams/:id/members |
Add member to team |
PATCH |
/api/teams/:id/members |
Update member role |
DELETE |
/api/teams/:id/members |
Remove member from team |
GET |
/api/teams/:id/agents |
List team-scoped agents |
POST |
/api/teams/:id/agents |
Create agent scoped to team |
cortex teams list # List your teams
cortex teams create <name> # Create a team (instance admin)Users can share resources (agents, sessions, services, etc.) with other users via the
resource_shares table (migration 047).
| Method | Path | Description |
|---|---|---|
POST |
/api/shares |
Share a resource with another user |
GET |
/api/shares/given |
List shares you've created |
GET |
/api/shares/received |
List shares shared with you |
DELETE |
/api/shares/:id |
Revoke a share |
Ownership validation is enforced — only the resource owner can create a share.
Every API request is assigned a RequestIdentity via extractIdentity() in src/server/auth.ts:
interface RequestIdentity {
type: 'user' | 'instance' | 'anonymous';
userId?: string; // User ID (when type === 'user')
username?: string; // Username
teamIds?: string[]; // Teams the user belongs to
currentTeamId?: string; // Active team (from x-cortex-team header)
sessionId?: string; // Session ID (when authenticated via session cookie)
isInstanceAdmin?: boolean; // Whether the user is an instance admin
}Identity is extracted from either:
-
Authorization header (
Bearer <token>) — API token or node token -
Session cookie (
cortex_session) — web UI session
Four coarse-grained authorization guards in src/server/guards.ts enforce access control:
| Guard | Requirements |
|---|---|
requireInstanceAdmin(identity) |
identity.isInstanceAdmin === true |
requireTeamAdmin(identity, teamId) |
User is a member of the team with admin role (instance admins bypass) |
requireTeamMember(identity, teamId) |
User is a member of the team (instance admins bypass) |
requireResourceOwner(identity, resourceType, resourceId) |
User owns the resource (instance admins bypass) |
Guards return null if authorization passes, or a Response with the appropriate error
(401 Unauthorized or 403 Forbidden) if it fails.
requireResourceOwner maps resource types to database tables:
| Resource Type | Table |
|---|---|
agent |
agents |
session |
sessions |
service |
services |
node |
nodes |
channel |
channels |
Agents are scoped in a three-layer hierarchy:
User → Team → Instance
- User-scoped: Agent owned by a specific user, visible only to that user
- Team-scoped: Agent associated with a team, visible to all team members (validates team membership before creation)
- Instance-scoped: Global agent visible to all users on this instance
listAgents() in src/agent/manager.ts accepts optional userId and teamIds for scope-aware
filtering. Built-in agents are seeded into the agents table as instance-scoped.
In v0.53.0, agent storage moved from config.json to the agents database table (migration 044):
| Field | Description |
|---|---|
id |
Unique agent identifier |
name |
Agent name |
kind |
builtin / custom
|
user_id |
Owner user (nullable for instance-scoped) |
team_id |
Owning team (nullable for user/instance-scoped) |
scope |
user / team / instance
|
config_json |
Full agent configuration as JSON |
Legacy agents in config.json are preserved as fallback during the transition.
- API Tokens — Token creation, team-scoping, revocation
- Federation — Instance-to-instance trust
- Login & Auth — Authentication flow
- Security Model — Parallax security architecture
CortexPrism — Open-source AI agent operating system · Discord · Apache 2.0 License · Built with Deno 2.x + TypeScript
- Agent Loop
- Built-in Agents
- Metacognition
- Memory System
- Skills System
- Sub-Agents
- Built-in Tools
- Code Intelligence
- Code Sandbox
- Cross-Agent Context Protocol
- Prompt Lab
- PKM Assistant
- Voice Pipeline
- Computer Use
- Browser Tool
- Git & GitHub
- Scheduler & Jobs
- Dashboard
- Observability
- A2A Protocol
- MCP Gateway
- Distributed Nodes
- Memori Checkpoints
- Eval System
- Workflow Engine
- Triggers
- Projects
- TUI
- Glossary
- Update System
- Chrome Bridge
- Swarm
- AgentLint
- Model Benchmarking
- Smart Context
- Cost Optimizer