Nodes

Nodes are the atomic processing steps of MetaLoom. A pipeline is a graph of nodes, and Cortex workers execute the individual node tasks that Loom dispatches. Each node has a unique kind (name) used to reference it in a pipeline definition and to route its work to a worker that can run it.

A node writes its result back to Loom over the REST API — a typed component plus an asset_node_result ledger row. Downstream nodes do not name the node they depend on: they connect to one of its ports. A port has a name that is local to its node, a content type that says what it carries, and a cardinality that says whether it carries one element or a sequence of them.

Between them the built-in nodes cover any media file type — images, videos, audio and documents. What is actually analysed for a given asset depends entirely on which nodes the pipeline contains.

Tip
Every node listed below is also in the interactive pipeline editor on this site, which needs no server and no account. Drag a few onto the canvas to see which ports will connect to which — the editor enforces the same type rules Loom does, so a wiring it rejects is one a real pipeline would reject too.

Every node page opens with a diagram of that node in a pipeline: what flows in on the left, what comes out on the right, and a tab per alternative configuration. Hover any port — or tap it, or reach it with the keyboard — for a card giving its content type, its cardinality, and what the value actually is. A stacked marker on a port means it carries a sequence rather than a single element. The key below covers both the type icons and the cardinality:

The built-in nodes fall into four categories.

Hashing & Deduplication

Node Applies to Purpose

Hashing (md5, sha256, sha512, chunk-hash)

Any file

Content hashes for identity and deduplication

Fingerprint (fingerprint)

Video

Perceptual video fingerprint for similarity search

Consistency (consistency)

Video, Audio

Detect incomplete / corrupt media

Deduplication (sha512-dedup, fingerprint dedup)

Any / Video

Detect and move duplicates

Extraction & AI

Node Applies to Purpose

Asset Metadata (metadata)

Image, Document, Audio, Video

Read the metadata already inside a file — title, creator, keywords, date, rights and GPS position

Tika (tika)

Any

Extract format metadata + text with Apache Tika

OCR (ocr)

Image

Extract text with Tesseract

VLM (vlm)

Image

Read images with a vision-language model; olmOCR document transcription

Speech-to-Text (whisper)

Video, Audio

Transcribe audio with Whisper

Text-to-Speech (tts)

Any (text connected to its text port)

Synthesize narration audio (Orpheus/Kartoffel DE, Kokoro EN)

Sentiment Analysis (sentiment)

Any (text connected to its text port)

Score the tone of extracted text (German and English)

Translate (translate)

Any (text connected to its text port)

Translate extracted text into a target language with a language model

Content Guard (guard)

Any (text connected to its text port); Image on a multimodal model

Screen content against a harm taxonomy with a guardrail model, and gate a branch on the verdict

LLM Enrichment (llm)

Any

Enrich metadata with a language model — one output port per prompt

Captioning (captioning)

Image, Video

Natural-language captions for images and videos

Image Generation (imagegen)

Image

Generate images from a prompt (or remix the asset) with a diffusion model

Video Generation (videogen)

Image

Generate a short video clip from a prompt (or animate the asset’s image) with a diffusion model

Face Detection (facedetect)

Image, Video

Detect faces + embeddings — its detections port carries one element per face

Object Detection (objectdetect)

Image, Video

Detect objects with YOLO — its detections port carries one element per object, and labels feeds the tag node directly

Face Description (facedescription)

Image

Describe detected faces with a vision model, one description per face

Segment Anything (sam2)

Image, Video

Turn boxes into exact outlines with SAM 2 — segment everything, cut out what a detector found, or track a mask through a clip

Depth Map (depthmap)

Image

Estimate how far each part of a photo is from the camera

Scene Layout (scene-layout)

Image (a depth map and detections connected)

Work out what is in front of, behind or next to what

Media Analysis

Node Applies to Purpose

Thumbnail (thumbnail)

Video

Contact-sheet preview thumbnails

Quality (quality)

Image, Video

Resolution / blurriness / bitrate metrics

Scene Detection (scene-detection)

Video

Optical-flow scene boundaries

Dominant Colour (dominant-color)

Image (optionally with detections connected)

Work out which colours a picture is made of, as HEX and in words (English and German)

Watermark (watermark)

Image, Video

Stamp your own logo or mark onto the asset at a relative position — the original is never modified

Image Manipulation (image-manipulation)

Image (optionally with detections connected)

Straighten by EXIF orientation, crop, reframe to a target ratio (including the blurred vertical-video fix) and resize — the original is never modified

Pipeline

Node Applies to Purpose

Filesystem Source (filesystem-source)

— (source)

Enumerate media from disk

S3 Source (s3-source)

— (source)

Enumerate media from S3-compatible object storage, picking up only what changed

Google Drive Source (gdrive-source)

— (source)

Enumerate media from Google Drive, picking up only what changed — including renames and moves

OneDrive Source (onedrive-source)

— (source)

Enumerate media from OneDrive or a SharePoint library, picking up only what changed

Filter (filter)

— (routing)

Route each item down one branch per configured bucket — the output port is the branch

Tag (tag)

Any

Attach tags from rules over what upstream nodes worked out — a tagged asset is a findable asset

Script (script)

Any

Run your own code as a pipeline step and emit declared ports — list outputs fan out

S3 Sink (s3-sink)

Any

Upload produced files to an S3 bucket and register them as assets — its artifacts port takes many

Move (move)

Any local file

Relocate the file to a folder, a storage pool, a library or an S3 bucket — never overwriting, and only removing the original once the destination is verified

Assign (assign)

Any known asset

Add the asset to a collection or a library. Writes the membership only; it never touches the file

Requirements at a Glance

Most nodes are pure CPU. A few need a native library or an external model service:

Requirement Nodes

OpenCV / video4j native runtime

fingerprint, thumbnail, quality, scene-detection

InspireFace native runtime (GPU optional)

facedetect

YOLO native runtime + an ONNX model (GPU strongly recommended for video)

objectdetect

Whisper runtime (whisper.cpp; GPU optional)

whisper

Tesseract (Tess4J)

ocr

An LLM provider service

llm, facedescription

A vision-language model service

captioning, vlm

A TTS sidecar (Orpheus/Kartoffel + Kokoro)

tts

A SAM 2 sidecar (GPU strongly recommended)

sam2

An image-generation sidecar (SDXL-Turbo / diffusion model; GPU recommended)

imagegen

A video-generation sidecar (LTX-2; a 24 GB GPU is required)

videogen

A sentiment sidecar (german-sentiment-bert + twitter-roberta; CPU is enough)

sentiment

A depth sidecar (Depth Anything V2 Small; CPU is enough, GPU is much faster)

depthmap

The ffmpeg / ffprobe binaries on PATH

watermark (video only — the image path needs nothing)

S3-compatible object storage (AWS S3, MinIO, Ceph)

s3-source, s3-sink, move (bucket target only)

Google Drive, OneDrive or SharePoint credentials

gdrive-source, onedrive-source

A reachable OpenAI-compatible language model endpoint

llm, translate, filter, guard

A reachable OpenAI-compatible endpoint serving a guardrail model (Llama Guard, ShieldGemma or Granite Guardian)

guard

CPU only

md5/sha256/sha512/chunk-hash, consistency, tika, metadata, filesystem-source, script, tag, scene-layout, dominant-color, watermark (images), image-manipulation, dedup

Pin the heavy kinds to dedicated or GPU workers via CORTEX_NODE_WHITELIST — see Cortex Configuration.

Processing Capabilities

What the built-in node set gives you, and which node provides it:

Relocation and disposal

move is the one node that changes where an asset’s bytes live — a trash folder, a storage pool, a library, or an S3 bucket for cold storage. It refuses to overwrite, works out whether a destination is on another disk before it starts copying, and only removes the original after the destination has been verified. assign is its counterpart for curation: it files an asset into a collection or a library and never touches the file at all.

Asset hashing

md5, sha256, sha512, chunk-hash run in parallel over any file. Hashes are the basis for exact deduplication and for skipping already-processed assets.

Video fingerprinting

fingerprint computes a perceptual multi-sector fingerprint using the video4j-fingerprint library. It survives transcoding, resolution changes and minor edits, which makes near-duplicate detection possible at scale via vector similarity search.

Face detection

facedetect finds faces in images and video with the InspireFace library, returning bounding boxes, facial embeddings and the optimal focal point for cropped thumbnails. Its detections port carries one element per face, so facedescription, scene-layout and dominant-color all work per face simply by connecting to it.

Object detection

objectdetect finds objects — people, vehicles, animals, furniture — in images and video frames with a YOLO model, reporting each as a labelled box with a confidence score. The classes it can report come from the model’s own vocabulary, so choosing the model is choosing what the library can be searched for. Its labels port lists the distinct classes found and connects straight to tag, which turns every asset into something searchable by what is in it.

Segmentation

sam2 answers the question detection cannot: not where a thing is, but which pixels are it. Given the boxes objectdetect already found, it returns each one as an exact outline; given nothing at all, it finds every distinct region in the picture by itself; given a video, it follows an outline from frame to frame as the subject moves. That boundary is what separates a product from its backdrop, crops to a person rather than to a rectangle around one, and turns "how much of this shot is sky" from an impression into a number.

Thumbnail generation

thumbnail renders contact-sheet previews from video frames and source images and uploads them to Loom as asset binaries.

Metadata ingest

metadata reads what a file already says about itself — the photographer’s title, caption and keywords, the camera and exposure, the licence and credit line, and where the shutter was pressed — out of EXIF, IPTC, XMP, companion .xmp files, PDF and Office properties and audio tags, and normalises all of it onto one Dublin Core shape. It records which original field supplied each value, so nothing has to be trusted blindly, and it needs no model and no GPU. Its text output carries the authored prose alone, ready for translate, sentiment or llm.

Document text extraction

tika uses Apache Tika to pull the full text out of any supported document format. It is the companion to metadata: one gives you the words, the other the properties.

Scene detection

scene-detection splits video into scenes with an optical-flow detector, producing cut timestamps that can drive per-scene thumbnails or clips.

OCR and speech-to-text

ocr extracts text from images and document pages with Tesseract; vlm transcribes document pages with a vision-language model such as olmOCR, which keeps the layout — tables, columns, formulas — that plain glyph recognition flattens; whisper transcribes audio and video soundtracks with the Whisper model.

AI captioning and enrichment

captioning generates natural-language descriptions of both images and videos with a vision-language model — images from a still frame (SmolVLM), videos from their temporal content (Qwen2.5-VL), optionally as a per-scene timeline — and llm enriches metadata through an LLM provider such as llama.cpp or vLLM.

Image generation

imagegen generates a new image with a diffusion model behind a small HTTP sidecar — either from a text prompt or by remixing the asset’s own image — and writes the PNG to the worker’s local cache.

Video generation

videogen generates a short video clip with a diffusion model behind a small HTTP sidecar — either from a text prompt or by animating the asset’s own image as the opening frame — and writes the MP4, with a synchronised audio track, to the worker’s local cache.

Watermarking

watermark stamps a logo or mark you supply onto an asset at a relative position, so one setting works across a library of mixed resolutions. Stills are composited in-process; video goes through the ffmpeg overlay filter, which re-encodes the picture but copies the audio through untouched. The original file is never modified — the marked copy is a new artifact.

Image manipulation

image-manipulation straightens, crops and reframes a picture in one pass — applying its EXIF orientation so it is upright, cutting it to a fixed region or one built around the faces connected to its detections port, forcing a target aspect ratio (padding vertical pictures with a blurred enlargement of themselves rather than black bars), and bounding the result’s size. No model or external tool is needed, and the original file is never modified.

Text-to-speech

tts turns text connected to its text port — an llm summary, a caption, or a translated transcript — into narration audio, using Orpheus/Kartoffel for German and Kokoro for English behind a small HTTP sidecar.

Sentiment analysis

sentiment scores the tone of text the pipeline already produced — connect document text, OCR output, a caption or an LLM answer to its text port — as positive, neutral or negative with a signed polarity value, using dedicated German and English models behind a small HTTP sidecar.

Translation

translate turns text the pipeline already produced into another language — connect a transcript, document text or an OCR result to its text port and the translation comes out on translation, ready for tts to speak. One node translates into one language, so several languages means several nodes; each translation is stored under its own language and stays separately retrievable. Documents longer than the model’s context window are split at paragraph and sentence boundaries, never mid-sentence, and rejoined.

Content screening

guard checks content against a harm taxonomy — connect a transcript, document text, an OCR result or a caption to its text port, or point it at image assets — and answers safe or unsafe with a confidence score and the categories that fired. Its safe output is a branch, so a publishing or upload step connected behind it runs only for the items that came back clean, while flagged assets are still fully processed and their verdicts stored for review. Three families of open guardrail model are supported behind the one node — Meta’s Llama Guard, Google’s ShieldGemma and IBM’s Granite Guardian — and all of them are normalised onto one shared vocabulary of harm categories and one comparable score, so changing the model does not mean rewiring the pipeline. Llama Guard 4 and ShieldGemma 2 read pictures directly; the rest screen text.

Depth and spatial layout

depthmap works out how far each part of a photo is from the camera, from the photo alone, and scene-layout uses that to say how the detected things relate — which is in front, which is behind, which one hides part of another. Together they turn a flat list of boxes into a scene you can caption accurately and search spatially.

Colour analysis

dominant-color works out which colours a picture is actually made of — the whole frame, a fixed region, or every box arriving on its detections port — and reports each one as HEX, RGB, HSL and CIELAB alongside a name a person would use, in English and German. It needs no model and no GPU, so it can run over an entire archive cheaply.

Consistency checking

consistency validates that stored metadata — hashes, dimensions, codec information — still matches the file on disk, flagging inconsistencies for review or remediation.

Cloud drive ingest

gdrive-source and onedrive-source read media straight out of Google Drive, OneDrive and SharePoint, without anyone having to copy it to a disk or a bucket first. Both are differential: a re-run asks the drive what changed and processes only that, so watching a large drive costs a single request when nothing has happened. And because a file in a drive keeps its identity when someone renames it or files it away, both report a move as a move rather than as a deletion followed by a fresh upload — so the metadata you have already built up stays attached to it.

Automatic tagging

tag attaches tags from rules you configure over what the pipeline already worked out — a quality metric, a transcript, a list of colour names. It matters because of where a tag lands: most analysis results sit on the asset where you can read them but not search them, while a tag becomes part of the asset’s search document as soon as it is written. A vocabulary can be pinned to an allowed list so automatic tagging cannot litter the shared tag list, and the node only ever removes a tag it can prove it wrote itself.

Branching a pipeline

filter sorts items into buckets you configure and grows one output port per bucket, plus an other port for everything else. The port is the branch: anything wired to a port that carried nothing is skipped for that item, and the skip carries on down that branch — so one node routes a pipeline any number of ways without a condition repeated at every step. Today it sorts by language, decided by a language model.

Authoring Your Own Node

Cortex is designed to be extended, but there is no drop-in plugin mechanism: the node set of a Cortex process is wired at build time through Dagger modules, so the shipped cortex-server image serves exactly the built-in kinds listed above. Running a node of your own means building your own Cortex instance that includes it. A worker announces the node kinds its factory has registered when it registers with Loom, so a custom instance becomes dispatchable as soon as it connects, and it can run alongside the stock workers — which keep serving the built-in kinds.

A custom node in Java is three steps:

  1. Extend AbstractMediaNode<YourOptions>.

  2. Implement name(), isProcessable() and compute().

  3. Expose the node from a Dagger module, include that module in your instance’s node collection, and register the node kind with the pipeline node factory.

The examples/ directory of the source repository carries the complete, working setup rather than a sketch: cortex-custom-node holds the node with its options, payload and Dagger module; cortex-custom assembles the daemon that includes that module and connects to a Loom backend; and cortex-python implements a minimal worker in Python that speaks the wire protocol directly, for logic you would rather not write in Java. See Cortex Examples for the code and the build and run commands.