steamroom-cli 0.2.0

Command-line tool for downloading Steam depot content
Documentation
# steamroom

Utilities for interacting with Steam's API

## History

This project is a **cleanroom** reimplementation of [DepotDownloader](https://github.com/steamre/depotdownloader).

I originally used an LLM to translate DepotDownloader to Rust, and put all of that [DepotDownloader-rs](https://github.com/landaire/depotdownloader-rs). However, I realized that GPL licensing is a pain in the ass for Rust projects because of static linking, and decided to do the following:

1. Generate docs for the conversion library
2. Delete the source code from the docs
3. Copy that + the file tree and old `ddl` binary to a new repo
4. Instruct a new LLM session how to reverse engineer steam (using Binary Ninja MCP + Steam libs loaded)
5. Told it to reimplement it to the API spec
6. ???
7. 4 Hours later, we're GPL-free

Any major improvements done to this library should, in spirit of collaboration, be shared back to the SteamRE/DepotDownloader project in the spirit of advancing everyone's capabilities.

Not to air my personal grievances with GPL in this README, but DepotDownloader has been a godsend for many projects and I do believe in the spirit of upstreaming changes you make to libraries you use. I don't like the idea of GPL infecting things which statically link against the library, however. And that is the only reason why this library exists as a cleanroom reimplementation.

## Install

```bash
cargo install --path crates/steamroom-cli
```

## Quick Start

```bash
# Download Spacewar (free game, no login required)
steamroom download --app 480 --depot 481 -o spacewar/

# Download with authentication (prompts for password + 2FA)
steamroom --username myaccount download --app 440 -o tf2/

# QR code login (scan with Steam mobile app)
steamroom --username myaccount --qr download --app 440 -o tf2/

# Use a saved token (auto-detected from ~/.depotdownloader/tokens.json)
steamroom --username myaccount download --app 440 -o tf2/
```

## Commands

### `download`

Download depot content to a local directory.

```bash
# Basic download
steamroom download --app 480 --depot 481 -o output/

# Specific manifest version
steamroom download --app 480 --depot 481 --manifest 3183503801510301321 -o output/

# Download a specific branch
steamroom download --app 480 --depot 481 --branch previous -o output/

# Filter files by regex
steamroom download --app 480 --depot 481 --file-regex '\.dll$' -o output/

# Filter files by list
steamroom download --app 480 --depot 481 --filelist files.txt -o output/

# Verify existing files (skip up-to-date, re-download changed)
steamroom download --app 480 --depot 481 --verify -o output/

# Control parallelism
steamroom download --app 480 --depot 481 --max-downloads 16 -o output/
```

### `info`

Show app metadata, depots with sizes, and branches.

```bash
steamroom info --app 730

# Filter depots by OS
steamroom info --app 730 --os linux

# Include redistributable depots
steamroom info --app 730 --show-all

# JSON output for scripting
steamroom info --app 730 --format json
```

Example output:

```
App ID:  730
Name:    Counter-Strike 2
Type:    Game

Depots:
  ID        CONFIGURATION          SIZE          DL.
  2347770   64-bit            50.44 GiB    42.93 GiB
  2347771   Windows            7.07 GiB     5.05 GiB
  2347772   macOS              9.06 KiB     1.66 KiB
  2347773   Linux, 64-bit      6.62 GiB     4.71 GiB
  2347774   64-bit          1023.01 MiB   843.02 MiB
  ...

Branches:
  NAME               DESCRIPTION                           BUILD      TIME BUILT    TIME UPDATED
  animgraph_2_beta   Animgraph 2 Beta                      22720547   2d ago        2d ago
  1.41.4.1           1.41.4.1                              22627914   9d ago        9d ago
  public                                                   22627914   9d ago        9d ago
  1.41.4.0           1.41.4.0                              22370414   26d ago       26d ago
  ...
```

### `manifests`

List depot manifest IDs for a branch.

```bash
steamroom manifests --app 480
steamroom manifests --app 480 --branch previous
steamroom manifests --app 480 --format json
```

Example output:

```
Manifests for branch 'public':

  depot 229006   -> --
  depot 481      -> 3183503801510301321
```

### `save-manifest`

Download and save a depot manifest without downloading content. Saves the raw CDN response (`.zip`), decompressed manifest (`.manifest`), and depot key (`depot.json`).

```bash
# Save latest manifest
steamroom save-manifest --app 552990 --depot 552993 -o manifests/

# Save a specific manifest version
steamroom save-manifest --app 552990 --depot 552993 --manifest 6791242355553147175 -o manifests/
```

### `files`

List files in a depot manifest.

```bash
steamroom files --app 480 --depot 481

# Plain output (one filename per line, for piping)
steamroom files --app 480 --depot 481 --format plain

# Raw byte sizes
steamroom files --app 480 --depot 481 --bytes

# JSON output
steamroom files --app 480 --depot 481 --format json

# Read from a local manifest file (key auto-detected from depot.json)
steamroom files --manifest-file manifests/.depotdownloader/manifests/552993_123.manifest --depot 552993

# Explicit depot key (hex)
steamroom files --manifest-file path/to/552993_123.manifest --depot-key a4ac589393a2c8679c1f99b2e6fcee10554c030a0a6bf69bd4e22a13da7aab55

# Show raw encrypted filenames (no key needed)
steamroom files --manifest-file path/to/552993_123.manifest --raw
```

Example output:

```
Depot:    481
Manifest: 3183503801510301321
Created:  2019-02-06 21:51:33 UTC
Size:     1.82 MiB
Files:    8

FILENAME                          SIZE   CHUNKS
DejaVuSans.txt                2.76 KiB        1
sdkencryptedappticket.dll   558.28 KiB        1
DejaVuSans.ttf              703.96 KiB        1
installscript.vdf                514 B        1
steam_api.dll               219.78 KiB        1
SteamworksExample.exe       374.00 KiB        1
controller.vdf                1.53 KiB        1
D3D9VRDistort.cso                576 B        1
```

### `diff`

Compare two manifests and show added, removed, and changed files.

```bash
steamroom diff --app 480 --depot 481 --from 3183503801510301321 --to 8271816315493618441
steamroom diff --app 480 --depot 481 --from 3183503801510301321 --to 8271816315493618441 --format json
```

### `packages`

Query Steam package (sub) details by ID.

```bash
steamroom packages 17906
steamroom packages 17906 29197 --format json
```

### `workshop`

Download Steam Workshop items.

```bash
steamroom workshop --app 440 --item 123456789 -o workshop/
```

### `local-info`

Show locally cached depot keys and beta branches from Steam's config.vdf.

```bash
steamroom local-info
steamroom local-info --format json
steamroom local-info --users
steamroom local-info --user myaccount
```

## Daemon mode

`steamroom` can run as a background daemon that holds an authenticated Steam session and
services CLI invocations over a local socket. Reusing the session avoids the per-command
CM discovery, handshake, and logon round trip, so repeated commands run faster.

The daemon authenticates either at launch, when `daemon start` is given auth flags, or
lazily on its first job, when started without them (using an auto-detected saved token, or
anonymous). It serves one account for its lifetime; to switch accounts, stop and restart
it. It reconnects if the CM connection drops.

```bash
# Start a daemon. With auth flags it logs in now; without them it logs in
# lazily on the first job.
steamroom --username myaccount daemon start
steamroom daemon start

# Route commands through the daemon. If none is running, --use-daemon
# starts one in lazy auth mode first.
steamroom --use-daemon info --app 730
steamroom --use-daemon download --app 480 --depot 481 -o spacewar/

# Jump the queue.
steamroom --use-daemon --priority info --app 730

# Submit without waiting, then reattach by job id.
steamroom --use-daemon --detach download --app 480 --depot 481
steamroom daemon attach <job-id>

# Observe.
steamroom daemon status              # ratatui dashboard
steamroom daemon status --text       # one-shot text snapshot
steamroom daemon status --format json
steamroom daemon info                # pid, socket, and stop command

# Stop.
steamroom daemon stop
steamroom daemon stop --force        # cancel the active job too
```

Job history persists across restarts, so `daemon status` and `daemon attach` can see jobs
from earlier daemon runs.

Auth flags (`--username`, `--password`, `--qr`, `--use-steam-token`, `--remember-password`,
`--device-name`) and `--capture` are ignored, with a warning, under `--use-daemon`; the
daemon serves the account it authenticated as. Set them on `daemon start` instead.

## Authentication

steamroom supports multiple authentication methods:

| Method         | Flag                        | Notes                                            |
| -------------- | --------------------------- | ------------------------------------------------ |
| Anonymous      | (none)                      | Works for free games                             |
| Password       | `--username X --password Y` | Prompts if password omitted                      |
| Password + 2FA | `--username X`              | Prompts for guard code                           |
| QR code        | `--username X --qr`         | Scan with Steam mobile app                       |
| Saved token    | `--username X`              | Auto-loads from `~/.depotdownloader/tokens.json` |
| Steam token    | `--use-steam-token`         | Reuses cached token from local Steam installation |

Tokens are saved automatically after successful login and reused on subsequent runs.

## Legacy Compatibility

Set `DD_COMPAT=1` to use single-dash arguments compatible with the original DepotDownloader:

```bash
DD_COMPAT=1 steamroom -app 480 -depot 481 -dir output/ -validate
```

## Features

- TCP and WebSocket CM transports
- HTTP/2 multiplexed chunk downloads with CDN server pool rotation
- Chunk-level delta downloads (only fetches changed chunks via Adler-32 comparison)
- Local Steam credential reuse (`--use-steam-token`) on Windows, Linux, and macOS
- Local depot key and beta hash reuse from Steam's config.vdf (`--local-keys`)
- Manifest diff, package queries, manifest-only download, local manifest reading
- Non-atomic write mode for direct chunk-to-file writes
- Serde deserializer for Valve KeyValue format
- C/C++ FFI bindings via Diplomat, Python bindings via nanobind
- Proto extraction tool for steamclient64.dll
- Fuzz targets for binary parsers

## Architecture

```
steamroom              — Core Steam protocol: crypto, connection, transport, depot, messages
steamroom-client       — High-level: download orchestration, manifest cache, credentials
steamroom-cli          — CLI binary (produces `steamroom` executable)
steamroom-ffi          — C/C++ FFI bindings via Diplomat
steamroom-proto-extract — Tool to extract protobuf definitions from Steam binaries
```

## Benchmarks

Compared against [DepotDownloader](https://github.com/SteamRE/DepotDownloader) v3.4.0 (C#/.NET) using [hyperfine](https://github.com/sharkdp/hyperfine). Anonymous login, Windows 11, same network.

| Benchmark                     | steamroom     | DepotDownloader | Speedup  |
| ----------------------------- | ------------- | --------------- | -------- |
| App info query (480)          | 0.67s ± 0.06s | 2.85s ± 1.02s   | **4.3x** |
| File listing (480/481)        | 1.67s ± 0.06s | 3.34s ± 1.01s   | **2.0x** |
| Download Spacewar (1.8 MB)    | 1.23s ± 0.14s | 4.04s ± 0.16s   | **3.3x** |
| Download CS2 content (2.5 GB) | 23.6s         | 32.1s           | **1.4x** |

Both tools are network-bound for large downloads. Results will vary by network and hardware. Run `bench/run.sh` to reproduce on your own setup.

<details>
<summary>Reproduce benchmarks</summary>

```bash
# Build release
cargo build --release -p steamroom-cli

# Run with hyperfine (clean state each run to prevent resume skew)
hyperfine --min-runs 3 -N \
  --prepare "rm -rf /tmp/sr /tmp/dd" \
  -n steamroom "steamroom download --app 480 --depot 481 -o /tmp/sr" \
  -n DepotDownloader "DepotDownloader -app 480 -depot 481 -dir /tmp/dd"
```

Or use the included benchmark script with nix:

```bash
nix develop
./bench/run.sh /path/to/scratch
```

</details>

See [FEATURES.md](FEATURES.md) for a full feature comparison.

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE]LICENSE-APACHE)
- MIT License ([LICENSE-MIT]LICENSE-MIT)

at your option.