--- title: "ADR 0001 — One instance serves one project" type: decision tags: [signpost, adr, decision] proposed_by: tok_bc09b340db294c709763789154d8113d model: kmem-docs-publisher extracted_at: "2026-10-08T22:36:54.398Z" --- # ADR 0001 — One instance serves one project **Status:** superseded by [ADR 0013](./0013-multi-tenancy-supersedes-single-project.md) on 2026-08-18 — the hosted product serves many orgs. The body below is unchanged, and its operational description stays true of the running code until Wave 2 wires host-based resolution in. **Date:** 2026-08-08 ## Decision A Signpost deployment holds exactly one project. Two projects means two deployments, each with its own D1 database, R2 bucket, Vectorize index and tokens. There is no project selector, no project-scoped query parameter, and no cross-project search. ## Alternative rejected Multi-project per instance: one deployment, a `project_id` column on every table, and a project picker in the UI. ## Why Multi-tenancy is not a column. It is a permission model, a scoping rule on every query, a cross-project search policy, a per-project token model, an invitation flow, a quota story, and a migration path when one project needs to move out. Each of those is a decision, and each one has to be right or the whole thing leaks. That is a large amount of work whose entire payoff is saving a solo maintainer from running `npx signpost init` twice. The self-hosted case does not want it. A team deploying Signpost for one codebase gets a smaller, faster, more auditable system: every query is unscoped because there is nothing to scope to, every token grants access to the whole instance because the instance is the boundary, and a `SELECT` that forgets a `WHERE project_id = ?` cannot leak another team's data because there is no other team's data. The hosted case does want it — but the hosted case is a different product with a billing system, and guessing at its tenancy model a year early produces the wrong abstraction. `ProjectContext` (ADR 0004) is the one concession: it threads a resolved handle through every data-access function so that a future hosted version can resolve it per-request without rewriting every query. That costs one parameter. Full multi-tenancy costs a quarter. ## Consequences - No `project_id` anywhere in the schema. Adding one later is a migration, not a redesign, because `ProjectContext` already marks every place that would need it. - Cross-project retrieval is impossible. A team that genuinely wants one search across two codebases has to merge them into one instance. - Deploy cost scales with project count. That is a real cost, and it is the price of the simplification. - PRD section 14 lists multi-project as explicitly out of scope for v1, and it stays there.