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

# Build and deploy a workflow project

> Initialize a Python workflow project, publish a workflow release, and deploy it to a development cluster.

Use workflow releases when the code under test should match the code that runners execute. A release packages a Python workflow project, records the discovered task identifiers, and lets release runners load the deployed code from a cluster.

This guide summarizes the build and deploy path. For the underlying model, see [Workflow releases](/workflows/concepts/workflow-releases) and [Release lifecycle](/workflows/build-and-deploy/releases).

## Prerequisites

* You have installed the [Tilebox CLI](/agents-and-ai-tools/tilebox-cli).
* `TILEBOX_API_KEY` is set in the shell where you run commands.
* `uv` is installed and available on `PATH`.

## Initialize the project

Create a project directory and initialize it as a Tilebox workflow project.

```bash theme={"system"}
mkdir my-workflow
cd my-workflow
tilebox workflow init --name "My Workflow"
```

The init command creates the Tilebox workflow, writes `tilebox.workflow.toml`, creates a minimal Python project with `runner.py`, adds the `tilebox` dependency, and runs `uv sync`. It aborts if `tilebox.workflow.toml`, `pyproject.toml`, `runner.py`, or `uv.lock` already exists in the current directory.

<Tree>
  <Tree.Folder name="my-workflow" defaultOpen>
    <Tree.File name="pyproject.toml" />

    <Tree.File name="uv.lock" />

    <Tree.File name="tilebox.workflow.toml" />

    <Tree.File name="runner.py" />
  </Tree.Folder>
</Tree>

## Configure a deployment target

Create a logical cluster to deploy the workflow release to, enabling [release runners](/workflows/concepts/runners#release-runners).

```bash theme={"system"}
tilebox cluster create "workflow-dev"
```

```text Output theme={"system"}
Slug               workflow-dev-<...>
Name               workflow-dev
Deletable          true
```

Add the returned cluster slug to `tilebox.workflow.toml` so deployment commands can refer to a logical environment instead of repeating cluster slugs.

```toml tilebox.workflow.toml theme={"system"}
[workflow]
slug = "my-workflow-<...>"
root = "."
runner = "runner:runner"

[build]
include = [
  "tilebox.workflow.toml",
  "pyproject.toml",
  "uv.lock",
  "runner.py",
]

[targets.dev]
clusters = ["workflow-dev-<...>"]
```

## Build and publish the release

Create a new release of the workflow and publish it to Tilebox.

```bash theme={"system"}
tilebox workflow publish-release
```

Publishing creates an immutable release. It does not change what any cluster runs until you deploy it.

<Tip>
  Build locally first when you want detailed validation output.

  `tilebox workflow build-release --debug`
</Tip>

## Deploy to a development cluster

Deploy the release to the development target.

```bash theme={"system"}
tilebox workflow deploy-release --latest --target dev
```

Start a release runner in an environment you control.

```bash theme={"system"}
tilebox runner start --cluster workflow-dev-9xK2mQ4pL8nR7s --debug
```

## Run and inspect a job

Submit a task that matches one of the identifiers discovered from the release.

```bash theme={"system"}
tilebox job submit \
  --name my-workflow-test \
  --task my-workflow/HelloWorld \
  --version v0.1 \
  --cluster workflow-dev-9xK2mQ4pL8nR7s \
  --input '{"name":"Tilebox"}' \
  --wait
```

```text theme={"system"}
Job submitted: 019ef7a2-56b4-7a86-9c4d-52a1792b1e90
```

Inspect the result before making the next change.

```bash theme={"system"}
tilebox job logs <JOB_ID>
tilebox job spans <JOB_ID>
```

## Next steps

<Columns cols={2}>
  <Card title="Project structure" icon="folder-tree" href="/workflows/build-and-deploy/project-structure" horizontal>
    Learn the details of Python workflow project layout.
  </Card>

  <Card title="Deploy to your compute" icon="server" href="/guides/workflows/deploy-to-your-compute" horizontal>
    Choose where release runners run and how clusters map to environments.
  </Card>
</Columns>
