Tessera

Tessera is a command-line and web-based file tagging tool backed by SQLite. It lets you attach arbitrary tags — including typed key=value pairs — to any file on your filesystem, then query those tags to find, organise, or generate views of your collection.

What Tessera does

  • Tag anything — images, videos, documents, archives, music, or any other file. Tags live in a small SQLite database (.tessera/db.sqlite3) alongside your files, not in the files themselves.
  • Key=value tags — a tag is either a plain word (genre) or a typed pair (year=2024, rating=5). Values support numeric comparisons in queries.
  • Query language — find files with boolean expressions: genre/rock and year>=2020 and not live.
  • Symlink views — materialise a query result as a folder of symlinks, ready to hand to any other tool.
  • Linked databases — split a large collection across multiple directories, each with its own database, and query them together.
  • Web interface — a local web app with a file browser, tag editor, thumbnail previews, AI-assisted tagging, and semantic search.
  • Cross-platform — macOS and Linux.

About this guide

This guide covers everyday use of Tessera: the CLI, the web interface, and the reference material you need to get the most out of the query language and settings.

Architecture and internal design are documented separately in the filetag-blueprint repository.

Installation

Prerequisites

  • Rust toolchain — install via rustup (stable, edition 2024).
  • SQLite — bundled; no system library needed.
  • For the web interface: ffmpeg and ffprobe (for video thumbnails and trickplay sprites).
  • Optional: ffsubsync on $PATH for automatic subtitle/audio synchronization. The container images include it.

Tessera searches $PATH, ~/.local/bin, ~/bin, Homebrew's standard directories and the usual system binary directories. This also works when the web server is started by a service manager with a minimal $PATH. Add custom locations with the platform-separated TESSERA_TOOL_PATH environment variable.

From source

git clone <tessera repository URL>
cd tessera

# CLI only
cargo install --path tessera-cli

# Web interface
cargo install --path tessera-web

Both binaries end up in ~/.cargo/bin/. Make sure that directory is on your $PATH.

Verifying the installation

tessera --version
tessera-web --version

Updating

cd tessera
git pull
cargo install --path tessera-cli
cargo install --path tessera-web

Quick start

This page walks you through tagging your first files and finding them again in under five minutes.

1. Initialise a database

Go to the root of a directory tree you want to tag — your music folder, photos, or any other collection:

cd ~/Music
tessera init

This creates .tessera/db.sqlite3 in the current directory. Every file you tag must live somewhere inside this directory (or a subdirectory).

2. Tag some files

# Tag a single file
tessera tag song.flac -t lossless

# Tag with a key=value pair
tessera tag song.flac -t year=2024

# Multiple tags at once
tessera tag song.flac -t lossless,genre/rock,year=2024

# Tag a whole directory recursively
tessera tag -r Albums/Kraftwerk -t genre/electronic,year=1974

# Tag files piped from another command
fd -e flac | tessera tag -t lossless

3. List tags on a file

tessera tags song.flac

4. Find files by tag

# Simple tag query
tessera find lossless

# Combine tags
tessera find "lossless and genre/rock"

# Key=value comparison
tessera find "year>=2020 and genre/electronic"

Results are printed one path per line, ready for piping:

tessera find lossless | xargs -I{} cp {} ~/export/

5. Open the web interface

tessera-web ~/Music

Open http://localhost:4141 in your browser to browse, search, and tag files visually.

Next steps

Initialising a database

A tessera database is a single SQLite file stored at .tessera/db.sqlite3 inside the root directory of a collection. All file paths are stored relative to that root, so the database is portable: move the whole directory and everything still works.

Creating a database

cd /path/to/your/collection
tessera init

This creates .tessera/db.sqlite3 in the current directory. You only need one database per directory tree; files in subdirectories are automatically within scope.

Registering in the global registry

If you have several collections and want to query them all at once with --all-dbs, register the database:

tessera init --register
# or, after the fact:
tessera db register

The registry is stored at ~/.config/tessera/databases.json.

Nested collections

You can have a database inside a directory that already has a parent database. tessera will find the deepest database root for any given file and use that one. Queries on the parent automatically include child databases — see Linked databases for details.

The .tessera/ directory

Everything tessera writes lives here:

PathContents
.tessera/db.sqlite3The main database
.tessera/cache/thumbs/Thumbnail cache (web interface)
.tessera/cache/vthumbs/Trickplay sprite sheets (video)
.tessera/cache/ai_sprites/AI analysis sprite sheets
.tessera/cache/transcodes/Transcoded video for streaming
.tessera/logs/tessera.logCurrent tessera-web application log
.tessera/logs/tessera.log.1Previous log after rotation

tessera never writes outside .tessera/.

Tagging files

Basic tagging

tessera tag FILE... -t TAG[,TAG,...]

Tags are case-sensitive strings. A tag can be:

  • A plain word: lossless, favourite
  • A hierarchical path using / as separator: genre/rock, status/todo
  • A key=value pair: year=2024, rating=5, artist=Kraftwerk

Multiple tags can be given as a comma-separated list or by repeating -t:

tessera tag song.flac -t lossless,year=2024
tessera tag song.flac -t lossless -t year=2024

Recursive tagging

Tag all files in a directory (and its subdirectories):

tessera tag -r Albums/Kraftwerk -t genre/electronic

Tagging from stdin

tessera accepts file paths from standard input, one per line. This lets you combine it with find, fd, fzf, and similar tools:

fd -e flac | tessera tag -t lossless
find . -name "*.jpg" -newer reference.jpg | tessera tag -t new

Use -0 to read NUL-delimited paths (safer for filenames containing newlines or spaces):

fd -0 -e mp4 | tessera tag -0 -t video

Listing tags

# Tags on specific files
tessera tags FILE...

# All tags in the database
tessera tags

# JSON output
tessera tags --json FILE

The tags command is also available as tessera ls.

Removing tags

tessera untag FILE... -t TAG[,TAG,...]

Viewing full file info

tessera show FILE

Shows all tags, the file's database record, size, modification time, and file identity.

Renaming a tag

Renames the tag everywhere in the database:

tessera mv OLD_TAG NEW_TAG

Merging tags

Merge all occurrences of SOURCE into TARGET (destructive — prompts for confirmation):

tessera merge SOURCE TARGET
tessera merge SOURCE TARGET --force   # skip confirmation

Global options

OptionDescription
--jsonJSON Lines output
--color auto|always|neverColour mode
-q, --quietSuppress informational messages, and log only errors
-v, --verboseExtra detail, including debug-level log records
--log-level SPECLog verbosity, optionally per target; beats TESSERA_LOG, -v and -q
--db PATHOverride the database location
--no-parentsDo not include ancestor databases in queries

Log records go to stderr, never to stdout, so --json output stays pipeable. The command writes no log file: it has no lifetime worth a forensic trail, and tessera-web is the process that keeps one. The default level is warn, so an ordinary invocation says nothing beyond its own output; --log-level accepts the same per-target specs as the server, such as info,tessera::embedding=error.

Querying and finding files

Basic usage

tessera find QUERY

Returns one file path per line. The command is also available as tessera f.

For the full query language reference, see Query syntax.

Examples

# Files with a single tag
tessera find lossless

# Boolean AND
tessera find "lossless and genre/rock"

# Boolean OR
tessera find "genre/jazz or genre/blues"

# Boolean NOT
tessera find "lossless and not live"

# Key=value exact match
tessera find "artist=Kraftwerk"

# Numeric comparison
tessera find "year>=2020"
tessera find "rating>3 and rating<=5"

# Glob on a tag namespace
tessera find "genre/*"

# File type filter
tessera find "type:image and landscape"
tessera find "type:video and year=2024"

# Combined
tessera find "(genre/rock or genre/metal) and year>=2000 and not live"

Output options

# With tags listed after each path
tessera find QUERY --with-tags

# Count only — no paths printed
tessera find QUERY --count

# NUL-delimited output (safe for xargs -0)
tessera find QUERY -0

# JSON Lines
tessera find QUERY --json

Scope options

By default, a query runs against the current database and any linked child databases and ancestor databases. To change this:

# Current database only
tessera find QUERY --isolated
tessera find QUERY -i

# All globally registered databases
tessera find QUERY --all-dbs

Piping results

# Copy matching files
tessera find "genre/rock" | xargs -I{} cp {} ~/export/

# Open in mpv
tessera find "type:video and year=2024" -0 | xargs -0 mpv

# Pass to another command safely
tessera find QUERY -0 | xargs -0 some-command

Symlink views

A view is a directory full of symlinks — one per matching file — generated from a query. Views make it easy to hand a tag-filtered selection to tools that don't know about tessera: media players, editors, import dialogs, etc.

Generating a view

# Default output: _.tags/ in the current directory
tessera view QUERY

# Custom output directory
tessera view QUERY -o /tmp/my-view

The symlinks use relative targets so the view directory is portable as long as it stays on the same filesystem.

A file at Music/Rock/song.flac becomes a symlink named Music__Rock__song.flac (path separators replaced with __). This keeps all links flat in the output directory while preserving the original path as the name.

Long filenames are truncated at 255 bytes while preserving the file extension.

Keeping views clean

tessera automatically removes broken symlinks (pointing to files that no longer exist) and empty subdirectories from the output directory before generating new links.

Example workflow

# Build a playlist view for all lossless rock tracks
tessera view "lossless and genre/rock" -o ~/playlists/rock-lossless

# Open the whole view in a media player
mpv ~/playlists/rock-lossless/

# Refresh after tagging more files
tessera view "lossless and genre/rock" -o ~/playlists/rock-lossless

Database status and repair

Status

Show which files are missing (moved or deleted) and which are untagged:

tessera status
tessera status PATH    # limit to a subdirectory

Output includes:

  • Missing — files in the database whose path no longer exists on disk.
  • Untagged — files on disk that are not in the database.

Repair

The repair command finds files that have been moved (or renamed) and updates the database records to match their new location. It uses the platform file identity (inode + device on Unix) and, as a fallback, name + size matching.

# Preview what would change
tessera repair --dry-run

# Apply changes
tessera repair

# Limit to a subdirectory
tessera repair path/to/subdir

How matching works

  1. File identity (inode) — exact match regardless of path. Works for simple moves within the same filesystem.
  2. Name + size fallback — if the inode is unavailable or has changed (e.g. copy + delete across filesystems), tessera matches by filename and file size.

When multiple candidates match a file, repair reports a conflict and skips that record. Use tessera show to investigate and tessera mv / manual SQL to resolve.

Linked databases

tessera supports multiple databases that know about each other. This is useful when a large collection is spread across several drives, or when you want independent databases per sub-collection but still want to query them together.

Concepts

  • Root database — the database you run tessera commands from.
  • Linked (child) database — a database registered as a child of the root.
  • Ancestor database — a database whose root is a parent directory of the current root. tessera finds these automatically by walking up the directory tree.

By default, queries include the root database, all linked children, and all ancestors.

Managing linked databases

# List linked databases
tessera db ls

# Add a child database
tessera db add /path/to/child/collection

# Remove a child database
tessera db remove /path/to/child/collection

# Remove dead registrations (paths that no longer exist)
tessera db prune

Global registry

For collections that are not in parent/child directory relationships, use the global registry:

# Register the current database globally
tessera db register

# Unregister
tessera db unregister

# List all globally registered databases
tessera db registered

Query scope

# Default: current DB + children + ancestors
tessera find QUERY

# Current database only
tessera find QUERY --isolated

# All globally registered databases
tessera find QUERY --all-dbs

# Exclude ancestor databases
tessera find QUERY --no-parents

Pushing and pulling tags

Copy tag records between databases when files exist in both:

# Copy tags from root → child (for files the child knows about)
tessera db push /path/to/child --dry-run
tessera db push /path/to/child

# Copy tags from child → root
tessera db pull /path/to/child --dry-run
tessera db pull /path/to/child

Push/pull match files by their file identity (inode), so they work even if relative paths differ between the two databases.

Shell completions

tessera can generate completion scripts for Bash, Zsh, and Fish.

Bash

tessera completions bash > ~/.local/share/bash-completion/completions/tessera

Or for a system-wide install:

tessera completions bash | sudo tee /etc/bash_completion.d/tessera

Zsh

tessera completions zsh > ~/.zfunc/_tessera

Make sure ~/.zfunc is in your $fpath (add to ~/.zshrc if needed):

fpath=(~/.zfunc $fpath)
autoload -Uz compinit && compinit

Fish

tessera completions fish > ~/.config/fish/completions/tessera.fish

Getting started with the web interface

tessera-web is a local web application that provides a visual file browser, tag editor, search bar, and media previews on top of the same database that the CLI uses.

Starting the server

# Serve the collection in the current directory
tessera-web

# Serve a specific path
tessera-web ~/Photos

# Custom port and bind address
tessera-web --port 8080 ~/Photos

# Include parent databases in queries
tessera-web ~/Photos   # parents are included by default
tessera-web --no-parents ~/Photos

Open http://localhost:4141 in your browser.

Authentication

When binding to localhost (the default), no password is required.

When binding to a non-loopback address (e.g. --bind 0.0.0.0), a random password is automatically generated and printed to stderr. You must supply it on the login page.

To set a specific password:

tessera-web --password mysecretpassword ~/Photos
# or via environment variable:
TESSERA_PASSWORD=mysecretpassword tessera-web ~/Photos
# or read from a file:
tessera-web --password-file /run/secrets/tessera ~/Photos

To generate a random password explicitly:

tessera-web -P ~/Photos   # prints password to stderr

To disable authentication entirely (e.g. behind a reverse proxy that handles auth):

tessera-web --no-auth --bind 0.0.0.0 ~/Photos

Logging

Two independent settings decide what happens to a log record: how much is logged, and where it goes. The startup banner prints the resolved answer to both, so you never have to guess:

Logs: /home/you/Photos/.tessera/logs/tessera.log (info)

How much

--log-level sets the verbosity to off, error, warn, info, debug, or trace; the default is info. TESSERA_LOG sets the same thing for environments where a flag is awkward, and the flag wins when both are given.

Either accepts per-target overrides, so one noisy subsystem can be quietened without dimming the rest:

tessera-web --log-level info,tessera::embedding=error ~/Photos

A target matches on its module-path prefix, longest match first, so tessera::embedding=error also covers tessera::embedding::batch.

Where

The server writes its application log to <primary-root>/.tessera/logs/tessera.log. In a multi-database session this is the single process-wide log; entries concerning another database include that database's root path. The log rotates at 10 MiB and keeps one previous file as tessera.log.1. Use --log-file <path> to write elsewhere, or --log-file none to write no file at all — useful in a container, where the root may be a read-only mount and the collector wants the stream instead.

--log-stderr decides whether records are also streamed to the terminal:

ValueBehaviour
auto (default)Stream only when stderr is not a terminal — a container, a systemd unit, a pipe. An interactive session stays quiet.
alwaysStream regardless, for watching a run as it happens.
neverNever stream; the log file is the only sink.

Records never go to stdout: that stream carries program output, and a stray log line there would corrupt a --json pipeline.

A container therefore usually wants:

tessera-web --log-file none --log-level info ~/Photos   # stderr only, collected by the runtime

and someone debugging locally wants:

tessera-web --log-stderr always --log-level debug ~/Photos

Panics and graceful shutdown signals (SIGINT, SIGTERM, SIGHUP, and SIGQUIT) are recorded with their reason. SIGKILL cannot be caught by any application. Tessera therefore keeps a run marker and reports an unclean prior shutdown on the next start. For the exact cause of a SIGKILL—for example an out-of-memory kill—consult the operating-system or service-manager logs.

See Authentication for more.

Multiple roots

Pass multiple paths to serve several collections at once:

tessera-web ~/Photos ~/Music ~/Documents

The browser shows a root selector at the top of the sidebar.

Browsing and tagging

The file browser

The main view shows the contents of the current directory as a grid of thumbnails (or a list). Click any thumbnail to open the detail panel on the right.

  • Navigate — click a folder tile to enter it; use the breadcrumb at the top to go back.
  • Switch view — use the grid/list toggle in the toolbar.
  • Sort — click column headers in list view, or use the sort menu in grid view.
  • Zoom — drag the slider in the toolbar to resize grid thumbnails.

The activity rail switches between Files, Chats, Documents, and—when enabled—Videolab. Management tools such as Tag Manager and Collections live below the content sections. A floating chat or text editor can remain open while you move between sections.

Collections

Collections are named working sets of documents; they do not move the source files or replace directory scopes. Add the current selection from its context menu, then open Collections from the activity rail to create, rename, or delete sets and remove individual members. A non-empty collection can be opened as one chat context or sent to a multi-document transformation project.

Split-pane view

Press F3 (or click the split-view button in the toolbar) to open a second browser pane side by side. Each pane browses independently — different directories, different searches, different roots.

  • Active pane — click anywhere in a pane to make it active. The active pane has a coloured top border and a tinted header. The sidebar, search bar, and detail panel all operate on the active pane.
  • Resize — drag the handle between the panes to adjust the split.
  • Close — press F3 again or click the toolbar button to collapse back to a single pane.

The detail panel

Click any file to open its detail panel. From here you can:

  • View and copy the file path.
  • See all tags attached to the file.
  • Add tags using the tag input field (type and press Enter, or pick from the autocomplete list).
  • Remove tags by clicking the × on a tag chip.
  • Preview the file (image, video, PDF, archive pages, etc.).

Adding tags

Type a tag into the input field in the detail panel and press Enter or click Add. The autocomplete list shows existing tags in the database — use it to avoid typos and keep tags consistent.

For key=value tags, type the whole expression: year=2024, rating=5.

Removing tags

Click the × button on any tag chip in the detail panel.

Tagging multiple files

Select multiple files by holding Shift or Cmd/Ctrl while clicking. When more than one file is selected, the detail panel switches to bulk-tag mode: you can add or remove a tag across all selected files at once.

File operations

Right-click any file or folder to open the context menu. Available operations:

OperationDescription
Rename…Rename the file or folder in place.
Rename selection…Search and replace in several names at once, using plain text or a regular expression. This can include subdirectories and can be undone.
Move to…Move to a different directory (within the same root or to another root). Tags are preserved.
Copy to…Copy files or directories to a different directory. Tags are copied to the new files.
New folder from selectionPut selected items in a new folder. Tessera suggests a name and opens it directly for editing.
CompressCreate an archive from the selection, or create a separate archive for each selected directory. Format and compression preferences are configurable.
ExtractExtract one or more selected archives in list order. A containing directory is added unless the archive already has exactly one directory at its root.
Move to TrashMove to the .tessera/trash/ folder inside the root. Recoverable from the Trash panel.
New folder…Create a subfolder (directories only).
New text file…Create a text file and open it in the standalone editor.

To operate on multiple files at once, select them first (Shift/Cmd+click), then right-click for the multi-file menu.

Completed file operations can be undone and redone from the operation history. For reversible archive moves, undo restores the original items and removes the created archive or directory when nothing new has since been added to it.

Standalone text editor

Open a supported text file from its context menu, or create one with New text file… on a directory. The editor is a movable, resizable window independent of document-transformation projects. It provides local undo/redo and saves with a modification-time check so an external edit is never silently overwritten.

Saved edits are also recorded in filesystem history. Undo saved edit can restore the recovery copy after the editor has been closed or the page reloaded.

Trash

Trashed files are stored in .tessera/trash/ and can be restored at any time. Open the Trash panel from the toolbar to review, restore, or permanently delete trashed items.

The sidebar

The left sidebar has two tabs:

  • Tags — shows all tags in the current root. Click a tag to add it to the current query; click an active tag to remove it. Existing manual query terms are preserved and simple added criteria are combined with AND. Clicking the arrow next to a hierarchical tag (e.g. genre) expands it to show subtags.
  • Files — shows a navigable file tree of the current root. Click a directory to navigate the main panel to it; click a file to navigate to its parent directory and select the file.

Click the split-view button (⊞) in the sidebar header to show both tabs side by side.

File tree navigation

  • Click a directory — navigate the main panel to it and use it as the sole direct search scope.
  • Cmd/Ctrl+click or Shift+click a directory — toggle an additional scope. Multiple directories from different roots can be combined.
  • Change a scope between only direct and with subfolders from its labelled control in the query composer.
  • Click a file — navigate to the file's parent directory and open the file in the detail panel.
  • Drag a file onto a tag in the Tags pane to apply that tag.
  • Drag a file or directory onto a directory row to move it there. Hold Alt before or during the drag to copy instead of move.

Keyboard shortcuts

KeyAction
F3Toggle split-pane view
↑ ↓ ← → or h j k lMove cursor through the grid or list
EnterOpen the focused item
SpaceSelect the focused item
Cmd/Ctrl+SpaceToggle the focused item in the selection
Shift+↑ ↓ ← →Extend the selection from its anchor
Home / EndMove to the first / last item
Page Up / Page DownMove by a visible page
u or BackspaceGo to parent directory
Cmd/Ctrl+ASelect all files in the current view
Alt+← / Alt+→Navigate back / forward
F4Toggle Follow Cursor, keeping the focused item selected and visible in the detail panel
Shift+F10 or Context MenuOpen the focused item's context menu
EscapeCancel multi-selection or clear keyboard cursor

When a query is active, Escape first clears its criteria and reloads the active directory. It does not remove the directory scope.

Searching

The search bar at the top of the page accepts the same query language as tessera find on the command line.

genre/rock and year>=2020
(jazz or blues) and not live
type:image and landscape
artist=Kraftwerk

Press Enter to run the search. Results replace the current directory listing. The composer supports a block editor and a raw-text editor for the same query; switching editors does not change its meaning.

A standalone search term such as horse performs a broad discovery search across all available information:

  • tags, subjects, and AI-generated tags;
  • filenames and directory names;
  • indexed document content;
  • indexed image and video content.

Document, image, and video content is found through semantic embeddings. Configure and index embeddings under Settings → Embeddings to enable those matches. Filename and tag matches continue to work when embeddings are not configured.

Use explicit query syntax when you want precise filtering, for example type:image and horse. Use name: for a file-path match, dirname: to return matching directories themselves, or use ~ for semantic ranking.

The query composer below the toolbar keeps directory scopes separate from query criteria. Selecting a tag, subject, or person adds it to the current expression without replacing manually typed terms. Directory scopes can be switched between direct children and all subfolders without modifying the query text.

Click an and or or block in the composer to switch that operator. Criteria can also be grouped, negated, reordered, or removed without rebuilding the whole expression. Clear criteria preserves directory scopes; Clear all removes both.

For the full query language reference, see Query syntax.

Prefix your query with ~ to switch to semantic search — a vector similarity search using embedding models rather than tag matching.

~ a red sports car at sunset
~ jazz piano solo
~ aerial landscape photography

Semantic search requires embedding models to be configured and files to be indexed. See Semantic search for setup instructions.

Click Clear criteria, or press Escape outside an editor, to clear query criteria and return to the active directory listing. Escape does not remove the directory scope chip. Use the chip's remove button or Clear all when you also want to leave that scope.

Filesystem index and fallback

Filename discovery uses a disk-backed FTS index under each Tessera database. It is rebuilt and reconciled in the background, so untagged files participate without keeping every path in process memory. While an index is not ready, scoped searches fall back to a bounded live walk. Full walks run serially and do not follow directory symlinks, avoiding duplicate traversal through overlapping or cyclic trees.

dirname: always uses a bounded live directory walk because the filename index contains files, not directory objects.

Scope

Clicking a directory makes it the sole direct scope. Cmd/Ctrl-click or Shift-click adds scopes; scopes may come from different roots. Multiple scopes are ORed together, then ANDed with the query criteria. Each chip can search only direct children or include every subfolder.

Without a directory scope, searches use the roots selected by the current web context. Linked child and ancestor databases participate unless the server was started with --no-parents.

Chats and document transformations

The Chats and Documents sections use the configured AI endpoint but serve different workflows. Chats are conversations with optional file context; Documents keeps a durable project and version history for text transformations.

Chats

Start a chat from the activity rail or from selected files in the browser. A conversation can include files from the active, unambiguous database root. Attached images, archive pages, video sprites, and supported documents expose a preview so you can verify the context before sending it.

Chats can be docked in their section or opened as a movable, resizable floating window while you browse. Saved conversations keep their existing session ID and autosave subsequent exchanges. A brand-new unsaved conversation is not silently turned into a saved one; save it explicitly when you want it in the session list.

If an attached file disappears, Tessera marks it unavailable rather than silently substituting a file with the same name from another root.

Transformation projects

Choose a supported document or text file in Files and start a transformation. The Documents section opens a project workspace containing:

  • the original source;
  • an instruction composer;
  • a project list and version tree;
  • the selected result editor;
  • a project chat for follow-up changes.

The project, its jobs, chat messages, and derived versions are persistent. A follow-up transformation or manual edit creates a child version, so alternate branches remain visible. Panel widths are resizable and remembered locally.

Finished results can be edited, exported, renamed, or deleted. Deleting one derived version keeps its descendants by reconnecting them to the deleted version's parent. Deleting the project is a separate action that removes the whole project history.

Running versions remain read-only. Failed transformations can be resumed when completed chunks are available, or restarted as a fresh run.

The standalone file editor described in Browsing and tagging is intentionally separate: editing an ordinary file does not create a transformation project.

Tag Manager, subjects, and people

Open Tag Manager from the activity rail or the Tags sidebar. It is a full workspace section with separate Tags, Subjects, and People tabs.

Scope

The root selector at the top controls the manager's catalogue and every exact name mutation performed inside it. Choose one root when equal tag or subject names exist in several databases. All roots is useful for inspection, but identity-sensitive operations may require an explicit root.

The file browser sidebar remains a merged browsing catalogue; leaving Tag Manager restores that global view. Changes made in scoped Tag Manager menus do not silently switch the manager back to the global catalogue.

Tags

Select a tag to inspect assignments and values. Depending on the tag, the manager can rename or delete it, move a hierarchy, change the hierarchy separator, manage value synonyms, promote a tag to a subject property, prune unused tags, and edit its property contract.

Separator changes use a guarded confirmation. Press Escape while the guard is armed to cancel it.

Subjects

Subjects group properties that belong to the same entity rather than directly to a file. Subject names and pure hierarchy prefixes can be renamed in the manager. Subject synonyms affect only subject: queries; they never broaden a plain tag query with the same text.

Autocomplete in tag and subject editors replaces only the segment at the caret, up to the next / or =. Existing suffixes are preserved, which makes editing long hierarchical names predictable.

People

The People tab combines named face identities with their file assignments. Because identities are database-owned, select an explicit root before making changes when several roots are loaded. See Face recognition for detection and assignment workflows.

Videolab

Videolab is an optional workspace for applying a configured restoration model to video. Enable it under Settings → Features, then configure its worker in the Videolab settings tab. The recommended setup imports the password-protected connection document produced by tessera-worker show-connection; advanced settings also accept the worker URL, token, and CA certificate separately.

Starting from a video

Right-click a video in Files and choose Open in Videolab. Select only a bounded interval for a preview, choose settings advertised by the connected worker, and start the preview job. A completed preview can be compared with the source and promoted to a full render.

Preview and full-render records are persistent. The history shows queued, running, completed, failed, and cancelled work. Completed or failed records can be cloned into a new draft without modifying the original settings record. Jobs continue to appear in the global jobs panel when you leave the workspace.

Privacy and recovery boundary

Tessera probes the local source, crops the requested interval, strips source metadata and non-video streams, segments the frames, and encrypts each bounded segment before transfer. Worker configuration, model identity, frame geometry, and other required technical fields cross the boundary; source filenames, paths, tags, and document metadata do not.

Cancellation is explicit and remains pending until remote cleanup and key destruction are acknowledged. Interrupted transfers resume only at persisted, authenticated chunk boundaries. A missing encryption key causes Tessera to cancel or clean up the old execution rather than assuming that encrypted work can still be resumed.

See the worker's own deployment guide for installation and network setup.

Semantic search

Semantic search lets you find files by describing what you're looking for in natural language, rather than by exact tag names. It works by comparing embedding vectors: a mathematical representation of the "meaning" of a file's content.

How it works

  1. An embedding model converts each file into a vector (a list of numbers that encodes meaning).
  2. Your search query is converted into a vector using the same model.
  3. Files whose vectors are closest to the query vector are returned as results.

tessera supports two modalities:

ModalityModel typeCovers
VisionImage/vision embedding (e.g. nomic-embed-vision)Images, videos (via sprite sheet), comic archives (cover image)
TextText embedding (e.g. nomic-embed-text)Text files, Markdown, EPUBs, ZIP entry listings

Setup

1. Run an embedding server

You need an OpenAI-compatible embedding endpoint. Infinity is recommended:

pip install infinity-emb[all]

# Start a vision + text server
infinity_emb v2 \
  --model-id nomic-ai/nomic-embed-vision-v1.5 \
  --model-id nomic-ai/nomic-embed-text-v1.5 \
  --port 7997

Or use Ollama with a compatible model:

ollama pull nomic-embed-text
ollama serve

2. Configure the endpoints in tessera-web

Open Settings → Embeddings and fill in:

FieldExample value
Text endpointhttp://localhost:7997
Text modelnomic-ai/nomic-embed-text-v1.5
Vision endpointhttp://localhost:7997
Vision modelnomic-ai/nomic-embed-vision-v1.5

If your server hosts both models at the same URL, set both endpoints to the same value.

3. Index your files

In Settings → Embeddings, click Index all files. A progress bar shows how many files have been processed. You can cancel and resume at any time — already-indexed files are skipped automatically.

Supported file types:

TypeHow it's embedded
Images (jpg, png, webp, …)Thumbnail sent to vision model
Videos (mp4, mkv, avi, …)Sprite sheet (contact sheet of frames) sent to vision model
Comic archives (cbz, cbr)Cover image sent to vision model
Text files (txt, md, rst)File content (up to 8 KB) sent to text model
EPUBsExtracted text sent to text model
ZIP archivesEntry listing sent to text model

In the search bar, type ~ followed by your query. Quote a multi-word semantic phrase when combining it with structured criteria:

~ sunset over the ocean
~ a person playing guitar on stage
~ invoice from 2023
~ technical documentation about networking
~"sunset over the ocean" and type:image
~"invoice from 2023" and dir:Documents/

The semantic term ranks the candidates selected by the rest of the expression. It can therefore be combined with and, but not placed under or, not, or a subject group. A badge appears in the search bar to confirm semantic ranking.

Results are sorted by similarity (most similar first). The score shown is cosine similarity — closer to 1.0 means more similar.

Finding similar files

In the detail panel (right side), click Find similar to search for files visually or textually similar to the file you are viewing. This uses the stored embedding vector rather than a text query.

Tips

  • A semantic phrase does not implicitly mean tags: ~ jazz piano ranks by similar content. Add an explicit tag criterion when both are required.
  • For best results with images and videos, use a dedicated vision model (nomic-embed-vision, CLIP variants).
  • For text documents, use a text model (nomic-embed-text, BGE, E5, etc.).
  • The quality of results depends heavily on the model. Larger models generally give better results at the cost of speed.
  • Indexing is one-time — only new or updated files need to be re-indexed.

AI analysis

tessera-web can use a vision language model (VLM) to automatically suggest tags for images, videos, and archives. The model looks at the file and returns a list of descriptive tags.

Setup

You need an OpenAI-compatible chat endpoint that supports vision (image input). Ollama with a model like llava, llava-phi3, or minicpm-v works well locally:

ollama pull llava-phi3
ollama serve

Or use any other OpenAI-compatible endpoint (OpenAI API, LM Studio, llama.cpp server, etc.).

Configuring the AI endpoint

Open Settings → Features and fill in:

FieldExample
AI endpointhttp://localhost:11434
AI modelllava-phi3
Tag prefixai/ (optional — keeps AI-generated tags namespaced)
Collection descriptionMy personal photo library (optional context for the model)

Analysing a file

Open a file in the detail panel and click Analyse with AI. The model receives a (resized) JPEG of the file and returns a list of suggested tags. Review the suggestions, then click Apply to add them, or dismiss the panel to ignore them.

What the model receives

File typeInput sent to model
ImageResized JPEG (max 1024 px)
VideoSprite sheet (contact sheet of frames)
Comic/archiveBounded multi-page overview sampled across the archive
EPUBExtracted plain text

Batch analysis

In Settings → Features, click Analyse all files to run AI analysis on every unanalysed file in the database. A progress indicator shows the status.

Previously analysed files are skipped (their ai/* tags are already present). Use the Re-analyse option to force re-analysis.

Clearing AI tags

To remove all tags with the configured AI prefix from a file or from the entire database, use the Clear AI tags button in the settings or detail panel.

Customising the prompts

Advanced users can override the prompts used for image, video, and archive analysis in Settings → Features:

  • Image prompt — instructions for single-image analysis
  • Video prompt — instructions for sprite-sheet (video) analysis
  • Archive prompt — instructions for archive (cover + listing) analysis

The model always responds in structured JSON regardless of the prompt; the prompt controls what aspects to focus on. Suggested tags may carry an explicit subject, which Tessera preserves as structured subject metadata rather than encoding it into the tag text.

Face recognition

tessera-web can detect faces in images and associate them with named subjects. Once a face is assigned a name, tessera can find all images containing that person.

Enabling face detection

Face detection requires an optional face detection model. Configure the endpoint in Settings → Features → Face detection.

Detecting faces

Open an image in the detail panel. If faces are detected, bounding boxes appear over the image. Each face has a label showing the assigned name (if known) or "Unknown".

Click a bounding box to open the face panel, where you can:

  • Assign a name to the face.
  • Confirm or reject a suggested match.
  • Remove the detection.

Finding all images of a person

Once a subject has been named, use the tag sidebar or search to find all images containing them:

subject:Alice

Or in the web search bar:

subject:Alice and year=2024

Training and matching

tessera stores a face embedding (a vector representation of the face) for each detection. When you name a face, all future detections of similar faces are automatically suggested as the same person.

The quality of matching depends on image resolution and the detection model. Detections with low confidence scores may produce more false positives.

Previews and media

The detail panel in the web interface shows a preview of the selected file. The type of preview depends on the file format.

Images

JPEG, PNG, WebP, GIF, BMP, TIFF, and HEIC files are displayed directly. HEIC files are converted on the fly to JPEG for display in the browser.

RAW camera files (CR2, NEF, ARW, etc.) are extracted and displayed if a supported decoder is available; otherwise a placeholder is shown.

Double-clicking an image (or clicking the expand button in the detail panel) opens the media viewer. The viewer navigates through all viewable files currently shown in the grid—including cross-root search results—so the sequence reflects active filters and sort order rather than raw directory order.

The shared media toolbar supports page navigation, reading direction, spreads, continuous scrolling, zoom, fullscreen, pinning, and opening the viewer in a real same-origin browser window. Moving near the top edge reveals an unpinned toolbar; pin it when browser chrome makes edge access inconvenient. Cmd/Ctrl + mouse wheel zooms towards the pointer.

Video

Videos are streamed directly in the browser when the codec is browser-compatible (H.264 in MP4, AV1 in MP4/WebM). Other formats are transcoded on the fly to H.264/MP4 using ffmpeg.

Trickplay — hover over the video scrubber to see a sprite sheet of frames, letting you jump to any position without seeking.

Trickplay sprites are generated on first play and cached in .tessera/cache/vthumbs/.

The expanded video viewer uses the same toolbar lifecycle as the media viewer and adds a collapsible queue of videos from the current result set. Space owns one complete key press (down and up), so one press toggles playback once even when a media control has focus.

PDF

PDF files are rendered locally in the browser with PDF.js. Use the arrow buttons to navigate pages; the viewer also supports two-page spreads, right-to-left reading, continuous vertical or horizontal scrolling, and zoom/pan. In continuous mode only nearby pages are rasterised, so opening a large document does not render every page at once.

The PDF.js library and worker are bundled with Tessera and do not load code from a CDN. Server-side PDF tools remain useful for grid thumbnails, OCR, translation and AI analysis, but are not required for the reading surface.

Archives (ZIP, CBZ, CBR)

Archive contents are listed in grid or list form and have their own context menus. Image/comic pages load progressively: the active page is prioritised, then nearby previews and full-resolution pages are prefetched within bounded caches. The archive info action reports file, directory, image, compression, and solid-block metadata where the format exposes it.

Archive optimisation is available from the archive actions and settings. It can rebuild archives with configured compression and optionally replace the source; source metadata and files are preserved unless an explicit exclusion or replace option says otherwise. Solid 7z/RAR inputs are extracted sequentially rather than repeatedly decoding the same compression block.

Audio

Audio files (MP3, FLAC, OGG, WAV) are played via the browser's built-in audio player. Metadata (title, artist, album, duration) is shown if available.

Unsupported types

For file types without a preview, the detail panel shows file metadata and tags only.

Thumbnail generation

Thumbnails for the grid view are generated on demand and cached in .tessera/cache/thumbs/. Generation uses the image crate for raster images and ffmpeg for video.

To clear the thumbnail cache, use Settings → Database → Clear cache.

Resume and pop-out

The video and media viewers each have an opt-in resume control. Video positions and archive/PDF pages are stored in local browser storage; starts and completed items are discarded so reopening begins naturally. Resume never overrides an explicit browser Back/Forward restore, compact-player handoff, or pop-out handoff.

Open in new window transfers the current viewer state to a real browser window on the same Tessera origin, including video time, pause state, volume, playback speed, and media page. If the browser blocks the popup, the original viewer stays open.

Settings

Open the settings panel by clicking the gear icon in the top-right corner. Settings are organised into tabs.

Features

SettingDescription
AI endpointURL of the OpenAI-compatible VLM endpoint for AI tag analysis
AI modelModel name to use for analysis
Tag prefixPrefix applied to AI-generated tags (e.g. ai/)
Collection descriptionOptional context passed to the model
Image/video/archive promptOverride the default analysis prompts
Face detection endpointURL for the face detection model
VideolabShow the optional video-processing workspace
Archive optimisationEnable archive rebuilding actions
Replace originalAllow an optimised archive to replace its source after confirmation
Archive exclusionsOptional patterns omitted while optimising an archive

Video

SettingDescription
Max trickplay framesMaximum number of frames in a trickplay sprite sheet
Frame selectioninterval (evenly spaced) or scene (scene-change detection)

Tiles

Controls the appearance of the file browser grid:

SettingDescription
Tile sizeSmall / Medium / Large
Show filenamesWhether to show filenames below thumbnails

Embeddings

SettingDescription
Text endpointURL of the text embedding endpoint
Text modelModel name for text embedding
Vision endpointURL of the vision embedding endpoint
Vision modelModel name for vision embedding
Index all filesStart bulk indexing of all files in the database
Cancel indexingStop the running index job

See Semantic search for a full setup guide.

Database

ActionDescription
Clear cacheDelete all thumbnails, trickplay sprites, and transcoded files
Database infoShow statistics (file count, tag count, database size)

Compression and archive optimisation

Compression settings control new archives created from file selections. The automatic ZIP mode stores already-compressed media and deflates text and metadata. Archive optimisation is a separate opt-in feature: it can rebuild an existing archive, optionally exclude configured metadata patterns, and—only when explicitly enabled and confirmed—replace the original.

The replace option is destructive in intent but still participates in Tessera's filesystem-history and recovery mechanisms. Leave it disabled when you want the optimised archive beside the source for comparison.

Authentication

Default behaviour

BindingDefault
localhost (default)No authentication
Non-loopback (e.g. 0.0.0.0)Random password auto-generated and printed to stderr

Setting a password

# Command-line flag
tessera-web --password mysecretpassword ~/Photos

# Environment variable (useful in scripts and containers)
TESSERA_PASSWORD=mysecretpassword tessera-web ~/Photos

# Read password from a file (takes precedence over --password and env)
tessera-web --password-file /run/secrets/tessera ~/Photos

# Generate a random password and print it to stderr
tessera-web -P ~/Photos

Disabling authentication

If tessera-web is running behind a reverse proxy that handles authentication (e.g. Caddy, nginx, Authelia), you can disable the built-in auth:

tessera-web --no-auth --bind 0.0.0.0 ~/Photos

Session management

Successful login sets an HttpOnly, SameSite=Strict cookie (ft_session) that lasts 24 hours. To log out, click the Log out button in the top-right corner or navigate to /logout.

Security notes

  • The Secure cookie flag is not set — tessera-web does not manage TLS. If you expose the server over the internet, place it behind a TLS-terminating reverse proxy.
  • Passwords are stored as SHA-256 hashes in memory only; they are never written to disk.
  • There is no rate limiting on the login endpoint; use a reverse proxy or firewall rules to limit access from untrusted networks.

Query syntax

Tessera queries combine tags, file properties, paths, subjects, and optional semantic ranking in one boolean expression. The language is used by tessera find, tessera view, and the web query composer. Features that depend on the live filesystem are identified below.

Literals, quoting, and operators

Tag names are plain tokens. Quote values that contain spaces:

genre/rock
"Extra models"
artist="Kraftwerk live"
OperatorMeaningExample
andBoth conditions matchlossless and genre/rock
orEither condition matchesgenre/jazz or genre/blues
notThe condition does not matchlossless and not live

Precedence is not, then and, then or. Parentheses override it:

(genre/rock or genre/metal) and not live

Tags and values

A bare tag matches files carrying that tag. tag: makes the same intent explicit and is useful when a single bare word in the web UI would otherwise start broad discovery.

favourite
tag:favourite
genre/rock

Key/value tags support =, !=, <, <=, >, and >=:

year=2024
rating>=4
artist!=Unknown

Numeric-looking values compare numerically. Other values compare as strings. Property contracts may additionally validate types, units, ranges, cardinality, and controlled concepts; see Property contracts and concepts.

Use * to match tag namespaces:

genre/*

Names, paths, and directories

name: (aliases filename: and file:) matches the complete root-relative file path. A plain pattern is a case-insensitive substring; a pattern containing * or ? is a glob over the whole path.

name:invoice
name:"summer holiday"
name:photos/*.jpg

dir: restricts results to one concrete root-relative directory. Without a trailing slash it selects direct children; with a trailing slash it includes all descendants:

dir:Photos
dir:Photos/
dir:Photos/2026/

In the web UI, directory scope chips are kept separately from the text query. Multiple chips are ORed together; their combined scope is ANDed with all query criteria, including any dir: criterion. Scope chips carry a root ID, so they remain unambiguous across multiple or nested databases.

dirname: searches for directory objects by basename in the web interface. Like name:, it uses a case-insensitive substring unless * or ? is present:

dirname:holiday
dirname:"Old photos"
dirname:project-20??

The matching directories themselves appear in the results. An active directory scope limits where Tessera searches. dirname: is currently web-only because the CLI query universe consists of file records rather than live directory entries.

Regular-expression literals match root-relative file paths:

/IMG_\d{4}/

File types

Use type: to select a logical file category:

ExpressionMatches
type:imageJPEG, PNG, WebP, GIF, TIFF, HEIC, RAW, and other images
type:videoMP4, MKV, AVI, MOV, WebM, and other video formats
type:audioMP3, FLAC, OGG, WAV, AAC, Opus, and other audio formats
type:documentPDF, office documents, text, Markdown, EPUB, and more
type:archiveZIP, CBZ, CBR, RAR, 7z, TAR, and more

Aliases include img, photo, and pic for images; vid and movie for video; aud and music for audio; doc for documents; and arc for archives.

Subjects

subject: matches a subject and its descendants. Subject groups bind several conditions to the same subject assignment:

subject:person/alice
{species=bird and colour=blue}

Subject and concept synonyms are resolved within their own domains; a subject alias does not broaden an unrelated plain-tag query.

Intrinsic properties

Intrinsic file predicates compose with tags and other criteria. Available forms cover dimensions, aspect ratio, orientation, dominant colour, and GPS location. Common examples:

width>=1920 and height>=1080
ratio>=16:9
megapixels>=12
orientation=landscape
color:blue
gps
near:52.37:4.90:10

near: is latitude, longitude, then radius in kilometres.

Semantic ranking

~ ranks the candidates selected by the rest of the expression using an embedding:

~"sunset over the ocean"
~"jazz piano" and type:audio
~"invoice from 2023" and dir:Documents/

A semantic term may occur only on the positive and spine. It cannot be used under or, not, or inside a subject group because those placements do not define one coherent candidate ranking. See Semantic search for setup and indexing.

Combined examples

(genre/rock or genre/metal) and year>=2000 and not live
type:image and width>=3000 and color:blue
dirname:archive and dir:Projects/
~"technical drawing" and type:document and not status=obsolete

Tag values

Tags in tessera are either plain words or key=value pairs.

Plain tags

A plain tag is any string without =:

tessera tag photo.jpg -t favourite
tessera tag photo.jpg -t genre/rock
tessera tag photo.jpg -t status/todo

Key=value tags

A key=value tag stores a value alongside the tag name:

tessera tag photo.jpg -t year=2024
tessera tag photo.jpg -t rating=5
tessera tag photo.jpg -t artist=Kraftwerk
tessera tag photo.jpg -t "title=Autobahn"

The key and value are stored separately but treated as a single unit. Querying year without a value matches any file that has a year tag regardless of its value. Querying year=2024 matches only files where the value is exactly 2024.

Numeric comparisons

Values that look like numbers support comparison operators in queries:

year>=2020
rating>3 and rating<=5

Values are stored as strings; numeric comparison is attempted first and falls back to lexicographic comparison.

Tag hierarchy with /

The / character is just a separator in the tag name string — there is no tree structure in the database. genre/rock and genre/jazz are two independent tags that happen to share a prefix. Queries like genre/* use glob matching on the stored strings.

Special characters

  • Commas (,) separate multiple tags on the command line: -t lossless,year=2024
  • Spaces: wrap in double quotes in the query language: "Extra models"
  • /: used as namespace separator by convention, but has no special database meaning
  • =: separates key from value
  • *: glob wildcard in queries only

Listing all tags in a database

tessera tags          # all tags in the current database
tessera info          # database statistics including tag count

Property contracts and concepts

Every key=value tag is schemaless by default. Existing tags therefore keep working without configuration. A root administrator can optionally give a key a property contract to add validation, cardinality, units, or a controlled concept vocabulary.

Supported value kinds are text, concept, number, quantity, range, date, datetime, boolean, and identifier. Cardinality is many (the default) or one; applying a new value to a single-valued property replaces the previous value for that file/subject.

Declarative CLI management

Property resources are versioned JSON documents, designed for source control and repeatable application in the same spirit as kubectl apply -f:

{
  "apiVersion": "tessera.dev/v1alpha1",
  "kind": "PropertySet",
  "properties": [
    {
      "name": "size-class",
      "value_kind": "concept",
      "cardinality": "one",
      "concepts": [
        {
          "value": "small",
          "labels": [
            { "language": "nl", "label": "klein", "preferred": true },
            { "language": "en", "label": "small", "preferred": true },
            { "language": "en", "label": "S", "preferred": false }
          ]
        },
        {
          "value": "microscopic",
          "parent": "small",
          "labels": [
            { "language": "nl", "label": "microscopisch", "preferred": true }
          ]
        }
      ]
    },
    {
      "name": "fibre-diameter",
      "value_kind": "quantity",
      "cardinality": "many",
      "canonical_unit": "µm",
      "allowed_units": ["µm", "nm", "mm"]
    }
  ]
}
tessera property apply -f properties.json
tessera property apply -f - < properties.json
tessera property get
tessera property get size-class
tessera property delete size-class

get always emits a complete PropertySet, so its output can be edited and applied again. Applying a manifest replaces the concept metadata for the named properties but never rewrites unrelated properties or tag assignments. Deleting a contract also leaves assignments intact; the key simply becomes schemaless again.

Controlled concepts

A concept has a stable canonical value, an optional parent, and any number of language-aware labels. Labels work as key-scoped aliases in equality queries:

size-class=klein

matches assignments stored as size-class=small. A query for a parent concept also includes its descendants, so size-class=small includes size-class=microscopic.

Concepts can carry typed properties whose names refer to other property contracts. Files and subjects still store only the stable concept value; shared facts about that concept live in one place:

{
  "properties": [
    {
      "name": "typical-age",
      "value_kind": "range",
      "cardinality": "one",
      "canonical_unit": "years",
      "allowed_units": ["years"]
    },
    {
      "name": "life-stage",
      "value_kind": "concept",
      "cardinality": "one",
      "concepts": [
        {
          "value": "menopause",
          "labels": [
            { "language": "nl", "label": "overgang", "preferred": true }
          ],
          "properties": [
            { "name": "typical-age", "value": "40-60 years" }
          ]
        }
      ]
    }
  ]
}

An assignment such as life-stage=menopause is therefore the reference. Its typical-age metadata is validated using the range contract. Referenced property contracts may appear before or after the concept in one manifest.

Quantities

A quantity validates a numeric magnitude followed by an optional unit. When allowed_units is non-empty, input must use one of those exact units. The initial v1alpha1 contract does not convert magnitudes between units: the canonical unit records intent and supports consistent administration, but queries still compare the stored textual values using Tessera's existing numeric behaviour. Unit conversion can be added without turning each measured value into a concept.

Ranges

A range is one value with two bounds. Bounds may be numeric with a shared unit, such as type1/size=2-10 µm or age=40-60 years, textual (letter=a-z), or ISO dates (period=2020-01-01..2022-12-31). The separators -, , , and .. are accepted. Use .. when a bound itself contains a hyphen, especially for dates and compound words.

Numeric lower bounds must not exceed their upper bounds. ISO date bounds are also checked chronologically. As with quantities, allowed_units can restrict the shared unit; configured units make numeric bounds mandatory.

range is a value kind, not a cardinality. Cardinality independently says whether one or several ranges may be assigned to the same file or subject.

Web administration

Select a tag in Tag Manager and open Property contract. The editor can set the value kind, cardinality, quantity/range units, description, and controlled concept structure. Removing a contract from this screen never removes tags from files, directories, or subjects.

File types

tessera recognises file types by extension for two purposes: the type: query filter and the embedding modality selector.

Type filter categories

CategoryExtensions
imagejpg, jpeg, png, gif, webp, bmp, tiff, tif, heic, heif, avif, cr2, cr3, nef, arw, raf, dng, orf, rw2, pef, srw, x3f, raw
videomp4, mkv, avi, mov, webm, m4v, ts, flv, wmv, ogv, 3gp
audiomp3, flac, ogg, opus, wav, aac, m4a, wma, alac, aiff, ape, mka
documentpdf, docx, doc, odt, rtf, txt, md, markdown, rst, tex, epub, html, htm
archivezip, cbz, cbr, rar, 7z, tar, gz, bz2, xz, zst

Aliases for type: queries:

AliasResolves to
img, photo, picimage
vid, movievideo
aud, musicaudio
docdocument
arc, archivearchive

Embedding modalities

For semantic search, files are embedded according to their extension:

ModalityExtensionsMethod
Visionjpg, jpeg, png, webp, bmp, gif, tiff, tifThumbnail → vision model
Visionmp4, mkv, avi, mov, webm, m4v, ts, flvSprite sheet (video frames) → vision model
Visioncbz, cbrCover image → vision model
Texttxt, md, markdown, rstFile content → text model
TextepubExtracted text → text model
TextzipEntry listing → text model

Files with other extensions are skipped during bulk indexing.

Configuration keys

tessera-web stores configuration in the settings table of the database (key TEXT PRIMARY KEY, value TEXT). Keys can be read and written via Settings in the web interface, or directly with tessera-web's settings API.

AI analysis

KeyDefaultDescription
ai.endpoint(empty)URL of the OpenAI-compatible VLM endpoint
ai.model(empty)Model name for image/video/archive analysis
ai.api_key(empty)API key (if required by the endpoint)
ai.tag_prefixai/Prefix added to all AI-generated tags
ai.max_tokens512Maximum tokens in the model's response
ai.formatjsonResponse format (json or text)
ai.subject(empty)Description of the collection, sent as context
ai.prompt_image(built-in)Override the image analysis prompt
ai.prompt_video(built-in)Override the video analysis prompt
ai.prompt_archive(built-in)Override the archive analysis prompt
ai.video_sheet_max_frames64Maximum frames per sprite sheet for video analysis
ai.video_frame_selectionintervalFrame selection method: interval or scene
KeyDefaultDescription
embedding.text_endpoint(empty)URL of the text embedding endpoint
embedding.text_modelnomic-ai/nomic-embed-text-v1.5Text embedding model name
embedding.vision_endpoint(falls back to text_endpoint)URL of the vision embedding endpoint
embedding.vision_modelnomic-ai/nomic-embed-vision-v1.5Vision embedding model name

Face detection

KeyDefaultDescription
face.endpoint(empty)URL of the face detection endpoint
face.model(empty)Face detection model name