FastVLM is integrated as an optional advisory captioning sidecar for local Lux Depth V3 runs. It is not a quality gate and is not part of the main Python runtime.
FastVLM MUST stay outside Transformation_Portal/.venv. Use this local layout:
.runtime/fastvlm/
.venv-fastvlm/
ml-fastvlm/
mlx-vlm/
checkpoints/
FastVLM-0.5B-fp16/
FastVLM-1.5B-int8/
FastVLM-7B-int4/
test_images/
reports/
The main pipeline calls FastVLM by subprocess only:
python -m mlx_vlm.generate \
--model "$MODEL" \
--image "$IMAGE" \
--prompt "$PROMPT" \
--max-tokens 120 \
--temperature 0.0No production code imports mlx_vlm, MLX, or CoreML packages.
Use these model roles for local operation:
default_caption_model = apple/FastVLM-1.5B-int8
review_caption_model = apple/FastVLM-7B-int4
smoke_caption_model = apple/FastVLM-0.5B-fp16
The default is apple/FastVLM-1.5B-int8 because the May 2, 2026 benchmark
showed clean flat-schema adherence, roughly 2.5 GB peak memory, and about
200-209 generated tokens/sec. The apple/FastVLM-7B-int4 model produced the
best captions but used roughly 4.95 GB peak memory and about 99-102 generated
tokens/sec. The benchmark report was written to
.runtime/fastvlm/reports/fastvlm_caption_benchmark_20260502_142926.txt.
FastVLM prompts are governed in
src/transformation_portal/vlm_captioning/fastvlm_runtime.py. The default
prompt is conservative and requires one flat parser-compatible line:
SCENE=...; MATERIALS=...; FEATURES=...; NATURAL=...; LIGHTING=...; ISSUES=...; UNCERTAIN=...
The review role uses a stricter prompt automatically, whether selected by
role or by the FastVLM-7B-int4 checkpoint directory. It forbids unsupported
inference about dusk, sunset, weather, season, traffic, construction activity,
maintenance, purpose, ownership, market value, architectural intent, quality
status, building condition, or property condition unless those details are
directly visible.
Do not add per-run prompt overrides through the Portal or Lux Depth CLI unless
the governance contract is intentionally expanded. The active prompt is recorded
in each sidecar under vlm_captioning.runtime_diagnostics.command as the
--prompt argument. The raw text file captures mlx-vlm stdout, which may
include runtime logs, the rendered chat prompt, and the model response.
Canonical TIFF/RAW assets remain authoritative. FastVLM consumes deterministic 8-bit RGB proxies by default:
source TIFF/JPEG/PNG/RAW preview -> RGB PNG proxy -> FastVLM subprocess
Direct TIFF inference is tolerated for local diagnostics, but PNG proxy normalization is the production input policy for reproducibility.
FastVLM output MUST be treated as advisory metadata.
FastVLM output MUST NOT be used as a quality gate.
FastVLM output MUST NOT satisfy Materials V3 segmentation or material-confidence requirements.
Canonical TIFF/RAW assets MUST remain authoritative; FastVLM proxy images are derived runtime inputs only.
All sidecars use role: advisory and used_for_quality_gate: false. Run-card
validation fails closed if a captioning status claims
used_for_quality_gate: true.
Portal controls for FastVLM advisory captioning are hidden by default. Enable them only through the backend bootstrap feature flag:
export TP_PORTAL_FASTVLM_CAPTIONING_ENABLED=1
export TP_PORTAL_FASTVLM_CAPTIONING_ROLLOUT_PERCENT=100/portal/bootstrap exposes the cohort decision as
features.fastVlmCaptioning. Disabled cohorts cannot dispatch
vlm_captioning_enabled=true; config preview returns the
captioning_feature_disabled field error instead.
When enabled, the portal maps the captioning controls to the existing Lux Depth V3 flags and shows the resulting command preview, effective config, readiness warnings, and review-side advisory caption panel. Missing FastVLM runtime paths remain non-blocking preview warnings because captions are metadata only and do not satisfy quality gates.
/v1/config-preview exposes captioning_summary.runtime_readiness as a
lightweight operator preview. It checks only configured path existence and does
not import mlx_vlm, initialize MLX/Metal, spawn FastVLM, download models, or
validate model file checksums.
The stable statuses are:
off captioning is disabled for the current draft
ready configured Python, mlx-vlm, and model paths exist
missing_runtime one or more runtime paths are absent
invalid_config one or more runtime path values failed portal path validation
Each readiness check reports the component path, expected type, whether it is
required for the current draft, and a short remediation. The
verification_scope is always path-existence in config preview. Use
make check-fastvlm-runtime or scripts/validation/validate_fastvlm_runtime.py
for manifest, checksum, source revision, and import-smoke validation.
Use the governed runtime installer from the repository root:
./scripts/setup/install_fastvlm_runtime.shThe default install prepares the source clones, isolated virtual environment,
and smoke,default model roles. Add the review model explicitly when needed:
./scripts/setup/install_fastvlm_runtime.sh --models smoke,default,reviewThe installer is manifest-backed and fail-closed:
./scripts/setup/install_fastvlm_runtime.sh --dry-run --models smoke,default
./scripts/setup/install_fastvlm_runtime.sh --verify-only --models smoke
./scripts/validation/validate_fastvlm_runtime.py --verify-only --models smoke
./scripts/validation/validate_fastvlm_runtime.py --json --models smokeThe manifest lives at config/fastvlm_runtime_manifest.json and pins:
apple/ml-fastvlm@592b4add3c1c8a518e77d95dc6248e76c1dd591f
Blaizzy/mlx-vlm@1884b551bc741f26b2d54d68fa89d4e934b9a3de
The isolated Python dependency set is pinned in
config/fastvlm_runtime_requirements.txt; the installer installs that file
first and then installs the pinned mlx-vlm checkout with --no-deps so the
manifest and requirements file remain the source of truth.
Model downloads are limited to the allowlisted FastVLM roles, pinned Hugging
Face revisions, and SHA-256-checked required files. Partial downloads, unsafe
paths, symlink escapes, unpinned revisions, checksumless artifacts, and checksum
mismatches are rejected before a checkpoint is promoted into
.runtime/fastvlm/checkpoints/.
Make targets are available for operator workflows:
make install-fastvlm-runtime
make check-fastvlm-runtime
TP_PORTAL_FASTVLM_CAPTIONING_ENABLED=1 \
TP_PORTAL_FASTVLM_CAPTIONING_ROLLOUT_PERCENT=100 \
make validate-portal-fastvlm-captioning-liveRun the local command against one source image:
python -m transformation_portal.vlm_captioning \
--input-image /path/to/source.tif \
--output-dir /path/to/vlm_captioning_out \
--model-path /Users/richardcheetham/Desktop/Transformation_Portal/.runtime/fastvlm/checkpoints/FastVLM-1.5B-int8 \
--fastvlm-python /Users/richardcheetham/Desktop/Transformation_Portal/.runtime/fastvlm/.venv-fastvlm/bin/python \
--mlx-vlm-dir /Users/richardcheetham/Desktop/Transformation_Portal/.runtime/fastvlm/mlx-vlm \
--proxy-format png \
--max-side-px 1600Expected outputs:
vlm_captioning_out/
image_proxy.png
vlm_captioning.sidecar.json
vlm_captioning.raw.txt
Captioning is off by default:
python -m transformation_portal.lux_depth_v3 \
--input-dir /Users/richardcheetham/Desktop/Transformation_Portal/input_images \
--output-dir /Users/richardcheetham/Desktop/Transformation_Portal/output/lux_depth_v3_with_fastvlm \
--quality-tier apex \
--vlm-captioning on \
--vlm-captioning-backend fastvlm \
--vlm-captioning-model review \
--vlm-captioning-proxy-format png \
--fastvlm-python /Users/richardcheetham/Desktop/Transformation_Portal/.runtime/fastvlm/.venv-fastvlm/bin/python \
--fastvlm-mlx-vlm-dir /Users/richardcheetham/Desktop/Transformation_Portal/.runtime/fastvlm/mlx-vlmThe run card records captioning_status.role = advisory and
captioning_status.used_for_quality_gate = false.
Preview readiness is intentionally lightweight: the portal checks configured FastVLM paths for existence only. It does not import MLX, spawn FastVLM, download models, or validate checksums during preview.
After dispatch, job list/detail payloads expose additive
run_summary.captioning_status diagnostics derived from the run card and
indexed captioning artifacts. The status values are:
offrequestedsucceededfailedskippedmissing_runtimeinvalid_configunsupported_backend
The diagnostic object also reports backend, model_role, model_id,
model_path, sidecar_count, raw_count, proxy_count, failed_count,
role: advisory, and used_for_quality_gate: false. If a run card claims
FastVLM output was used for a quality gate, the portal reports a failed
policy diagnostic and keeps the serialized status advisory-only.
The portal evidence UI surfaces only post-dispatch evidence that already exists
in job payloads and indexed artifacts. Queue and review surfaces may link the
advisory sidecar, raw FastVLM output, and deterministic proxy artifact, plus
the normalized model/status counts from run_summary.captioning_status.
These links do not trigger FastVLM, verify model checksums, import MLX, or change quality gates. Missing or unreadable advisory sidecars render as caption-unavailable evidence only; the underlying job outcome remains governed by the runner state and existing run-card validation.