Skip to content

Architecture

Style Dataset Lab has one unified pipeline that runs from canon definition through a frozen dataset, then loops through production briefs, critique, batch work, selection, and re-ingest. The same flow is walked narratively in End-to-End Production Loop.

canon → generate → curate → bind → snapshot → split → export → eval
↑ │
│ v
│ brief ← workflow training
│ │ │
│ v v
│ run → critique → refine eval-run
│ │ │
│ v │
│ batch → select → re-ingest ──────────────────────────────┘
└────────────────────────────────────────────────────────────────

Each stage produces structured artifacts with IDs that link back to their predecessors. Selected outputs from the production leg return as candidate records through sdlab reingest selected — they go through the same curate + bind review as every other record, never auto-approved.

painterly (img2img style pass) and compare (A-vs-B preference capture) remain in the CLI surface but are not part of the core loop. painterly is a post-processing convenience. compare feeds DPO/ORPO pair data for preference training and is only needed when you are building preference datasets.

style-dataset-lab/
bin/sdlab.js CLI entry point (single binary)
lib/ Shared modules (paths, errors, logging, schemas)
scripts/ Per-command scripts (each exports run(argv))
schemas/ JSON schemas for records, snapshots, splits, manifests
templates/ Starter content (ships with the npm package)
canon/ Starter constitution.md and review-rubric.md
inputs/prompts/ Example prompt pack (example-wave.json)
domains/ Five domain starters (per-domain project + config + workflows)
game-art/
character-design/
creature-design/
architecture/
vehicle-mech/
projects/ Project data (repo-only, not in npm)
star-freight/ Star Freight example (canon, records, outputs, exports)
<your-project>/ Scaffolded with `sdlab init <name>`
workflows/ Reserved; see workflows/README.md
site/ Documentation site (Starlight)
package.json

The npm package ships bin/, lib/, scripts/, and templates/ only. Project data stays in the repo. Each project is fully isolated — its own canon, records, and assets. All sdlab commands read from and write to projects/<name>/ based on the --project flag (default: star-freight).

Each domain template under templates/domains/<domain>/ ships a complete starting point:

FilePurpose
project.jsonProject metadata + generation defaults (checkpoint, LoRAs, resolution, sampler)
constitution.jsonMachine-readable rules that canon-bind maps scores and failure modes to
lanes.jsonSubject lane definitions (portrait, full-body, streetscape, etc.)
rubric.jsonScoring dimensions and approval thresholds
terminology.jsonGroup/faction labels, detection patterns, and training profiles
workflows/profiles/*.jsonComfyUI workflow profiles copied into the project on sdlab init

The shared canon markdown (templates/canon/constitution.md, templates/canon/review-rubric.md) is copied into every new project’s canon/ directory as a writable starting point.

To scaffold a new project:

Terminal window
sdlab init my-project --domain character-design

This creates projects/my-project/ with the full directory structure, config files pulled from the domain template, canon markdown stubs, and an example prompt pack ready to edit.

Every asset in the dataset is represented by a JSON file in projects/<name>/records/. Records accumulate data over time as the asset moves through the pipeline.

{
"id": "wave3_compact_officer_bridge_s42",
"asset_path": "outputs/approved/wave3_compact_officer_bridge_s42.png",
"provenance": {
"checkpoint": "dreamshaperXL_v21TurboDPMSDE.safetensors",
"loras": [{ "name": "classipeintxl_v21.safetensors", "weight": 1.0 }],
"prompt": "concept art of a Compact military officer...",
"negative_prompt": "photorealistic, photograph...",
"seed": 42,
"steps": 8,
"cfg": 2.0,
"sampler": "dpmpp_sde",
"scheduler": "karras",
"width": 1024,
"height": 1024,
"generated_at": "2026-03-15T10:30:00.000Z"
},
"judgment": {
"status": "approved",
"reviewer": "human:mike",
"reviewed_at": "2026-03-15T11:00:00.000Z",
"explanation": "Clean silhouette, correct palette, good material read",
"criteria_scores": {
"silhouette_clarity": 0.9,
"palette_adherence": 0.85,
"material_fidelity": 0.8,
"faction_read": 0.9,
"wear_level": 0.75,
"style_consistency": 0.85,
"clothing_logic": 0.8,
"composition": 0.9
},
"failure_modes": [],
"improvement_notes": null,
"confidence": 0.9
},
"canon": {
"assertions": [
{ "rule": "RND-001", "verdict": "pass", "rationale": "Painterly style, visible texture" },
{ "rule": "MAT-001", "verdict": "pass", "rationale": "Surfaces read as pressed/stamped" },
{ "rule": "COL-001", "verdict": "pass", "rationale": "Steel blue dominant, charcoal secondary" }
]
}
}

Identity records extend the standard schema with two additional blocks:

{
"identity": {
"subject_name": "renna_vasik",
"subject_type": "named_character",
"faction": "reach",
"role": "crew",
"view_type": "anchor_portrait",
"shot_type": "portrait",
"identity_anchor": true,
"location_name": null,
"ship_name": null,
"scene_function": "establish face and costume truth"
},
"lineage": {
"generation_phase": "discovery",
"anchor_source_image": null,
"anchor_subject_version": null,
"identity_persistence_score": null,
"derived_from_record_id": null
}
}

The identity block tracks who or what the image depicts. The lineage block tracks how it was generated — discovery (txt2img from scratch), anchor (promoted discovery), or follow-on (img2img derived from an anchor).

Follow-on records must reference their anchor via anchor_source_image and derived_from_record_id. sdlab generate:identity enforces this with a hard validation failure.

The style constitution lives in projects/<name>/canon/constitution.md. It defines every rule that judgments can cite. The machine-readable mirror in projects/<name>/constitution.json is what sdlab bind reads to emit canon.assertions.

CategoryPrefixScope
RenderingRND-*Universal — applies to all images
MaterialMAT-*Faction-specific material vocabulary
ShapeSHP-*Faction-specific shape language
ColorCOL-*Faction-specific palette and saturation
ClothingCLO-*Faction-specific construction logic
Ship exteriorSHP-EXT-*Ship hull and exterior design
Ship interiorSHP-INT-*Interior spaces and habitation
EquipmentEQP-*Weapons, tools, props
EnvironmentENV-*Scene atmosphere and faction footprint

rubric.json defines the scoring dimensions (0.0 to 1.0) that apply to all image types. Identity records add further subject-specific dimensions.

Approval defaults: all dimensions >= 0.6, average >= 0.7. Rejection defaults: any dimension < 0.4, or average < 0.5.

Thresholds are configurable per project in rubric.json.

FilePurpose
projects/<name>/canon/constitution.mdFull style rules with faction details
projects/<name>/canon/review-rubric.mdQuick review protocol and common failure modes
projects/<name>/canon/identity-gates.mdNamed-subject acceptance criteria and lineage schema
projects/<name>/canon/species-canon.mdAlien species anatomy and design specifications (if applicable)
candidate (uncurated)
v
sdlab curate --> judgment block written to record
│ │ │
v v v
approved rejected borderline
v
sdlab bind --> canon.assertions written to record
v
sdlab compare --> pairwise comparison records (optional, for preference data)
v
ready for snapshot → split → export

Key design decisions:

  1. Record before move. sdlab curate writes the judgment to the record file before moving the image. This prevents orphaned images if the process crashes mid-operation.

  2. Scores are human-entered. Per-dimension scores come from the curator, not from automated analysis. This is intentional — the dataset trains models to replicate human aesthetic judgment.

  3. Canon binding is deterministic. sdlab bind maps scores and failure modes to constitution rules deterministically. A low material_fidelity score maps to MAT-001. A wrong_palette failure mode maps to COL-001.

  4. Comparisons are separate. Pairwise preferences live in projects/<name>/comparisons/, not inside records. This allows comparing images across different waves and categories.

The export is handled by the external @mcptoolshop/repo-dataset CLI, which scans a project directory and produces multimodal training data.

Point repo-dataset at a project directory: repo-dataset visual generate ./projects/star-freight --format trl

SourceWhat it reads
projects/<name>/records/*.jsonProvenance, judgment, canon assertions
projects/<name>/outputs/approved/*.pngApproved images (classification + critique)
projects/<name>/outputs/rejected/*.pngRejected images (classification + critique)
projects/<name>/comparisons/*.jsonPairwise preferences (DPO/ORPO pairs)
TypeInputOutputUse case
ClassificationImageapproved/rejected labelTrain binary quality classifier
CritiqueImageExplanation + scores + failuresTrain grounded evaluation
PreferenceImage pair + winnerReasoning for preferenceDPO/ORPO alignment training

TRL, LLaVA, Qwen2-VL, Axolotl, LLaMA-Factory, ShareGPT, OpenAI, DPO, ORPO, KTO.

Identity packets handle named subjects — specific characters, ships, and locations that must be visually recognizable across multiple images.

  1. Discovery — txt2img from composed prompts, 3 seeds per shot. Purpose: find the face, silhouette, and costume truth.
  2. Anchoring — curate discovery outputs, promote the strongest to anchor status. The anchor is the recurring truth source.
  3. Follow-on — img2img from the anchor at low denoise (0.30-0.45). Purpose: prove identity persists across views, lighting, and context.

Identity images must pass both the standard constitution gates AND identity-specific gates:

GateWhat it checks
IC-1Silhouette distinction from other characters in the same faction
IC-2Faction legibility through character-specific expression
IC-3Identity persistence across 2+ images of the same character
IC-4Costume integrity — no drift into other factions
IC-5Spec compliance with identity lock non-negotiable details
IC-6No generic drift — must read as this person, not an archetype

Locations and ships have their own parallel gates (IL-1 through IL-5) focused on structural repeatability, material language, and lived-in proof.

projects/<name>/inputs/identity-packets/ Identity packet definitions (JSON)
projects/<name>/records/ Extended records with identity + lineage blocks
projects/<name>/outputs/candidates/ Discovery outputs (uncurated)
projects/<name>/outputs/approved/ Curated approved (anchors + follow-ons)