What local-first means when I ship
Local-first is useful only when it changes architecture, failure modes, and the promises made to a user.
“Local-first” can describe a philosophy, a storage decision, or simply a marketing adjective. When I ship a product, I need it to mean something observable. A user should be able to tell what remains on their machine, what leaves it, what keeps working without an account, and how they can recover their own work.
Local is the default path
The primary workflow should not depend on a remote service when the work can happen on the device. BrainBar reads an existing Markdown graph from disk. Corewise inspects Mac signals locally. The value appears before a login, a sync subscription, or an upload.
This does not forbid networks. Updates, public links, or an explicitly requested AI service may still use them. The difference is that the boundary is legible and narrow. Network access is a capability invoked for a reason, not the invisible foundation of every click.
The user's files remain understandable
Ownership is stronger when data has a durable form outside the application. Plain Markdown, JSON, and familiar folders make inspection and backup possible with ordinary tools. A proprietary database can still be appropriate for indexes or caches, but it should not quietly become the only copy of what matters.
That rule also improves engineering. Derived indexes can be deleted and rebuilt. Corruption has a smaller blast radius. Migration is a transformation of known files rather than a rescue operation from an opaque service.
Failure should be graceful
A local-first product must be honest about the device it runs on. Permissions can be denied, files can move, disks can fill, and a laptop can go offline. Useful failure messages explain what was checked, what remains safe, and what the user can do next. “The cloud is unavailable” should not erase access to yesterday's work.
Privacy is a product surface
Privacy is not complete merely because a backend is absent. Logs, analytics, crash reports, temporary exports, and AI prompts all cross boundaries. The product should minimize those paths, label them, and prefer aggregate signals where detail is unnecessary. On this site, private repositories contribute only to an aggregate commit count; their names, messages, and paths never enter the public data contract.
This note remains working because each shipped product exposes a new edge case. The promise I want to keep is stable: local-first should give the user more agency when the network, vendor, or product itself disappears.