Internals

Architecture

The state machine, provider boundary, output identity, and durable writes.

PixelKiln separates provider mechanics from the project state machine:

manifest + lock + planning + review + recovery + artifact pipelines
──────────────────── Provider interface ─────────────────────────
PixelLabProvider      RetroDiffusionProvider      FakeProvider      future adapters

Everything above the provider boundary is backend-neutral. URL shapes, auth headers, request/response schemas, and optional account capabilities remain in the adapter.

Manifest and resolved specs

The committed manifest is intent. Resolution combines one style and one asset, loads/reference-hashes style images, applies overrides, chooses a provider- supported generator, and computes a deterministic spec hash. The hash excludes project root, output location, and tags but includes every pixel-affecting setting.

See manifest reference.

Lockfile

pixelkiln.lock.json is the committed paid-work record. Version 2 entries retain:

  • style/asset identity and spec hash;
  • provider and remote object/job ids;
  • explicit lifecycle status and errors;
  • source URLs/candidates/selections;
  • outputs[] with portable path, SHA-256, optional structural role, and optional PNG/GIF media type;
  • provider-specific metadata under a provider-id namespace;
  • successful submission cost and cost unit.

Lock keys are styleId/assetId. Output paths use manifest-relative / separators so a clone or moved checkout remains valid. Legacy absolute v2 paths are rebased in memory and rewritten portably on the next save. The current manifest remains destination authority; a stale lock path cannot redirect restore into an unrelated project file.

Cost units that differ are never summed. Built-in adapters currently use generations, usd, and free; custom adapters may register another non-empty unit. Candidate count also belongs to the provider estimate rather than being assumed globally.

State machine

The provider pipeline is deliberately resumable:

plan → submit → poll → pick (when needed) → fetch
                    └──────── structural/inline outputs ────────┘

Remote ids are saved immediately after submission. Generation and download failures remain separate, so paid work with a temporary CDN failure is recoverable at zero generation cost. Each stage can be rerun independently; gen is only their everyday orchestration.

Provider responses are runtime-validated before entering lock state. A 2xx response with a missing object id, malformed URL set, invalid estimate, or changed field type becomes an explicit adapter error rather than corrupted durable state.

Output identity

One manifest asset may produce multiple structural members. Roles such as tile-03 are load-bearing identity, not presentation. Audits, packs, mounts, and exporters all use the same role model. A consumer must request a role when there is no unambiguous primary output.

PNG ingestion validates signature, chunks, CRCs, palettes, compressed data, scanlines, dimensions, and supported color modes. GIF ingestion walks the logical screen, color tables, extensions, image-data blocks, and trailer. Both formats are validated before bytes become durable output or recovery cache data.

Concurrency and lock saves

Lock writes use a same-directory temporary file and rename. An advisory writer lock serializes separate processes. In-process saves queue per path, and field-level dirty patches merge separate snapshots so updates to different assets, or to different fields of one asset, do not silently lose the earlier write. Stale advisory locks are recoverable after their safety window.

Derived artifact transactions

Pack, mount, and export use a separate managed bundle writer:

  1. Recover an interrupted prior transaction.
  2. Validate provenance ownership and manual edits.
  3. Compare every desired member and skip identical bytes.
  4. Write an immutable transaction journal.
  5. Stage all changing members beside their destinations.
  6. Move existing members to unique backups.
  7. Promote every stage.
  8. Write a durable commit marker.
  9. Remove backups, stages, journal, and marker.

Before the marker, recovery restores the old complete set. After the marker, recovery keeps the new complete set and finishes cleanup. Journal paths are validated against current destinations and reserved same-directory temp names. See derived artifacts.

Caches

The project content cache is keyed by output SHA-256. The account cache maps provider object ids to remote content hashes for adoption/salvage. Neither is authoritative or committed; both can be deleted and rebuilt. Every recovery byte is structurally validated before use.

Provider capability boundary

Providers are selected from a registry by the manifest's top-level provider id. Required members cover support/estimate, submit, poll, and download; candidate selection is required only when an adapter can return alternatives. Account-wide listing, tagging, deletion, and balance are optional. Commands such as adopt or salvage report a capability gap rather than failing through an undefined method.

PixelLabProvider is production and live-tested. RetroDiffusionProvider is an experimental still, tileset, and animation adapter. Authenticated RD Fast and RD Plus single-candidate still lifecycles have passed end to end. Its multi-candidate, tileset, GIF, and spritesheet paths retain mocked coverage pending paid live smokes. FakeProvider implements the same contract in memory, which keeps the paid pipeline testable without credentials or network access. See library API and PixelLab vs. Retro Diffusion.