The empty-state workspace shell (used on index and search pages) was using a 50/50 grid split. When the miller-browser only shows 1-2 columns the left side looks too wide. Change to a 36/64 split so the browser column maxes out at 36% while keeping its 300px minimum.
Cairnquire
Cairnquire is a Go-first documentation platform for serving Markdown as secure, fast HTML with room for later sync, collaboration, and offline features.
Current Status
This repository now contains the Milestone 1 foundation scaffold:
- Go application server with chi routing, slog logging, config loading, and graceful shutdown
- SQLite/libsql-oriented data layer with startup migrations
- Markdown rendering pipeline with wiki-link rewriting, tag extraction, and SSR templates
- Content-addressed attachment storage with secure serving
- Go-served HTML templates with embedded CSS and browser scripts
- Docker, Compose, CI, OpenAPI, and local development targets
Quick Start
Prerequisites
mise- Docker (optional)
- CGO-capable toolchain for
go-libsql airfor Go live reload (go install github.com/air-verse/air@v1.65.1)- Xcode command-line tools for the optional macOS sync app and CLI
Install the pinned toolchain with:
mise install
Development Mode (with live reload)
Run the Go server with live reload:
mise run dev
This starts the Go server with air live reload on http://localhost:8080.
Production Mode
Run the Go server:
mise run server-run
The server listens on http://localhost:8080 by default.
macOS Sync and CLI
The menu bar sync app and companion CLI live in apps/macos-sync. For local
development, start the server with its local-only auth shortcut:
PORT=9000 CAIRNQUIRE_DEV_MODE=1 mise run server-run
cd apps/macos-sync
swift run cairnquire-cli config \
--server http://localhost:9000 \
--token dev \
--folder "$HOME/Documents/Cairnquire"
swift run cairnquire-cli sync
swift run CairnquireSync
The app automatically uses the dev token for localhost servers. For a
deployed server, create an API token from /account and store that token in
the app settings. See apps/macos-sync/README.md
for upload, sync, and Keychain details.
Fresh Server Deployment
The Compose deployment keeps its database and attachment store in ./data and
its editable Markdown source in ./content.
cp .env.example .env
# Edit CAIRNQUIRE_PUBLIC_ORIGIN in .env to match your HTTPS URL.
docker compose up -d --build
curl http://127.0.0.1:8080/health
Open ${CAIRNQUIRE_PUBLIC_ORIGIN}/setup in a browser. The first-run wizard
creates the admin account and asks whether visitors may create accounts. The
setup endpoint closes after the first admin is created. An admin can change the
signup setting later from the account page.
Common commands
mise run server-test
mise run server-build
mise run docker-build
mise run ci
mise run fmt
Configuration
Configuration can come from:
config.jsonviaCAIRNQUIRE_CONFIG- Environment variables
Supported variables:
CAIRNQUIRE_PUBLIC_ORIGIN- Required for deployment. Exact public HTTPS origin used for passkeys and device-flow URLs, for examplehttps://cairnquire.example.com.CAIRNQUIRE_SERVER_ADDR- Listen address. Defaults to:8080.PORT- Optional shorthand for the listen port, for examplePORT=9000.CAIRNQUIRE_DATABASE_PATH- Local SQLite/libsql path. Defaults to../../data/db.sqlitewhen running fromapps/server.CAIRNQUIRE_DATABASE_PRIMARY_URL- Optional remote libsql primary URL for an embedded replica.CAIRNQUIRE_DATABASE_AUTH_TOKEN- Optional auth token for the remote libsql primary.CAIRNQUIRE_CONTENT_SOURCE_DIR- Editable Markdown source directory.CAIRNQUIRE_CONTENT_STORE_DIR- Content-addressed attachment store.CAIRNQUIRE_EMAIL_SMTP_HOST- SMTP host. Set to an empty string in JSON config to disable delivery.CAIRNQUIRE_EMAIL_SMTP_PORT- SMTP port. Defaults to1025.CAIRNQUIRE_EMAIL_FROM- Notification sender address.CAIRNQUIRE_LOG_LEVEL- Defaults toINFO.CAIRNQUIRE_DEV_MODE- Optional local-only auth shortcut. Do not enable on a deployed server.
Dev Mode
With CAIRNQUIRE_DEV_MODE=1, API requests using Authorization: Bearer dev
authenticate as the local development admin. This is intended only for
localhost testing.
Noted Gaps
- The docs call for
golang-migrate, but the current foundation uses an internal migration runner whilego-libsqlintegration details are validated. - The sync docs describe JSON messages while the Milestone 1 layout mentions a protobuf package; both are preserved in
packages/protocol/pending a later protocol lock.