> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bytesell.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Publishing

> Git deployment, versioning, and publish validation.

Themes deploy from a git repository. Once connected, every push to the tracked
branch redeploys.

## Connecting a repository

<Steps>
  <Step title="Push the theme">
    Commit everything under the theme root, including the compiled stylesheet.
  </Step>

  <Step title="Connect it in the dashboard">
    Open **My Store**, connect the GitHub repository and select the branch.
    ByteSell reads the tree, locates directories containing `theme.json` and
    validates the shape before accepting the connection.
  </Step>

  <Step title="Set it live">
    A connected theme installs as a private theme and is not live. Check the
    deploy status, then set it live.
  </Step>
</Steps>

Themes connected this way are private to the store and do not appear in the
marketplace catalog. They are read-only in the builder, since the repository is
the source of truth.

## Versions

The version is assigned by the server, which takes the highest existing clean
semver and bumps its patch, starting at `1.0.0`.

<Warning>
  `version` in `theme.json` is not read at publish. Changing it has no effect.
  It is read only when the dashboard detects a theme in a connected repository,
  for display.
</Warning>

## Schema version

`schema` in `theme.json` declares which generation of the section system the
theme targets.

The gate is one-directional. A deployment newer than the theme is accepted. A
theme declaring a version higher than the deployment supports is rejected:

```
theme.json declares schema 3, but this ByteSell deployment supports up to 2.
Publishing would silently drop settings this theme declares.
Update ByteSell, or build the theme against schema 2.
```

## Validation

Checks run in this order. Any failure rejects the entire publish.

<Steps>
  <Step title="Size and paths">
    File count, per-file size, total size and path rules. See
    [Limits](/themes/reference/limits).
  </Step>

  <Step title="Templates parse">
    Every `.slurp` must be valid UTF-8 and must parse within a 10 second budget
    per file.
  </Step>

  <Step title="No {fetch} in a block">
    Any file under `blocks/` containing a `{fetch}` at any depth is rejected.
  </Step>

  <Step title="Linked stylesheets exist">
    Every literal root-relative `.css` referenced by an `href` must be in the
    bundle.
  </Step>

  <Step title="Schema version is supported">
    See above.
  </Step>

  <Step title="Defaults and schemas extract">
    `templates/*.json` must be valid JSON with a `sections` array, every entry
    needs a string `type`, and ids must be unique within a page.
  </Step>
</Steps>

Bytes are uploaded before the database commit, so a failed commit leaves
unreferenced objects rather than a manifest pointing at missing files.

## Common rejections

| Message                                                                            | Cause                                 |
| ---------------------------------------------------------------------------------- | ------------------------------------- |
| `no theme.json manifest at the theme root`                                         | Wrong directory selected              |
| `theme.json found, but no .slurp files in this folder`                             | Wrong directory selected              |
| `{path} links stylesheet "/css/theme.css" but no "css/theme.css" is in the bundle` | Stylesheet not built or not committed |
| `{path}: a theme block cannot use {fetch}`                                         | Move the fetch to the browser         |
| `{path}: template has parse errors`                                                | Run `slurp validate --dir site` first |
| `{path}: sections[0] reuses id "hero"`                                             | Duplicate section id within a page    |
| `theme slug is owned by another account`                                           | The slug belongs to another account   |

## Propagation

Store configuration is cached, so a published theme reaches buyers within about
60 seconds.

The builder preview is uncached and updates immediately. For the first minute
after a publish, the preview reflecting a change the live store does not is
expected.

## Deploying a built artifact

A theme built in CI should publish the built artifact rather than have ByteSell
pull raw source. The deploy action mints a short-lived OIDC token, so no secret
is stored.

```yaml .github/workflows/deploy.yml theme={null}
permissions:
  contents: read
  id-token: write

steps:
  - uses: actions/checkout@v5
  - run: npm ci && npm run build
  - uses: bytesell/theme-deploy-action@v1
    with:
      publish-url: https://api.bytesell.io/internal/git/publish
      theme-dir: dist
```

<Note>
  In a repository already connected by webhook, both paths fire on the same
  push. The first successful action run switches the theme to artifact mode and
  the webhook stops deploying it, so only the first push after adding CI can
  race.
</Note>
