[Skip to content](#main-content)

[![Jx Suite](/favicon.svg)
Suite](/)Search⌘KESC

Jump to

[Install Jx Studio](/docs/start/install)[Build your first project](/docs/start/first-project)[Document format](/docs/framework/concepts/documents)[Formula catalog](/docs/framework/reference/formulas)

↵
select↑↓
navigateesc
close

[Studio](/studio)[Framework](/framework)[Templates](/templates)[Compare](/compare)[Docs](/docs/start/first-project)[GitHub](https://github.com/jxsuite/jx)[Download](/download)

✕

[Studio](/studio)[Framework](/framework)[Templates](/templates)[Compare](/compare)[Docs](/docs/start/first-project)[GitHub](https://github.com/jxsuite/jx)

Color scheme&#xA;

[Download](/download)

☰

Docs menu

Start here[Overview](/docs/start/)Get started[Install Jx Studio](/docs/start/install/)[Your first project](/docs/start/first-project/)[A tour of Jx Studio](/docs/start/studio-tour/)Tutorials[Tutorial: interactive component](/docs/start/first-component/)[Tutorial: blog with collections](/docs/start/first-collection/)[Video tutorials](/docs/start/videos/)Coming from another tool[Coming from WordPress](/docs/start/coming-from-wordpress/)[Coming from Webflow or Framer](/docs/start/coming-from-webflow/)[Coming from Wix or Squarespace](/docs/start/coming-from-wix/)[Coming from Lovable or Builder.io](/docs/start/coming-from-ai-builders/)Studio[Overview](/docs/studio/)[The desktop app](/docs/studio/desktop/)The workspace[Overview](/docs/studio/interface/)[Welcome screen](/docs/studio/interface/welcome-screen/)[Editors and views](/docs/studio/interface/modes/)[The canvas](/docs/studio/interface/canvas/)[Documents and panes](/docs/studio/interface/tabs/)[Quick Access](/docs/studio/interface/quick-access/)[Keyboard shortcuts](/docs/studio/interface/shortcuts/)[Preferences](/docs/studio/interface/preferences/)[Languages](/docs/studio/interface/languages/)[Problems and progress](/docs/studio/interface/problems-and-progress/)[Commands](/docs/studio/interface/commands/)Projects[Overview](/docs/studio/projects/)[Create a project](/docs/studio/projects/create/)[Pages, layouts, components](/docs/studio/projects/pages-layouts-components/)[The Content workspace](/docs/studio/projects/browse/)[Starter templates](/docs/studio/projects/starters/)[Media](/docs/studio/projects/media/)[Content types](/docs/studio/projects/content-types/)[Project settings](/docs/studio/projects/settings/)[Dependencies and imports](/docs/studio/projects/dependencies/)Edit mode[Overview](/docs/studio/editing/)[Writing and formatting](/docs/studio/editing/writing/)[Slash commands](/docs/studio/editing/slash-commands/)[Frontmatter and metadata](/docs/studio/editing/frontmatter/)[Grid mode](/docs/studio/editing/grid/)Design mode[Overview](/docs/studio/design/)[Outline](/docs/studio/design/layers/)[Insert](/docs/studio/design/elements/)[Content tab](/docs/studio/design/properties/)[Style inspector](/docs/studio/design/style-inspector/)[Breakpoints](/docs/studio/design/breakpoints/)[States and selectors](/docs/studio/design/states-and-selectors/)[Design tokens](/docs/studio/design/tokens/)[Project Styles](/docs/studio/design/stylebook/)[Working with components](/docs/studio/design/components/)[Repeaters](/docs/studio/design/repeaters/)Logic[Overview](/docs/studio/logic/)[Formulas and expressions](/docs/studio/logic/formulas/)[Formula workspace](/docs/studio/logic/formula-workspace/)[Statements](/docs/studio/logic/statements/)[Logic tab](/docs/studio/logic/events/)[Data](/docs/studio/logic/data/)[Data sources](/docs/studio/logic/data-sources/)[Code editing](/docs/studio/logic/code/)Databases[Overview](/docs/studio/data/)[Connections](/docs/studio/data/connections/)[Data tables](/docs/studio/data/tables/)[Data grid](/docs/studio/data/grid/)[Auth and secrets](/docs/studio/data/auth-and-secrets/)AI assistant[Overview](/docs/studio/ai/)[The AI assistant](/docs/studio/ai/chat/)[Document assistant](/docs/studio/ai/document-assistant/)Publish[Overview](/docs/studio/publish/)[Source control](/docs/studio/publish/source-control/)[GitHub](/docs/studio/publish/github/)[Cloudflare Pages](/docs/studio/publish/cloudflare/)[Other hosts](/docs/studio/publish/other-hosts/)[Redirects](/docs/studio/publish/redirects/)[Real-time collaboration](/docs/studio/publish/collaboration/)Framework[Overview](/docs/framework/)Concepts[Documents](/docs/framework/concepts/documents/)[Elements](/docs/framework/concepts/elements/)[Components](/docs/framework/concepts/components/)[Props and scope](/docs/framework/concepts/props-and-scope/)[State](/docs/framework/concepts/state/)[Reactivity](/docs/framework/concepts/reactivity/)[References](/docs/framework/concepts/references/)[Expressions](/docs/framework/concepts/expressions/)[Statements](/docs/framework/concepts/statements/)[Functions and sidecars](/docs/framework/concepts/functions/)[Styling](/docs/framework/concepts/styling/)[Color schemes](/docs/framework/concepts/color-schemes/)[Popovers and overlays](/docs/framework/concepts/overlays/)[Accessibility](/docs/framework/concepts/accessibility/)[Lists and iteration](/docs/framework/concepts/lists/)[Data prototypes](/docs/framework/concepts/data-prototypes/)[Timing](/docs/framework/concepts/timing/)[Dynamic switching](/docs/framework/concepts/switching/)[Security](/docs/framework/concepts/security/)Site architecture[Overview](/docs/framework/site/)[project.json](/docs/framework/site/project-json/)[Routing](/docs/framework/site/routing/)[Layouts](/docs/framework/site/layouts/)[Content collections](/docs/framework/site/content-collections/)[Jx Markdown](/docs/framework/site/jx-markdown/)[Obsidian vault as content](/docs/framework/site/obsidian-vault/)[Relationships](/docs/framework/site/relationships/)[SEO and metadata](/docs/framework/site/seo/)[Locales and languages](/docs/framework/site/i18n/)[Images](/docs/framework/site/images/)[Redirects](/docs/framework/site/redirects/)[Feeds](/docs/framework/site/feeds/)[Site search](/docs/framework/site/search/)[Build output and adapters](/docs/framework/site/deployment/)How compilation works[Overview](/docs/framework/build/)[The dev server](/docs/framework/build/dev-server/)[CLI commands](/docs/framework/build/cli/)Working with agents[Overview](/docs/framework/agents/)[Authoring rules for agents](/docs/framework/agents/authoring-rules/)[Machine-readable docs](/docs/framework/agents/machine-readable/)Reference[Overview](/docs/framework/reference/)[Formula catalog](/docs/framework/reference/formulas/)[Operator reference](/docs/framework/reference/operators/)Extending[Overview](/docs/extending/)Extensions[Extension anatomy](/docs/extending/extensions/anatomy/)[Schema composition](/docs/extending/extensions/schema-composition/)[Custom classes](/docs/extending/extensions/classes/)[Custom formats](/docs/extending/extensions/formats/)[Capability methods](/docs/extending/extensions/capabilities/)[Project sections](/docs/extending/extensions/project-sections/)[Server mounts](/docs/extending/extensions/server/)[Connectors](/docs/extending/extensions/connectors/)[Search indexes](/docs/extending/extensions/search/)[Security and secrets](/docs/extending/extensions/security/)[Tutorial: a TOML format](/docs/extending/extensions/tutorial-toml-format/)[Tutorial: a guestbook](/docs/extending/extensions/tutorial-guestbook/)[First-party extensions](/docs/extending/extensions/first-party/)Embedding[Overview](/docs/extending/embedding/)[Hosting the Studio assets](/docs/extending/embedding/hosting/)[Writing a platform adapter](/docs/extending/embedding/platform-adapter/)[The backend protocol](/docs/extending/embedding/backend-protocol/)[Dev server internals](/docs/extending/embedding/dev-server/)[Embedding the runtime in your app](/docs/extending/embedding/runtime-host/)[Writing assistant tools](/docs/extending/embedding/assistant-harness/)UI kit[The Jx UI kit](/docs/extending/ui-kit/)Reference[Protocol routes](/docs/extending/reference/studio-routes/)[Implementation status](/docs/extending/reference/implementation-status/)[Spec changelog](/docs/extending/reference/spec-changelog/)[Standards alignment](/docs/extending/reference/standards/)Contributing[Working in the monorepo](/docs/extending/contributing/monorepo/)[Contributing to these docs](/docs/extending/contributing/docs/)[AI assistant evals](/docs/extending/contributing/ai-evals/)

# The backend protocol

The Studio Backend Protocol is the wire contract every Jx Studio backend implements. It lives in one package, `@jxsuite/protocol`, with two entrypoints. `@jxsuite/protocol/types` holds the request/response shapes (`DirEntry`, `GitStatusResult`, `StarterInfo`, and friends), which are environment-agnostic and importable in browsers, Bun, and Workers alike. `@jxsuite/protocol/routes` holds `STUDIO_ROUTES`, the canonical endpoint table. If you're serving the protocol over HTTP, this page plus the [route reference](/docs/extending/reference/studio-routes) is your specification; if you're [writing a platform adapter](/docs/extending/embedding/platform-adapter) instead, these are still the semantics your adapter must preserve.

## What exactly is the contract

The **sub-path, method, and body shapes are the contract**. The transport and path prefix are not. The dev server serves the literal `/__studio/*` routes; the desktop app dispatches the same operations over typed RPC / WebSocket JSON-RPC; cloud platforms serve them over HTTP behind a session gateway prefix. All three answer the same shapes for the same sub-paths, so Studio can't tell them apart.

Each entry in `STUDIO_ROUTES` carries its method, path, a one-line contract summary, and, for optional routes, what Studio does without it:

```ts&#x20;shiki
```

The full table is generated into the [protocol route reference](/docs/extending/reference/studio-routes). Consult it there rather than re-reading the source.

## Core vs optional

Optional routes back optional `StudioPlatform` members. Omitting one is not an error. Studio degrades exactly as the entry's `degradation` describes: the starter picker empties, the Projects catalogue hides, the Publish panel explains git-push publishing instead, and so on.

A few optional routes back no member at all. They let an adapter serve the members it already has more cheaply, and their `degradation` names the route they stand in for. `filesRead` (`POST /__studio/files/read`) is the first: the cloud adapter folds the `readFile` calls issued in one tick into one batch request, and against a backend without the route it reads one file per request, exactly as before. Answer it only if your reads cross a network. The answer may be partial: list the paths you did not get to under `omitted` (never a 400), always answer the first path, and give each answered path its own content or error.

`coreRouteNames()` and `optionalRouteNames()` split the table programmatically, so a conformance test for a new backend can iterate `STUDIO_ROUTES` and assert that every core route answers.

The core set is what a minimal backend must serve: project session and probing (`activate`, `project`, `project-info`, `resolve-site`, `create-project`), the filesystem CRUD family, component discovery, package listing, the git suite, and the AI proxy pair (`ai/chat`, `ai/models`). Everything else is optional: collab, starters, the data surface, secrets, Cloudflare publishing.

## Versioning

`STUDIO_PROTOCOL_VERSION` (currently `1`) bumps whenever any route's request or response shape changes incompatibly. The types are published as TypeScript source on the monorepo's release train; the package's only runtime dependency is `@jxsuite/schema`.

## The error shape

Every failure is an [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document, sent as `application/problem+json`:

```json&#x20;shiki
```

Four things are worth knowing before you implement one:

- **`type` is what Studio keys on**, and it's an absolute URI. The full list is in [Studio routes](/docs/extending/reference/studio-routes#failures), generated from the same table the reference backend answers from, so it can't drift.
- **`title` describes the *type*; `detail` describes *this* failure.** Keep `title` identical across occurrences and put the specifics in `detail`. Swapping them is the standard's most common misuse, and it's what stops Studio grouping two instances of the same problem.
- **The status belongs to the type.** If you find yourself wanting to send one type at two statuses, it's two types.
- **Extension members carry anything else the type documents**: `conflicts` on a pull conflict, `installUrl` on a missing GitHub App installation. Studio's recovery UI reads them.

Note

`error`
&#x20;is emitted alongside&#x20;
`detail`
, with the same value, for one release. It's the pre-RFC-9457 field name, kept so a client written against the older shape keeps working while it migrates. Don't write new readers against it.

Three surfaces deliberately answer **200 with an error field instead**, and a conforming backend should too:

| Surface                   | Why                                                                                            |
| ------------------------- | ---------------------------------------------------------------------------------------------- |
| Code services (`/code/*`) | A syntax error in the author's snippet is the *result* of a lint, not a failed request         |
| AI model catalogue        | Degraded success: the catalogue is still delivered, from defaults                              |
| Mid-stream SSE frames     | The response began with a 200; nothing can change the status, so the frame *carries* a problem |

## Behaviors implementers must match

Route shapes alone don't capture everything. These semantics are part of the contract:

- **`git/commit`** commits the staged files if any are staged, otherwise all dirty files. Cloud backends may make commit+push atomic and treat `git/push` as a sync check (`ahead` stays 0).
- **`git/pull`** returns `409 { code: "pull_conflict", conflicts: [paths] }` when local dirty files overlap remote changes; a clean pull fast-forwards.
- **`format`** dispatches `{ format, action: "parse" | "serialize", source? | doc?, options? }` through the project's format registry. Without it, only `.json` documents open.
- **`ai/chat`** accepts `{ messages, tools, systemPrompt, model }` and streams the normalized `StreamEvent` SSE defined by `@jxsuite/ai/streaming-client`. Studio also sends the conversation's id in an `X-Jx-Ai-Session` header so a backend can keep a conversation's requests on one warm prompt cache. Never forward that id to a provider: check it with `isAiSessionId`, hash it with `affinityKey(scope, id)` under a scope of your own, and forward only the hash. A missing or malformed header means no hint, never a refusal. The union and its eight members are exported, so implementers can import the type they are satisfying rather than reconstruct it. Two of them carry a turn's text: `delta` is the answer, and `reasoning` is a thinking model's chain-of-thought (`reasoning_content`, or `reasoning` at OpenRouter). A backend **must forward the second as well as the first**, because DeepSeek's thinking mode requires every prior turn's reasoning back on any request carrying `tools`, which is every request the assistant makes; a proxy that swallows those frames turns the round after a tool call into a 400 no client can repair. `usage` is optional: send it once, immediately before `done`, when the provider reported a count (`inputTokens`, `outputTokens`, and `cachedInputTokens` or `reasoningTokens` when the provider says). Studio replaces its four-characters-per-token estimate with it, and a reader that predates the frame ignores it. With OpenAI's `include_usage` the count arrives in a chunk of its own after the one carrying `finish_reason`, so keep reading past the finish until `[DONE]`. Tool calls run whenever the stream carried any, whichever finish the provider reported (`stop`, `length` or `tool_calls`), because some OpenAI-compatible providers end a tool-calling turn with `stop`. A round that ends `cancelled` runs nothing: that is the author pressing Stop, not a finish. `ai/models` returns `AiModelsResponse`; report `configured: true` when the backend holds credentials (Studio then unlocks the assistant without a locally stored key) and `managed: true` when the platform brokers them. It is a capability probe, so it answers `200` in every credential state. A non-2xx makes the probe throw, which withdraws the connect affordance from exactly the users who need it. Where a model's capabilities are known, report them per entry: `toolSupport: false` makes Studio warn that the chosen model will answer but never edit, and `contextWindow` replaces Studio's model-id prefix table, which recognizes only the families it was written for and budgets everything else at its default. A brokered backend distinguishes `cf_not_connected` (invite), `cf_reconnect_required` (the grant lapsed, so explain and offer reconnection), `cf_account_required` (the grant is live but no account is chosen; offer a picker, since re-authorizing lands back here) and `cf_upstream_error`, which is reported **with**`configured: true` because a briefly unreachable provider is not a credential problem. Listing is best-effort per BYOK endpoint: a provider is not required to serve one at all (Cloudflare Workers AI's OpenAI-compatible surface has no `/models` route), so a backend that cannot list still answers `200` with `upstreamError` set, and should carry the upstream's own reason in `upstreamMessage` rather than leave a caller unable to tell a missing route from a bad key.
- **`@jxsuite/ai/gateway`** implements both AI routes for a TypeScript backend, and it is the code the dev server itself runs. `createChatHandler({ resolveUpstream })` answers `ai/chat`: it reads and checks the body, forwards it as an OpenAI-compatible streaming request, and normalizes the provider's stream into the frames above, so a backend inherits the `reasoning`, `usage` and finish rules instead of re-deriving them. The policy stays yours. `resolveUpstream` decides whose key a request uses and which base URL it may reach (the dev server never sends its own environment key to a URL the caller chose, and refuses link-local hosts), and the optional `admit`, `maxBodyBytes`, `maxMessages` and `onAccepted` add rate limits, size limits and an audit hook. An upstream may carry a `sessionAffinity` (the hashed key above), which the gateway forwards in the form the provider understands: `prompt_cache_key` to OpenAI, the `x-session-affinity` header to Workers AI and AI Gateway, and nothing to any other host. A refusal at any of those steps is an `application/problem+json` answer, sent before the provider is contacted. `modelsResponse(body)` answers `ai/models` with the `200` the probe requires, whatever catalogue you pass it. The module imports nothing host-bound, so the same handler runs in a Cloudflare Worker, under Bun or under Node.
- **`collab`** is a WebSocket upgrade speaking the `@jxsuite/collab` wire envelope: one socket per project, documents multiplexed by path. A plain GET (no Upgrade) answers `{ collab: true, protocols, version }` as the capability probe.

  `protocols` lists the WebSocket subprotocols the backend speaks, currently `["jx.collab.v1"]`, and it is also the negotiation: Studio offers one of them as `Sec-WebSocket-Protocol` and the backend must echo the one it accepts. **A backend that lists none is offered none**, because [RFC 6455 §4.1](https://www.rfc-editor.org/rfc/rfc6455#section-4.1) makes a client whose offer went unechoed fail the connection. An older backend keeps working exactly as before. A backend that lists only tokens Studio cannot parse gets no socket at all, which is the point: two peers whose envelopes disagree would merge divergent histories.
- **`files`** answers in **stable path order**, both when listing a directory (`?dir=`) and when searching (`?glob=`). `readdir` and glob scans report in filesystem order, which varies with a directory's write history; Studio's collection grid inserts rows in listing order, so an unsorted listing reaches the user as a table that reshuffles itself between opens. Sort by codepoint rather than locale collation, so two backends and two machines agree.
- **`cf/proxy`** is an allowlisted Cloudflare API passthrough (accounts and Pages projects/deployments only). The backend injects credentials (a header-borne user token on the dev server, a vaulted OAuth token on cloud), and stateless implementations must never persist them.
- **The data routes** (`data/connections`, `data/rows`, `data/push`, …) intentionally bypass table permission rules. They are the owner console, and the backend boundary (loopback/token locally, collaboration permission on cloud) is the gate. The secrets routes carry env-var **names only**, never values. See [connectors](/docs/extending/extensions/connectors) and the [extension security model](/docs/extending/extensions/security).

## Related

- [Protocol route reference](/docs/extending/reference/studio-routes): the generated table of every route, method, summary, and degradation
- [Dev server internals](/docs/extending/embedding/dev-server): the reference implementation of these routes
- [Writing a platform adapter](/docs/extending/embedding/platform-adapter): the in-page interface these routes back

✕

Start here[Overview](/docs/start/)Get started[Install Jx Studio](/docs/start/install/)[Your first project](/docs/start/first-project/)[A tour of Jx Studio](/docs/start/studio-tour/)Tutorials[Tutorial: interactive component](/docs/start/first-component/)[Tutorial: blog with collections](/docs/start/first-collection/)[Video tutorials](/docs/start/videos/)Coming from another tool[Coming from WordPress](/docs/start/coming-from-wordpress/)[Coming from Webflow or Framer](/docs/start/coming-from-webflow/)[Coming from Wix or Squarespace](/docs/start/coming-from-wix/)[Coming from Lovable or Builder.io](/docs/start/coming-from-ai-builders/)Studio[Overview](/docs/studio/)[The desktop app](/docs/studio/desktop/)The workspace[Overview](/docs/studio/interface/)[Welcome screen](/docs/studio/interface/welcome-screen/)[Editors and views](/docs/studio/interface/modes/)[The canvas](/docs/studio/interface/canvas/)[Documents and panes](/docs/studio/interface/tabs/)[Quick Access](/docs/studio/interface/quick-access/)[Keyboard shortcuts](/docs/studio/interface/shortcuts/)[Preferences](/docs/studio/interface/preferences/)[Languages](/docs/studio/interface/languages/)[Problems and progress](/docs/studio/interface/problems-and-progress/)[Commands](/docs/studio/interface/commands/)Projects[Overview](/docs/studio/projects/)[Create a project](/docs/studio/projects/create/)[Pages, layouts, components](/docs/studio/projects/pages-layouts-components/)[The Content workspace](/docs/studio/projects/browse/)[Starter templates](/docs/studio/projects/starters/)[Media](/docs/studio/projects/media/)[Content types](/docs/studio/projects/content-types/)[Project settings](/docs/studio/projects/settings/)[Dependencies and imports](/docs/studio/projects/dependencies/)Edit mode[Overview](/docs/studio/editing/)[Writing and formatting](/docs/studio/editing/writing/)[Slash commands](/docs/studio/editing/slash-commands/)[Frontmatter and metadata](/docs/studio/editing/frontmatter/)[Grid mode](/docs/studio/editing/grid/)Design mode[Overview](/docs/studio/design/)[Outline](/docs/studio/design/layers/)[Insert](/docs/studio/design/elements/)[Content tab](/docs/studio/design/properties/)[Style inspector](/docs/studio/design/style-inspector/)[Breakpoints](/docs/studio/design/breakpoints/)[States and selectors](/docs/studio/design/states-and-selectors/)[Design tokens](/docs/studio/design/tokens/)[Project Styles](/docs/studio/design/stylebook/)[Working with components](/docs/studio/design/components/)[Repeaters](/docs/studio/design/repeaters/)Logic[Overview](/docs/studio/logic/)[Formulas and expressions](/docs/studio/logic/formulas/)[Formula workspace](/docs/studio/logic/formula-workspace/)[Statements](/docs/studio/logic/statements/)[Logic tab](/docs/studio/logic/events/)[Data](/docs/studio/logic/data/)[Data sources](/docs/studio/logic/data-sources/)[Code editing](/docs/studio/logic/code/)Databases[Overview](/docs/studio/data/)[Connections](/docs/studio/data/connections/)[Data tables](/docs/studio/data/tables/)[Data grid](/docs/studio/data/grid/)[Auth and secrets](/docs/studio/data/auth-and-secrets/)AI assistant[Overview](/docs/studio/ai/)[The AI assistant](/docs/studio/ai/chat/)[Document assistant](/docs/studio/ai/document-assistant/)Publish[Overview](/docs/studio/publish/)[Source control](/docs/studio/publish/source-control/)[GitHub](/docs/studio/publish/github/)[Cloudflare Pages](/docs/studio/publish/cloudflare/)[Other hosts](/docs/studio/publish/other-hosts/)[Redirects](/docs/studio/publish/redirects/)[Real-time collaboration](/docs/studio/publish/collaboration/)Framework[Overview](/docs/framework/)Concepts[Documents](/docs/framework/concepts/documents/)[Elements](/docs/framework/concepts/elements/)[Components](/docs/framework/concepts/components/)[Props and scope](/docs/framework/concepts/props-and-scope/)[State](/docs/framework/concepts/state/)[Reactivity](/docs/framework/concepts/reactivity/)[References](/docs/framework/concepts/references/)[Expressions](/docs/framework/concepts/expressions/)[Statements](/docs/framework/concepts/statements/)[Functions and sidecars](/docs/framework/concepts/functions/)[Styling](/docs/framework/concepts/styling/)[Color schemes](/docs/framework/concepts/color-schemes/)[Popovers and overlays](/docs/framework/concepts/overlays/)[Accessibility](/docs/framework/concepts/accessibility/)[Lists and iteration](/docs/framework/concepts/lists/)[Data prototypes](/docs/framework/concepts/data-prototypes/)[Timing](/docs/framework/concepts/timing/)[Dynamic switching](/docs/framework/concepts/switching/)[Security](/docs/framework/concepts/security/)Site architecture[Overview](/docs/framework/site/)[project.json](/docs/framework/site/project-json/)[Routing](/docs/framework/site/routing/)[Layouts](/docs/framework/site/layouts/)[Content collections](/docs/framework/site/content-collections/)[Jx Markdown](/docs/framework/site/jx-markdown/)[Obsidian vault as content](/docs/framework/site/obsidian-vault/)[Relationships](/docs/framework/site/relationships/)[SEO and metadata](/docs/framework/site/seo/)[Locales and languages](/docs/framework/site/i18n/)[Images](/docs/framework/site/images/)[Redirects](/docs/framework/site/redirects/)[Feeds](/docs/framework/site/feeds/)[Site search](/docs/framework/site/search/)[Build output and adapters](/docs/framework/site/deployment/)How compilation works[Overview](/docs/framework/build/)[The dev server](/docs/framework/build/dev-server/)[CLI commands](/docs/framework/build/cli/)Working with agents[Overview](/docs/framework/agents/)[Authoring rules for agents](/docs/framework/agents/authoring-rules/)[Machine-readable docs](/docs/framework/agents/machine-readable/)Reference[Overview](/docs/framework/reference/)[Formula catalog](/docs/framework/reference/formulas/)[Operator reference](/docs/framework/reference/operators/)Extending[Overview](/docs/extending/)Extensions[Extension anatomy](/docs/extending/extensions/anatomy/)[Schema composition](/docs/extending/extensions/schema-composition/)[Custom classes](/docs/extending/extensions/classes/)[Custom formats](/docs/extending/extensions/formats/)[Capability methods](/docs/extending/extensions/capabilities/)[Project sections](/docs/extending/extensions/project-sections/)[Server mounts](/docs/extending/extensions/server/)[Connectors](/docs/extending/extensions/connectors/)[Search indexes](/docs/extending/extensions/search/)[Security and secrets](/docs/extending/extensions/security/)[Tutorial: a TOML format](/docs/extending/extensions/tutorial-toml-format/)[Tutorial: a guestbook](/docs/extending/extensions/tutorial-guestbook/)[First-party extensions](/docs/extending/extensions/first-party/)Embedding[Overview](/docs/extending/embedding/)[Hosting the Studio assets](/docs/extending/embedding/hosting/)[Writing a platform adapter](/docs/extending/embedding/platform-adapter/)[The backend protocol](/docs/extending/embedding/backend-protocol/)[Dev server internals](/docs/extending/embedding/dev-server/)[Embedding the runtime in your app](/docs/extending/embedding/runtime-host/)[Writing assistant tools](/docs/extending/embedding/assistant-harness/)UI kit[The Jx UI kit](/docs/extending/ui-kit/)Reference[Protocol routes](/docs/extending/reference/studio-routes/)[Implementation status](/docs/extending/reference/implementation-status/)[Spec changelog](/docs/extending/reference/spec-changelog/)[Standards alignment](/docs/extending/reference/standards/)Contributing[Working in the monorepo](/docs/extending/contributing/monorepo/)[Contributing to these docs](/docs/extending/contributing/docs/)[AI assistant evals](/docs/extending/contributing/ai-evals/)

[![Jx Suite](/favicon.svg)
Suite](/)The visual IDE for the web. Build any website, save it as plain files, own it forever. MIT licensed.

Product

[Studio](/studio)[Download](/download)[Templates](/templates)[Features](/features)[Compare](/compare)[Jx Cloud (soon)](/cloud)

Developers

[Docs](/docs/start/first-project)[Framework](/framework)[Get Studio](/docs/start/install)[Spec](/docs/framework)[GitHub](https://github.com/jxsuite/jx)

Project

[MIT License](https://github.com/jxsuite/jx/blob/main/LICENSE)[Releases](https://github.com/jxsuite/jx/releases/latest)[Privacy](/privacy)[Terms](/terms)[Support](/support)

Built with Jx Suite. © 2026 Avunu LLC. Open source under the MIT License.
