Skip to the content.

Validation record

Validated locally on 2026-09-13, Linux amd64. Account payloads, API keys, IPC passwords, and generated two-factor codes are intentionally absent from this report.

Automated checks

Test coverage includes form/query placement, Unicode/repeated parameters, lossless large JSON integers, authenticated ASF command bodies, application-level failures, offline network prevention, URL/path validation, cross-host redirect rejection, secret-safe errors, response limits, GET-only retries, per-key schema cache isolation, configuration precedence, VDF parsing, ID conversions, archive traversal/escaping links/duplicates and deferred safe framework links, bootstrap checksums/idempotency, argument preservation/order, success marker streaming, app manifest validation, process exit propagation, and Unix batch cancellation.

The test suite uses local HTTP servers, temporary directories, and small fake subprocesses. An optional STEAM_CLI_TEST_ARCHIVES fixture test audits previously downloaded official archives without executing their contents. It needs neither a Steam account nor ASF service. Hosted native-OS CI is supplied but has not been executed in this workspace.

Live integration checks

Check Result
Public Steam server information, no key Passed
Authenticated Steam GetSupportedAPIList Passed: 54 interfaces, 169 method/version entries
Offline catalog filtering after online discovery Passed
Authenticated player summaries, helper and discovered call Passed; payload discarded
Raw IPlayerService/GetOwnedGames using input_json Passed; payload discarded
ASF instance 1: authenticated status, named bot read, OpenAPI Passed; ASF 6.3.10.1, 46 schema paths
ASF instance 2: authenticated status, named bot read, OpenAPI Passed; ASF 6.3.10.1, 46 schema paths
SteamCMD Linux bootstrap from Valve CDN Passed
Actual Windows/macOS bootstrap archive extraction on Linux Passed, including four macOS framework symlinks; no foreign executable launched
SteamCMD first-run self-update and quit Passed; Valve client version 1788292693
SteamCMD anonymous app 1007 download with validation Passed; 107,911,652 bytes reported by Valve
SteamCMD repeat validation in the requested installation directory Passed
Download manifest check Matching app 1007, StateFlags marks fully installed
Local Steam library scan, offline Passed: one library, four apps, zero warnings
Offline SteamID conversion Passed

ASF checks used the user-supplied LAN services on port 1242 with the password in the Authentication header. Only read-only endpoints were exercised; bot start/stop/pause, commands that change state, key redemption, trades, and token generation were not run against the user’s accounts.

The test SteamCMD runtime and downloaded redistributable are retained under ignored .references/runtime/. The CLI did not replace or install over the desktop Steam executable. Valve’s own runtime also wrote its standard Steam logs outside that directory, so the managed installation should not be mistaken for an OS sandbox.

Remaining validation boundaries


Validation record: workshop and status remediation

Validated on 2026-09-14, Linux amd64, after the audit of the status and workshop features.

Automated checks

Package Before After
internal/status 1.2% 91.1%
internal/workshop 33.5% 88.7%
internal/community new 89.4%
internal/cli 44.2% 58.3%
internal/webapi 56.7% 60.7%

The previous internal/status suite contained a TestFetchPlayerCount that never called fetchPlayerCount; it could not, because the probes hardcoded Valve’s hostnames. Probe endpoints are now injectable and the function is tested against a fixture server.

New coverage includes: EResult interpretation from both the x-eresult header and the response body, including the silent-success case; per-item batch outcomes where one item succeeds and another is refused; collection membership add/remove against a fixture Community server; CSRF double-submit (the sessionid cookie and form field must agree); expired-session detection via login redirect; cursor pagination including a server that repeats a page; workshop ACF parsing against a manifest whose item blocks contain sizes, timestamps, manifest IDs and ugchandles that must not be mistaken for item IDs; and the refusal paths that report a missing Community session instead of a false success.

Live integration checks

Check Result
status --output raw, full probe set Passed; 4 endpoints, 8 player counts, CS2 coordinator with matchmaking and 30+ datacenter regions, 5 CMs
Steam Help returning HTTP 302 Classified normal; the host is serving traffic
workshop installed 107410 Passed; 191 items, matching an independent block-level parse of the same manifest
workshop collection 3052582377 Passed; title and 47 children
workshop search 4000 "car" Passed; 129,656 total, cursor-paged
workshop search-collections 4000 "weapons" --all Passed; walked ~49 cursor pages, 968 of 1,007 returned
workshop search --page 4 Passed; returns results past the depth where page-based paging is capped
Session-required commands without a cookie Passed; each names STEAM_LOGIN_SECURE and exits nonzero
delete-collection without --yes Passed; refuses

Remaining validation boundaries

Addendum, 2026-09-14: binary rename, client, --bots, --output parsed

Addendum, 2026-09-14: default output

--output auto became the default, with -o as shorthand. Verified live: status renders its full report with no flags, library, id, doctor, workshop collection, search, subs, installed and the batch summaries render as tables, and asf token reduces to the bare code.

Making the ASF reduction automatic initially broke asf bots and asf status, which were flattened to their envelope message and lost the data being asked for. asf.Parse now claims a payload only when each entry carries a scalar result or a message, and reports anything else as unparsed so it prints whole; asf bots gained its own table. Both directions are covered by tests, including that a bot listing is never reduced to A: OK.

--output raw on status still renders the report rather than JSON: emit is only given values this CLI assembles, never server bytes, so raw has no other meaning there and the pre-existing behaviour is preserved.

This is a breaking change for scripts that parsed the previous JSON default; -o json restores it. Tests that parse output were updated to request it explicitly.


Addendum, 2026-09-15: audit of the 0.8.0 work

Reviewed 18 commits adding info, apps, search, library custom/--sort, styled tables with colour, CSV output, and logged-in-user auto-detection. Build, go vet and the suite passed on arrival; the following were corrected.

Coverage moved 71.9% → 69.2% with 2,695 lines added; internal/library fell to 47% and gained tests only for the redaction added here. Raising coverage on the new info, apps and search code remains outstanding.

Refactoring pass

After the defect fixes above, the following structural problems were addressed.

Coverage: internal/library 47% → 83.8%, internal/cli 63.9% → 67.2%, project 69.2% → 72.6%, above the 71.9% that preceded this round of work.

The ASF memory conversion was checked against a live instance: 182,319 KB reported by ASF renders as 178.1 MiB, matching its OpenAPI schema’s KB unit.

steamcli server (Game Servers)

Added a command set mirroring the client’s Game Servers dialog. Verified live:

Check Result
server browse "counter-strike 2" --not-empty Passed; name resolved to AppID 730, 5 servers, busiest first
server info <addr> --players Passed against a live CS2 server: map, 16/64, version, OS, ping, scoreboard
server favorites Passed; 19 entries read from the client’s own file
server history Passed; 94 entries
server favorites --refresh Passed; 1 of 19 servers from 2018 still answering
server add / remove round trip Passed on a copy of the real file: 19 → 20 → 19, history untouched, all 226 entries preserved, backup written
server lan Ran; nothing answered on this network

A panic in the A2S library was found and contained. go-a2s indexes into replies without always checking length, and a truncated challenge from one of the stale favourites crashed the process mid-listing. Server replies are untrusted input from arbitrary hosts, so every entry point into the library now recovers and returns an error for that address instead. Found only by querying real servers; a fixture would not have produced it.

Not exercised: server connect (it launches the desktop client and joins a game), and writes against the live file while Steam is running — the commands detect a running client and warn that it will overwrite the file on exit.

Provenance drift

go-pretty, go-runewidth, uniseg and golang.org/x/text were vendored into the binary without being recorded in docs/THIRD_PARTY.md, the same class of gap as the embedded xPaw catalog. All four are now documented, the bundled licence file regenerated, and internal/meta holds a test that fails when a module in go.mod is missing from the document.

2026-09-15 Claude handoff audit

See the audit for findings and scope. Final go test -race ./..., go vet ./..., formatting, and git diff --check passed. New regression tests cover strict VDF rejection/round-trips, secure backup retention, concurrent-writer exclusion, account selection, root aliases, symlinked tool discovery, launch/DLC/branch/compatibility writers, CLI write refusal and redaction, branch-download argument construction, server editing and unknown-field preservation, and failed CM discovery.

STEAMCLI_AUDIT_ROOT opt-in validation parsed and rewrote eight real configuration/manifest files on temporary copies only. Local read-only checks passed for compatibility tools, SteamVR branch/DLC metadata and branch-download dry-run. Public HTTP checks returned Store/Community/Web API 200 and Help 302; the live player-count request succeeded. No real Steam configurations, subscriptions, favorites or game files were changed.

The final source cross-built CGO-free for Linux, macOS and Windows on amd64 and arm64. A separate vendored build with GOPROXY=off, GOSUMDB=off and the already installed compiler passed. The local binary is 0.10.0-dev; these are local development artifacts, not a published release. Native macOS/Windows process inspection was cross-compiled but not executed here. Real branch downloads and Steam’s adoption of edited DLC/branch preferences were not exercised; the tests use temporary files, and SteamCMD’s existing validation is reused.

2026-09-16 native Steamworks SDK

Read ai history --workspace /run/media/system/Data/Projects/steam-cli and ai handoff, including the newer Antigravity handoff. Preserved its account, workshop and ASF changes; corrected its native idle integration to pass the runtime path, require a successful initialization acknowledgement, stay alive independently of stdin, and shut down through a private control file instead of killing an unverified PID.

See SDK usage and limitations. No achievements, stats, workshop content, account settings or game files were modified by the live checks. Brief SDK initialization may update Steam’s running-app presence.