Development Guide
Standard Red Notes is a multi-root monorepo. The root workspace owns MCP and OpenClaw; the application and server retain their own workspace roots and build systems. The root scripts compose those systems into repository-wide gates.
Repository map
| Path | Responsibility |
|---|---|
app/packages/web |
Main web application and shared UI |
app/packages/desktop |
Electron shell and native desktop services |
app/packages/mobile |
React Native mobile shell and native adapters |
app/packages/clipper |
Firefox/Chromium browser extension |
app/packages/snjs |
Client protocol, item, encryption, sync, and service logic |
server/packages/api-gateway |
Public routing, admin, integrations, OCR, workflows, CalDAV |
server/packages/auth |
Accounts, sessions, roles, settings, audit, workers, srn-admin |
server/packages/syncing-server |
Item sync, shared-vault enforcement, backup events |
server/packages/files |
Encrypted file transfer |
server/packages/revisions |
Revision storage and retrieval |
server/packages/websocket-gateway |
Realtime token and socket paths. Runs in-process inside the api-gateway and the home-server; there is no separate gateway service. |
server/packages/websockets |
Dormant. The standalone AWS-era gateway service; nothing imports it, and it serves no route in any shipped topology. It is still compiled and still counted by the coverage tooling. |
mcp |
Headless Standard Notes MCP bridge |
openclaw |
Provider-driven CLI assistant over MCP |
cli/srn-client |
Standalone encrypted note CLI |
cli/srn-server |
Standalone operator/Compose CLI |
e2e |
Cross-component browser and operations tests |
scripts |
CI, coverage, release, backup, docs, and hardening contracts |
docs |
Jekyll documentation site |
Toolchain
Repository-wide development uses Node.js 26 and Yarn 4.17.1. Some standalone CLI packages declare Node 24+, but use the root toolchain when changing multiple components. Docker with the Compose plugin is required for live server and cross-service tests.
Install from the repository root:
corepack enable
yarn install --immutable
Do not regenerate an app or server lockfile from the wrong workspace root.
Dependency upgrades and maintained upstream packages
Update each workspace and its lockfile together, then run its build, tests and
the production dependency audit. A registry latest tag is not proof that a
package supports this application’s runtime.
The October 2026 upgrade retains TypeScript 6.0.3 because the current ts-jest
release requires TypeScript below 7. React Native’s Babel tooling stays on the
latest compatible Babel 7 releases: its plugins reject Babel 8. These holds
should be reviewed when those upstream tools add support.
The desktop’s embedded home server uses a matching upstream source cohort in
app/vendor for packages referenced by the published release but missing from
npm. Preserve the licenses, provenance and rebuild instructions there when
making local fixes. The desktop loopback binding remains a separate Yarn patch;
updating upstream must not expose that server on public interfaces.
The shared domain-core 1.41.8 package also has a narrow Yarn patch: its UUID
generator uses the cross-platform uuid package instead of importing
node:crypto into browser bundles. Its added dependency is declared in
app/.yarnrc.yml so clean installs reproduce the same graph.
Common commands
yarn build
yarn typecheck
yarn lint
yarn format:check
yarn test
yarn check
The root build covers MCP, OpenClaw, app, and server. check runs typecheck,
lint, formatting, and tests. The server test command builds before running its
tests.
Use focused commands while iterating:
yarn workspace @standard-red-notes/mcp typecheck
yarn workspace @standard-red-notes/mcp test
yarn workspace @standard-red-notes/openclaw typecheck
yarn workspace @standard-red-notes/openclaw test
cd app && yarn test
cd server && yarn build && yarn test
Then run the repository-level gate appropriate to the change.
Launch preflight
Before a local launch binds a port, scripts/detect-running-instance.mjs checks
whether the port is taken and — the part that matters — whether the thing already
listening is this app, and which build it is:
yarn preflight # every local port, plus a desktop process scan
yarn preflight:web # webpack dev server port
yarn preflight:docker # docker compose app and gateway ports
yarn preflight:desktop # desktop extensions server and running instances
Identity comes from /.well-known/srn-deployment.json, the same marker used to
answer “which commit is live?” during an incident. The report names the running
revision next to the one being launched, so a stale instance is visible instead
of being mistaken for the build you just made.
Collision behaviour differs by occupant, deliberately:
| Occupant | Behaviour |
|---|---|
| Nothing listening | Launch proceeds |
| Unrelated process | Move to the next free port, where the service allows it |
| This app, any build | Stop and report — the choice is yours |
Moving off a port this app already holds is never automatic: the browser tab and
bookmarks would still point at the stale instance, so a relocation that looks
like a successful restart is the exact confusion the check exists to prevent.
Nothing is ever killed or restarted. yarn start:web runs the check
automatically; set SRN_SKIP_LAUNCH_PREFLIGHT=1 to bypass it.
The desktop app keeps its Electron single-instance lock unchanged — a second launch still exits and focuses the running window — but now logs which version was blocked and which is running, so relaunching a rebuild over a stale instance is stated rather than silent.
Contract and operations gates
| Command | Contract |
|---|---|
yarn ci:contracts |
CI tooling, generated app-docs/search consistency, and docs link integrity |
yarn ci:docker-hardening |
Container user, permissions, secrets, and installed admin wrapper |
yarn ci:verify-playwright |
Required Playwright report evidence |
yarn release:contract |
Release workflows, assets, matrices, and provenance |
yarn ops:backup-restore |
Backup/restore script contract |
yarn ops:load |
Operations load suite |
yarn deps:security:owned |
Recursive dependency vulnerability audit |
yarn coverage |
App/server coverage collection and report generation |
Run git diff --check before committing.
Change workflow
- Reproduce the behavior or identify the source contract.
- Trace the complete path: client, API, service, persistence, restart, and recovery where applicable.
- Add the smallest focused test that would fail without the change.
- Implement within the owning package.
- Run focused typecheck/test/format gates.
- Run cross-package or contract gates for touched boundaries.
- Inspect the actual diff for generated files, secrets, and unrelated changes.
- Update runtime documentation when configuration, behavior, safety, or recovery changes.
For feature gates, test all four states: master off, user off, both on, and stale/invalid client input. Authorization must fail closed at the server.
End-to-end encryption changes
Changes around keys, serialization, sync, recovery, sharing, files, assistant content, OCR, or backup require explicit boundary review:
- What is plaintext and where?
- Which process receives it?
- What is persisted or logged?
- Can authorization be bypassed by a modified client?
- What happens offline, on retry, and during conflict?
- How is access revoked?
- How is data restored?
Use real wire/E2E tests where possible rather than only mocking the API.
Server settings and persistence
Several operator settings use a persisted runtime overlay layered over environment defaults. A change is incomplete if only the admin control exists. Verify:
- read and write API;
- validation and sensitive-value withholding;
- effective precedence;
- live/restart behavior;
- container persistence/mounting;
- CLI parity or recovery path;
- audit evidence; and
- tests for missing/corrupt settings.
Documentation
Documentation pages use YAML front matter and Markdown. Internal links should
point to repository docs rather than generated .html when authoring. Mermaid
pages include {% include mermaid.html %} once and use
fenced mermaid blocks.
Do not hand-edit generated search or coverage artifacts unless the generating script identifies them as source files. Run the documented generator/checker and commit source plus generated output together when the contract requires it.
# Rebuild after changing any documentation page
yarn docs:search:index
# Check generated docs, search freshness, screenshots, links, navigation,
# code fences, prose contracts, and every Mermaid diagram
yarn docs:check
The link gate also requires every top-level page to appear in
docs/_data/navigation.yml; add the page and its substantive headings to the
correct runtime or reference group rather than leaving it discoverable only
through search. It also rejects redundant Markdown horizontal rules and
roadmap-style wording that mislabels shipped MCP or OpenClaw functionality.
Commit discipline
Keep commits coherent by concern. Avoid mixing dependency churn, generated artifacts, UI behavior, server persistence, and documentation when they can be reviewed independently. A clean final status and exact validation record make later release and incident work substantially safer.