adr

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

README

Architecture Decision Records

This directory records the significant architectural decisions made on Atlas, using the MADR-influenced format described in template.md.

An ADR captures a decision, the context that forced it, the options considered, and the consequences accepted. ADRs are immutable once accepted: if a decision changes, a new ADR supersedes the old one rather than editing it.

A number belongs to exactly one decision, and it is assigned when the record lands on main — never on a branch. go test ./docs/adr enforces unique, gapless numbers, keeps the index below in step with the directory, and checks that every ADR-NNNN citation anywhere in the repository still resolves. The index is a table of contents: one row per record, carrying that record's own # ADR-NNNN: heading, so what the decision says belongs in the record, not in the cell.

Writing a record

Do not pick a number. A record in flight carries none:

  1. Copy template.md to docs/adr/draft-<slug>.md — a kebab-case slug, no number.
  2. Keep the heading as # ADR-DRAFT: Your title, and fill in the record.
  3. Add no row to the index below.
  4. Cite it as ADR-draft-<slug> from code comments and docs, or link draft-<slug>.md.

When the PR merges, a workflow on main runs make adr-number. That renames the file to NNNN-<slug>.md, rewrites the heading, appends the index row, and rewrites every citation of the draft to the number it just got. Nothing for you to remember; you can also run make adr-number by hand on main.

Why the ceremony: the number used to be taken when the record was written, which is the earliest possible moment and the one with the least information. Two open branches both saw the same "next free" number and both took it — that is how 0090, 0103 and 0105 came to be shared by unrelated ADRs (the later record of each pair now lives at 0139, 0140 and 0141). Once a test caught the collision, the cost became a renumber on every merge instead: one record walked 0164 → 0169 across six of them without a word of its content changing. Assigning the number where the question has one answer removes both. The full argument is in the record on merge-time numbering.

A number, once assigned, is never reassigned — that is what makes (ADR-0168) in a comment safe to write.

Index

ADR Title Status
0001 Event sourcing and log-structured state Accepted
0002 Single-writer partition model Accepted
0003 Pebble as embedded state store Accepted
0004 Compile BPMN to an integer-indexed graph Accepted
0005 Group commit and fsync strategy Accepted
0006 Partition routing and cross-partition communication Accepted
0007 Job worker protocol Accepted
0008 FEEL expression compilation strategy Accepted
0009 Record serialization format Accepted
0010 Go as implementation language, no CGO Accepted
0011 Single-binary distribution with an embedded web viewer and editor Accepted
0012 A buildless, self-contained web UI app shell Accepted
0013 Embed the bpmn-js modeler as a vendored asset Accepted
0014 DMN business rule tasks via the temis engine Accepted
0015 Reuse the external FEEL engine behind an expr boundary Accepted
0016 Model Context Protocol server as a stdio adapter over the HTTP API Accepted
0017 Retain finished process instances in a history index Accepted
0018 Test-driven development as the default workflow Accepted
0019 Durable deployments via an on-disk sidecar store Accepted
0020 Message events and correlation Accepted
0021 Diagram drafts, separate from deployments Accepted
0022 Retain a per-element token-visit history for the Operations overlay Accepted
0023 Collaborations and pools as multi-process deployments Accepted
0024 Parallel gateway join synchronization Accepted
0025 Extend the hand-written properties panel instead of vendoring bpmn-js-properties-panel Proposed
0026 A Problems panel with validation targeted at an engine version Proposed
0027 Element templates for pre-configured, reusable elements Proposed
0028 User tasks, forms, and the Tasks app Proposed
0029 Public process start via a published form link Accepted
0030 Play mode — ephemeral in-Modeler process simulation Proposed
0031 Diagram version history in the Modeler Proposed
0032 In-Modeler AI copilot over the MCP/HTTP surface Proposed
0033 Inclusive gateway join synchronization Accepted
0034 Projects as containers for heterogeneous artifacts Accepted
0035 Message start events and the processInstanceKey built-in Accepted
0036 A clio connector — server-registered event-store integration Accepted
0037 Structured JSON variables Accepted
0038 Collaboration message-flow replay Accepted
0039 Input/output variable mappings for business rule tasks Accepted
0040 Boundary events — timer and message, interrupting and non-interrupting Accepted
0041 Connector management and the secret store Accepted
0042 User-task runtime assignment and claim/unclaim Accepted
0043 An OpenAPI spec and an embedded API explorer for the HTTP API Accepted
0044 User management and the authentication boundary Accepted
0045 Binding user-task assignment to real identities Accepted
0046 Single-process step-by-step replay Accepted
0047 Polyglot script tasks (PowerShell, …) via job workers Accepted
0048 Per-step variable snapshots in the single-process replay Accepted
0049 Internal service authentication for the in-process MCP adapter Accepted
0050 Central DMN decisions via a temis decision connector Accepted
0051 Timer start events (duration, date, cycle) Proposed
0052 Message end events Accepted
0053 First-class data objects — typed, event-sourced state, and lineage Accepted
0054 Date and cycle timers for catch and boundary events Proposed
0055 FEEL-expression timer schedules for catch and boundary events Proposed
0056 FEEL cycles, and FEEL on timer start events Proposed
0057 First-class FEEL temporals for timer schedules Proposed
0058 Data output associations — write a value and transition a data object's state Accepted
0059 Data input associations — read a data object into an activity Accepted
0060 Field-level data object writes — set one member of a structured object Accepted
0061 Incident model — job-failure incidents, raise, resolve, resume Proposed
0062 An embedded DMN editor (dmn-js) Accepted
0063 DMN decision binding (latest vs deployment) Accepted
0064 Timer FEEL-failure incidents — park and raise instead of firing immediately Proposed
0065 Multi-token process replay and causal token lineage Accepted
0066 Durable decision-evaluation records for debugging Accepted
0067 A service-task connector catalog, and REST with a model-authored endpoint Accepted
0068 Task input/output variable mappings with activity-local scopes Proposed
0069 An engine-internal encrypted secret vault (ADR-0041 option A3) Accepted
0070 The secret vault is on by default, with a generated key Accepted
0071 Sharing scopes — private and shared access boundaries for design-time work Accepted
0072 Multiple DMN models per process deployment Accepted
0073 A principals directory for member and assignee pickers Accepted
0074 Embedded subprocesses (scope lifecycle via child counters) Accepted
0075 A clio inbound event bridge — at-least-once ingestion with engine-side idempotent delivery Accepted
0076 Call activities (single-partition) Accepted
0077 Multi-instance activities (parallel and sequential) Accepted (amended)
0078 Design-view token simulation — a client-side control-flow walkthrough Accepted
0079 An outbound mail connector (SMTP first) Accepted (amended)
0080 Sublinear runtime views via maintained aggregate counters Accepted
0081 A community marketplace for connectors, service tasks, and script tasks Proposed
0082 Event subprocesses (message- and timer-triggered, interrupting and non-interrupting) Proposed
0083 An O(1) instances summary — per-definition finished-count and last-activity counters Accepted
0084 CSV batch validation — upload a file, validate every row against business rules, correct the failures Proposed
0085 Process-instance TTL — self-cleaning via the due-timer index Accepted
0086 Gateway conditions resolve over the scope chain Proposed
0087 In-process CSV ingestion — upload in a user task, parse in the process Accepted
0088 Signal events (broadcast throw/catch) Accepted
0089 Error events (scoped propagation to the nearest handler) Accepted
0090 Bulk-terminate running instances — an explicit selection and a filtered scope Accepted
0091 User-task scheduling — priority and due date Accepted
0092 One-click clio credential provisioning Accepted
0093 Native Gmail and Microsoft Graph mail providers Accepted
0094 Singleton message start — at most one live instance per correlation key Accepted
0095 External variable modification on a running instance Accepted
0096 Token simulation — event triggers, inclusive gateways, and an auto-decide mode Accepted
0097 Token simulation — message starts, event-subprocess triggers, and multi-instance Accepted
0098 Audit trail for external variable modifications Accepted
0099 An ArchiMate 3.2 enterprise-architecture view Accepted
0100 Token simulation — configurable multi-instance count, modelled cardinality wins Accepted
0101 Token simulation — a thrown message/signal delivers to a waiting catch Accepted
0102 Receive tasks Accepted
0103 Compensation and compensation handlers Accepted
0104 Token simulation — entering embedded subprocesses Accepted
0105 Per-server call-activity target overrides Accepted
0106 A BMC Remedy connector — server-registered ITSM entry creation Accepted
0107 Backup and restore — a one-file download of the design-time data directory Accepted
0108 BPMN transactions (cancel end event, cancel boundary, transactional compensation) Accepted
0109 Whole-instance snapshot — a full backup that includes running instances Accepted
0110 Event-based gateways (deferred choice) Accepted
0111 Completing the incident model — retry backoff and timer-FEEL failure incidents Accepted
0112 Send tasks Accepted
0113 Org-wide UI brand theme Accepted
0114 OpenSearch event exporter — a WAL-tailing sink, off the hot path Accepted
0115 History retention — an export-gated, age-based hard delete of finished instances Accepted
0116 Terminate end events Accepted
0117 An AI agent task — an LLM agent as a managed connector on the job path Proposed
0118 A web-scraping connector — model-authored URL + CSS selector extraction Accepted
0119 Deactivating a deployed process Accepted
0120 Mockup (engine-simulated) service tasks Accepted
0121 BPMN lanes Accepted (Layer A)
0122 A protected system project and bootstrap-deployed platform processes Accepted
0123 A sanctioned automated user-provisioning path for system processes Accepted (amended)
0124 Server-side BPMN diagram auto-layout in Go Accepted
0125 Escalation events (non-interrupting, propagating throw/catch) Accepted
0126 Self-service registration link on the login screen Accepted
0127 A layered layout pipeline and executable layout invariants Accepted (amended)
0128 Process applications — the project, elevated into a deployable, versioned, portable unit Proposed
0129 Remote deployment targets — publish an application to another Atlas server Proposed
0130 Deprecating a process version — a drain state distinct from pausing Proposed
0131 Engine recovery checkpoints and WAL compaction Accepted
0132 Link events (intra-scope goto — a compile-time synthetic flow) Accepted
0133 Standard loop activities (the ↻ marker) Accepted (amended)
0134 Git-backed applications — a repository as an application's source of truth Proposed
0135 Retries as a property of every job-backed task Accepted
0136 Terminated tokens in the step-by-step replay Accepted
0137 Conditional events (data-triggered catch/boundary) Accepted
0138 Ad-hoc subprocesses (on-demand, unordered contained activities) Accepted
0139 A first-class "CSV to JSON" connector kind with model-authored layout Accepted
0140 Live collaborative modeling sessions — real-time co-editing of drafts by people and AI agents Proposed
0141 A SharePoint connector (create list item, via Microsoft Graph) Accepted
0142 Operational metrics over a Prometheus endpoint Accepted
0143 Process documentation export Accepted
0144 Per-definition history TTL — retention the model declares Accepted
0145 A Developer View for code-bearing fields Accepted
0146 History expiry as a due-date index — retention that scales with what is due Accepted
0147 Splitting the api Server object, without weakening the single writer Accepted
0148 Org-wide brand logo Accepted
0149 A bounded outbound-call budget for every connector Accepted (amended)
0150 A preview mail provider, and incidents on the live diagram Accepted (amended)
0151 Incidents beyond the live diagram — the replay, the lists, and one shared action Accepted
0152 OAuth2 client-credentials for the REST connector Proposed
0153 SCIM 2.0 provisioning connector Proposed
0154 Generic LDAP connector Proposed
0155 The Secrets panel says what a value has to be Accepted
0156 In-process vs. out-of-process service tasks — where a step's work runs, and what we recommend Proposed
0157 Every side-effecting task on a worker process — atlas worker, optional supervision, and a Workers console Proposed
0158 A connector reference that explains itself — and an incident you can actually resolve Accepted
0159 Auditable manual task completion Accepted
0160 Fix the connector from the incident Accepted
0161 What an element was handed, on the diagram Accepted
0162 Process instance migration Proposed
0163 Deleting a connector deployed models still reference — and keeping a table inside its card Accepted
0164 No in-process service tasks — the core loop must never be able to get stuck Accepted
0165 SOAP / Web Services (WSDL) connector Proposed
0166 Active Directory connector Proposed
0167 A released connector ships in the marketplace Proposed
0168 Moving a connector onto a worker — where the task detail travels, and where the credential lives Accepted
0169 A form on the incident — repairing an instance with named fields instead of raw JSON Accepted
0170 ADR numbers are assigned at merge, not on a branch Accepted
0171 A directory-file connector — LDIF and DSML Proposed
0172 A Microsoft Entra ID connector Proposed
0173 Three SQL connectors, and the first kinds born on a worker Proposed
0174 A connector task's input mappings are its outbound payload Proposed

Status values

  • Proposed — under discussion
  • Accepted — decided and in effect
  • Superseded by ADR-XXXX — replaced by a later decision
  • Deprecated — no longer relevant

Documentation

Overview

Package adr carries the ADR directory's own conventions as code: the parser for a decision record, the guard tests in adr_test.go that keep the directory and its index honest, and the merge-time numbering below.

The problem it solves is structural. A number used to be taken when a record was written, on a branch — so two branches that each wrote a record each took the same "next free" number, and whichever merged second had to renumber: rename the file, fix the heading, move the index row, and chase every citation. Numbers 0090, 0103 and 0105 were each shared by two unrelated decisions that way before there was a test; afterwards the test caught it, but the renumbering churn stayed, and one record walked 0164 → 0165 → 0166 → 0167 → 0168 → 0169 across six merges without a word of its content changing.

So a record in flight carries no number at all. It lives at draft-<slug>.md, heads with `# ADR-DRAFT: title`, and is cited as ADR-draft-<slug>. Two branches writing records touch different files and no shared line of the index, so they cannot collide. AssignNumbers gives every draft its number once it is on main — where "the next free number" is finally a question with one answer — and rewrites the file name, the heading, the index row and every citation in one pass.

A number, once assigned, is never reassigned. That is what makes a citation safe: ADR-0168 in a comment means today what it will mean in a year.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Assignment

type Assignment struct {
	Slug   string
	Num    int
	From   string // draft-<slug>.md
	To     string // NNNN-<slug>.md
	Title  string
	Status string
}

Assignment is one draft becoming a numbered record.

func AssignNumbers

func AssignNumbers(root string) ([]Assignment, error)

AssignNumbers gives every draft under root/docs/adr the next free number and makes the whole repository agree about it: the file is renamed, its heading rewritten, its row appended to the index, and every `ADR-draft-<slug>` citation and `draft-<slug>.md` link in the tree rewritten to the number it just got.

It is meant to run on main, where "the next free number" has one answer — see the package comment. With no drafts present it changes nothing, which is the common case for the workflow that runs it on every push.

type Record

type Record struct {
	Num    int    // 0 while the record is a draft
	Name   string // file name within docs/adr
	Slug   string // the file name's kebab-case part, stable across numbering
	Title  string // from the `# ADR-NNNN: title` heading
	Status string // from the `- **Status:** ...` line
}

Record is one decision record on disk. A record still in flight has Num 0 and lives at draft-<slug>.md; a record that has landed carries its number in both the file name and the heading, and the guard tests insist the two agree.

func LoadRecords

func LoadRecords(dir string) ([]Record, error)

LoadRecords reads every record in dir — numbered and draft alike — and reports every malformed one in a single joined error, so a run names all the problems rather than the first. Records that parsed well enough to identify are returned even when the error is non-nil, which is what lets the guard tests check the index against the directory while still reporting a record's own defects.

func (Record) IsDraft

func (r Record) IsDraft() bool

IsDraft reports whether this record is still waiting for a number.

Directories

Path Synopsis
cmd
adrnum command
Command adrnum assigns a number to every architecture decision record that is still in flight, and makes the repository agree about it.
Command adrnum assigns a number to every architecture decision record that is still in flight, and makes the repository agree about it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL