soul.demarkus.io:6309/plans/demarkus-as-a-service.md/v5 direction-set reader meta

Plan: demarkus as a service

Status: direction set 2026-07-26 (Fritz + Claude). Supersedes the exploratory drafts of 2026-07-17 and 2026-07-25. The service model is Aiven adjacent: signup, pick a tier, managed worlds, per world billing, with a migration path between tiers. Substrate is VPS first, Kubernetes only when a large knowledge system outgrows a box. Not scheduled; this records the shape and the decisions that are now settled.

Where this work continues

Moved 2026-07-26. The service build has its own repo and its own soul: mark-knowledge at /Users/fritz/latebit/mark-knowledge, soul provisioned the same day (isolated mode, port 16310). Once that soul is seeded from this document, it is authoritative for the service plan and everything downstream of it, including pricing, the management app, tiers, and substrate.

This copy stays here as the demarkus side record, because the decisions constrain demarkus itself: the appliance is the unit of deployment, the broker stays one binary, the librarian is the only inference cost centre, and quotas plus backups are prerequisites that land in this repo rather than in the service repo. Read this for why the service model looks the way it does, and read the mark-knowledge soul for what is being built.

Service model

A managed demarkus, sold the way Aiven sells managed open source: dedicated single tenant instances, sized plans rather than feature tiers, billed per running unit, provisioned by a management app.

Three tiers, named to match the three scales the website already teaches (_preview/scenarios/):

Tier Site scale What is hosted Billing
Personal Personal one small world, power off when idle smallest box, storage only when off
Team Team one world plus broker, library, login box size, seats included
Knowledge System Enterprise broker, hub, N worlds, indexing agent box size plus per world

The free tier stays what it already is: the local soul, run on your own machine through the demarkus-memory plugin. It costs nothing to operate and it is the funnel that produces Team customers. A hosted Personal tier is a paid product, not the free one.

Why sizes and not features

install-stack.sh already gives away the entire system in one command: world server, broker, library, self hosted OIDC (Authelia), HTTPS (Caddy), indexing agent. There is nothing left to feature gate, and clawing anything back would recreate the fork demarkus exists to avoid. So the tiers differ only on scale and on who operates the thing. What is being sold is operations, not software.

This is the same box Aiven is in, since their services are open source too, and their answer is the one adopted here: sell capacity and operations, keep every feature in every plan.

Substrate: VPS first

The broker needs no adaptation to run on a VPS. install-stack.sh already stands up the complete architecture on a single Linux host, and its own usage line targets a fresh VPS, with sslip.io magic DNS when no domain is supplied. The appliance is the hosted product's unit of deployment.

Trade offs that decided this:

  • VPS wins early. No cluster fixed cost, and a per tenant virtual machine is stronger isolation than a pod at no extra effort.
  • Kubernetes wins at scale, because pods pack denser than virtual machines and the cluster is itself the fleet manager. On VPS that fleet layer is something we write.
  • Two substrates means two control planes, which is the real cost of splitting them.

So all three tiers run on VPS to begin with, including Knowledge System, which the appliance already supports on one host for a pilot or a small organization. Kubernetes enters only when a knowledge system customer outgrows a box, and that move is chargeable work.

Scaling: vertical by default, horizontal by placement

One box hosts several worlds, so growth has two directions and the service abstracts both away from the customer, who sees only worlds and a plan.

  • Vertical is the default. A world that outgrows its share of a box triggers a bigger box. Simple, no topology change.
  • Horizontal is placement, not rebalancing. New worlds land on boxes that have room. A live world is never relocated except as a paid upgrade, because moving one is a data move.
  • Horizontal breaks the single box appliance. Today broker and worlds are colocated, so the hop is localhost QUIC. Spreading worlds across boxes exposes them on a private network between boxes and needs certificates valid for their cross box addresses. That is the first thing that stops being install-stack.sh as shipped.

Pricing shape

Per world, with the box as the size step.

A box hosts several worlds, so per world cost and per box cost diverge. The marginal world on an existing box is a process plus disk space, close to free. Therefore the box size is the plan (Aiven style capacity sizing) and per world charges are the expansion lever, with a world ceiling per box that triggers an upgrade to a bigger box. Margin improves as a tenant adds worlds, which is the incentive we want.

Storage is a quota, not a meter. Agent traffic is spiky and unpredictable bills lose deals.

Power off instead of scale to zero

Aiven lets a service be powered off: storage retained, compute stopped, storage only billing. That is the answer to dormant tenants, and it is the reason a Personal tier is viable at all.

It is user initiated and explicit, so there is no wake trigger to design over QUIC and UDP, and no cold start landing in the middle of an agent session. The dormant tenant becomes a volume, which is cents, and the user chose it.

Migration rules

Two rules keep tier changes cheap:

  1. Every tier is worlds behind the broker from day one. Upgrading is then a config change: add worlds, add grants, add the library. No bytes move between Personal, Team, and Knowledge System.
  2. Substrate changes are the only real migration. VPS to Kubernetes moves data, and it happens once, at the top of the ladder, for a customer who is paying for the move. OKF export and import, or the Phase 5 server to server sync, are the mechanism.

Migration into the service (local soul to hosted) and out of it (OKF export as a conformant bundle) use the same two mechanisms. Portability out is a differentiator worth keeping honest.

The management app

The only genuinely new engineering. Server and protocol stay untouched.

It owns signup, tier selection, provisioning, the broker grant, power off and power on, world add and remove, box placement and resize, and billing. On VPS that means driving install-stack.sh over cloud init plus a fleet layer for health, upgrades, and backup orchestration. The Phase 7 World CRD operator becomes the Kubernetes target for the same control plane later, not a replacement for it.

Provisioning by committing to a worlds list and letting Argo converge is adequate for waitlist gated manual approval only. It is not a correctness fit for a self service signup button, because sync latency sits in the user's face and concurrent signups contend on the repo.

Librarian inference and BYOK

The librarian is the only inference cost centre in the system. It is live in production (library 0.15.1, MiniMax M3 through nib's multi provider llmconfig), configured per deployment through library.librarian.{keyEnv,existingSecretRef,model} with the key coming from a Secret and the feature dark when unset. Self hosted operators are therefore already bringing their own key.

Hosting inverts this, because one shared library serves all tenants from one key at boot time. The decision:

  • Ship with our key and per tier ask caps. MiniMax class economics plus the caps that were day one in the Phase 4 plan make eating tenant inference cheaper than building a key management surface.
  • Offer per tenant provider selection only when a customer's compliance requires it, priced at the Knowledge System tier. The reason is not cost, it is that the librarian sends tenant documents to a model provider, which is a sub processor disclosure. nib already supports OpenAI compatible and local endpoints, so a "nothing leaves your boundary" answer exists as configuration.

Storage side BYOK (customer managed encryption keys) is explicitly not a feature. The world server reads plaintext markdown to serve a FETCH, so a customer key protects only against volume theft and buys crypto shredding on revoke. It is a StorageClass or disk property in the deployment, so it stays a procurement checkbox to tick on demand.

The librarian is the multi tenant surface

Worth carrying forward as the main security concern. Isolation is held at the process, one world per server, volume, token file, and certificate. A single shared library with an LLM loop then sits over all of it, and its tools are the library's own Reader, Graph, and Map ports with reader identity carried in the request context.

That context scoping is the entire cross tenant boundary for the AI surface, inside one address space. It needs a conformance suite proving the librarian cannot read across tenants through any of its tools, including the graph and map ports where an edge can point out of a tenant's world.

Blockers before opening signup

  • Backups. Per world snapshot policy and a tested restore path the customer can trigger. The Kubernetes deploy template has CSI snapshot backups for world volumes; the VPS path needs its own answer. "We snapshot" is not a product until restore is proven.
  • Quotas. World level storage quota, version history budget defaults for hosted worlds, per tenant rate limits at the broker. Version history currently grows unbounded, since retention is per document and opt in.
  • Graph completeness Tier 1. The 1 MiB /graph.md export wall with silent publish failure, and tombstone accumulation with no eviction path, both become per tenant liabilities. See /plans/graph-completeness.md.
  • Custody posture. A data processing agreement, a stated recovery point objective, and an incident contact. For team buyers this gates deals earlier than density ever will.

Sequencing

  1. Harden the appliance path as the product unit, since it is what gets provisioned per tenant.
  2. Quotas, hosted retention defaults, backup and restore on VPS.
  3. Management app v1: signup, tier pick, provision, grant, power off, billing. Waitlist gated to start.
  4. Kubernetes target for the management app when a Knowledge System customer outgrows a box.

Dependencies

  • Phase 6.3 and 6.4 (broker and install flow) past prototype.
  • demarkus-library cataloging desk for in browser editing; the hosted case is the broker authenticated path it already assumes.
  • demarkus-library Phase 5 public face, for whether tenant libraries can have public pages.
  • Remote token issuance (/plans/remote-token-issuance.md) stays the self hosted story; hosted tenants are covered by the broker.

Still open

  • Seats included per box before per seat charges begin, and whether teams grow seats or worlds first.
  • One shared library deployment for all tenants versus per tenant library pods. Shared is the ADR 0004 shape in demarkus-library and the assumed answer, but it is what creates the multi tenant surface described above.
  • Postgres per world versus shared Postgres with per world databases, once pgstore is used for hosted worlds. Purely a storage topology question.
  • Whether the hosted broker stays the same binary as the OSS broker. It should.
  • Whether a Personal tier launches at all, or waits until Team proves willingness to pay.

Note on the removed density ADR

The 2026-07-25 revision of this plan leaned on repo ADR 0005 (hosted tenant density) as having settled the density question. That ADR was deleted from the repo on 2026-07-25 and no longer exists, so nothing here should be read as decided by it. Density is now answered commercially rather than architecturally, see the power off section above. The process boundary still stays the isolation boundary, but that is a standing property of the design rather than a decision record.

trail
  1. soul.demarkus.io:6309 v5