soul.demarkus.io:6309

Map: soul.demarkus.io:6309

77 connected · 3 unlinkedrelateddepends-onrelatedrelatedrelatedrelatedrelatedrelatedrelatedrelateddepends-onrelatedimplementsrelatedrelatedrelatedrelatedimplementsrelatedrelatedrelatedrelatedrelatedrelatedrelatedrelatedrelateddemarkus-souldemarkus-soul — /index.mdArchitectureArchitecture — /architecture.mdRoadmapRoadmap — /roadmap.mdDebuggingDebugging — /debugging.mdCoding GuidelinesCoding Guidelines — /guidelines.mdConventions and W…Conventions and Working Agreements — /conventions.mdPatterns & Conven…Patterns & Conventions — /patterns.mdDemarkus / Knowle…Demarkus / Knowledge System FAQ — /rfc-review-faq.mdThe Universe Patt…The Universe Pattern — /universe.mdCompleted PlansCompleted Plans — /completed-plans.mdDocument GraphDocument Graph — /graph.mdGuide: Setting Up…Guide: Setting Up demarkus-soul — /guide.mdThe Reading Room …The Reading Room authoring contract — /.well-known/library/authoring.mdTrail URLs — the …Trail URLs — the shared reading-context format — /.well-known/library/trails.mddemarkus-souldemarkus-soul — /.well-known/agent-manifest.mdADR 0008: GCS wor…ADR 0008: GCS world state commits through one root CAS — /adr/0008-gcs-root-cas-storage.mdADR 0007: SNI sel…ADR 0007: SNI selects a virtual Mark server — /adr/0007-sni-virtual-world-routing.mdADR 0005 — Node i…ADR 0005 — Node identity omits the default port — /adr/0005-node-identity-default-port.mdADR 0004 — Edge s…ADR 0004 — Edge semantics: provenance on every edge, typed relations via rel- metadata — /adr/0004-edge-semantics-rel-convention.mdADR 0006: The Pos…ADR 0006: The Postgres backend is an optional build, not a dependency — /adr/0006-postgres-backend-is-an-optional-build.mdADR 0003 — Defaul…ADR 0003 — Default OKF type on publish — /adr/0003-okf-type-default-on-publish.mdADR 0002 — Align …ADR 0002 — Align store frontmatter with the Open Knowledge Format — /adr/0002-okf-metadata-alignment.mdADR 0001 — Broker…ADR 0001 — Broker confidential web-client registry — /adr/0001-broker-confidential-web-clients.mddemarkus-knowledg…demarkus-knowledge-system-deploy: project hub — /demarkus-knowledge-system-deploy/index.mdJournal 2026-08-23Journal 2026-08-23 — /demarkus-knowledge-system-deploy/journal/2026-08-23.mdJournal 2026-08-21Journal 2026-08-21 — /demarkus-knowledge-system-deploy/journal/2026-08-21.md2026-06-12 — dema…2026-06-12 — demarkus-library in-cluster deploy — /demarkus-knowledge-system-deploy/journal/2026-06-12.md2026-07-15: libra…2026-07-15: library 0.21.2 deployed (enriched /graph.md parsing) — /demarkus-knowledge-system-deploy/journal/2026-07-15.md2026-07-14: broke…2026-07-14: broker 0.12.2 + agent 0.21.1 bump (graph hub seeding) — /demarkus-knowledge-system-deploy/journal/2026-07-14.md2026-07-062026-07-06 — /demarkus-knowledge-system-deploy/journal/2026-07-06.md2026-07-052026-07-05 — /demarkus-knowledge-system-deploy/journal/2026-07-05.mdJournal 2026-08-12Journal 2026-08-12 — /demarkus-knowledge-system-deploy/journal/2026-08-12.mdADR 0005 — The Re…ADR 0005 — The Reading Room: spatial trails over temporal history — /demarkus-library/adr/0005-reading-room-spatial-trail.mdADR 0006 — Readin…ADR 0006 — Reading Room interaction model: dock, palette, and on-demand overlays — /demarkus-library/adr/0006-reading-room-interaction-overlays.mdADR 0002 — Hexago…ADR 0002 — Hexagonal (ports & adapters) architecture — /demarkus-library/adr/0002-hexagonal-architecture.mdThe Reading Room …The Reading Room — design notes (draft) — /demarkus-library/plans/reading-room.mdPhase 5 — Public …Phase 5 — Public Face: the anonymous-read decision (plan) — /demarkus-library/plans/phase-5-public-face.mdPhase 3 — Catalog…Phase 3 — Cataloging Desk (plan) — /demarkus-library/plans/phase-3-cataloging-desk.mdPhase 1b — Web SS…Phase 1b — Web SSO over the Broker (two-repo plan) — /demarkus-library/plans/phase-1b-web-sso.mddemarkus-librarydemarkus-library — /demarkus-library/index.mdADR 0003 — SSR-fi…ADR 0003 — SSR-first, htmx-hard, no JSON — /demarkus-library/adr/0003-htmx-ssr-philosophy.mddemarkus-library …demarkus-library — Roadmap & Resume — /demarkus-library/roadmap.mdADR 0004 — Broker…ADR 0004 — Broker confidential web client + redirect SSO (reject device flow) — /demarkus-library/adr/0004-broker-web-sso.mdADR 0001 — Echo +…ADR 0001 — Echo + bulwarkauth-style layout for the front-end — /demarkus-library/adr/0001-echo-bulwarkauth-layout.mdJournal 2026-08-18Journal 2026-08-18 — /journal/2026-08-18.mdJournal 2026-08-17Journal 2026-08-17 — /journal/2026-08-17.md2026-06-21 — Leid…2026-06-21 — Leiden clustering: built, measured, shelved as a grouping feature — /journal/2026-06-21.md2026-06-022026-06-02 — /journal/2026-06-02.md2026-07-22: migra…2026-07-22: migrating soul.demarkus.io off the Orange Pi to a droplet — /journal/2026-07-22.mdJournal: 2026-08-…Journal: 2026-08-22 — /journal/2026-08-22.md2026-06-08 — Brok…2026-06-08 — Broker-global OIDC AllowDomains gate — /journal/2026-06-08.md2026-07-25: Hoste…2026-07-25: Hosted tenant density ADR (0005) — /journal/2026-07-25.md2026-06-25 — pi c…2026-06-25 — pi command fix, plugin lint debt, poison-lock fix — /journal/2026-06-25.mdJournal — 2026-05…Journal — 2026-05-31 — /journal/2026-05-31.mdJournal — 2026-05…Journal — 2026-05-30 — /journal/2026-05-30.mdmemoryleaderboard…memoryleaderboard: Project Hub — /memoryleaderboard/index.mdmemoryleaderboard…memoryleaderboard production deployment — /memoryleaderboard/deployment.mdAgent Memory Lead…Agent Memory Leaderboard — /memoryleaderboard/agent-memory-leaderboard.mdmemoryleaderboard…memoryleaderboard debugging — /memoryleaderboard/debugging.mdJournal 2026-08-17Journal 2026-08-17 — /memoryleaderboard/journal/2026-08-17.mdJournal 2026-08-16Journal 2026-08-16 — /memoryleaderboard/journal/2026-08-16.mdJournal 2026-08-14Journal 2026-08-14 — /memoryleaderboard/journal/2026-08-14.mdJournal 2026-08-13Journal 2026-08-13 — /memoryleaderboard/journal/2026-08-13.mdMulti-world Knowl…Multi-world Knowledge Server — /plans/knowledge-server.mdPlan: Agent Memor…Plan: Agent Memory Leaderboard entry — /plans/agent-memory-leaderboard.mdPlan: demarkus as…Plan: demarkus as a service — /plans/demarkus-as-a-service.mdKnowledge Ingesti…Knowledge Ingestion Pipeline — /plans/knowledge-ingestion.mdPlugin Prompt Sou…Plugin Prompt Source of Truth — /plans/plugin-prompt-source-of-truth.mdPlan: Plugin Know…Plan: Plugin Knowledge-Quality Enforcement — /plans/plugin-knowledge-quality.mdPlan: Absolute pa…Plan: Absolute parity between the file store and the Postgres store — /plans/store-parity.mdCode Quality Swee…Code Quality Sweep 2026-08 — /plans/code-quality-sweep-2026-08.mdKnowledge graph c…Knowledge graph completeness analysis (2026-07-15) — /plans/graph-completeness.mdPlan: the five-mi…Plan: the five-minute appliance — /plans/five-minute-appliance.mdPlan — /soul-join…Plan — /soul-join: managed remote souls + catalog + project binding — /plans/soul-join.mdPlan: APPEND meta…Plan: APPEND metadata loss — /plans/append-metadata-loss.mdObsidian Plugin P…Obsidian Plugin Plan — /plugins/obsidian/plan.mdObsidian Plugin —…Obsidian Plugin — obsidian-demarkus — /plugins/obsidian/index.mdunlinkedJournal 2…Journal 2026-08-23 — /demarkus/journal/2026-08-23.md2026-08-2…2026-08-21 PostgreSQL request snapshots — /journal/2026-08-21.mdAgent Mem…Agent Memory Leaderboard application readiness — /memoryleaderboard/application-readiness.md
soul.demarkus.io:6309/journal/2026-07-25.md draft reader meta

2026-07-25: Hosted tenant density ADR (0005)

Explored packaging demarkus as a hosted knowledge base service, then drafted repo ADR 0005 settling the density question the as-a-service plan left open.

Where it started

Question was whether we can compose a knowledge base service. The product reading (hosted, signup, multi-tenant) is already sketched in /plans/demarkus-as-a-service.md, so the session went straight to its unresolved fork: the plan names idle-tenant economics as the go/no-go gate for open signup and in the same section forbids the only lever that addresses it ("server remains one-world-per-process by design"). That is a deferred decision, and the control plane has to be built on one assumption or the other.

The finding that changed the argument

I expected in-process multi-tenancy to be blocked on the wire format, since protocol.Request is {Verb, Path, Metadata, Body} with no tenant selector. It is not. The client sets TLS ServerName from the hostname it dials (client/fetch/fetch.go around L383) and the server already takes a GetCertificate callback receiving ClientHelloInfo, so a connection can be bound to a world at handshake via SNI: per-tenant DNS name, wildcard cert, broker world entry pointing at one shared Service. Resolution is once per connection, not per request. Zero protocol change.

So the mechanism is cheap. That moved the whole argument off feasibility and onto isolation, which is where it belonged.

Why the ADR still says no

Today a world is enforced four separate ways: a process, a PVC, a token file, a certificate. Collapsing those into a map lookup in one address space means any path-scoping or catalog-keying bug becomes cross-tenant disclosure instead of a bug inside one tenant's world, and one panic becomes a multi-tenant outage. For a single-maintainer project that is the wrong risk for a cost curve that does not bite yet.

The second half of the argument matters as much: density only pays off with many dormant tenants, meaning a consumer tier, and the plan itself concludes a free tier is viable only after density works. Team tenants are not dormant. So B is speculative work on the one component that cannot be thrown away. Decision landed on option C (one world per process, priced to cover a warm pod, team-sized tenants), with scale-to-zero also declined for now.

Details worth keeping

  • Rejected alternatives recorded in the ADR so the next pass does not re-derive them: a tenant key in request metadata or a /tenants/<id>/ path prefix would put the tenancy scheme into document identity, so every published mark:// URL, graph edge, and OKF export would carry it. Per-tenant ports break the default 6309 dial that every client and join string assumes.
  • No world column in the postgres schema. Tenancy in the store contract drags it into the storetest conformance suite, and by the backend-parity principle the file backend would have to implement it too, which it cannot do well. Schema or database per world keeps tenancy above the store.
  • pgstore is still the right backend for hosted worlds (external storage, backups, multi-replica reads). What was rejected is pgstore as the enabler for one process serving many tenants. Note the existing comment in main.go: LOOKUP is served from the postgres catalog table specifically so a per-process index cannot diverge across pods, so the postgres path is already multi-pod safe for a single world.
  • Reversal trigger written into the ADR: revisit when dormant-tenant infra cost exceeds their revenue, or when a consumer tier is actually decided. That follow-up must clear an isolation bar this ADR does not attempt, namely a conformance suite proving cross-world access is impossible through every verb, plus a per-world resource ceiling, before any shared-process code ships.

Product framing raised, not settled

Personal-library hosting is a crowded, low willingness-to-pay market. The differentiators that exist here (agent-native read and write, OKF export as real portability, the promote pipeline) sell to teams already running Claude Code. Team tenants also happen to defuse the idle-economics problem, which is part of why option C is coherent. Separately: install-stack.sh is already a five-minute appliance, so self-host plus paid support is a commercial step with near-zero new engineering and none of the uptime, backup, or GDPR burden of hosting.

State

Branch docs/adr-0005-tenant-density, file docs/adr/0005-hosted-tenant-density.md, status proposed, uncommitted. Open follow-up offered but not done: revise the sequencing sketch in /plans/demarkus-as-a-service.md, whose step 4 is a scale-to-zero go/no-go gate this ADR removes from the near path.

Related documents

trail
  1. soul.demarkus.io:6309 soul.demarkus.io:6309 — map
  2. 2026-07-25