| name | stage1-scaffolder |
| description | Methodology for Stage 1 Skeleton โ set up the minimum architecture (model, dataset adapter, config, registration) so the data-flow can be traced end-to-end before any optimization. Activate when the user asks "how do I add a new model", "what files does a curryTrain model need", "set up the architecture skeleton", "where does my model.py go", or "how does registration work". |
Stage 1 ยท Skeleton ยท Scaffolder methodology
Before any tuning, before any sanity check, the architecture must exist as four small files with a clean, layered boundary. This skill describes the contract.
Stage question
"Does the architecture exist and does data flow through it from input to loss?"
If the answer is "I'm not sure", you're still in Stage 1.
The four-file contract
Every model in curryTrain lives at curry_train/models/<name>/ and has exactly these files:
| File | Job | Typical size |
|---|
config.py | Architecture parameters as a frozen dataclass. HuggingFace-style. | ~50โ90 lines |
model.py | Layers and the model class, built from curry_train.primitives.*. | ~150โ260 lines |
checkpoint.py | HF weight โ internal weight conversion (uses primitive-hf-bridge). | ~120โ180 lines |
protocol.py | register_model(...) call with a build function. | ~30โ50 lines |
If a file grows past these sizes, you are likely mixing layers and should split.
Layer boundaries (do not violate)
- Runtime โ Primitive: the runtime sees only the
TrainingRuntime protocol from curry_train.runtime. It never imports model code.
- Primitive โ Model: model code calls
from curry_train.primitives import .... It never imports a specific runtime backend.
- Model โ User project: the user's
configs/<name>.yaml and register_model(...) are the only public seams.
If an arrow goes the wrong way, the architecture is wrong. Surface this to the user immediately.
Procedure when scaffolding a new model
Follow this exact order; every step is verifiable.
-
Decide the tensor shape contract before writing any code.
- Standard transformer:
(B, N, D).
- SNN model:
(B, T, N, D) where T is the spike-time dimension.
- CNN / vision:
(B, C, H, W) until a flattening point.
Document the shape contract at the top of model.py as a comment.
-
Write config.py first. Frozen dataclass with __post_init__ validation. No defaults that hide bugs (e.g. don't default n_layers=12 silently โ require it).
-
Write model.py second. Use only curry_train.primitives.* for the building blocks. If a primitive is missing, write a stub in curry_train.primitives and a one-line note in the relevant primitive-* skill โ do not inline the missing logic into model.py.
-
Write checkpoint.py only when an HF source exists. If the user is starting from scratch (no pre-trained weights), this file may be empty initially. Mark it with TODO: HF weight conversion not yet needed.
-
Write protocol.py last. Call register_model(ModelSpec(name=..., package=..., impls={...})). The impls dict points to functions that build a runtime; for V1 most users will register a single impl backed by runtimes/local_torch.LocalTorchRuntime.
-
Run preflight asserts (stage1-preflight-asserts) and bench (1 step) before declaring Stage 1 complete.
Hard rules to enforce on the user
- No custom training loop in
model.py. Loops live in curry_train.loop.
- No
import torch.distributed in model.py. Distributed concerns live in primitives like parallel-state and distributed-optimizer.
- No silent shape coercions in
model.py. If a tensor enters with the wrong shape, raise immediately.
- No magic numbers in
model.py that aren't sourced from config.py.
Stage exit criteria
Stage 1 is done when:
bench --steps=1 produces a finite loss and finite grad-norm.
stage1-preflight-asserts passes all checks.
- The user can explain in one sentence what shape goes in and what shape comes out at each layer.
If any of these fail, do not let the user advance to Stage 2.
Common failure modes to flag
- Mixing primitives across layer boundaries (e.g. doing an
all_reduce inside model.py).
- Using
nn.LayerNorm directly when an RMSNorm primitive exists (or vice versa) โ every choice should go through a primitive.
- Hand-rolling attention instead of using
primitive-gqattention.
- Forgetting to register the model โ
create_runtime(<name>) raises KeyError before the user notices.
Related
skills/stage1-preflight-asserts โ the checks to run after scaffolding.
skills/stage1-data-pipeline โ leakage-safe split + transform.
agents/scaffolder.md โ the agent that actually writes the four files for you.
template/curry_train/runtime.py โ the protocol you must satisfy.