1"use strict";(globalThis.webpackChunk_bitwarden_contributing_docs=globalThis.webpackChunk_bitwarden_contributing_docs||[]).push([[6815],{63491(e,n,t){t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>c});const i=JSON.parse('{"id":"architecture/adr/adopt-engineering-documentation-standard","title":"0034 - Adopt engineering documentation standard","description":"Context and problem statement","source":"@site/docs/architecture/adr/0034-adopt-engineering-documentation-standard.md","sourceDirName":"architecture/adr","slug":"/architecture/adr/adopt-engineering-documentation-standard","permalink":"/architecture/adr/adopt-engineering-documentation-standard","draft":false,"unlisted":false,"editUrl":"https://github.com/bitwarden/contributing-docs/tree/main/docs/architecture/adr/0034-adopt-engineering-documentation-standard.md","tags":[{"inline":true,"label":"clients","permalink":"/tags/clients"},{"inline":true,"label":"mobile","permalink":"/tags/mobile"},{"inline":true,"label":"server","permalink":"/tags/server"},{"inline":true,"label":"sdk","permalink":"/tags/sdk"}],"version":"current","sidebarPosition":34,"frontMatter":{"adr":"0034","status":"Accepted","date":"2026-08-05T00:00:00.000Z","tags":["clients","mobile","server","sdk"]},"sidebar":"architecture","previous":{"title":"0033 - Adopt Mermaid diagram standard","permalink":"/architecture/adr/adopt-mermaid-diagram-standard"},"next":{"title":"0035 - Service-oriented architecture","permalink":"/architecture/adr/service-oriented-architecture"}}');var s=t(74848),o=t(28453);const r={adr:"0034",status:"Accepted",date:new Date("2026-08-05T00:00:00.000Z"),tags:["clients","mobile","server","sdk"]},a="0034 - Adopt engineering documentation standard",d={},c=[{value:"Context and problem statement",id:"context-and-problem-statement",level:2},{value:"Considered options",id:"considered-options",level:2},{value:"Decision outcome",id:"decision-outcome",level:2},{value:"Positive consequences",id:"positive-consequences",level:3},{value:"Negative consequences",id:"negative-consequences",level:3},{value:"Plan",id:"plan",level:3}];function l(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",ol:"ol",p:"p",strong:"strong",ul:"ul",...(0,o.R)(),...e.components},{AdrTable:t}=n;return t||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("AdrTable",!0),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"0034---adopt-engineering-documentation-standard",children:"0034 - Adopt engineering documentation standard"})}),"\n",(0,s.jsx)(t,{frontMatter:r}),"\n",(0,s.jsx)(n.h2,{id:"context-and-problem-statement",children:"Context and problem statement"}),"\n",(0,s.jsx)(n.p,{children:"Documentation practice has fragmented as the organization has grown:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Major repos use divergent layouts (",(0,s.jsx)(n.code,{children:"docs/"}),", ",(0,s.jsx)(n.code,{children:"Docs/"}),", per-crate READMEs, none), inconsistent README\ncasing and quality, and no shared definition of what must be documented where."]}),"\n",(0,s.jsx)(n.li,{children:"The de facto standards page lives in Confluence and is not enforced; practice diverges from it."}),"\n",(0,s.jsx)(n.li,{children:"Content sits in the wrong home: single-repo architecture on this site, shipped-code architecture\ndeep dives in Confluence, production runbooks in personal spaces, and duplicated guidance across\nhomes."}),"\n",(0,s.jsx)(n.li,{children:"Stale content accumulates with no supersession discipline, leaving superseded pages beside current\nones with no deprecation."}),"\n",(0,s.jsxs)(n.li,{children:["AI agents have become first-class documentation consumers and maintainers, and their instruction\nfiles (",(0,s.jsx)(n.code,{children:"CLAUDE.md"}),", rules, and skills across all repos) accumulate documentation-like content with\nnothing defining whether they are documentation at all."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"A 2026-07 audit classified every documentation artifact across the major repos, this site, and\nConfluence against a proposed routing model, confirming these gaps."}),"\n",(0,s.jsx)(n.h2,{id:"considered-options",children:"Considered options"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Status quo:"})," per-team conventions, advisory Confluence page."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Confluence-first:"})," centralize engineering docs in the wiki."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Per-repo standards:"})," each repo defines its own documentation rules and keeps its own ADRs."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"One org-wide, docs-as-code documentation standard:"})," close-to-code default, single routing\nmodel, enforced through PR review and AI-agent guardrails."]}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"decision-outcome",children:"Decision outcome"}),"\n",(0,s.jsxs)(n.p,{children:["Chosen option: ",(0,s.jsx)(n.strong,{children:"one org-wide, docs-as-code documentation standard"}),", published as the\n",(0,s.jsx)(n.a,{href:"/contributing/documentation/",children:"Documentation section"}),". The standard is the living\nreference. Its rules evolve by PR without superseding this decision and this ADR is superseded only\nif the model itself changes. A snapshot of the rules at adoption:"]}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Public by default"}),". Private content is limited to documentation about working at Bitwarden and\nsensitive information."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Located at the lowest common ancestor"})," of what is described."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Every doc has an audie
1nce"}),". AI agents and humans are both first-class audiences and\nmaintainers."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Always up to date"}),". Doc maintenance is a top priority and happens alongside changes to what it\ndescribes."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Discoverable and unified"}),", enforced by the style guide the standard publishes."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["Diagrams follow the separate diagram standard adopted in\n",(0,s.jsx)(n.a,{href:"/architecture/adr/adopt-mermaid-diagram-standard",children:"ADR-0033"}),", which keeps its own living reference at\nContributing \u203a Documentation \u203a Diagrams."]}),"\n",(0,s.jsx)(n.p,{children:"AI instruction files are explicitly not documentation and are out of the standard's scope. Their\nguidance lives with the AI tooling."}),"\n",(0,s.jsx)(n.h3,{id:"positive-consequences",children:"Positive consequences"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:'One place to answer "where does this doc live" and "which docs do I update", for engineers and AI\nagents alike.'}),"\n",(0,s.jsx)(n.li,{children:"Documentation rides the code PR, so freshness is enforced by review and agent guardrails."}),"\n",(0,s.jsx)(n.li,{children:"Public-by-default locations serve external contributors and AI agents without special access."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"negative-consequences",children:"Negative consequences"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"A migration backlog: existing content sits in homes the routing model forbids and must move."}),"\n",(0,s.jsx)(n.li,{children:"Strict-move deletions can break unknown inbou
1nd links. Known links are updated at move time and\nlink checkers in CI are the mitigation for the rest."}),"\n",(0,s.jsx)(n.li,{children:"Every repo carries adoption work before the standard applies in practice."}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"plan",children:"Plan"}),"\n",(0,s.jsx)(n.p,{children:"Follow-up PRs complete the standard:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The standard, with its format guidance and templates, publishes as the Documentation section under\nContributing and becomes the living reference this ADR mandates."}),"\n",(0,s.jsx)(n.li,{children:"An ai-plugin is produced and made available to help identify when local documents need to be\nupdated as well as adding both local and external documentation update requirements to AI review\ntools."}),"\n",(0,s.jsxs)(n.li,{children:["Each repo adopts the standard: base documentation obligations in the root ",(0,s.jsx)(n.code,{children:"CLAUDE.md"}),", a\n",(0,s.jsx)(n.code,{children:"CONTRIBUTING"})," pointer, and markdown tooling parity."]}),"\n",(0,s.jsx)(n.li,{children:"Remediation work items are filed for every rule that current reality violates, and the superseded\nConfluence standards page is deleted."}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"The migration backlog proceeds opportunistically under named owners. Small one-shot fixes are\ntracked as work items; the long-running efforts:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Single-repo content migrates off this site"}),": ",(0,s.jsx)(n.code,{children:"architecture/{clients,server,sdk,mobile-clients}"}),"\nand 12 of 28 deep-dive pages (including the whole ",(0,s.jsx)(n.code,{children:"autofill/"})," subtree) move into their repos per\nthe routing table. Contributing docs' Deep Dives section holds only cross-repo or conceptual\nmaterial."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Shipped-code architecture migrates out of Confluence"}),": pages describing shipped code (the SSH\nagent suite, event collection, key management cryptography) move in-repo or to this site per the\ndecision rule."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"README coverage in Bitwarden repositories"}),": generated stubs and missing module READMEs brought\nto the module README standard, and filename casing normalized."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Confluence hygiene"}),": stale and superseded pages deleted or stale-marked, and team runbook\nindexes adopt the runbook standard and its Last verified discipline."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Incident documentation consolidation"}),": RCAs converge on the incident.io export as the single\nhome."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Style long tail"}),": style violations fixed across the site as pages are touched."]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,o.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(l,{...e})}):l(e)}},28453(e,n,t){t.d(n,{R:()=>r,x:()=>a});var i=t(96540);const s={},o=i.createContext(s);function r(e){const n=i.useContext(o);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.