Command Palette
Search for a command to run...
The Decision Record
Core ConceptA decision in Arbtr represents a choice your team needs to make or has made.
Anatomy of a Decision
Title
A clear, specific statement of what's being decided.
Bad: "Database stuff"
Context
Background information explaining why this decision matters. What problem are you solving? What constraints exist?
Positions
The options being considered. Each position can have arguments supporting or opposing it.
Arguments
Structured claims supporting or opposing positions. Each argument has a claim and optional evidence.
Against DynamoDB: "Cost model doesn't work for our read-heavy workload"
Status
The current state in the decision lifecycle.
Decision Lifecycle
Stub / Proposed (Ghost only)
Used in scenario/branch workflows for what-if planning. Stub is a placeholder; Proposed is ready for merge consideration.
Active
Published and open for discussion. Visible to the team.
Under Discussion
Active debate happening. Arguments and rebuttals are being added. Automatically triggered when engagement starts.
Approved
Decision concluded with a "yes" outcome. A winning position is selected and rationale is documented.
Rejected
Decision concluded with a "no" outcome. The proposed change was not adopted.
Deferred
We decided not to decide yet. The decision is parked for future consideration.
Archived
Soft-deleted. Hidden from normal views but preserved for historical record.
Concluding a Decision
When you conclude a decision, you:
- Select the outcome (Approved, Rejected, or Deferred)
- Choose a winning position (if Approved)
- Write the rationale explaining why this outcome was chosen
- Add follow-ups (optional) for tasks that result from the decision
Once concluded, the decision is locked. Arguments and votes are preserved as a historical record, but no new ones can be added.
State Machine
Valid state transitions are enforced by the system. Not all transitions are possible—the state machine prevents invalid paths.
┌─────────────────────────────────────────────────────────────────┐
│ GHOST (Branch) States │
│ ┌──────┐ conclude() ┌──────────┐ merge() ┌──────┐ │
│ │ Stub │ ───────────────► │ Proposed │ ────────────► │ Live │ │
│ └──────┘ └──────────┘ └──────┘ │
│ │ │ │
│ └───────────────────────────┼── abandon() ──► Deleted │
└─────────────────────────────────┼───────────────────────────────┘
│
┌─────────────────────────────────▼───────────────────────────────┐
│ LIVE States │
│ │
│ ┌────────┐ engagement ┌──────────────────┐ │
│ │ Active │ ─────────────► │ Under Discussion │ │
│ └────────┘ └──────────────────┘ │
│ │ │ │
│ │ conclude() │ │
│ └──────────────┬───────────────┘ │
│ │ │
│ ┌──────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Approved │ │ Rejected │ │ Deferred │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ └──────────┼──────────┘ │
│ │ │
│ ▼ archive() │
│ ┌──────────┐ │
│ │ Archived │ │
│ └──────────┘ │
└─────────────────────────────────────────────────────────────────┘
Triggers:
• Active → Under Discussion: First argument, vote, or comment added
• Conclude: Owner or delegate explicitly closes with outcome
• Archive: Owner or admin soft-deletes the decisionDelegation & Ratification
Delegation
The owner can assign a delegateId to another team member. The delegate can conclude the decision on behalf of the owner.
- Useful when the owner is on vacation or unavailable
- Delegate has same conclusion powers as owner
- Delegation can be revoked at any time
Ratification
Teams can require a designated approver (e.g., CTO) to sign off on concluded decisions before they're considered final.
pending— Awaiting approver reviewratified— Approver confirmed the decisionvetoed— Approver rejected with a reason
Enable in Team Settings → Governance. Set the ratification approver to control who has veto power.
Data Model
Complete TypeScript interface from lib/types.ts. Database table: decisions.
type DecisionStatus =
| "Stub" // Ghost only: Placeholder with just a title
| "Proposed" // Ghost only: Ready for merge consideration
| "Active" // Live: Freshly created
| "Under Discussion" // Live: Active debate
| "Approved" // Live: Concluded yes
| "Rejected" // Live: Concluded no
| "Deferred" // Live: Decided not to decide yet
| "Archived" // Live: Soft deleted
type DecisionImportanceLevel = "anchor" | "committed" | "standard" | "tentative"
type RatificationStatus = "pending" | "ratified" | "vetoed" | null
interface Decision {
id: string
title: string
slug: string // URL-safe identifier
teamId: string
teamSlug?: string // For URL generation
domainId?: string // Architectural clustering
status: DecisionStatus
context?: string // Background/problem statement
tags: string[]
owner: string // Display name
positions: Position[]
// Delegation
delegateId?: string // User ID who can conclude on owner's behalf
delegateName?: string // Delegate display name
delegateAvatar?: string
// Conclusion (when status is Approved/Rejected/Deferred)
winningPositionId?: string // Selected position ID
outcomeMatchesVotes?: boolean // True if matches vote results
finalRationale?: string // Why this outcome was chosen
followUps?: string[] // Action items resulting from decision
concludedAt?: Date
// Ratification (when team requires approval)
ratificationStatus?: RatificationStatus
ratifiedAt?: Date
ratifiedById?: string
ratifiedByName?: string
vetoReason?: string
// Scenario support (what-if branching)
scenarioId?: string // NULL = live, UUID = ghost in scenario
// Provenance (git blame for decisions)
originScenarioId?: string // Branch that introduced this
originScenarioName?: string
originScenarioColor?: string
originMergedAt?: Date
originMergedByName?: string
// Visibility & Access
groupIds?: string[] // Limit visibility to specific groups
memberIds?: string[] // Limit visibility to specific members
// Metadata
importanceLevel?: DecisionImportanceLevel
confidence?: number // 0-100, manually set or calculated
documentedAsExisting?: boolean // True if imported via Magic Paste
sourceContent?: string // Original text from Magic Paste
isDraft?: boolean // Hidden until approved (bulk imports)
createdAt: Date
updatedAt: Date
}
interface Position {
id: string
label: string // Display name (e.g., "PostgreSQL")
color: string // Hex color for visual distinction
icon?: string // Optional emoji
description?: string // Explanation of this option
}decision_positions, decision_arguments,decision_votes, decision_relationships, decision_audit_log