Skip to content

Architecture Boundaries

The rules a change to ScribeKit is expected to preserve. The durable contract is AGENTS.md in the repository; this page is the readable version of the boundaries it enforces.

Domain models

Keep domain models small, testable value types, free of I/O. Model mutually exclusive state with enums rather than sets of booleans, so contradictory states are unrepresentable.

Adapt frameworks at the subsystem boundary

Frameworks such as ScreenCaptureKit stay inside their provider. Domain models, state owners and views work with ScribeKit's own value types, so behaviour stays testable without system permission.

Capture, transcription, persistence and presentation are separate concerns and stay separate.

Filesystem

Reach the filesystem only through a location the user chose in a system panel, persisted as a security-scoped bookmark, with access started for the work that needs it and stopped afterwards. Never weaken or disable the App Sandbox to reach a path, and never write to a location the user did not pick.

Read and write are different types

HistoryStoring has no method that creates, replaces, appends to or deletes anything. The protocol that writes derived state can address no source artifact, so a failed derived write cannot damage one. Recovery keeps its own store, because recording an interruption is a write and History never writes.

The meeting is not the window

An active meeting's lifetime is application-scoped. Nothing that ends, pauses, finalises or observes a meeting lives in a view hierarchy, and no presentation object may be what keeps a meeting alive. See Presentation Lifecycle.

The audio path

Bounded memory, no high-frequency audio callback through the main actor, every producer/consumer queue bounded with overflow measured and reported, and nothing on the delivery path — memory or stack — growing with the length of a meeting. See Audio Capture.

Design for event-driven work rather than polling: minimal timers, coalesced UI updates, lazy rendering, batched persistence, appropriate task priorities, and minimal work while the UI is hidden. Do not prematurely optimise; do not knowingly introduce a hot loop either.

No fake features

An unimplemented control is disabled or absent — never simulated, stubbed with fabricated output, or described as working. Never simulate unimplemented behaviour, and never rewrite raw transcripts.

Documentation comments

Use native Swift /// comments on non-trivial public and internal types, protocols, methods, functions and important properties. Document parameters, return values and thrown errors where applicable. Do not restate a symbol name, and keep comments synchronised with the implementation.