← Back to Explore
Complete Guide

Explore Tenstorrent hardware & software for the first time

Seven chapters from first boot to a model you can talk to, using the tt command line.

7 chapters · 51 min read time

Chapter 1

What to Know About Your Workstation

Your workstation is a Tenstorrent Quietbox 2: four AI accelerators inside, an operating system you may not have used before, and the software stack already configured and waiting. The machine is ready to go — what’s left is knowing what you’ve got.

This guide doesn’t assume you know Linux, or Python, or what a PCIe slot is. It assumes you’re curious, and that curiosity is enough.

What’s Inside

The Tenstorrent Quietbox 2 (QB2) is a workstation with two Blackhole p300c cards — four Blackhole chips in total — on PCIe. Each p300c is a dual-chip card, and each chip is independent — four separate devices from the software’s point of view, connected to a standard CPU running Ubuntu 24.04 LTS.

What Detail
AI chips 2× Blackhole p300c cards (4 Blackhole chips)
Tensix cores per chip 120 (12×10 compute grid)
Connection PCIe Gen4 (4 independent devices)
OS Ubuntu 24.04 LTS
Pre-installed Drivers, tt-smi/tt-flash, the TT-Metalium and tt-inference-server containers, tt-studio
Source tree Not included — and neither is ~/tt-metal. TT-Metalium runs as a container (tt-metalium)

The chips don’t share memory. When you open device 0, you’re talking to one Blackhole chip. To use all four together, you use ttnn.CreateDevices({0, 1, 2, 3}) — not four separate open_device() calls.

⬡ Each Blackhole chip is a 17×12 Network on Chip (NoC) grid — 204 positions in total. Of those, 140 are Tensix compute tiles (120 are enabled on QB2's chips; the rest are harvested); the remainder are DRAM controllers, Ethernet cores for chip-to-chip links, the PCIe interface, and the routing fabric between them. The grid is how work moves — not through a shared bus, but through a programmable mesh of message-passing nodes.
Four Blackhole chips connected via PCIe to the CPU, with software stack and Python environments
🔌 Before anything else: power switch on the back panel to the ON position, then press the front power button. The fans spin up. That's the QB2 waking up. That sound is correct and expected.

What Ships Pre-Installed

Tenstorrent ships the QB2 ready to serve models. You don’t install drivers. You don’t compile anything. The full stack is already there:

What’s intentionally absent: ~/tt-metal — not just the source code, the whole directory. TT-Metalium reaches you as a container image instead, and tt-metalium is how you get inside it. You can build models, run inference, and work with the full API stack without ever having a checkout. Building from source is a later chapter — a much later chapter.

⚠️ Pre-installed is not the same as current. That list is the stack as it stood when your box was built — driver, firmware, tooling and container images all included. Upgrading is not most people's first instinct, and being behind almost never announces itself: it shows up as a tutorial that fails or hardware that looks broken. Once you've confirmed the chips respond (Chapter 3), take the upgrade step in Chapter 4 before you go looking for a bug.

Physical Tour

The QB2 looks like a standard tower workstation. On the inside:

The chips run warm under load. Fans will get louder when you run inference. This is correct. The cooling is designed for sustained operation at full chip temperature.

⬡ Tensix Grid — Blackhole (P100/P150/P300c / QB2)

One Blackhole chip. You have four, on two p300c cards.


Next: First Boot →

Chapter 2

First Boot

Power on. Ubuntu loads. You log in. Now what?

Everything from here happens in a terminal. That’s the command line — a text window where you type instructions and the machine responds. On a QB2, the terminal is your instrument panel. Learning its three or four most-used commands will get you surprisingly far.

Finding a Terminal

If you’re looking at the GNOME desktop:

Once a terminal window is open, you’re in the right place. It shows a prompt ending in $ — everything you type goes after that.

The Three Commands You Need Right Now

Check disk space first. Models are large. This is non-negotiable to understand before you do anything else:

df -h ~

This shows your home directory’s disk usage. The Size column is total, Avail is what’s free. You need room — at minimum 3 GB for a small model (Qwen3-0.6B), 20+ GB for anything like Llama-3.1-8B. If you’re under 5 GB free, stop here and figure out where the space went before continuing.

Check internet connectivity:

ping -c 3 google.com

If this fails, check your network cable or go to Settings → Network. Everything else in this guide requires internet access for model downloads.

Update the package list (do this once after first boot):

sudo apt update

sudo means “run as administrator.” Ubuntu will ask for your password. This doesn’t install or change anything — it just refreshes the list of what’s available. You’ll see a lot of text scroll by. That’s normal.

QB2 first boot terminal: uname, ping, df, home directory, tt-smi version
Live QB2 — Ubuntu 24.04, internet up, disk space, tt-smi on PATH

Ubuntu: What You Should Know

The QB2 runs Ubuntu 24.04 LTS. If this is your first time with it:

Your Login, Password, and SSH

Many QB2 units ship with a default login — username ttuser, password ttuser. If that’s how yours arrived, change the password the moment you’re in, before the machine is reachable on a shared network:

passwd

It asks for the current password (ttuser), then a new one twice.

Turn on SSH

Later in this guide — and on every other path — you reach the QB2 from your own laptop over SSH: forwarding a model server’s port back to your machine, copying files, running commands remotely. SSH isn’t always running on a fresh box, so turn it on once:

# Install and enable the SSH server
sudo apt install -y openssh-server
sudo systemctl enable --now ssh

# Confirm it's listening
systemctl status ssh

Then find the address other machines use to reach you:

hostname -I     # the QB2's IP address on your network
hostname        # its name — often <name>.local

From your laptop you can now run ssh ttuser@<that-ip>. This is what makes the remote-access steps in Serving Models on QB2 — and bringing tt-studio’s web UI to your own browser — work.

💡 Ubuntu's ufw firewall is installed but inactive by default, so nothing on the QB2 is blocked out of the box. If you or your IT team turn it on (sudo ufw status tells you), remember to allow SSH with sudo ufw allow 22/tcp — and any service port you forward later, like 8000 for the inference server.

Python: A Field Guide to the Confusion

This is where new Linux users often hit a wall. Ubuntu ships with its own Python. The Tenstorrent software has its own Python environments. These are separate and don’t mix. Here’s the landscape:

What exists on your system

Name Location What it is
System Python /usr/bin/python3 Ubuntu’s built-in Python — don’t pip install here
Hardware tooling venv ~/.tenstorrent-venv/ tt-smi and tt-flash. That’s the whole inventory — don’t install into it
TTNN / Direct API inside the tt-metalium container /opt/venv/bin/python3 once you’re in. Nothing on the host to activate
TT-Forge (TT-XLA) pip wheel in a venv you create Compile PyTorch/JAX models — install it yourself (see TT-Forge)

The important surprise is the third row. There is no TTNN environment on the host. You may find older notes pointing at ~/tt-metal/python_env/ — that path doesn’t exist on a QB2 and the installer never creates it. TT-Metalium arrives as a container image, and tt-metalium is the wrapper that puts you inside it with your home directory mounted. import ttnn works in there and nowhere else.

Why does this matter?

Ubuntu 24.04 enforces what’s called externally-managed Python — the system Python is protected. If you try to pip install something directly, Ubuntu will refuse with an error about breaking system packages. This is intentional. It protects you.

So when you need a Python package of your own, make it a new venv (python3 -m venv ~/.venvs/mine) or let uv tool / pipx make one for you. What you should not do is install into ~/.tenstorrent-venv to dodge the error. That venv exists to hold tt-smi and tt-flash, your QB2 activates it for you at login, and a dependency resolution gone wrong in there takes out the tools you’d use to work out what broke.

What which python3 tells you

Before running any Python code, check which Python is active:

which python3

If you see /usr/bin/python3 — you’re on the host, using Ubuntu’s Python. Tenstorrent imports will fail.

If you see /home/yourname/.tenstorrent-venv/bin/python3 — you’re in the tooling venv. tt-smi works; import ttnn still won’t.

If you see /opt/venv/bin/python3 — you’re inside the tt-metalium container, which is where TTNN lives. Go ahead.

pip, pyenv, uv — a brief map

You may encounter other Python tools in documentation or online:

For this guide: ignore pyenv. Reach for uv or pipx when you want a CLI of your own, and use tt-metalium when you want TTNN.

Map of Python environments on the QB2: system Python, the hardware-tooling venv, the TT-Metalium container, and Forge

Activating and deactivating

# Enter the TTNN environment — a container, not a venv
tt-metalium

# You're now in a shell inside the container, home directory mounted.
which python3          # → /opt/venv/bin/python3
python3 -c "import ttnn; print('TTNN ready')"

# Leave it the way you leave any shell
exit

There’s no (python_env) prefix to look for, because nothing is being activated — you’re in a different shell on a different filesystem. which python3 is the signal: /opt/venv/bin/python3 means you’re inside.

ℹ The first tt-metalium run pulls a multi-GB image. Later runs start immediately.
💡 The QB2 has pre-activation scripts in /etc/profile.d/ that activate ~/.tenstorrent-venv automatically at login — which is why tt-smi just works. Run which python3 before sourcing any venv to see what's already active; activating on top of an active venv is messy.
⚠️ tt-metalium: command not found? The wrapper lives in ~/.local/bin, which isn't on PATH in every shell — zsh never reads ~/.profile, where Ubuntu's default rule for it lives. Run export PATH="$HOME/.local/bin:$PATH" and add that line to ~/.zshrc. Same story for tt-studio and tt-forge.

Next: Is This Thing On? →

Chapter 3

Is This Thing On?

Before running a model, confirm the hardware is alive and the software can see it. One command, four chips, zero guessing.

Ask tt

tt device status
                 Tenstorrent devices (driver: TT-KMD 2.11.0)
┏━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━┓
┃ # ┃ Board ┃ Bus ID       ┃ Temp    ┃ Power  ┃ AIClk      ┃ Voltage ┃ DRAM ┃
┡━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━┩
│ 0 │ p300c │ 0000:01:00.0 │ 55.0 °C │ 74.0 W │ 1337.0 MHz │ 0.81 V  │ True │
│ 1 │ p300c │ 0000:02:00.0 │ 59.9 °C │ 49.0 W │ 1343.0 MHz │ 0.82 V  │ True │
│ 2 │ p300c │ 0000:03:00.0 │ 45.9 °C │ 13.0 W │ 800.0 MHz  │ 0.73 V  │ True │
│ 3 │ p300c │ 0000:04:00.0 │ 47.9 °C │ 18.0 W │ 800.0 MHz  │ 0.73 V  │ True │
└───┴───────┴──────────────┴─────────┴────────┴────────────┴─────────┴──────┘

Four rows, all p300c, all DRAM True: the machine is healthy. (If you get tt: command not found, see the PATH note in Install and Upgrade with tt.)

Two more tt commands answer the next questions:

tt device info      # board ids, PCIe speed and width, firmware versions, one column per chip
tt smi              # hands the terminal to the live tt-smi dashboard (q to quit)

tt device info shows the firmware bundle on each chip (fw.fw_bundle_version), which is the first thing support asks for. tt device status --json gives the same data as JSON, plus the host’s OS, kernel, memory and driver version, so scripts do not have to parse a table.

The rest of this chapter looks one level lower, at tt-smi, which tt runs for you. You need it for the raw fields, and when something is wrong and you are diagnosing.

Reading Your Hardware with tt-smi

tt-smi is the Tenstorrent System Management Interface. Your window into the chips. Run it in snapshot mode to get JSON instead of the interactive TUI:

tt-smi -s

A healthy QB2 returns four entries — one per Blackhole chip. The real shape is nested, not flat — board_info and telemetry are their own sub-objects:

{
  "device_info": [
    {
      "board_info": {
        "bus_id": "0000:01:00.0",
        "board_type": "p300c",
        "board_id": "0000046131924062",
        "dram_status": true,
        "pcie_speed": 4,
        "pcie_width": "4"
      },
      "telemetry": {
        "voltage": "0.72",
        "current": "23.0",
        "power": "16.0",
        "aiclk": "800",
        "asic_temperature": "40.3"
      },
      "firmwares": {
        "fw_bundle_version": "19.13.1.0"
      }
    }
  ]
}

board_type is the board SKU (p300c on a QB2), not a chip-family string — Blackhole doesn’t appear literally anywhere in the output. Four entries in device_info means four chips, all alive. Check it directly:

tt-smi -s | python3 -m json.tool | grep board_type

You should see "p300c" printed four times.

🌡️ Idle temperatures of 35–55°C are normal. Under full inference load, Blackhole chips run 70–85°C. The QB2 cooling system is sized for this. Hot chips doing real work is a good sign.
tt-smi -s showing four Blackhole chips on a QB2
tt-smi -s on a live QB2 — four Blackhole chips, JSON snapshot mode

Reading the Output

A healthy QB2 shows four entries in device_info. Look at each one for:

Count the entries:

tt-smi -s | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d['device_info']), 'devices')"

If you see 4 devices, move on. The QB2 is ready.

⚡ Chips enumerating means the hardware is alive — but the fastest proof it actually runs a model is the preloaded Qwen3-32B: launch tt-studio, pick it from the Deploy dropdown, and chat. No download. Full walkthrough in Your First Model.

If You See Fewer Than Four

A missing device usually means one of three things:

PCIe link not established:

sudo dmesg | grep -i tenstorrent | tail -20

sudo is required here — Ubuntu 24.04 restricts the kernel log buffer by default, and a plain dmesg fails with “read kernel buffer failed: Operation not permitted.” Look for errors about PCIe enumeration or firmware loading failure. A loose card is possible — the QB2 ships with cards seated, but transit happens.

Firmware mismatch:

tt-smi -s | python3 -m json.tool | grep -i fw_bundle_version

If firmware versions differ across devices, or show 0.0.0, you may need to reflash. See the tt-flash documentation for instructions.

Driver not loaded:

lsmod | grep tenstorrent

If nothing prints, the kernel driver isn’t loaded. This shouldn’t happen on a stock QB2, but if it does:

sudo modprobe tenstorrent
🔬 What tt-smi actually reads: The monitoring daemon talks to the chips via the kernel driver over PCIe. Temperatures come from on-chip thermal sensors. Power readings come from board-level current monitors. The data path: chip hwmon → kernel driver → tt-smi → your terminal. If a chip is missing from output, the driver never established a PCIe link to it.

Watching in Real Time

For a live view of all four chips while running inference:

tt-smi

This opens the interactive TUI — press q to quit. You’ll see per-chip utilization, temperature, and memory usage update live. Useful when a model is running and you want to see all four chips light up.

For something richer than the built-in TUI, tt-toplike renders the same telemetry as live ASCII art — every chip’s power, temperature, and DRAM state, animated:

tt-toplike host + chip view — live ASCII telemetry for the QB2 host and its four Blackhole chips
tt-toplike — the host and all four Blackhole chips, live telemetry as ASCII art
⬡ Tensix Grid — Blackhole (P100/P150/P300c / QB2)

This is what active inference looks like inside one chip. Four of these run in parallel on a QB2.

tt-smi -s on a live QB2 — four Blackhole chips, JSON snapshot output
tt-smi -s on a live QB2 — four Blackhole chips, JSON snapshot mode

Next: Installing the Stack →

Chapter 4

Install and Upgrade with tt

tt is the Tenstorrent command line. It is the single tool you use to install the software stack, keep it current, look at your hardware, serve models and connect apps to them. Under the hood it runs tt-installer, tt-smi, tt-flash, tt-inference-server and tt-studio for you, each at a version Tenstorrent has tested together.

A QB2 ships with the software already installed, so this chapter is mostly about upgrading. The same two commands install everything on a fresh Ubuntu machine.

See What You Have

tt --version
tt device status

If you get tt: command not found, ~/.local/bin is not on your PATH in this shell. Run uv tool update-shell (or add export PATH="$HOME/.local/bin:$PATH" to ~/.bashrc) and open a new terminal.

If tt --help does not list device, model, serve and update, another program named tt is earlier on your PATH. which -a tt lists every match in the order the shell tries them. Put ~/.local/bin first (export PATH="$HOME/.local/bin:$PATH"), or start a login shell with bash -l. A non-login shell, such as a plain docker run <image> bash -c '...', skips ~/.profile and can leave the other program in place.

tt device status lists one row per chip. A QB2 has four, on two p300 boards:

                 Tenstorrent devices (driver: TT-KMD 2.11.0)
┏━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━┓
┃ # ┃ Board ┃ Bus ID       ┃ Temp    ┃ Power  ┃ AIClk      ┃ Voltage ┃ DRAM ┃
┡━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━┩
│ 0 │ p300c │ 0000:01:00.0 │ 55.0 °C │ 74.0 W │ 1337.0 MHz │ 0.81 V  │ True │
│ 1 │ p300c │ 0000:02:00.0 │ 59.9 °C │ 49.0 W │ 1343.0 MHz │ 0.82 V  │ True │
│ 2 │ p300c │ 0000:03:00.0 │ 45.9 °C │ 13.0 W │ 800.0 MHz  │ 0.73 V  │ True │
│ 3 │ p300c │ 0000:04:00.0 │ 47.9 °C │ 18.0 W │ 800.0 MHz  │ 0.73 V  │ True │
└───┴───────┴──────────────┴─────────┴────────┴────────────┴─────────┴──────┘

In that capture, chips 0 and 1 were running a model (high power, 1.3 GHz clock) and chips 2 and 3 were idle (800 MHz). The clock column is the quickest way to see which chips are in use.

Preview an Upgrade

Tenstorrent publishes a golden set: the versions of the kernel driver, firmware, HugePages setup, tt-smi, tt-flash, tt-inference-server and tt-studio that have been tested together. tt update moves your machine onto it. Preview first. This changes nothing:

tt update --dry-run
  Update plan (goldens: bundled supplement.toml + golden.json v3.0.0 (cached))
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ component       ┃ kind     ┃ installed       ┃ golden           ┃ action     ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ tt-flash        │ uv-tool  │ 4.0.0           │ 4.0.0            │ up-to-date │
│ tt-inference-s… │ git-venv │ v0.25.0         │ v0.25.0          │ up-to-date │
│ tt-model        │ uv-tool  │ a7aa9cefdd3086… │ a7aa9cefdd3086b… │ up-to-date │
│ tt-smi          │ uv-tool  │ 6.6.0           │ 6.6.0            │ up-to-date │
│ tt-studio       │ git-venv │ —               │ v2.12.0          │ optional   │
│ system-stack    │ system   │ —               │ hugepages 1.4.1, │ converge   │
│                 │          │                 │ kmd 2.11.0, ...  │            │
└─────────────────┴──────────┴─────────────────┴──────────────────┴────────────┘

Read the action column:

Action Meaning
up-to-date Nothing to do.
install / update tt update will install or upgrade it.
optional Fetched the first time a command needs it (tt-studio here). Add --include-lazy to fetch it now.
converge The system layer (driver, firmware, HugePages) is checked and brought to the golden versions by tt-installer.

Upgrade

tt update

tt update runs in three phases: it checks the golden manifest, installs or upgrades the tools into isolated environments under ~/.local/share/tenstorrent/, and then downloads the matching tt-installer release and runs it. The last phase uses sudo, so it asks for your password. It also asks before flashing firmware, because flashing resets the devices. Stop any model you are serving first (tt model ps shows what is running).

Upgrade the tt command itself separately:

tt self update --check    # is there a newer release?
tt self update

On the QB2 used to test this guide, tt self update --check reported tt 1.2.1 is available (you have 1.2.0). tt update brings the system and its tools onto the golden set, and tt self update upgrades tt. Run both when you want to be current.

Firmware only moves forward. A plain tt update, with no --force and no version argument, flashes a device only when its firmware is older than the golden bundle. A box that is already ahead is left alone. --force, or naming an older installer version, is what allows a downgrade. Run tt update on the machine itself, not inside a docker run shell: it reloads the kernel driver and can install Docker through systemd.

Reboot after a first install, or if the driver changed. tt update never reboots for you. If it installed the kernel driver or changed the HugePages configuration, run sudo reboot before you serve anything. On a first install it also adds you to the docker group, which takes effect at your next login.

tt update ignores older copies of tools that a previous tt-installer run left in ~/.local/lib/ (for example tt-inference-server and tt-studio) and warns you about them. It manages its own pinned copies under ~/.local/share/tenstorrent/tools/. The warning prints the rm -rf commands that reclaim the space.

Installing on a Fresh Machine

You need Ubuntu 22.04 or 24.04, sudo, and a network connection. Install uv, then tt:

sudo apt update && sudo apt install -y python3 python3-venv python3-pip git curl ca-certificates
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"   # uv and tt install here; this makes them work in this terminal
uv tool install tenstorrent
uv tool update-shell        # puts ~/.local/bin on PATH for future terminals
tt update

The PyPI package is named tenstorrent. The unrelated tt-cli package on PyPI is a time tracker. tt update installs the kernel driver, firmware tooling and HugePages configuration as root, so reboot afterwards.

Using tt-installer Directly

tt update runs tt-installer for you, and for almost everyone that is the right way to use it. tt update <VERSION> runs a specific installer release instead (and implies --force, which allows downgrades). The installer’s own options, and the manual path it replaces, are covered in Installing by hand.

Check Your Work

tt --version
tt update --dry-run      # every row should say up-to-date
tt device status         # four rows, all DRAM True
tt model list            # models for your hardware

If tt device status shows fewer than four rows, go back to Is This Thing On? for the diagnosis steps.


Next: Serve a Model →

Chapter 5

Serve a Model

Four chips, one command. tt serve downloads or finds the weights, starts the model in a container, waits until it answers, and tells you the address. What you get is an OpenAI-compatible HTTP API running on your own hardware, which every chat app, coding agent and SDK already knows how to talk to.

This chapter serves Qwen3-32B, the model your QB2 shipped with. Its weights and compiled kernels are already on disk, so the first serve does not download 62 GB.

Pick the Model

tt knows which models run on your hardware:

tt model list

On a QB2 it detects a p300x2 configuration (two p300 boards, four chips) and lists the models that have a serving profile for it. tt model info tells you what a model needs and how well it is validated:

tt model info Qwen3-32B
┌─────────────────────┬────────────────────────────────────────────────────────┐
│ hf_repo             │ Qwen/Qwen3-32B                                         │
│ type                │ llm                                                    │
│ engines             │ vLLM                                                   │
│ via                 │ inference-server, studio                               │
│ servable            │ yes — `tt serve Qwen3-32B` (`--studio` deploys it with │
│                     │ TT-Studio)                                             │
│ parameters          │ 32B                                                    │
│ min disk            │ 84 GB                                                  │
│ min ram             │ 80 GB                                                  │
│ on p300x2           │ vLLM — FUNCTIONAL, max context 131072                  │
│ ...                 │                                                        │
└─────────────────────┴────────────────────────────────────────────────────────┘

Validation status goes EXPERIMENTAL, FUNCTIONAL, COMPLETE. FUNCTIONAL means it runs correctly and is not fully tuned. The status is per board, so check the p300x2 row.

Models worth starting with on a QB2

These have a p300x2 profile in the released catalog, from tt model list --catalog:

Model Kind Status on QB2 Why start here
Qwen3-32B LLM FUNCTIONAL Ships with the box. Weights and compiled cache are local.
Qwen3.8-27B LLM COMPLETE Fully validated chat and reasoning model, 262k context.
gemma-4-31B-it / gemma-4-12B-it LLM COMPLETE Fully validated, 262k context.
Llama-3.3-70B-Instruct LLM FUNCTIONAL The largest LLM in the catalog for this box.
FLUX.1-dev / FLUX.1-schnell Image COMPLETE Image generation.
whisper-large-v3 Audio COMPLETE Speech to text.
Wan2.2-T2V-A14B-Diffusers Video COMPLETE Text to video.

Gated models (Llama, Gemma) need you to accept the license on the model’s Hugging Face page first. The hf_repo line in tt model info names the page.

Log In to Hugging Face

Serving needs a Hugging Face token, even for models that are free to download, because tt-inference-server checks it before it starts. Log in once:

tt model login

Choose Log in with your browser (it shows a URL and a short code) or paste a read token from huggingface.co/settings/tokens. tt finds the token again on every later run, and tt serve --dry-run tells you where it came from without printing it.

Check That tt Will Reuse the Shipped Weights

Preview the serve before you run it. --dry-run starts nothing:

tt serve Qwen3-32B --dry-run
✓ Detecting device configuration  p300x2 (override with --device)
                    tt serve Qwen3-32B — dry run
┌──────────────────┬──────────────────────────────────────────────────────────┐
│ backend          │ tt-inference-server                                      │
│ workflow         │ server                                                   │
│ device           │ p300x2                                                   │
│ engines          │ vLLM                                                     │
│ status           │ FUNCTIONAL                                               │
│ docker image     │ ghcr.io/tenstorrent/tt-inference-server/vllm-tt-metal-…  │
│ tool-call parser │ hermes                                                   │
│ reasoning parser │ qwen3                                                    │
│ weights          │ /home/ttuser/data/tt-cache                               │
│                  │ pre-seeded volume — weights and tt_metal_cache reused;   │
│                  │ the HF cache is not consulted                            │
│ HF token         │ from the Hugging Face login store                        │
│ port             │ 20000  (server default)                                  │
└──────────────────┴──────────────────────────────────────────────────────────┘

Look at the weights row. pre-seeded volume means tt found the shipped weights and the compiled kernel cache, so the first start takes minutes and downloads nothing. If it says ~/.cache/huggingface instead, tt did not recognize the shipped directory and a real serve would download 62 GB. The fix is one symbolic link:

Magic of symlinks. tt looks for a volume named volume_id_tt_transformers-Qwen3-32B-v<version> (the version comes from the model spec; the dry run’s image tag shows it). The shipped directory on our QB2 ended in -vqb2_launch, so we aliased it:

ln -s ~/data/tt-cache/volume_id_tt_transformers-Qwen3-32B-vqb2_launch \
      ~/data/tt-cache/volume_id_tt_transformers-Qwen3-32B-v0.17.0

Re-run the dry run after every tt update; if it falls back to the Hugging Face cache, the version changed. Two more links are handy: ln -s .cache/huggingface/hub ~/models (run from your home directory, so the target is relative) for a short path to the Hugging Face cache (skip this one if you use the hf download --local-dir ~/models/... steps elsewhere in this guide, which want ~/models to be a real directory), and ln -s code/tt-metal ~/tt-metal so older instructions work. Make links relative and keep targets inside your home directory. Containers mount home at /home/user, so absolute links and links that leave home dangle inside them (a Hugging Face cache linking to a blob store outside the model directory failed this way).

Serve It

tt serve Qwen3-32B

tt serve shows the boot as a live checklist instead of thousands of log lines: host ready, weights ready, image ready, container started, engine started, device opened, KV cache configured, model warmed up, endpoint answering. It returns only once the endpoint answers, so whatever you run next will work. When it finishes you get a box with the endpoint (http://127.0.0.1:20000/v1) and the commands to look at logs and stop the model.

To watch the raw server log while it boots, run this in a second terminal:

tt model logs Qwen3-32B --follow

Pressing Ctrl-C in the tt serve terminal stops watching. The server is a separate container and keeps booting, and tt model stop Qwen3-32B ends it.

A first serve of a model you have not run before takes longer. The image (about 18 GB) and the weights are downloaded, then the model is compiled for your chips and warmed up. In the tt documentation, a first serve of a 27B model on a QB2 took about 15 minutes, 7 of them downloading weights. The shipped Qwen3-32B skips the download and the compile.

The endpoint has no password. In tt 1.2.1 and later, tt serve starts the server with authentication off, and the server’s default bind address is 0.0.0.0 (every network interface). Anyone who can reach port 20000 can use your model. Serve only on a network you trust or behind a firewall, and do not forward the port to the internet. To keep a server local-only, or to turn authentication on, run tt-inference-server yourself as shown in Serving Models on QB2.

Ask It a Question

tt model curl "Explain what an API is in one sentence." --max-tokens 2048

tt model curl asks the server which model it is serving, sends your prompt as a chat completion, and prints the JSON reply. The text is in choices[0].message.content. Unknown options become fields of the request, so --max-tokens 2048 sets max_tokens. Add --print to see the equivalent curl command.

Qwen3-32B is a reasoning model (the dry run above shows a qwen3 reasoning parser): it thinks first, in a separate reasoning field, and then answers in content. A small token budget can be used up by the thinking, so give it room when content comes back empty.

Pick prompts that do not depend on the model knowing about Tenstorrent. We asked Llama-3.1-8B “In one sentence, what is Tenstorrent?” and it replied with a confident, invented company history. Small models do not know recent or niche facts. That is a property of the model and says nothing about your hardware.

The same endpoint speaks the standard OpenAI API, so any client works. Note the model name: the server reports the full Hugging Face id, which differs from the short name you gave tt serve (for Llama-3.1-8B-Instruct we saw meta-llama/Llama-3.1-8B-Instruct).

curl -s http://localhost:20000/v1/models | python3 -m json.tool | grep '"id"'
curl -s http://localhost:20000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Qwen/Qwen3-32B",
    "messages": [{"role": "user", "content": "Explain what an API is in one sentence."}],
    "max_tokens": 2048
  }' | python3 -m json.tool

Manage What Is Running

tt model ps                    # what is served, on which port, and whether it is healthy
tt model logs Qwen3-32B        # the newest server log

Keep the model running for the next chapter. When you are finished with it, tt model stop Qwen3-32B stops it.

tt model ps shows every server tt started, including ones on other ports:

┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━┳━━━━━━━━┓
┃ name                  ┃ backend          ┃ container                    ┃ port  ┃ health  ┃ uptime ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━╇━━━━━━━━┩
│ Llama-3.1-8B-Instruct │ inference-server │ tt-inference-server-162a825f │ 20000 │ healthy │ 5m     │
└───────────────────────┴──────────────────┴──────────────────────────────┴───────┴─────────┴────────┘

healthy means the server answers GET /v1/models. starting means the container is running and not answering yet. tt model stop stops only the named model’s container.

Serving on Half the Machine

A QB2 is two p300 boards. A model with a p300 profile uses one board (two chips). For example, Llama-3.1-8B-Instruct has a p300 profile:

tt serve Llama-3.1-8B-Instruct --device p300 --dry-run

Use --device to override what tt detected. tt serve does not let you choose which board: the container is given every Tenstorrent device node on the machine, so run a half-machine model only when nothing else is using the chips. How to pin a server to specific chips is in Serving Models on QB2.

What Just Happened

tt serve ran tt-inference-server, which started a container holding vLLM and the Tenstorrent plugin. The container opened a mesh across your chips, loaded the weights into device memory, compiled and warmed up the kernels, and published the API. The detail of each stage, and how to run tt-inference-server yourself, is in Serving Models on QB2.


Next: Launch Software →

Chapter 6

Launch Software

An API endpoint is the foundation. tt launch connects a ready-made application to the model you are already serving, so you can use it without copying a URL into a settings page. You do not tell the app where the model is: tt asks every server it started what it serves (GET /v1/models) and configures the client from the answer.

Keep the model from the last chapter running, and see what you can connect:

tt launch list
┏━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ client      ┃ kind        ┃ model          ┃ status         ┃ configures                           ┃
┡━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ opencode    │ terminal    │ tool calling   │ needs opencode │ ~/.config/opencode/opencode.json     │
│ pi          │ terminal    │ tool calling   │ needs pi       │ ~/.pi/agent/models.json              │
│ aider       │ terminal    │ tool calling   │ needs aider    │ environment (this run only)          │
│ qwencode    │ terminal    │ tool calling   │ ready          │ command-line arguments (this run…)   │
│ hermes      │ terminal    │ tool calling   │ ready          │ environment (this run only)          │
│ openwebui   │ web service │ any chat model │ stopped        │ container tt-open-webui              │
│ anythingllm │ web service │ any chat model │ ready          │ container tt-anythingllm             │
└─────────────┴─────────────┴────────────────┴────────────────┴──────────────────────────────────────┘

There are two kinds of client, and the difference is who installs them:

The status column says what is missing: needs opencode means the agent is not installed, ready means it can launch now, and stopped is a web UI container that exists and is not running.

A Chat Window in Your Browser

tt launch openwebui --dry-run     # show what would happen, change nothing
tt launch openwebui

The dry run prints what tt found and what it will do:

┌───────────────────────┬───────────────────────────────────────────────────────────┐
│ model                 │ meta-llama/Llama-3.1-8B-Instruct  (Llama-3.1-8B-Instruct) │
│ endpoint              │ http://127.0.0.1:20000/v1                                 │
│ tool-call parser      │ llama3_json                                               │
│ container             │ tt-open-webui (stopped)                                   │
│ image                 │ ghcr.io/open-webui/open-webui:main                        │
│ endpoint in container │ http://host.docker.internal:20000/v1                      │
│ open                  │ http://localhost:3000                                     │
└───────────────────────┴───────────────────────────────────────────────────────────┘

The first time, tt asks before it pulls the image (a few GB) and runs it as tt-open-webui. It waits until the page answers and prints tt-open-webui is ready at http://localhost:3000. Open that address in a browser. The container is configured with your endpoint (OPENAI_API_BASE_URL=http://host.docker.internal:20000/v1), so its model list comes from your server.

If two models are being served, say which one: tt launch openwebui --model Qwen3-32B. Web UIs start on port 3000, or the next free port above it; --web-port 3080 asks for another. When you are done:

tt launch stop openwebui      # stops the container, keeps your chats and settings

Open WebUI starts with sign-in turned off (WEBUI_AUTH=False), and anyone who can reach port 3000 can read your chats and use the model. To chat from a laptop, tunnel the port and keep it private: ssh -L 3000:localhost:3000 <you>@<your-QB2-address>, then browse to http://localhost:3000. A tunnel does not close the port on the QB2 itself, so use this only on a network you trust or behind a firewall.

A Coding Agent in Your Terminal

Terminal agents work on your files, so they need a model that can call tools. Qwen3-32B can, with one caveat:

Qwen3-32B thinks first, and that can drop tool calls. With thinking on, a reasoning model sometimes ends a turn without making the tool call the agent asked for. In a test on the cloud Qwen3-32B deployment, 8 of 20 runs did this (tt-inference-server issue #4386, still open when we checked). We have not verified how tt launch clients behave against a local Qwen3-32B. If an agent stalls or answers without acting, send chat_template_kwargs: {"enable_thinking": false} with the request if your client lets you add request fields, or serve a model without a reasoning mode, such as Llama-3.1-8B-Instruct.

Faster agent models come from the community catalog. The fastest tool-calling models on a QB2 are mixture-of-experts coders with 3B parameters active per token, published as community bundles: raahemnabeel/qwen3-coder-30b-a3b and raahemnabeel/qwen3-coder-next, both with the qwen3_coder tool parser and no thinking mode. Measured on 2026-10-30 on one P300 board: 80 tok/s and 107 tok/s on a real prompt, against about 8 seconds a response for As an alternative to the model from the last chapter, stop it first (tt model stop Qwen3-32B), then serve one with tt serve raahemnabeel/qwen3-coder-30b-a3b --profile p300x2 (see The Model Zoo for the warning that applies to every bundle). tt launch finds it the same way. It prints not in the model catalog and shows tool-call parser — because it has no catalog row to check; the bundle’s card and tt serve <bundle> --dry-run show the parser is set. We ran tt launch qwencode --dry-run and a smolagents task against Qwen3-Coder-Next this way; the task was answered in one 2 s step.

Install one agent, then launch it. Qwen Code and Hermes Agent were ready in the listing above:

tt launch qwencode --dry-run
┌──────────────────┬───────────────────────────────────────────────────────────┐
│ model            │ meta-llama/Llama-3.1-8B-Instruct  (Llama-3.1-8B-Instruct) │
│ endpoint         │ http://127.0.0.1:20000/v1                                 │
│ tool-call parser │ llama3_json                                               │
└──────────────────┴───────────────────────────────────────────────────────────┘

commands:
qwen --auth-type openai --openai-api-key tt-local --openai-base-url http://127.0.0.1:20000/v1 --model meta-llama/Llama-3.1-8B-Instruct

The dry run shows the exact command tt launch runs: your agent, pointed at your endpoint, with no cloud account. Run it without --dry-run to start the agent.

Client Install it first What tt launch writes
opencode opencode.ai/docs A tenstorrent provider in ~/.config/opencode/opencode.json
pi github.com/earendil-works/pi A tenstorrent provider in ~/.pi/agent/models.json
aider aider.chat/docs/install Nothing on disk (environment variables, this run only)
qwencode Node.js 22+, then npm install -g @qwen-code/qwen-code Nothing on disk (command-line arguments)
hermes hermes-agent.nousresearch.com/docs Nothing on disk (environment). --web opens its browser dashboard

tt shows what it will change and asks before writing a config file. tt launch disconnect opencode removes what it wrote.

Claude Code with Tenstorrent skills

The development version of tt (after release 1.2.1) adds tt agent, which sets up Claude Code with the plugins from the tenstorrent/skills marketplace for what you are doing today (deploy, bringup or develop) and starts it. Preview with tt agent deploy --dry-run. Check tt --help for an agent entry to see whether your release has it.

Prefer Point and Click? TT-Studio

TT-Studio serves the model and provides its own web interface. You start it with tt serve --studio, not tt launch:

tt model stop Qwen3-32B        # TT-Studio takes the chips and port 3000 for itself
tt serve Qwen3-32B --studio

On first use tt fetches the latest TT-Studio release, and TT-Studio asks you to accept its terms. It prints a TT Studio is ready box with its address, http://localhost:3000. Stopping the model with tt model stop Qwen3-32B also takes TT-Studio’s services down and keeps your settings and chat history. Start TT-Studio before any tt launch web UI, since both want port 3000 and only the web UIs move when it is taken.

Check Your Work

tt model ps               # your model is healthy
tt launch list            # your chosen client is ready or connected
tt launch stop openwebui  # clean up the web UI when you are done
tt model stop Qwen3-32B   # and the model

Next: What Comes Next →

Chapter 7

What Comes Next

You unboxed a machine that most people have never touched. You confirmed four Blackhole chips were alive, upgraded the software with tt update, served a model with tt serve, asked it a question, and connected an app to it with tt launch. That is the whole loop, and you ran it on your own hardware.

The rest is up to you.

Inference stack diagram showing the path from user interfaces through tt-inference-server and vLLM down to four Blackhole chips

Tools in Your World

The QB2 ships with a full stack, but the ecosystem is bigger. Start with tt-toplike — htop for your chips, except the telemetry comes alive as ASCII art:

tt-toplike insights mode — live ASCII visualization of all four Blackhole chips during inference
tt-toplike insights mode — all four Blackhole chips under live inference, power and DRAM state rendered in real time

Where to Go From Here

Pick a thing you want to do and jump straight in.

Choose Your Next Track

Run & build →
Serve real models. Understand performance. Integrate with your existing ML workflow. If you're coming from CUDA, this is where the familiar parts live and where the new parts pay off.
Tinker →
Write code that runs on the chips directly — kernels, data movement, compute pipelines. The architecture goes all the way down and you can follow it.
Customize →
Customize, illuminate, break, and fix things. The LEDs, the desktop, the demos that make people stop and ask what that machine is.

The QB2 is a beginning. There’s a lot of surface area here, and you’ve only scratched it.


← Back to Explore