+ Most recent first · Up to the first 50 commits in this session
+
+
+
+
+
+
+ Go further: edit queries and transactions Public Triplex JSON APIs
+
+
+ Change the query to explore other relationships, or write your own transaction. Each new
+ transaction needs a unique meta.commandId. Guided actions fill in the
+ transaction editor for you.
+
+
+
+
+
Datalog query
+
+
+
+ find selects result columns. where matches facts and joins
+ shared variables; not checks for missing facts.
+
+
+
+
+
+ Raw query response and metrics
+
{{ queryOutput }}
+
+
+
+
+
Atomic transaction
+
+
+
+ An assert adds a fact. A retract uses an existing fact’s ID.
+ Operations in one transaction commit together.
+
+
+
+
+ Raw transaction receipt
+
{{ transactionOutput || "No transaction applied yet." }}
+
+
+
+
+
+
+
+
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
index 54743a5..bba4de8 100644
--- a/docs/.vitepress/theme/index.ts
+++ b/docs/.vitepress/theme/index.ts
@@ -7,6 +7,7 @@ import { h } from "vue";
import "@shikijs/vitepress-twoslash/style.css";
import "./custom.css";
+import Playground from "./Playground.vue";
export default {
extends: DefaultTheme,
@@ -14,11 +15,12 @@ export default {
h(DefaultTheme.Layout, null, {
"layout-top": () =>
h("div", { class: "triplex-prerelease", role: "status" }, [
- "Pre-1.0 canary · install with @next · requires effect@4.0.0-rc.112 · ",
+ "Pre-1.0 · new npm scope not published yet · use source checkout · ",
h("a", { href: "/current-state" }, "current state"),
]),
}),
enhanceApp({ app }) {
+ app.component("TriplexPlayground", Playground);
app.use(TwoslashFloatingVue, {
themes: {
twoslash: {
diff --git a/docs/concepts.md b/docs/concepts.md
new file mode 100644
index 0000000..b2cdcc1
--- /dev/null
+++ b/docs/concepts.md
@@ -0,0 +1,159 @@
+# Core concepts
+
+Triplex stores facts, not mutable rows. It keeps when each assertion was recorded, when it was valid
+in the domain, which configuration release governed a write, and which facts supported derived
+results. This guide uses one safety-training example to connect those ideas.
+
+## Facts and relationships
+
+Suppose worker Maria is placed at the Harbor site and has a safety certificate. Triplex represents
+that state as small typed facts:
+
+| Entity | Attribute | Value |
+| ------------------- | --------------------- | ------------------- |
+| `worker:maria` | `:worker/name` | `"Maria"` |
+| `placement:harbor` | `:placement/worker` | `ref(worker:maria)` |
+| `placement:harbor` | `:placement/site` | `ref(site:harbor)` |
+| `certificate:maria` | `:certificate/worker` | `ref(worker:maria)` |
+| `certificate:maria` | `:certificate/site` | `ref(site:harbor)` |
+
+An entity ID groups facts for convenient entity reads. A reference value creates a relationship to
+another entity. There is no separate relationship table or hidden object graph: queries join facts
+by their values.
+
+Entity type names such as `Worker` and global attribute names such as `:worker/name` are different
+identities. Configuration can say how an entity type uses an attribute—required, single-valued,
+unique, or reference-constrained—but those rules are not automatically enforced on every write.
+
+## Assertions, retractions, and correction
+
+An assertion says that a typed fact holds over a valid-time interval. A retraction closes that
+assertion's **recorded** visibility; it does not erase the original fact or rewrite its history.
+Corrections therefore append evidence:
+
+1. retract the assertion that is no longer part of the current recorded view;
+2. assert the corrected interval or value; and
+3. do both in one attributed `Triples.transact` call.
+
+`history(entityId)` includes retracted assertions. Current `entity` and `match` reads show only
+facts visible at their requested bitemporal basis.
+
+## Recorded time and valid time
+
+The two clocks answer different questions:
+
+- **Recorded time:** what the database knew at an instant.
+- **Valid time:** when the fact was true in the domain.
+
+Imagine this certificate history:
+
+- On January 5, the host records that Maria's certificate is valid from January 1 through December 31.
+- On March 1, the host learns it was actually revoked effective February 1. In one correction
+ transaction it retracts the original assertion and records the corrected January interval.
+
+The same `validAt` date can produce a different answer as knowledge changes:
+
+| Read basis | Certificate visible? | Why |
+| ----------------------------- | -------------------- | -------------------------------------------- |
+| recorded Feb 15, valid Feb 15 | Yes | The revocation was not known yet. |
+| recorded Mar 2, valid Feb 15 | No | The corrected interval ended on Feb 1. |
+| recorded Mar 2, valid Jan 15 | Yes | The corrected assertion still covers Jan 15. |
+
+Public reads accept one `{ recordedAt?, validAt? }` basis for the complete read, including every
+clause of a Datalog query. Times are non-negative epoch milliseconds and interval ends are
+exclusive. If `recordedAt` is omitted, Triplex uses the latest recorded state; if `validAt` is
+omitted, it uses the runtime's current time. Setting only one axis does not freeze the other.
+
+Recorded time is assigned by the Triplex transaction boundary, not supplied as application data.
+Use the journal's ordered commit positions when exact ordering matters; timestamps alone may not
+distinguish commits in the same millisecond.
+
+## Datalog asks across relationships
+
+A structural query can identify placed workers who lack a certificate for the same site:
+
+```ts
+const openTraining = {
+ find: ["?worker", "?site"],
+ where: [
+ ["?placement", ":placement/worker", "?worker"],
+ ["?placement", ":placement/site", "?site"],
+ [
+ "not",
+ ["?certificate", ":certificate/worker", "?worker"],
+ ["?certificate", ":certificate/site", "?site"],
+ ],
+ ],
+} as const;
+```
+
+Variables beginning with `?` join clauses. The `not` clause is safe because `?worker` and `?site`
+are already bound by the placement clauses. Before the corrected February basis the placement does
+not match; afterward it does. See [Datalog](/datalog) for predicates, disjunction, aggregation,
+recursion, and snapshot-stable pagination.
+
+## Configuration releases and refs
+
+Triplex configuration is a separate typed graph for schemas, forms, policies, routines, and other
+application-defined objects. A commit records the **complete** graph as an immutable release:
+
+- a `ConfigNode` has a stable logical `(kind, key)` and a content ID;
+- a revision records a version of one logical object and its dependency closure;
+- a `ConfigSnapshot` pins the full release and its revision set; and
+- a movable ref such as `test` or `live` points to one existing snapshot.
+
+Promoting or rolling back configuration means moving a ref. It does not copy nodes, mutate an old
+release, reverse operational facts, or run a data migration. Operational transactions should store
+the actual snapshot ID returned by `commit`/`resolveRef` in `meta.configSnapshot`, rather than only
+the movable ref name. Follow the [complete versioning walkthrough](/configuration-versioning).
+
+## Entity snapshots are not configuration snapshots
+
+Both use content identity, but they answer different questions:
+
+| Identity | Represents | Changes when |
+| ---------------- | ------------------------------------------------------ | ------------------------------------------------- |
+| `EntitySnapshot` | one fact entity materialized at a transaction or basis | that entity's visible facts change |
+| `ConfigSnapshot` | one immutable release of a configuration graph | a new complete configuration release is committed |
+
+Neither replaces the transaction journal. Entity snapshots are projections whose source position
+must be checked for freshness; configuration snapshots are immutable release roots addressed by
+configuration APIs.
+
+## Derived work and provenance
+
+A derivation pins a Datalog query, candidate identity, configuration snapshot, and dependency set.
+For the query above, a candidate might mean “Maria needs Harbor training.” Triplex can retain the
+source triple IDs and assertion transactions that explain the candidate, compare one evaluation
+with another, and report `added`, `removed`, `changed`, and `unchanged` candidates.
+
+The host decides what those changes mean. Triplex does not automatically create or cancel a task,
+send a notification, retry a delivery, or assign an owner. Materialized derivations are projections
+and report `current`, `stale`, or `unmaterialized`; a stale result is last-known data, not current
+truth. The host owns catch-up and timer delivery, including waking at a derivation's next valid-time
+boundary.
+
+Exact derivation provenance currently covers patterns, predicates, and negation. Derivations reject
+recursive rules, disjunction, aggregation, pagination, dynamic attributes, and transaction-binding
+clauses where Triplex cannot preserve a complete explanation. Raw Datalog supports more of those
+features when provenance is not requested.
+
+## Constraints and responsibility boundaries
+
+The ontology DSL produces requiredness, cardinality, uniqueness, and reference-target constraints.
+They become atomic write guards only when a host passes the rules in `meta.enforce`, normally from
+the same snapshot pinned in `meta.configSnapshot`. Observation-only validation remains useful for
+migrations and audits. Direct adapter writes and unconstrained commands are outside enforcement.
+
+Triplex owns facts, temporal reads, atomic transactions, the causal journal, configuration identity,
+and derivation mechanics. The host still owns authentication, authorization, database/tenant
+selection, domain commands, higher-order business invariants, durable workflow lifecycle, external
+delivery, retries, migrations, monitoring, retention, backup, and recovery. See [Host
+integration](/host-integration) for the operational boundary.
+
+## Where Triplex fits
+
+Triplex is designed for domains where history and rules are part of the answer: compliance,
+onboarding, eligibility, entitlements, governed back-office work, and agent-driven systems that
+need a durable causal record. It is usually a poor fit for high-volume telemetry, blob storage,
+queue-only workloads, or simple state that never needs temporal or provenance questions.
diff --git a/docs/configuration-versioning.md b/docs/configuration-versioning.md
new file mode 100644
index 0000000..ffd8cc9
--- /dev/null
+++ b/docs/configuration-versioning.md
@@ -0,0 +1,115 @@
+# Configuration releases and rollback
+
+This walkthrough defines a typed course schema, publishes two immutable releases, promotes them
+through refs, pins operational writes to the actual returned snapshot IDs, inspects history, and
+rolls `live` back. It uses the in-memory layer so the whole program is executable from a source
+checkout.
+
+For the underlying node, revision, compatibility, validation, and enforcement contracts, see the
+[configuration reference](/configuration).
+
+## Complete runnable example
+
+From the repository root, run:
+
+```sh
+pnpm exec tsx --tsconfig docs/snippets/tsconfig.json docs/snippets/config-versioning.ts
+```
+
+<<< @/snippets/config-versioning.ts{ts}
+
+The two snapshot values in the output are real IDs returned by `ConfigStore.commit`; never copy a
+made-up `sha256-…` placeholder into transaction metadata. The exact hashes are deterministic for
+this history, but application code should treat them as opaque.
+
+The stable outcomes are:
+
+- `testBeforePromotion` and `historicalV2` are `courses-2026.2`;
+- the change list contains the added `:course/status` attribute and changed `Course` schema;
+- `v2WritePin` equals the returned v2 snapshot ID;
+- after rollback, `liveAfterRollback` is `courses-2026.1`; and
+- `advancedFactsAfterRollback` is still `2`.
+
+## 1. Define typed schema objects
+
+`Attribute` owns a global keyword and value type. `EntityType` owns how that attribute is used by
+one entity type. Adding `status` as required changes the `Course` entity schema in v2 without
+changing the identity or definition of `:course/title`.
+
+`CourseV1.nodes` and `CourseV2.nodes` each evaluate to the complete configuration nodes needed by
+that schema, including generated graph-constraint nodes nested under the entity schema. A commit
+takes a complete object set, not a patch against the previous release.
+
+## 2. Publish without promoting
+
+Passing `ref: "test"` commits the release and moves `test` in the same atomic Triplex transaction.
+The example does not point `live` at arbitrary authoring state: it calls `setRef("live",
+v1.snapshot.id)` with the exact ID returned by the successful commit.
+
+The v2 commit moves only `test`, so `live` remains on v1 during inspection. `resolveRef("test")`
+returns the immutable snapshot behind the current pointer. A deployment tool can inspect that
+snapshot and its changes before promotion.
+
+## 3. Promote and pin writes
+
+Promotion is another `setRef` call. Moving a ref copies no configuration, and compare-and-retract
+prevents a stale concurrent writer from silently replacing a newer ref target.
+
+The operational transactions use:
+
+```ts
+{
+ configSnapshot: v2.snapshot.id,
+ enforce: GraphConstraint.enforcement(CourseV2.constraints)
+}
+```
+
+The snapshot pin records which rules governed the command. `enforce` is separate and opt-in: a
+snapshot ID in metadata does not itself turn constraints on. In a long-running host, resolve the
+intended ref once at the command boundary, collect constraints from that immutable snapshot when
+the TypeScript handles are not already present, and use that same snapshot and rule set throughout
+the transaction.
+
+## 4. Inspect an older release
+
+`snapshotById(id)` resolves an immutable historical release whether or not a ref still points to
+it. `load()` exposes the reference store model, and
+`InMemoryConfigStore.changesBetween(state, from, to)` reports added, removed, and changed logical
+objects. The detailed reference also exposes node-level Merkle diffs, revision history, reverse
+dependencies, and impact candidates.
+
+The CLI and dashboard provide operator views over the same records. See [CLI and
+dashboard](/tools#inspect-configuration) for commands that list releases, resolve a ref, inspect one
+object's immutable history, and move a ref.
+
+## 5. Understand rollback
+
+The final `setRef("live", v1.snapshot.id)` is a configuration rollback. It changes what future
+code resolving `live` sees. It does **not**:
+
+- retract or rewrite facts written while v2 was live;
+- change the `configSnapshot` stored on earlier transaction receipts;
+- delete v2, its object revisions, or its dependency graph;
+- transform data so it conforms to v1; or
+- reverse external work already performed by the host.
+
+That is why the v2 course still has two operational facts after rollback and its receipt still
+points to v2. Data migration, compensating commands, validation, and external side-effect recovery
+are separate host-owned operations. Plan them explicitly when a configuration change alters what
+old or new data means.
+
+## Durable version
+
+For persistence, compose `ConfigStore.layer` over one shared SQLite or PostgreSQL `Triples` layer.
+Do not create separate database layers for operational facts and configuration if they must share
+an atomic boundary:
+
+```ts
+const AppLayer = ConfigStore.layer.pipe(
+ Layer.provideMerge(SqliteTriples.layer({ filename: "./triplex.db" })),
+);
+```
+
+This is a focused composition fragment; imports and the complete in-memory program appear above.
+See [Getting started](/getting-started#use-durable-sqlite) and [Host
+integration](/host-integration) for runtime and migration choices.
diff --git a/docs/configuration.md b/docs/configuration.md
index cab191f..544efa8 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -3,6 +3,11 @@
Triplex configuration is immutable, typed, and content-addressed. It is separate from operational
facts even when persisted through the same `Triples` service:
+::: tip Looking for the release workflow?
+Start with the [complete publish, promote, pin, inspect, and rollback
+walkthrough](/configuration-versioning). This page is the detailed configuration contract.
+:::
+
- an `EntitySnapshot` materializes one fact entity at a transaction or time;
- a `ConfigSnapshot` is an immutable release root containing revisions, schema stamps, dependency
closures, and refs.
@@ -206,8 +211,13 @@ Validation observations remain useful for migrations and audit even when enforce
Applications normally resolve one pinned release, collect its rules, and pass both its
`configSnapshot` and enforcement set at the command boundary.
-## Browser explorer
+## Explore configuration
+
+The repository dashboard exposes typed nodes, releases, refs, immutable object history, and impact
+analysis over its demo database or a supplied SQLite/PostgreSQL database. The CLI provides the same
+operator-oriented history and ref controls as stable JSON. See [CLI and
+dashboard](/tools#inspect-configuration).
-The standalone [`examples/config-explorer`](https://github.com/bjacobso/triplex/tree/main/examples/config-explorer) workspace demonstrates
-typed nodes, releases, refs, impact analysis, evaluation, and proof tamper detection without
-importing source files from another package.
+Continue to [Derivations](/derivations) to use a pinned configuration snapshot in explainable
+derived work, or [Troubleshooting](/troubleshooting#does-moving-a-config-ref-roll-back-data) for
+common release and rollback surprises.
diff --git a/docs/current-state.md b/docs/current-state.md
index e113cac..32e7276 100644
--- a/docs/current-state.md
+++ b/docs/current-state.md
@@ -86,11 +86,12 @@ outside the normal test matrix.
## Honest limitations
- The seven public packages are prepared for coordinated publication under the `@triplex-build`
- organization scope. Stable `0.1.0` has not been published. The GitHub repository is
- `bjacobso/triplex`, and the local `origin` uses that canonical URL.
-- npm assigned the package family's first bootstrap snapshot to `latest` as well as `next`, and the
- registry rejects removing the only `latest` tag. Consumers must request `@next` explicitly until
- stable `0.1.0` replaces it.
+ organization scope, but no package under that scope is available from npm yet. Stable `0.1.0` has
+ not been published. The GitHub repository is `bjacobso/triplex`, and the local `origin` uses that
+ canonical URL.
+- The superseded `@bjacobso` bootstrap packages are not the installation path for new consumers.
+ Evaluation uses a current source checkout until the scoped package bootstrap and registry checks
+ pass.
- `SubscriptionManager` discovers dependencies and reports possible invalidations. It does not
push result deltas or automatically re-run queries.
- Entity snapshots, validation results, and derivation materializations are projections. Callers
@@ -114,9 +115,11 @@ outside the normal test matrix.
## First-release gates
-1. Merge the initial Changesets version PR, which advances the public packages from `0.0.0` to
+1. Bootstrap the `@triplex-build` package records, configure npm trusted publishing, and verify a
+ registry-only `next` consumer for the whole coordinated package family.
+2. Merge the initial Changesets version PR, which advances the public packages from `0.0.0` to
`0.1.0`.
-2. Publish the scoped stable packages together and verify their peer dependency, provenance, CLI,
+3. Publish the scoped stable packages together and verify their peer dependency, provenance, CLI,
and exports behavior from the registry.
Cloudflare and FoundationDB are private for the first release. Their source stays in the monorepo
diff --git a/docs/datalog.md b/docs/datalog.md
index 12d607b..89ca701 100644
--- a/docs/datalog.md
+++ b/docs/datalog.md
@@ -4,6 +4,12 @@ Triplex exposes bounded Datalog pages through `Triples.query` and a wrapped form
`Triples.queryPage`. Both default to 100 bindings and allow at most 1,000 per page. The in-memory KV and SQL engines share one schema, semantic preflight, result
identity, ordering contract, and bitemporal basis.
+If facts, relationships, or the two time axes are new, read [Core concepts](/concepts) first. A
+Datalog clause is a pattern over `(entity, attribute, value)`. Reusing a `?variable` joins clauses;
+the `find` list selects the bindings returned to the caller. For example, joining a worker's
+placement site to a certificate site answers whether the same relationship exists—not merely
+whether either entity has some site fact.
+
## Query shape
```ts
diff --git a/docs/derivations.md b/docs/derivations.md
index aa4f74b..fb971b0 100644
--- a/docs/derivations.md
+++ b/docs/derivations.md
@@ -5,6 +5,10 @@ with explicit identity, provenance, temporal basis, and configuration identity.
engine, not a workflow engine: applications decide whether a candidate opens a task, updates a
projection, triggers an integration, or has no operational consequence.
+For an accessible example of a placement producing safety-training work, start with [Derived work
+and provenance](/concepts#derived-work-and-provenance). This page defines the detailed evaluation,
+materialization, reconciliation, and overlay contracts.
+
## Definitions and candidates
```ts
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..80e3124
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,106 @@
+# Getting started
+
+This guide writes three facts to an in-memory Triplex database, joins them with Datalog, and prints
+the result. It is the shortest complete path from a source checkout to a running program.
+
+::: warning Package availability
+As of September 10, 2026, the new `@triplex-build` packages are **not yet available from npm**.
+The registry returns `404` for the core, SQLite, and CLI packages. Use the source-checkout path
+below until the [first release gates](/current-state#first-release-gates) are complete. Do not use
+the superseded `@bjacobso` package names for new work.
+:::
+
+## Prerequisites
+
+- Git
+- Node.js 22 or newer
+- Corepack and pnpm 10.11.0 (the repository declares the exact package-manager version)
+
+## Run the example
+
+Clone the repository and install its locked dependencies:
+
+```sh
+git clone https://github.com/bjacobso/triplex.git
+cd triplex
+corepack enable
+pnpm install --frozen-lockfile
+```
+
+Run the checked quickstart directly from the checkout:
+
+```sh
+pnpm exec tsx --tsconfig docs/snippets/tsconfig.json docs/snippets/getting-started.ts
+```
+
+The complete program is:
+
+<<< @/snippets/getting-started.ts{ts}
+
+It prints:
+
+```json
+{
+ "relationships": [
+ {
+ "person": "Alice",
+ "company": "Acme"
+ }
+ ]
+}
+```
+
+The repository's smaller demo is another executable starting point:
+
+```sh
+pnpm exec tsx --tsconfig docs/snippets/tsconfig.json examples/demo/demo.ts
+```
+
+## What the Effect code is doing
+
+You only need four Effect ideas for this example:
+
+1. `Triples` is a service tag. `yield* Triples` asks the current Effect context for the database.
+2. `Effect.gen` lets the program sequence database effects with generator syntax.
+3. `KvTriples.layer` constructs the in-memory implementation of that service.
+4. `Effect.provide` supplies the layer, and `Effect.runPromise` runs the fully provided program.
+
+Create and share a layer at your application boundary. Do not construct a new layer inside each
+request: each `KvTriples.layer` runtime owns a fresh in-memory database, and its contents disappear
+when that runtime/process ends.
+
+The transaction records three typed values atomically. `ref(acme)` is a relationship because its
+value is another `EntityId`; the Datalog query follows that relationship by using the same
+`?company` variable in two clauses. `query` returns one bounded page, which is enough for this
+one-row example. Follow `nextCursor` for larger results or use `queryAll` only for trusted batch
+work that intentionally needs the complete result set.
+
+## Use durable SQLite
+
+SQLite is the supported local persistent backend. Once the scoped packages are published, a
+registry consumer will install the exact compatible releases of core, SQLite, and Effect. Until
+then, use them from this workspace checkout.
+
+Replace the in-memory layer with a file-backed layer:
+
+```ts
+import { SqliteTriples } from "@triplex-build/triplex-sqlite";
+
+const DatabaseLive = SqliteTriples.layer({ filename: "./triplex.db" });
+const relationships = await Effect.runPromise(program.pipe(Effect.provide(DatabaseLive)));
+```
+
+This is a focused replacement fragment: `program` is the complete program above. The convenience
+layer opens the SQLite file and applies Triplex's current migration. Create it once and share it for
+the application lifetime. Production hosts that separate schema migration from runtime startup
+should use the explicit unmigrated composition described in [Host integration](/host-integration).
+
+## Next steps
+
+- Experiment without installing anything in the browser [Playground](/playground).
+- Read [Core concepts](/concepts) before modeling a domain with historical facts.
+- Follow [Configuration releases and rollback](/configuration-versioning) to version rules and pin
+ operational writes to them.
+- Learn query clauses and pagination in [Datalog](/datalog).
+- Explore a database through the [CLI and dashboard](/tools).
+- Check the [current maturity contract](/current-state) before choosing a production backend.
diff --git a/docs/host-integration.md b/docs/host-integration.md
index f1da7e3..e4196c9 100644
--- a/docs/host-integration.md
+++ b/docs/host-integration.md
@@ -5,6 +5,10 @@ an application that also owns relational operational records. The host remains r
authentication, authorization, HTTP contracts, durable work, response caching, external effects,
and product-specific invariants.
+Start with [Core concepts](/concepts#constraints-and-responsibility-boundaries) if that separation
+is unfamiliar. Use [CLI and dashboard](/tools) for local inspection and
+[Troubleshooting](/troubleshooting) for common runtime and freshness failures.
+
The executable companion is
[`examples/compliance-host`](https://github.com/bjacobso/triplex/tree/main/examples/compliance-host).
Despite its focused scenario, it uses only generic Triplex primitives: content-addressed
diff --git a/docs/index.md b/docs/index.md
index 0d32df6..01a3263 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -9,10 +9,10 @@ pageClass: triplex-index
---
::: warning Pre-1.0 release candidate
-Triplex is published only as npm canaries under the `next` tag and requires
-`effect@4.0.0-rc.112`. Effect 3 is not compatible. KV and SQLite are the supported baseline;
-PostgreSQL is a production candidate, while Cloudflare and FoundationDB are experimental.
-[Read the exact maturity contract](/current-state).
+The new `@triplex-build` packages are not yet published. Run Triplex from a source checkout; the
+current tree requires `effect@4.0.0-rc.112`, and Effect 3 is not compatible. KV and SQLite are the
+supported baseline; PostgreSQL is a production candidate, while Cloudflare and FoundationDB are
+experimental. [Read the exact maturity contract](/current-state).
:::
@@ -24,9 +24,10 @@ PostgreSQL is a production candidate, while Cloudflare and FoundationDB are expe
Bitemporal facts, Datalog, and typed, content-addressed configuration—built on Effect.
@@ -133,9 +134,12 @@ PostgreSQL is a production candidate, while Cloudflare and FoundationDB are expe
diff --git a/docs/operational-primitives.md b/docs/operational-primitives.md
index 9bd3d9b..4e91c83 100644
--- a/docs/operational-primitives.md
+++ b/docs/operational-primitives.md
@@ -4,6 +4,10 @@ Triplex is a durable substrate for applications that need temporal facts, deriva
This specification separates database/runtime guarantees that belong in Triplex from workflow and
product concepts that belong in a host application.
+Read [Core concepts](/concepts) for the beginner-oriented model and [Host
+integration](/host-integration) for application composition. This page is the low-level operational
+contract.
+
## Implemented foundation
### Atomic transactions
diff --git a/docs/playground.md b/docs/playground.md
new file mode 100644
index 0000000..d2bba6a
--- /dev/null
+++ b/docs/playground.md
@@ -0,0 +1,40 @@
+---
+title: Playground
+description: Run an in-memory Triplex database, Datalog queries, and transactions in your browser.
+aside: false
+---
+
+# Playground
+
+See how facts become answers. Pick a domain, try a change, and watch a real Triplex database
+update in your browser. No installation or JSON editing needed to get started.
+
+
+
+
+
+
+