Island-mode server

An on-premise fallback server: a live replica of your site's cloud data, LAN takeover when the internet drops, and a safe flush of offline work when it returns.

Released
September 29, 2026
npx skills add timerise-ai/island-mode-server
Current release
v0.1.11
Reference docs
8
Non-negotiables
4
License
MIT

What problem does Island-mode server solve?

A shop, gym or clinic cannot stop when the internet drops. The cloud system is unreachable, but customers are at the counter, stock is moving and doors need to open.

This skill builds a small server that runs at the site and keeps a live copy of the site's data. While the connection is up it stays invisible. When the connection drops, kiosks and staff terminals on the local network switch to it. The site keeps taking bookings, moving stock and opening doors. When the connection returns, the offline work flushes back to the cloud exactly once.

Node on the local box, Firestore in the cloud. Hardware authenticates with HMAC. The on-site operations (systemd, nginx) are written down.

What does the skill build?

An agent with this skill builds one module as a Node.js server at your site, next to your cloud app, on your stack. For Island-mode server that module consists of:

  • 1. Live RxDB replica of a site's Firestore slice
  • 2. LAN takeover when the internet drops
  • 3. Idempotent reconnect flush
  • 4. HMAC hardware auth

Where do the rules come from?

The skill was written by the engineers who have shipped this module; the earlier implementation it was audited against was the on-premise fallback of a multi-location venue booking system. The templates hold four properties: a live replica that takes over the LAN when the internet drops, a reconnect flush the cloud can apply any number of times with one result, hardware calls that are HMAC-verified with a replay window, and offline staff tokens that expire. The vitest suite in assets/ verifies the trust-critical logic, and `references/provenance.md` is the record of what the audit changed, what was kept and what is new.

Written by the engineers who have shipped this module. The earlier implementation it was audited against is a NestJS + RxDB local server replicating Firestore collections for a Next.js cloud app, with kiosk/staff PWA terminals and HMAC-authenticated lock hardware. Templates are hardened: they are that design with the audit findings below fixed in place. Everything not listed under "Added" ran in production in the earlier implementation.

The ledger separates what the audit changed, what was kept on purpose, and what has not run in production yet.

  1. Fixed in the templates

    • Cloud sync-ingestion endpoints had no authentication The earlier implementation's /api/sync/* routes (bookings, inventory-transactions, lock-logs) accepted unauthenticated POSTs on the public internet; anyone could inject confirmed bookings, apply arbitrary stock increments, or forge audit logs. Shipped: x-sync-secret shared-secret check on every ingestion endpoint (sync-flush.md).
    • Offline JWT fallback reachable while online Staff auth fell back to decode-without-verification whenever verifyIdToken threw, including for forged tokens while fully online, making signature verification unenforceable. Expiry was never checked. Shipped: fallback gated on the network monitor reporting offline, plus an exp check on the offline path (auth.md).
    • Non-idempotent stock apply under at-least-once delivery The ingestion route applied FieldValue.increment() per transaction with no already-applied check; a retried flush (lost ack, crash between apply and mark-synced) double-decremented stock and duplicated logs. Shipped: Firestore transaction doing receipt check + increment + log atomically, keyed on the client-generated transaction ID. The receipt is the inventoryLogs entry only the ingestion writes, not the inventory_transactions document push replication also writes (sync-flush.md); see Added.
    • Wholesale delta reset after a possibly-failed flush flushAll cleared the entire local stock-delta map after flushing, but the per-collection flush methods swallowed their own errors, so a failed flush still wiped the deltas and effectiveStock reverted to the stale snapshot (oversell window). Shipped: per-ID delta fold-out on acknowledged syncedIds only; no wholesale reset (sync-flush.md).
    • Flush only ran on the offline-to-online transition A flush that failed right after reconnect was not retried until the next outage cycle; unsynced work could sit indefinitely while online. Shipped: a 60 s retry timer that flushes whenever unsynced work remains (sync-flush.md).
    Show 5 more
    • Client never rescanned for the local server while offline The terminal-side manager searched for the local server once, at the online-to-offline transition. A local server that booted after that moment was never found until the cloud recovered and failed again. Shipped: rescan on every offline tick (network-failover.md).
    • Island availability ignored site config Slot generation hardcoded 10:00 to 20:00 and derived "today" from UTC ISO strings, diverging from the cloud's opening-hours-driven availability (and shifting the day boundary for non-UTC sites). Shipped: hours derived from the replicated site document, a day without hours offering no slots; site-timezone todayAtSite() helper (local-api.md).
    • Undeclared and dead meta-fields _locallyModified was patched but absent from every RxDB schema (worked only because schema validation was off); _syncConflict was written once at creation and never used by anything. Shipped: _locallyModified declared in schemas; _syncConflict dropped, with conflict handling documented as an explicit LWW decision (architecture.md, replication.md).
    • Dead persistence configuration RXDB_STORAGE_PATH existed in config, env examples, and the deployment guide (which instructed operators to provision a data directory) while the code unconditionally used memory storage; operators believed offline data survived restarts; it did not. Shipped: the config removed; the memory-vs-persistent trade-off stated loudly with options (replication.md), and the Restart=always interaction called out (operations.md).
    • Sticky replication errors lastError was never cleared after recovery, so /status showed a replica as erroring long after it had healed. Shipped: error timestamping + clearing once replication cycles cleanly (replication.md).
Read the full record in provenance.md ›

What are the 4 rules the module never breaks?

Every module built from this skill holds these, whoever builds it. The same list is in the skill's README and SKILL.md, so the agent reads it before it writes a line.

  1. Never expose the cloud sync-ingestion endpoints without auth.

    They apply stock increments and inject orders, so they are reachable only with a shared-secret header at the minimum; the reference route handlers check it before touching Firestore.

  2. Never verify offline staff tokens leniently while online.

    Decoding without verification is an accepted LAN-only trade-off, so it is gated on the server actually being offline; the suite's offline token tests cover the gate.

  3. Never reset local stock deltas for transactions not acknowledged as synced.

    Deltas are folded out per transaction ID on acknowledgment, so effectiveStock stays correct across a partial flush; the suite's delta fold-out tests run against a real RxDB instance.

  4. Never let the local server invent business rules the cloud owns

    (opening hours, pricing). The local server replicates the config and computes from it, so island-mode behaviour matches the website.

When should you use it, and when not?

Use it for

  • A site must survive internet outages with real writes (bookings, stock, hardware control), not just cached reads.
  • Terminals are browser-based (PWA or kiosk) and must fail over transparently.
  • Firestore is the cloud source of truth and stays that way.

Not for

  • Cached reads, or a PWA that only needs offline persistenceInsteadThe Firebase SDK's built-in offline mode, no server needed
  • Supabase, Postgres or another cloud databaseInsteadThe tier concept travels; every template here is Firestore-specific
  • Multi-master sync between peer sitesInsteadThis design is strictly hub-and-spoke, cloud as source of truth
  • The kiosk terminal itselfInsteadThe sibling `booking-kiosk` skill, which defines the client-side failover contract against this server

How do I install it?

One command. The skills.sh CLI installs the skill into every skills-compatible agent it finds.

$ npx skills add timerise-ai/island-mode-server

Claude Code

Invoke with /island-mode-server

Codex CLI

Invoke with $island-mode-server

Gemini CLI

Invoke with /skills

Name the agents instead with -a, for example npx skills add timerise-ai/island-mode-server -a claude-code -a codex. Or clone the repository into your agent's skills folder. Nothing in it is agent-specific.

What is inside the repository (16 entries)
  • SKILL.mdEntry point: the architecture diagram, six critical facts, four hard rules, the quick start, and the reference directory
  • README.mdThis front door
  • CHANGELOG.mdKeep a Changelog, one section per release, newest first
  • CLAUDE.mdWhat this repository is and the conventions for editing the skill itself
  • LICENSEMIT
  • references/architecture.mdModes, the two sync paths, replication tiers, tenant scope, the seams table
  • references/replication.mdRxDB setup, schemas, custom-token auth, security rules, the checkpoint trap
  • references/sync-flush.mdReconnect flush, per-ID stock deltas, idempotent cloud ingestion, retries
  • references/network-failover.mdHeartbeat/status chain, outage detection, terminal API switching, rescan
  • references/auth.mdLocal API guards: staff tokens, kiosk key, hardware HMAC, offline gating
  • references/local-api.mdThe offline endpoints: availability, booking mutex, check-in, pricing
  • references/operations.mdOn-site deployment: systemd, nginx TLS, mDNS, env vars, runbook
  • references/provenance.mdThe ledger: what the audit changed, what was kept, what is new and not yet run
  • assets/behavior.test.tsThe vitest suite carried into the target project as regression cover, 17 tests
  • evals/The prompts an operator types after installing (prompts.md) and one file per agent eval: the skill installed into an empty Next.js app, one prompt, no help, then type-checked, built and tested
  • .github/workflows/agent-eval.ymlThe caller of the index's agent eval workflow, run on every published release and on a maintainer's dispatch

Recent releases

  1. v0.1.11September 29, 2026

    From scoring the prompt-1 agent eval runs against 0.1.10.

  2. v0.1.10September 29, 2026

    Fix release, from scoring the prompt-1 agent eval runs against 0.1.9.

  3. v0.1.9September 29, 2026

    Fix release, from scoring the prompt-1 agent eval runs against 0.1.8.

What do I tell my agent?

Say what you need in your own words; the skill supplies the how. These are starting points, and the ones we tested say how it went.

  1. Our climbing gym's front desk must keep taking bookings when the internet drops. Build a local server that replicates our Firestore data, takes over the LAN, and syncs back when the connection returns.

  2. Our kiosks run in the browser. Make them switch to the local box on their own when the cloud is unreachable, without staff doing anything.

    Firestore + RxDB

How does it do in each agent?

We install the skill into an empty Next.js app, give the agent one of the prompts above and no further help, then type-check, build and run the tests it left behind. Nothing is fixed by hand before the checks, and a failing run is published like a passing one. The procedure and every result are public, and the first prompt runs again before each release.

  • Gemini CLI0.61.0

    gemini-3.8-flash

    Built, checks pass
    Our climbing gym's front desk must keep taking bookings when the internet drops. Build a local server that replicates our Firestore data, takes over the LAN, and syncs back when the connection returns.
    Typecheck: passBuild: passTests: pass
    Time
    8 min
    Changed
    47 files, +9,354 lines
    Stack
    Firestore + RxDB
    Skill
    v0.1.11
    Run
    Sep 29, 2026

    Result file ›Agent log ›

    What we saw

    Rubric 8/8, scored from the summary. Checks pass. The suite ran as shipped, 17 of 17. The locations pull filters by document ID, LOCATION_ID is required, ingestion is authenticated, and the handover names all four items, all three mirrored secrets included. Fifth full score in a row.

    The Codex job of this release run (36595239695) failed with "Quota exceeded" from its API and wrote no result, so round 5 of the loop is incomplete.

  • Claude Code2.1.284

    claude-opus-5-5

    Built, checks pass
    Our climbing gym's front desk must keep taking bookings when the internet drops. Build a local server that replicates our Firestore data, takes over the LAN, and syncs back when the connection returns.
    Typecheck: passBuild: passTests: pass
    Time
    11 min
    Changed
    58 files, +10,869 lines
    Stack
    Firestore + RxDB
    Skill
    v0.1.11
    Run
    Sep 29, 2026

    Result file ›Agent log ›

    What we saw

    Rubric 8/8, scored from the summary. Checks pass. The suite ran unchanged apart from its two imports, 17 tests beside 3 of its own (20). One copy of firebase 11.6.0. The templates were kept as written: the offline journal is a new file, and a suspected defect was reported instead of patched. Tenant scope, wiring, env, the four hard rules and all four handover items hold. It reported, not scored: the booking schema does not declare slotType, although availability filters on it and the offline booking writes it. That works only because schema validation is off.

  • Codex CLIcodex-cli 0.159.0

    gpt-6-astra

    Built, checks pass
    Our climbing gym's front desk must keep taking bookings when the internet drops. Build a local server that replicates our Firestore data, takes over the LAN, and syncs back when the connection returns.
    Typecheck: passBuild: passTests: pass
    Time
    15 min
    Changed
    70 files, +10,067 lines
    Stack
    Firestore + RxDB
    Skill
    v0.1.10
    Run
    Sep 29, 2026

    Result file ›Agent log ›

    What we saw

    Rubric 7/8, scored from the log. Checks pass. It asserted by script that the suite is the asset with its two imports relocated, and ran 17 of 17 beside 10 tests of its own. npm ls firebase shows one copy of 11.6.0. Both env files keep every name, tenant scope, wiring and the hard rules hold, and the runbook carries the handover. Item 2 fails on two one-line edits inside templates: the storage import in database.service.ts (its own SQLite-backed storage), and the custom-token uid in firebase-client.ts (a per-site uid, the upgrade the rules section names). Both are documented variants that the templates hardcode, so no file around a template can select them, which is what SKILL.md asks for.

How long does it take, and what does it cost?

We quote this module per project. The price depends on what it has to connect to. The path to a number is short and free:

  1. Step 1

    Brief

    Tell us what the module must connect to. Takes minutes, in a chat.

  2. Step 2

    Prototype in 48 hours

    A clickable prototype of your system and a quote, at no cost.

  3. Step 3

    Build and handoff

    One project price. Source code, documentation and IP are yours.

Two ways to get Island-mode server

Build it yourself

Install the skill. Your own agent builds the module.

  • MIT licensed, no strings
  • Runs in Claude Code, Codex CLI and Gemini CLI
  • The same rules our engineers build by
$ npx skills add timerise-ai/island-mode-server

Build it with Timerise

Send a brief. We build Island-mode server into a system you own.

  • Clickable prototype and a quote within 48 hours, free
  • One project price, no subscription, no commission
  • Source code, documentation and IP handed over
3 years of support included.

Generated from the skill's own files at commit eaf46b3. Every rule above links to where the repository says it. All skills