asset-cli normalizes Habbo asset storage. Raw asset dumps (Flash-era c_images/dcr exports, bundled Nitro packages, ad-hoc repacks) each tend to grow their own deeply-nested, inconsistently-named folder layout, full of ambiguous numeric names. asset-cli defines one canonical MinIO bucket layout — documented in docs/wiki/STRUCTURE.md — and gives you commands to check a bucket against it and repair what is missing, instead of auditing folders by hand in the MinIO console.
Functionality is organized as independent realms: small, transport-agnostic domains under internal/<realm>/, each exposing its capabilities through a Go interface (its port) and its own Cobra commands. This keeps a realm's logic reusable from the CLI or any future transport without change. Current realms cover bucket structure, clothing, effects, furniture, pets, aggregate statistics, and emulator synchronization. Under the hood this is Cobra command wiring, a MinIO object storage adapter, Uber Fx dependency injection, and structured Zap logging, validated by a real-process E2E harness. The tool is stateless: every invocation parses configuration, runs one command, and exits.
cp .env.example .env
go run ./cmd version
go run ./cmd structure check
go run ./cmd clothing check
go run ./cmd effects check
go run ./cmd furniture check
go run ./cmd pets check
go run ./cmd stats orphanASSET_CLI_MINIO_ENDPOINT, ASSET_CLI_MINIO_ACCESS_KEY, ASSET_CLI_MINIO_SECRET_KEY, and ASSET_CLI_MINIO_BUCKET are mandatory for any command that touches storage — every command except version.
structure— verifies and repairs the bucket's expected folder layout (seedocs/wiki/STRUCTURE.mdfor the full canonical tree and the reasoning behind it).asset-cli structure checkprints every expected path asokormissingand exits non-zero if anything is missing.asset-cli structure createcreates a placeholder object for every missing expected path so it renders as a folder in the MinIO console.
clothing— compares.nitrofiles underavatar/clothing/with the library IDs declared bygamedata/FigureMap.json.asset-cli clothing checkwarns about unreferenced bundles and exits non-zero when a declared library has no bundle.
effects— compares.nitrofiles underavatar/effects/with the library names declared bygamedata/EffectMap.json.asset-cli effects checkwarns about unreferenced bundles and exits non-zero when a declared effect library has no bundle.
furniture— compares.nitrofiles underfurniture/bundles/with classnames fromgamedata/FurnitureData.json.asset-cli furniture checknormalizes*Ncolor variants, warns about unreferenced bundles, and exits non-zero for missing bundles.
pets— compares.nitrofiles underpets/with Nitro's protocol-ordered standard pet asset names.asset-cli pets checkpermits custom bundles as warnings and exits non-zero when a standard pet asset has no bundle.
stats— reports.nitrototals and bundle/catalog integrity summaries.asset-cli stats nitrocounts clothing, effects, furniture, and pet bundles.asset-cli stats orphanchecks all four categories concurrently and reports matched, orphaned, and missing totals.
sync— reconcilesFurnitureData.jsoninto the selected emulator's furniture definition table.asset-cli sync furniture checkis read-only.asset-cli sync furniture applyis a dry run unless--yesis passed.
Clothing and effects intentionally have no emulator apply: Arcturus stores commercial clothing mappings and player effect grants, while Pixels has no clothing definition table and stores effect grants only. Pet behavior tables are also not asset catalogs. These operational tables are not equivalent to items_base/furniture_definitions and must not be populated from client asset maps.
Logging is configured independently from the environment:
ASSET_CLI_LOG_LEVEL=info
ASSET_CLI_LOG_FORMAT=consoleASSET_CLI_LOG_LEVEL accepts Zap levels such as debug, info, warn, and error. ASSET_CLI_LOG_FORMAT accepts console for local readability or json for structured ingestion.
Print the CLI version with:
go run ./cmd versionGHCR publication runs only for tags matching v*.*.*. The release workflow validates tests, Vet, Staticcheck and compilation, builds all supported binary targets, and then publishes the multi-architecture image. A tag such as v0.1.0 produces v0.1.0, 0.1.0, 0.1, 0, and latest image tags and embeds 0.1.0 in the binary.
The image entrypoint is the asset-cli binary itself, so any command runs directly against a container with the required ASSET_CLI_* variables:
docker run --rm --env-file .env ghcr.io/pixelados-net/asset-cli:latest versionConfigure the repository Actions secret DISCORD_WEBHOOK_URL to enable the tag notification workflow, then publish a release with:
git tag v0.1.0
git push origin v0.1.0cmd/contains the process entrypoint.internal/<realm>/contains each realm's port (Serviceinterface), its Fx-provided implementation, and its own Cobra command tree (e.g.internal/structure/).platform/cli/contains the Cobra root command and is the one place that assembles every realm's command tree.platform/minio/contains the reusable MinIO object storage client.platform/logger/builds the injected Zap logger.platform/config/unifies every platform module's ownConfigstruct and parsesASSET_CLI_*variables once.platform/bootstrap/composes the platform-owned Fx modules (config,logger,minio) and exposesInvoke, which realm commands use to resolve their own dependencies without importing MinIO or Zap directly.- Every DI-enabled package owns its
module.go; bootstrap only composes platform modules, never realms, to avoid an import cycle back intointernal/. e2e/builds the real binary and validates command output through a real process.docs/wiki/is synced to the GitHub wiki on every push tomainthat touches it — seedocs/wiki/STRUCTURE.mdfor the canonical bucket layout.
test -z "$(gofmt -l .)"
go test ./...
go vet ./...
staticcheck ./...
go test ./... -race
go build -trimpath -o /tmp/asset-cli ./cmd
docker build -t ghcr.io/pixelados-net/asset-cli:local .This repository intentionally does not include Docker Compose files.