Team
ProThe 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.
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
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 }