Team

Pro

The data behind the app shell and the team screens: an account has an owner and members; a member holds at most one role per environment; invites go to an email; audit events carry ids and codes, never names.

Markdown

Preview

It's types and helpers, listed below.

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/team

Brings in: chat, status

Types

Environment
Where agents act: a CRM instance, a database, a repository, a project. The app names them; TermsProvider sets what they're called ("project", "workspace").
{ id: string /** The name shown everywhere, e.g. "Shop". */ name: string /** What tells same-named ones apart, e.g. "dev-2" or "staging". */ detail?: string | undefined /** Changes here reach real users, so components warn and ask for more care. */ production: boolean /** A chart slot (1–5) so each environment keeps one colour everywhere it appears. */ hue?: 1 | 2 | 3 | 4 | 5 | undefined connectio
Role
A role someone can hold on an environment, from the app's own list. Higher rank includes what lower ranks can do. Policy (who can grant what, what needs approval) stays in the app; components only show it.
{ id: string label: string rank: number }
Member
{ id: string name?: string | undefined email: string /** The account's owner, shown as such; the app decides what that implies. */ owner?: boolean | undefined joinedAt: string /** At most one role id per environment id. */ roles: Record<string, string> }
Invite
{ id: string email: string invitedBy: string createdAt: string expiresAt: string status: "pending" | "accepted" | "expired" | "revoked" | "superseded" /** The role the invite grants on joining, per environment id. */ roles: Record<string, string> }
KnownAuditAction
The actions Candor knows the words for. AuditLog labels and groups them on its own.
| "signin.succeeded" | "signout" | "stepup.completed" | "account.created" | "member.invited" | "member.invite_revoked" | "member.invite_expired" | "member.joined" | "member.removed" | "role.set" | "role.removed" | "approval.requested" | "approval.approved" | "approval.self_approved" | "approval.rejected" | "approval.withdrawn" | "approval.expired" | "approval.applied" | "audit.read" | "approval.re
AuditAction
What a row records: one of Candor's known actions, or your app's own (`"connection.created"`). Your own actions take a label through AuditLog's `actions`; without one, the row shows the action's code as it is.
KnownAuditAction | (string & {})
AuditEvent
One append-only row. Ids, codes and hashes only: names are resolved on screen.
{ id: string at: string /** A principal id, or "system" for rows the app writes on its own. */ actorId: string action: AuditAction /** What it acted on, e.g. "account", "invite", "membership", "approval_request". */ target: { type: string; id: string } outcome: "ok" | "refused" /** Required when refused, e.g. "NOT_APPROVER". */ reasonCode?: string | undefined requestId: string }
Session
{ id: string title: string updatedAt: string environmentId?: string | undefined pinned?: boolean | undefined /** Set while agents are working in it, or it's waiting on the person. */ status?: RunStatus | undefined /** Your words for `status` ("Making", "Needs you"), shown with SessionList's `showStatus`; defaults to the status's own label. */ statusLabel?: string | undefined /** One line under the
InboxItem
{ id: string kind: "approval" | "question" | "failed" | "finished" title: string detail?: string | undefined environmentId?: string | undefined at: string agent?: AgentIdentity | undefined /** True when the item waits on the viewer. */ needsYou: boolean }
Notice
{ id: string /** What happened. "guardrail-stopped" is a guardrail (a budget, a limit, a rule) stopping an agent: not a finished run. */ kind: "invite" | "approval-waiting" | "role-change" | "approval-resolved" | "run-finished" | "guardrail-stopped" title: string detail?: string | undefined at: string read: boolean action?: { label: string; href?: string | undefined } | undefined }
SetupStep
{ id: string title: string detail?: string | undefined status: "done" | "current" | "todo" | "blocked" /** Required when blocked. */ blockedBy?: string | undefined action?: { label: string; onClick?: (() => void) | undefined } | undefined }
DataFlow
{ /** What moves, e.g. "Schema: tables, fields, workflows". */ what: string /** Where it goes, e.g. "Our servers in Google Cloud us-east4". */ to: string /** How long it's kept there. */ kept: string }