VRS Native Build / Update Experience
An explicit write node, so treat it like one
- encoder
- memory
- snapshot
- report
This is the node that turns your own image/tag pairs into a searchable personal memory. It's also the one node in the pack that writes data on every single submission, which is exactly the behaviour you want to understand before you leave it sitting in your main workflow.
What it's for
The pitch of the pack's VRS-INT subsystem is narrow and honest: retrieve tags and explicit names from your reference collection, then feed them to a prompt expander. It does not train the encoder, it does not reliably identify who drew an image, and it does not write finished prompts. What it does is find the neighbors of a new image in a store you built and report the tags they carried.
VRS Native Build / Update Experience is the build half. Its own description tells you the workflow rule in one line: use a separate build workflow; retrieval uses Memory Loader. Read that as an instruction, not a suggestion.
How it works
You give it a JSONL manifest (one image/tag pair per line, image as a path relative to images_root) and it does the following: loads the Gemma vision tower through your encoder, encodes each image to an FP16 vector, records the tags and source metadata, and writes an immutable snapshot into store_path. It then hands you the snapshot hash.
Immutability is the design. A build never edits the previous version - later batches take the same store directory plus the exact base_snapshot hash of the version you want to extend, and the earlier snapshots stay exactly as they were, along with your original files. Which means: incremental growth is supported, rollback is free, and nothing you do with a bad manifest can retroactively corrupt a good snapshot. Interrupted builds don't publish a finished snapshot at all, though unreferenced objects can be left on disk.
The encoder contract is fingerprinted rather than assumed - weight hashes plus the ComfyUI Gemma implementation plus torch/torchvision versions plus preprocessing and pooling. Change any of that and the store won't accept the base, because the vectors stopped being comparable. That's a feature pretending to be an obstacle.
The inputs
encoder(VRS_ENCODER) - comes fromVRS Native Vision Loader. Same file the recall side will use.manifest_path- the JSONL. The pack ships a fictional example pair set to copy the format from.images_root- the directory the manifest's relative paths resolve against.store_path- where the memory lives. Point this outside the repo, or in an ignored folder; the author is explicit that personal material should never end up in the repository directory.base_snapshot- empty on a first build; the 64-character hash of the previous snapshot when appending.label- free text, defaults tonative-personal. A note to future-you, nothing more.
Three of these are mandatory in the demanding sense: if manifest_path, images_root or store_path is blank, the node raises Manifest, image root and output store are required. No silent defaults here, which I appreciate.
Outputs: memory (a live handle into the snapshot you just wrote, so you can chain into recall in the same graph), snapshot (the hash, and the thing you write down), and report (JSON with counts, sizes and hashes, mirrored to the node's UI text).
The gotcha that will get you
The node's IS_CHANGED returns NaN, so ComfyUI never treats it as cached - it re-executes on every submission. It's an output node and an explicit write. Put it in your generation workflow and every time you hit Run you kick off a full rebuild on whatever manifest is still sitting in the text box.
The author anticipated this: build in its own workflow, and after the build, copy the snapshot hash into VRS Native Memory Loader (or use VRS Folder Memory if you'd rather it followed the latest version automatically). Recall workflows never call Build.
The other honesty note from the docs: captured candidate names are not identity claims. If the retrieval suggests an artist or character, that's a neighbour-vote, not a verified label. You explicitly select what passes through via Recall's keep_tags and target_tags.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/raspie10032/RS-Seasonal-Prompt-Generator
Restart when the queue is empty. No pip install is needed for the native VRS path - it runs on ComfyUI's own PyTorch and model management. No llama.cpp, no Transformers, no bitsandbytes, no torch replacement, no external retrieval server.
What it does need: CUDA, because native VRS has no CPU inference fallback, and a native unquantized Gemma 4 E2B safetensors in models/text_encoders/. If you don't have that file yet, the pack's VRS docs point at a preparation script that pulls only the vision tensors rather than the full language model:
cd ComfyUI/custom_nodes/RS-Seasonal-Prompt-Generator
python -m vrs_int.prepare_encoder /some/scratch/dir
It writes model.safetensors plus a provenance.json receipt into that directory; copy the safetensors into models/text_encoders/. No credentials, no remote Python, tensors unchanged.
Where people get burned
Nothing in the dropdown, or a mismatch later. The encoder file must be a .safetensors with vision_model.* keys. A GGUF or an mmproj from the TIPO side will be rejected outright - that's Select native unquantized Gemma 4 E2B safetensors, not GGUF/mmproj.
Mixing with old CLI memories. Legacy PIL/NF4 vectors are numerically different. Build a small separate native store from the original files instead of trying to reuse the old one; and if the originals are gone, that re-encode isn't possible.
Big first build, slow first query. Encoding a batch is real GPU time, sized by image count. Separately, the first search against a new store has to verify the store and prepare a persistent FP32 search array, so it's slow once and then fast.
Personal data in a git repo. store_path defaults to nothing, so you choose. Choose somewhere that isn't custom_nodes/RS-Seasonal-Prompt-Generator. Prompts, tags and paths persist in the store even though pixels don't - compression in this system is not anonymisation.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| encoder | VRS_ENCODER | — | |
| manifest_path | STRING | — | |
| images_root | STRING | — | |
| store_path | STRING | — | |
| base_snapshot | STRING | — | |
| label | STRING | native-personal | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| memory | VRS_MEMORY | — |
| snapshot | STRING | — |
| report | STRING | — |