Use this runbook to validate the built-in TypeScript coordinator on Node/Linux before adapting the flow to Cloudflare.
This is an Advanced/operator validation path. The normal user workflow is Projects → Sharing → Devices → Health; coordinator groups and direct sync are compatibility and deployment mechanics.
Use this path to prove the coordinator-assisted delivery path end-to-end:
- start the coordinator
- create a group
- generate an invite
- join from a second device
- inspect the discovered device in Advanced
- confirm Project access and delivery in Devices/Health
- run a direct sync only when diagnosing
The local browser fixture completed a real cmux WKWebView link flow over both IPv4 and IPv6 in separate fresh fixtures. It kept the original browser binding through session completion and used one existing Identity without changing its device assignment. This is not a real provider pilot, deployment, dogfood-ready result, or a claim about production configuration.
Run the local-only fixture on Node 24:
node packages/cloudflare-coordinator-worker/test/browser-auth-browser-fixture.mjsThe script starts two owned local services, prints a READY HTTPS origin,
certificate fingerprint, certificate path, and control URLs. It stays running
until stopped with SIGINT or SIGTERM; --sanity stops it automatically.
An expected SIGTERM/Node exit 143 during owned-server cleanup is not a failure.
Use --sanity to run its 14 assertions without the browser flow, including
confirmed cancellation and a failed attempt state. With --sanity-fail-cancel
also supplied, the fixture injects a cancellation outage and must exit nonzero
without reporting success; owned services still stop. Retain its ignored
.tmp artifacts for debugging; do not treat them as test inputs or publish them.
- The fixture uses a local fake provider, local D1 state, a demo actor, temporary device keys, a signed runtime, and a loopback Node receiver.
- Node clients pin the specific public certificate reported by
READY; TLS validation stays enabled. - The browser needs explicit permission for the disposable local certificate. Do not add a CA, change system trust, disable TLS checks, import profiles or cookies, or use real user keys.
- The TLS sanity check requires
Secure,HttpOnly, andSameSite=Laxon the source cookie; raw browser cookie values are not inspected or recorded. - The provider step extracts the provider link from the DOM but never navigates to a real provider. A local authorize endpoint validates that link and returns the local callback instead.
- Do not visit, resolve, or override a real provider domain, including HSTS. The fixture loads no external assets.
- POST to the
READYstart control URL, choosinghost=127.0.0.1orhost=::1. Use the reported certificate as the client's specific CA. Open the private start URL printed to terminal stderr in the browser; do not share or log it. - Submit the CSRF-protected form with its normal
Origin; the local provider continuation must omit link secrets and completion material. - Follow the local callback. The SDK verifies its token and JWKS against the signed fake provider; the confirmation view names the account, Identity, and device.
- Confirm with CSRF protection. The saved receiver is IPv4 HTTP; a fresh fixture can save the IPv6 HTTP receiver.
- Click the receiver's
Finish linkinglink back to the pinned coordinator's/auth/link/completepage. The return link contains only the public attempt ID and sends no referrer; an early click may show a read-only waiting page. - Redeem from the original cookie and confirm the account reports one session.
document.cookiebeing empty is expected because the browser cookie isHttpOnly.
The browser retains its original secure coordinator cookie during the loopback hop; the receiver does not read or set that cookie. A normal fresh sign-in after logout displays the fake profile, while the first link does not persist that profile. This checks the fixture's intended account behavior, not provider account merging or memory-rights changes.
Use a different database for an independent initial-link test: one account-to-
Identity mapping is unique. Repeating IPv6 on the already-used database should
finalize with 409; a fresh fixture should pass.
The fixture also checks one benign race: two submissions sharing the same
pre-start cookie yield 200 and 409, and the browser winner completes. That is
not proof that every cookie race is resolved. A replayed callback is rejected while
the existing browser session can still open its account page.
Occasional browser wait-script completion-handler errors or timeouts can occur after navigation has already arrived. Confirm the resulting URL and accessibility snapshot before calling that an application failure; do not relax browser or TLS security to work around it.
For a disposable two-owned-device fake-provider acceptance run, use:
node --test --test-timeout=60000 packages/cloudflare-coordinator-worker/test/local-two-device-owner-proof.native-http.test.mjsThis test links A through the maintained account-link flow, enrolls fresh B
through the fixture-only owner HTTP handoff, and sends one scoped memory A→B
using syncOnce against the maintained sync app over signed loopback HTTP
with pinned peer keys. Revoked-membership checks are separate in-process
preflights, not HTTP denial tests.
It provisions scope memberships and peer trust separately: an Identity-group
transport grant does not grant Team or Project access. The received memory keeps
its portable content and import_key, but not A's local session path or dedup
key. The three test cases fail the command on a broken handoff, wrong account,
or unsafe abort. It changes only disposable fixture state; it does not mount an
ordinary owner route, adopt an existing populated device, test real Google, or
approve deployment. The provider is local and fake; this HTTP test makes no
TLS or browser Secure-cookie claim. It also runs in the Worker package's
test:auth-http CI gate.
This fixture does not cover enrollment review, migration UX, real provider configuration or consent, independent key provisioning, remote database checks, migrations, isolated deployment, or separate approval. Relay-after-auth is not started. Existing plugin smoke-test flakiness has an unconfirmed cause and is not masked by this fixture.
If this flow does not work on a clean Linux/Node setup, fix that first. Do not blame Cloudflare for bugs that already exist locally.
- one reachable Linux machine will run the coordinator
- two codemem devices will join the same coordinator group
- the coordinator is reachable from both devices (direct IP, Tailscale Funnel, or Cloudflare Tunnel)
On the coordinator host:
rm ~/.codemem/coordinator.sqlite
codemem coordinator group-create my-team --db-path ~/.codemem/coordinator.sqlite
set -x CODEMEM_SYNC_COORDINATOR_ADMIN_SECRET (openssl rand -base64 32)
codemem coordinator serve --db-path ~/.codemem/coordinator.sqlite --coordinator-host 0.0.0.0 --coordinator-port 7347If you do not want to expose the raw host directly, put it behind Tailscale Funnel or Cloudflare Tunnel and use that public URL in the next steps.
On the device that will create invites:
{
"sync_enabled": true,
"sync_coordinator_url": "https://coord.example.com",
"sync_coordinator_group": "my-team",
"sync_coordinator_admin_secret": "<same admin secret from the coordinator host>"
}Use a coordinator URL the teammate device can actually reach.
If you create an invite with a LAN-only, localhost, or Tailnet-only URL, codemem now warns about that, but it will not block you because private-network deployments can still be valid.
On the admin device:
codemem coordinator create-invite my-team --db-path ~/.codemem/coordinator.sqliteThis returns:
- a pasteable encoded invite string
- a link form of the same payload
- optional warnings if the coordinator URL looks network-scoped
Share the encoded invite with the teammate device.
On the teammate device:
codemem coordinator import-invite <encoded-invite>Expected result:
sync_coordinator_urlis configured automaticallysync_coordinator_groupis configured automatically- if the invite uses
auto_admit, enrollment completes immediately - if the invite uses
approval_required, the teammate sees a pending state until approval
The invite import path now uses a more reasonable timeout than the old brittle 3-second default, but if it still times
out, check reachability of the invite’s coordinator_url from the teammate machine before doing anything else.
If the invite policy is approval_required, on the admin host:
codemem coordinator list-join-requests my-team --db-path ~/.codemem/coordinator.sqlite
codemem coordinator approve-join-request <request-id> --db-path ~/.codemem/coordinator.sqliteAfter both devices are enrolled and posting presence, open Advanced → Sync (or the compatible #sync route).
Expected state:
- the teammate appears in Coordinator-discovered devices
- the coordinator's group membership does not itself grant Project access
For a legacy/direct-peer workflow, on the device that should pair with the teammate:
- click Accept peer in Team sync
- codemem creates the local
sync_peer - the UI hands you off to the legacy scope editor in Advanced
If the discovered peer conflicts with stale local state, Team sync currently shows a note that the repair/removal needs to happen in Advanced. Fix or remove the conflicting local peer there, then return to Team sync and accept the discovered device again once the row refreshes.
For the normal teammate workflow, share exact Projects in Sharing, then inspect Devices and Health:
- the device has an owning Identity
- Projects shared directly appear in Devices under Direct Projects
- Team recipient intent appears in Sharing; authoritative per-device Team eligibility remains in Team policy administration
- an unavailable device is Waiting, not failed
- Needs attention means a terminal setup failure and exposes a retry action
Coordinator enrollment, sync_peers, scopes, Space grants, addresses, fingerprints, filters, epochs, and cursors are Advanced/operator diagnostics. They must not be used as the proof of normal Project access.
Removing Project access prevents future delivery; it cannot retract memories already delivered to a device.
In Advanced, click Sync now for the new peer.
Current behavior:
- a successful click means the sync run was started, not that it has already completed
- the UI refreshes local sync status once after the trigger
- legacy scope review can still warn after the trigger; resolve it in Advanced before relying on the direct-peer path
Good signals:
- the peer moves from stale/offline to healthier status over time
- sync attempts appear in the diagnostics surface
- the receiving device actually gets the expected memories
Useful checks:
codemem sync peers
codemem sync attempts --limit 10
curl "http://127.0.0.1:38888/api/sync/status?includeDiagnostics=1"The invite probably embeds a coordinator URL the joining machine cannot reach.
Recreate the invite with the real public or shared-network URL.
You likely have stale coordinator enrollment state for that device id.
Reset or repair the coordinator DB entry and try again from a clean state.
That can still mean:
- the peer was not accepted yet
- legacy scope review is still pending
- the local peer entry is stale or conflicting
- the direct peer address is unhealthy even though coordinator discovery works
Use the Team sync note plus Advanced diagnostics to inspect and repair the actual peer state.
Treat the Linux/Node path as validated only when all of this is true:
- teammate can import the invite successfully
- devices appear in coordinator discovery
- discovered device can be accepted into
sync_peers - Devices shows the owning Identity and direct Project access; Sharing shows Team inheritance
- Health distinguishes waiting from needs-attention recovery
- a direct sync run is triggered successfully
- data actually replicates between devices
Once this flow is solid, the next step is a Cloudflare compatibility/adaptation pass rather than more guesswork on the basic coordinator behavior.