Open the app

Build on hostnought

The swarm is the machine. Apps are folds.

hostnought is a platform for apps with no application server. A static bundle boots browser peers into a self-repairing storage-and-compute swarm. You write event schemas, fold rules, and a UI; the swarm handles durability, replication, repair, sync, search, and verified compute.

This page is the whole developer story: why you'd build here, how to build your first app in ten minutes, what the API actually is, and what's genuinely possible — plus the constraints that make some ideas a bad fit.


Why build here

Be skeptical of platform pitches. Here is the honest one: a $5 VPS beats this on every axis except the ones that kill projects.

The niche, stated plainly: survival, not performance. Build here when the data matters longer than the funding, when the community should own its own archive, or when there is no infrastructure to depend on.


Install the CLI

curl -fsSL https://hostnought.com/install.sh | sh

The installer verifies the download's SHA-256 against the published manifest before extracting; read it first if you like (curl https://hostnought.com/install.sh). The CLI is standalone — it ships its own runtime, so you never need the platform repo:

hostnought new fieldnotes && cd fieldnotes
hostnought dev      # a real local swarm (isolated playground) with your app
hostnought check    # the validator swarms enforce, before you can ship
hostnought build    # shippable bundle + content hash

Your first app in ten minutes

An app is id + schemas + folds + (optionally) a React view. That's it.

// guestbook.app.js — a complete, shippable hostnought app.
export default function register({ sdk, React }) {
  const { registerApp, createEvent, submitEvent, dag, useDagVersion } = sdk;
  const h = React.createElement;

  function Main({ identity }) {
    useDagVersion();                                     // re-render on new events
    const entries = dag.getState('guestbook', 'entries') ?? [];
    const sign = async (text) =>
      submitEvent(createEvent(
        { app: 'guestbook', type: 'entry', scope: 'main', ts: Date.now(), body: text },
        identity.privkey,
      ));
    return h('div', { className: 'apppage' },
      h('button', { onClick: () => sign('hello swarm') }, 'Sign'),
      ...entries.map((e, i) => h('div', { key: i }, e.text)),
    );
  }

  registerApp({
    id: 'guestbook',
    icon: '✎',
    title: 'Guestbook',
    schemas: { entry: {} },
    folds: [{
      app: 'guestbook', name: 'entries', version: 1,
      init: () => [],
      step: (state, e) =>
        e.type === 'entry' && typeof e.body === 'string'
          ? [...state, { who: e.author, text: e.body, ts: e.ts }]
          : state,                       // ignore anything else — see law 2
    }],
    views: { Main },
  });
}

Then:

hostnought check guestbook.app.js   # validate + bench locally (no network)
hostnought build guestbook.app.js   # bundle + content hash to hand a founder

Swarm founders ratify it (swarm apps add) and deploy; from then on every verified client loads it — no platform release involved.

The full working version ships in examples/guestbook.app.js. Poke at a live one in the Workbench tab of the app, and break things safely in the playground (/app?swarm=sandbox — isolated storage, throwaway identity).


The mental model

Everything is an event. A signed, content-addressed, immutable record: { id, app, type, author, scope, ts, body, sig }. Users emit events; the swarm floods, batches, erasure-codes, and repairs them forever.

All state is a fold. Your app's state is a pure function over the event log — init() plus a step(state, event) reducer. Every peer replays the same events in the same total order and gets the same state. There is no database, no migration, no write conflict: state is derived, always.

Two laws. The devkit enforces both before anything ships:

  1. Folds must be pure and deterministic. Same events, any arrival order → same state. No Date.now(), no randomness, no network inside a fold.
  2. Folds must tolerate junk. Anyone can emit any body under your app id. A fold that throws on unexpected input is a remote crash button. Check your types and ignore what doesn't fit.

Storage-neutral carriage. Peers store and repair your app's data even if they never load your app. You inherit the swarm's durability for free.


SDK reference

Everything an app may touch, and nothing else (src/sdk/index.ts — the boundary is enforced by a test).

Registration

ExportWhat it does
registerApp(def)Register schemas, folds, views, jobs, hooks. The only entry point.
getApp(id) / listApps() / registeredApps()Reflection; getApp(x).views is the sanctioned way to mount another app's UI.
subscribeApps(fn)Fires when apps register (external apps land after first paint).

AppDef: { id, title?, icon?, schemas, folds, jobs?, onSeal?, scatterResponders?, rpc?, views? }

Events & state

ExportWhat it does
createEvent(draft, privkey)Sign an event. draft = { app, type, scope, ts, body, parent? }.
submitEvent(event)Insert locally + gossip to the swarm.
dag.getState(app, name)Current fold state.
dag.getEvent(id) / dag.eventIds() / dag.sizeRead the log.
effectiveAuthor(event)Collapse device subkeys to one account identity.
useDagVersion()React hook: re-render on any DAG change.

Swarm & status

ExportWhat it does
swarmStatus() / subscribeSwarm(fn) / useSwarmStatus()Role, room, peers, segments, fragments, anchor/compute flags, repair metrics.
setAnchorMode(bool) / setComputeMode(bool)The user's volunteering toggles (both opt-in).
kvGet(key) / kvPut(key, value)Small durable per-browser key/value store.
stage1Init()Boot provenance — verified stage-0 boot vs. dev entry.
EPOCH_MSThe protocol's 10-minute epoch.

Compute & queries (the advanced half)

ExportWhat it does
runCompute(wasm, input)Run a WASM job on the swarm; resolves with the hash-majority-verified result. See JOBS.md.
postJob(post)Fire-and-forget job post (used by onSeal hooks).
scatterQuery(app, payload, opts)Fan a query out to peers; each answers via its scatterResponders. Powers search.
segmentHolderTargets(ids)Which peers hold given segments — target a scatter instead of broadcasting.
callRpc(app, payload)Call your app's leader-side rpc handler from any tab.

App capabilities (fields on AppDef)


What you can build

Things that are uniquely good here, not just possible:

What NOT to build here

Being straight with you saves your weekend:


Constraints worth knowing up front


Reference