Configuration File Reference¶
This guide provides a comprehensive reference for all the configuration files used in VIBE. Understanding these files is key to building, customizing, and managing both the system and individual templates.
Table of Contents¶
- System Configuration (
config.yml)- Core application and web server settings.
- Template Configuration (
config.yml)- Defines the questions, logic, and metadata for a single interview template.
- Component Configuration (
component.yml)- Defines the interface and logic for a reusable component.
System Configuration (config.yml)¶
This file is located in the root directory of the VIBE application. It controls the overall behavior of the system, including server settings, session management, and paths to template/component source directories.
| Key | Type | Required | Description |
|---|---|---|---|
secret_key |
string | Yes | A long, random string used for cryptographic signing, such as session cookies. |
session_storage_key |
string | Yes | A long, random string used to sign saved interview states (.vibestate files). Auto-generated if not present. |
template_sources |
mapping | Yes | Maps a unique template_id to its source directory. Each entry has either a path key (single template) or an include key (auto-discover templates in a directory). See Template Sources. |
component_sources |
list | No | A list of paths to directories containing reusable components. |
llm_endpoints |
mapping | No | Assistant extension: Central registry of available Large Language Models. |
assistant_logging_enabled |
boolean | No | Assistant extension: Enables writing assistant request/response/SSE logs to the data directory. Defaults to true. Set to false to disable assistant logging. |
embedding_providers |
mapping | No | Review extension: Defines embedding models for similarity search. See Embedding Providers. |
rerank_providers |
mapping | No | Review extension: Defines reranking models for search refinement. See Rerank Providers. |
review_backends |
mapping | No | Review extension: Configures OCR and other document processing backends. See Review Backends. |
dev_settings |
mapping | No | Development-time settings used when running in debug mode without a PASETO token. Contains user info, session_context data, and grants. See Development Settings and Session Context for details. |
template_validation |
boolean | No | If false, disables the initial validation run on startup. Defaults to true. |
session_file_system_dir |
string | No | Path to the directory for storing session files. Defaults to ./.flask_session. |
mount_path |
string | No | Optional URL path prefix where the application should be mounted. When set, all routes and static files are served under this prefix. For example, setting mount_path: "vibe" mounts the app at /vibe/ so the main page is at http://localhost:5001/vibe/. Leave empty (default) to mount at the root path. |
locale |
string | No | Sets the default locale for the entire application (e.g., 'en', 'sv'). Affects translations, date/number/currency formatting. Can be overridden by template-level config. |
docx_wrapper |
mapping | No | Configures the DOCX wrapper feature. Contains a path key pointing to the directory holding wrapper files. See DOCX Wrapper. |
# Example system config.yml
# --- Security ---
secret_key: a-very-long-and-random-string-for-sessions
session_storage_key: another-super-secret-key-for-state-files
# --- Application Mounting (optional) ---
# Leave empty or omit to mount at root path
# Set to a path like "vibe" to mount at http://localhost:5001/vibe/
mount_path: ""
# --- Template and Component Paths ---
template_sources:
# Explicit: register one template by path
nda_template:
path: ./templates/nda
# Include: auto-discover all templates in a directory
all_templates:
include: ./templates
component_sources:
- ./components/shared
- ./components/legal_clauses
# --- LLM Configuration (for Administrators) ---
llm_endpoints:
default:
provider: vibe.providers.llm.openai.OpenAIProvider
config:
api_key: "{{ env('OPENAI_API_KEY') }}"
model: gpt-4.1-mini
# --- Assistant Logging (optional) ---
assistant_logging_enabled: true
# --- Embedding and Rerank Providers (for VIBE Review) ---
embedding_providers:
local:
provider: vibe.providers.embedding.local.LocalEmbeddingProvider
config:
model: multilingual-large
rerank_providers:
local:
provider: vibe.providers.reranking.local.LocalRerankProvider
config: {}
# --- Review Backends (for VIBE Review scanned PDF support) ---
review_backends:
ocr:
backend: tesseract_docker
text_layer_min_chars: 10
tesseract:
oem: 1
psm: 4
user_words: null
pdf:
backend: pdfplumber
docx:
backend: libreoffice_docker
# --- Development Settings ---
# Used when running in debug mode without a PASETO token.
# In production, this data comes from the authentication system.
dev_settings:
user:
name: Development User
email: dev@example.com
session_context:
organization:
name: Development Corp
org_number: "123456-7890"
settings:
default_currency: USD
grants: []
# --- Internationalization ---
locale: en
Template Sources Configuration (template_sources)¶
Each entry under template_sources registers one or more interview templates. There are two forms:
Explicit path -- registers a single template directory:
The key (nda_template) becomes the template ID. The path value is resolved relative to the working directory.
Include directive -- auto-discovers templates in a directory:
VIBE scans all immediate subdirectories of the include path. Every subdirectory that contains a config.yml is registered as a template, using the subdirectory name as its template ID. Subdirectories without a config.yml are silently skipped.
The entry key (my_templates above) is only used for error messages -- it does not become a template ID.
Recursive scanning -- when templates are organized in a multi-level hierarchy (e.g., grouped by theme), set recursive: true to discover templates at any depth:
With a directory structure like:
This registers three templates: nda, employment, and intake. The template ID is always the leaf directory name (the directory containing config.yml). Intermediate directories (contracts, forms) are traversed but not registered.
If two leaf directories within the same recursive include share the same name (e.g., contracts/nda/ and legacy/nda/), the first one found (alphabetically by path) is kept and a warning is logged for the duplicates. Collisions between a recursive include and an explicit path entry or a different include remain hard errors.
When recursive is omitted or set to false, only immediate subdirectories are scanned (the default behavior).
Mixing both forms is supported:
template_sources:
# Explicit registration
special_template:
path: ../external/special
# Auto-discover everything under ./templates
local:
include: ./templates
Collision rules:
- If an
includediscovers a template ID that is already registered (by an explicitpathentry or by anotherinclude), VIBE raises an error at startup naming both sources. pathandincludeare mutually exclusive within a single entry; specifying both is an error.
LLM Endpoint Configuration (llm_endpoints)¶
This section is for System Administrators and applies to the Assistant extension. It provides a central, secure registry of Large Language Model (LLM) services that can be used by AI Drafting Assistants in templates. By defining endpoints here, you control which models are available, manage API keys securely, and can enforce cost and governance policies.
Template authors can then select from these predefined endpoints by referencing their key (e.g., claude-opus) in their template's assistants configuration.
Each entry in the llm_endpoints mapping consists of a unique alias and two keys: provider and config.
- Alias (e.g.,
default,claude-opus): A unique, friendly name for the endpoint. Template authors will use this name. It is recommended to always have an endpoint nameddefault. provider: The full Python path to the VIBE LLM Provider class that handles communication with the specific AI service.config: A dictionary of parameters passed directly to the provider. This is where you set API keys, model names, and other service-specific options.
Available Providers:
vibe.providers.llm.openai.OpenAIProvider: For OpenAI models (e.g., GPT-5) and any OpenAI-compatible API endpoint.vibe.providers.llm.anthropic.AnthropicProvider: For Anthropic's Claude models.vibe.providers.llm.gemini.GeminiProvider: For Google's Gemini models.vibe.providers.llm.mistral.MistralProvider: For Mistral AI's models.vibe.providers.llm.ollama. OllamaProvider: For connecting to a local Ollama instance.vibe.providers.llm.mock.ConfigurableMockProvider: A simple provider for development and testing that returns a fixed response.
Security Note: API keys should always be loaded from environment variables using the env() function for security, as shown in the example below.
# Detailed llm_endpoints example in system config.yml
llm_endpoints:
# The default model used when a template author does not specify one.
default:
provider: vibe.providers.llm.openai.OpenAIProvider
config:
# Securely load the API key from an environment variable.
api_key: "{{ env('OPENAI_API_KEY') }}"
model: gpt-4.1-mini
# An alias for a different provider or model tier.
claude-sonnet:
provider: vibe.providers.llm.anthropic.AnthropicProvider
config:
api_key: "{{ env('ANTHROPIC_CLAUDE_API_KEY') }}"
model: claude-sonnet-4-5-20250929
# An endpoint for a local model served via Ollama.
local-llama:
provider: vibe.providers.llm.ollama.OllamaProvider
config:
# No API key needed for local Ollama.
model: llama3
base_url: http://localhost:11434
# The mock provider for development and testing.
mock_drafter:
provider: vibe.providers.llm.mock.MockProvider
config: {}
Configurable Mock Provider (vibe.providers.llm.mock.ConfigurableMockProvider)¶
Use this provider when you need a deterministic assistant workflow (for demos, documentation, or local QA). Each entry in config.responses represents one AssistantMessage. Responds are expressed as a list:
nullmeans the assistant emits an empty message (no tool calls).- A nested list describes the tool calls for that turn. Each tool can be defined as either:
- A scalar tool name (
- finalize) - A mapping from tool name to arguments (
- update_chat: {content: ...})
- A scalar tool name (
- The provider auto-generates tool-call IDs and follows the order of the list, matching the behavior of
COMPLETE_WORKFLOW_RESPONSES(seetests/assistant/integration/browser.pyfor the equivalent Python fixture).
You can also control streaming behavior:
chunk_size(characters) splits tool arguments/text when streaming tool calls.chunk_delay(milliseconds) pauses between each chunk whenchunk_size > 0.
llm_endpoints:
demo_configurable_mock:
label: "Demo provider"
provider: vibe.providers.llm.mock.ConfigurableMockProvider
config:
chunk_size: 5
chunk_delay: 80
responses:
- null
- - update_chat:
content: Draft introduction placeholder
- - finalize
- null
- - insert_blocks:
position:
at: end
blocks:
- id: intro
content: |
# Project Goals
This document will outline the goals and objectives for the project.
reason: Creating initial project structure
OpenAI Provider (vibe.providers.llm.openai.OpenAIProvider)¶
Use this provider for OpenAI-hosted models (gpt-5-*, gpt-4.1*, o4-*, gpt-oss-*) and other services that expose the OpenAI Responses API. Set the following keys inside the endpoint’s config block:
- api_key (required) – API credential; load it via
{{ env('OPENAI_API_KEY') }}or a similar environment binding. - model (required) – Model identifier. The provider automatically selects the Responses API path for the latest OpenAI families listed above.
- base_url – Override the API host for OpenAI-compatible vendors (e.g. Berget). Defaults to
https://api.openai.com/v1. - timeout – Request timeout in seconds (default
60). - tools – Enable tool calling and streaming tool arguments (default
true). Setfalsefor plain text interactions. - remove_empty_content – Controls handling of empty content in assistant messages with tool calls. When
true(default), omits thecontentfield entirely for OpenAI/Mistral compatibility. Whenfalse, includescontent: nullfor third-party providers that require the field to be present. Only relevant when using tools. - max_tokens – Upper bound for generated tokens (
max_output_tokenswhen using Responses models). - temperature – Sampling temperature. Forwarded only when tools are disabled; omit it for Responses-first models where
reasoning.effortis preferred. - reasoning_effort – Sets
reasoning.effort(low,medium, orhigh) on Responses requests. Defaults tomediumwhen omitted. - text_verbosity – Sets
text.verbosity(low,medium, orhigh) for Responses models. Defaults tomediumand must match an allowed value. - playback_from_file / playback_session_id – Optional debug settings that replay logged provider output during local troubleshooting.
reasoning_effort and text_verbosity are ignored for legacy chat-completions models; they only apply when the provider opts into the Responses API pathway.
Example: Third-party provider requiring content: null
llm_endpoints:
third_party_provider:
provider: vibe.providers.llm.openai.OpenAIProvider
config:
api_key: "{{ env('THIRD_PARTY_API_KEY') }}"
model: third-party-model-name
base_url: https://api.thirdparty.com/v1
remove_empty_content: false # This provider requires content: null in tool call messages
Embedding Provider Configuration (embedding_providers)¶
This section defines embedding models used for similarity search in VIBE Review. Embeddings convert text into vector representations for similarity matching.
Each entry in the embedding_providers mapping consists of a unique alias and two keys: provider and config.
- Alias (e.g.,
local,berget): A unique name for the provider. Review templates reference this in theirreview.embeddingsetting. provider: The full Python path to the embedding provider class.config: A dictionary of parameters passed to the provider.
Available Providers:
vibe.providers.embedding.local.LocalEmbeddingProvider: Local inference using fastembed (multilingual by default). No API key required.vibe.providers.embedding.berget.BergetEmbeddingProvider: Cloud API using intfloat/multilingual-e5-large model.vibe.providers.embedding.mock.ConfigurableMockEmbeddingProvider: For testing.
# Embedding providers in system config.yml
embedding_providers:
# Local inference (default) - no API key needed
local:
provider: vibe.providers.embedding.local.LocalEmbeddingProvider
config:
model: multilingual-large # or: e5-large, multilingual-small
# Cloud API
berget:
provider: vibe.providers.embedding.berget.BergetEmbeddingProvider
config:
api_key: "{{ env('BERGET_API_KEY') }}"
Rerank Provider Configuration (rerank_providers)¶
This section defines reranking models used to refine search results in VIBE Review. Rerankers use cross-encoder models to score document-query relevance more accurately than embeddings alone.
Each entry in the rerank_providers mapping consists of a unique alias and two keys: provider and config.
- Alias (e.g.,
local,berget): A unique name for the provider. Review templates reference this in theirreview.rerankingsetting. provider: The full Python path to the rerank provider class.config: A dictionary of parameters passed to the provider.
Available Providers:
vibe.providers.reranking.local.LocalRerankProvider: Local inference using sentence-transformers cross-encoder. No API key required.vibe.providers.reranking.berget.BergetRerankProvider: Cloud API reranking service.vibe.providers.reranking.mock.ConfigurableMockRerankProvider: For testing.
# Rerank providers in system config.yml
rerank_providers:
# Local inference (default) - no API key needed
local:
provider: vibe.providers.reranking.local.LocalRerankProvider
config:
model: cross-encoder/ms-marco-MiniLM-L-6-v2
# Cloud API
berget:
provider: vibe.providers.reranking.berget.BergetRerankProvider
config:
api_key: "{{ env('BERGET_API_KEY') }}"
Using Providers in Review Templates¶
Extension note: This section applies only when the Review extension is enabled.
Review templates reference these providers by their alias in the review configuration block:
# In a review template's config.yml
interview_mode: review
review:
embedding: local # Key from embedding_providers
reranking: berget # Key from rerank_providers
evaluation: claude # Key from llm_endpoints
If not specified, templates default to local for embedding and reranking.
Review Backends Configuration (review_backends)¶
Extension note: Review backends are only used by the Review extension.
The review_backends section configures document processing backends for VIBE Review. This includes OCR (Optical Character Recognition) for processing scanned PDFs and DOCX conversion for viewing Word documents.
Structure:
| Key | Type | Default | Description |
|---|---|---|---|
ocr |
mapping | {} |
OCR backend configuration for scanned PDF processing. |
ocr.backend |
string | tesseract_docker |
OCR backend type. Set to none to disable OCR. |
ocr.text_layer_min_chars |
integer | 10 |
Minimum non-whitespace characters required to treat a page as text-layer. Pages below this threshold and dominated by a single large image (>80% of page area) are OCR'd. |
ocr.tesseract |
mapping | {} |
Tesseract-specific configuration overrides. |
ocr.tesseract.oem |
integer | 1 |
Tesseract OCR Engine Mode. Typical values: 0 (legacy), 1 (LSTM), 2 (legacy+LSTM), 3 (default). |
ocr.tesseract.psm |
integer | 4 |
Tesseract Page Segmentation Mode. Typical values: 4 (single column), 6 (single block), 11 (sparse text). |
ocr.tesseract.user_words |
string or mapping | null |
Optional wordlist file path (single list) or a mapping of language codes to file paths. Paths are resolved relative to the current working directory. |
docx |
mapping | {} |
DOCX to PDF conversion backend configuration for viewing DOCX files. |
docx.backend |
string | libreoffice_docker |
DOCX converter backend type. libreoffice_docker_volume uses a shared volume mount. Set to none to disable DOCX viewing. |
pdf |
mapping | {} |
PDF text extraction backend configuration. |
pdf.backend |
string | pdfplumber |
PDF text extraction backend. pymupdf is faster but may produce different text extraction results. |
Example (showing defaults explicitly):
review_backends:
ocr:
backend: tesseract_docker
text_layer_min_chars: 10
tesseract:
oem: 1
psm: 4
user_words: null
pdf:
backend: pdfplumber
docx:
backend: libreoffice_docker
Prerequisites for tesseract_docker backend:
- Docker must be installed and running
- Tesseract container must be running:
When a scanned PDF is uploaded without OCR configured, VIBE Review will display an actionable error message explaining how to enable OCR support.
Prerequisites for libreoffice_docker backend:
- Docker must be installed and running
- LibreOffice container must be running:
The libreoffice_docker_volume variant uses a shared volume mount instead of docker cp for file transfer, which can be more reliable in some environments (e.g., WSL with Docker Desktop).
Development Settings (dev_settings)¶
The dev_settings section provides a convenient way to simulate PASETO token data during local development. When running in debug mode (debug: true) and no PASETO token is present, VIBE uses these settings to populate the session.
Structure:
| Key | Type | Description |
|---|---|---|
user |
mapping | User information that would normally come from the authentication system. |
user.name |
string | The user's display name. |
user.email |
string | The user's email address. |
session_context |
mapping | Pre-filled data that templates can declare as requirements. This is the development equivalent of the vibe_config payload in a PASETO token. |
grants |
list | A list of permission grants (empty list for most development scenarios). |
How it works:
- When a user starts an interview, VIBE checks for a PASETO token first.
- If no token is found and
debug: trueis set, VIBE usesdev_settingsinstead. - If neither is available, the session starts with an empty context (which is fine as long as the template doesn't require session context).
Session Context Validation:
If a template declares session_context requirements (using definition-only components), VIBE validates the dev_settings.session_context against those requirements at session start. Missing or incorrectly typed values will result in a 400 error.
# Example dev_settings configuration
dev_settings:
user:
name: Fred Bloggs
email: fred@initrode.se
session_context:
organization:
name: Initrode AB
org_number: "556123-4567"
ramavtal:
svarsfrist:
antal: 10
enhet: arbetsdagar
grants: []
Production Note: In production, dev_settings is ignored entirely. All user information and session context must come from a valid PASETO token provided by your authentication system.
Template Configuration (config.yml)¶
This file is located inside each template's source directory (as defined in TEMPLATE_SOURCES). It is the brain of the interview, defining all questions, reusable data structures, and computed logic.
| Key | Type | Required | Description |
|---|---|---|---|
title |
string | No | A human-readable title for the template, shown on the main listing page. |
description |
string | No | A brief description of the template's purpose. |
template_file |
string | No | The name of the main document file (e.g., main.docx). Defaults to template.md or template.docx. |
interview_mode |
string | No | Controls the interview UI mode. Options: standard (traditional forms with live preview, default), assistant (Assistant extension), review (Review extension). |
session_context |
list | No | Declares external data requirements using definition-only components. See Session Context Requirements below. |
assistants |
mapping | No | Assistant extension: Defines AI Drafting Assistants available in this template. |
questions |
mapping | Yes | The master list of all possible questions for the interview. See Question Types Reference for available types including text, number, bool, tristate, date, amount, enum, multichoice, list, structured, computable, and assisted (Assistant extension). |
groups |
mapping | No | Divides questions into logical groups for long interviews. Each group (keyed by group ID) has title and questions (question definitions). See Paged Interviews. |
definitions |
mapping | No | Defines reusable data structures that can be used in structured and list questions. See Reusable Data with definitions. |
computables |
mapping | No | Defines variables whose values are calculated from other answers. See Automated Calculations with Computable Variables. |
component_defaults |
mapping | No | Provides default values for component inputs, reducing repetition in insert() calls. These are priority 2 in the value precedence order (after explicit insert() params, before component input defaults). See Value Precedence. |
locale |
string | No | Overrides the system-wide locale for this specific template. |
imports |
mapping | No | Adds Python objects as Jinja globals. Limited to an internal whitelist (datetime.date, datetime.timedelta, and a few VIBE internals). For custom functions, use template extensions instead. |
filters |
mapping | No | Adds Python callables as Jinja filters. Limited to the same internal whitelist as imports. For custom filters, use template extensions instead. |
template_functions |
string | No | Override the default functions extension filename (templatefunctions.py). See Template Extensions. |
template_filters |
string | No | Override the default filters extension filename (templatefilters.py). See Template Extensions. |
ui |
mapping | No | Customizes the interview UI (template overrides, stylesheet, preview, layout). See Customizing the Interview UI. |
docx_wrapper |
mapping | No | Opts the template into DOCX wrapping. Enables DOCX download for both DOCX and Markdown templates. Requires a filename key; optionally accepts path and style_map. See DOCX Wrapper. |
numbering_style |
string | mapping | No | Controls how section numbers are formatted in cross-references. As a string: "decimal" (default), "alpha", or "roman". As a mapping: per-level specification with levels and optional separator. See Cross-References. |
term_definitions |
mapping | No | Enables the defined-terms system (tooltips, validation). See Defined Terms below and Linguistic Features — Defined Terms for detailed behavior. |
_insert_questions_* |
null | No | A special marker key to insert a component's questions into the main question order at this position. The * should be the component's alias. |
# Example template config.yml in templates/my_template/
title: Service Agreement Template
description: Generates a standard service agreement for new clients.
template_file: agreement.docx
locale: en_US
assistants:
scope_drafter:
label: "AI: Draft Scope of Work"
model: default
component_defaults:
company_name: My Awesome Company Inc.
default_currency: USD
questions:
client_name:
type: text
label: Client's Full Legal Name
contract_value:
type: number
label: Total Contract Value
_insert_questions_signature_block: null
include_nda:
type: bool
label: Include a Non-Disclosure Agreement?
default: false
required: false
definitions:
person_definition:
first_name:
type: text
label: First Name
last_name:
type: text
label: Last Name
UI Customization (ui block)¶
Use the optional ui block when you need to change how the interview itself looks (as opposed to how the generated document renders). All paths are relative to the template directory and are sandboxed so they cannot escape the bundle.
| Key | Type | Required | Description |
|---|---|---|---|
extends |
string | No | Template ID whose UI configuration this template inherits. The base template's templates, css, labels, preview, layout, and progress_indicator are used as defaults — any setting explicitly defined in the extending template takes precedence. Chains are supported (A extends B extends C). Circular references are rejected. |
templates |
string | null | No | Directory containing override templates/widgets. When provided, VIBE checks this folder before the built-ins. Set to null (or omit the key) to disable overrides entirely. |
css |
string | No | Path to a CSS file that should be injected into the interview <head>. When present it is served at /interview/<template_id>/ui.css (respecting the selected version). |
preview |
boolean | No | Show the live preview panel (default true). Set to false for a single-column interview. |
layout |
string | No | Group layout for templates using groups:. Options: paged, accordion, tabs, flat. Defaults to paged when groups are present. |
progress_indicator |
string | No | Shows completion progress during the interview. Options: none (default, hidden), simple (checkmark per group), counter (answered/total badge per group), bar (counter badges plus an overall progress bar at the top). The simple and counter modes only display on grouped templates; bar works for both grouped and ungrouped. |
browser_title |
string | No | Jinja2 template string for the browser tab title. Rendered with meta (see below) and session context variables. Updates dynamically on each form submission. Defaults to "VIBE" when not set. |
icon |
string | No | Template icon on the selection page. Emoji string ("📊"), Material Symbol ("symbol:finance_mode"), or image file path ("logo.png"). See UI Customization for details. |
Example:
Put individual overrides under the configured directory using the same relative path as VIBE's built-in templates (for example ui/question_types/bool.html or ui/layout/fragments/site_header.html). The CSS file is optional; when configured it loads after VIBE's default stylesheet so you can safely override variables and component styles.
Sharing UI configuration across templates (ui.extends)¶
When multiple templates in a project should share the same look and feel, use extends to inherit UI settings from a base template rather than duplicating the configuration:
# base template (corporate_brand/config.yml) — defines the shared theme
ui:
templates: ui
css: ui/theme.css
preview: false
layout: accordion
progress_indicator: counter
# child template (onboarding/config.yml) — inherits everything from the base
ui:
extends: corporate_brand
# another child (assessment/config.yml) — inherits base theme, overrides layout
ui:
extends: corporate_brand
templates: ui # local ui/ dir with its own overrides
layout: paged # override just this setting; css, preview, etc. still inherited
All ui keys are inheritable: templates, css (and the labels.po derived from templates), preview, layout, progress_indicator, and browser_title. The extending template's own values always win. Chains are supported (A extends B extends C); circular references are rejected at validation time.
Per-file template merging: When a child declares its own ui.templates, individual HTML files are resolved with a fallback chain. VIBE checks the child's override directory first; for any file not found there, it checks the base's override directory (and further up the chain), before finally falling back to the built-in templates. This means a child only needs to provide the files it wants to change — all other overrides are inherited from the base.
Dynamic browser title (ui.browser_title)¶
The browser_title setting is a Jinja2 template string rendered with the meta namespace and any session context variables. It sets the browser tab title and updates it dynamically after each form submission. Particularly useful properties include meta.template.title, meta.template.name, and meta.progress.* — see the Metadata Reference for the full list.
Examples:
# Simple branded title
ui:
browser_title: "{{ meta.template.title }} | Prokur"
# With progress indicator in the tab
ui:
browser_title: "[{{ meta.progress.answered }}/{{ meta.progress.total }}] {{ meta.template.title }}"
# With session context (e.g., organization name from PASETO token)
ui:
browser_title: "{{ meta.template.title }} — {{ organization_name|default('VIBE') }}"
DOCX Wrapper (docx_wrapper)¶
The DOCX wrapper feature inserts rendered content into a shell DOCX document that provides styles, headers, footers, and numbering definitions. It works for both DOCX and Markdown templates:
- DOCX templates: The rendered DOCX is inserted as a subdoc into the wrapper.
- Markdown templates: The rendered Markdown is converted to HTML, then to a DOCX subdoc, and inserted into the wrapper. When enabled, the download menu offers DOCX as an additional format alongside HTML and PDF.
How it works:
- A template opts in by declaring
docx_wrapperin its ownconfig.ymlwith afilenamepattern. - At render time, VIBE resolves the pattern against the current interview state, which includes any session context variables and user answers.
- The matching wrapper file is opened as a
DocxTemplate. The rendered interview output is inserted as a subdoc at the{{p template }}placeholder inside the wrapper. - If any step fails (no path configured, missing variable, file not found), VIBE falls back to returning the unwrapped output and logs a warning.
System config (deployment concern -- where wrapper files live):
Template config (authoring concern -- opt-in per template):
The filename value is a Python format string resolved via str.format_map() against the interview state. Any top-level variable available in the interview (session context variables, user answers) can be used (e.g., {organization_id}, {client_id}).
Template-level path override:
By default, the wrapper file is resolved from the system-level docx_wrapper.path directory. A template can override this with its own path key. Relative paths are resolved against the template's own bundle directory:
# templates/my-template/config.yml
docx_wrapper:
path: . # look in this template's own directory
filename: wrapper.docx
Resolution priority:
docx_wrapper.pathin the template config (relative to template bundle directory)docx_wrapper.pathin the system config
Wrapper file requirements:
- Must be a valid
.docxfile. - Must contain a
{{p template }}placeholder (or the legacy{{p include_docx_template(template.path) }}form) where the rendered subdoc will be inserted. VIBE logs a warning if no placeholder is found.
Style mapping (style_map):
When converting Markdown to DOCX, the converter uses standard English style names (Heading 1, Body Text, List Bullet, etc.). If the wrapper document uses different styles, style_map remaps them:
docx_wrapper:
path: .
filename: wrapper.docx
style_map:
Heading 1: Title
Heading 2: Heading 1
Heading 3: Heading 2
Heading 4: Heading 3
Body Text: Brödtext 2
Quote: Citat
List Bullet: Lista (a)
List Number: Lista (1)
Keys are the converter's default style names; values are the wrapper's style names. Unmapped styles pass through unchanged -- Word resolves standard style names across locales automatically, so mapping is only needed when the wrapper uses non-standard names or when heading levels should be shifted.
The converter's default style names are:
| HTML element | Default style | Notes |
|---|---|---|
<h1> -- <h9> |
Heading 1 -- Heading 9 |
|
<p> |
Body Text |
Has paragraph spacing unlike Normal |
<blockquote> |
Quote |
Applied to paragraphs inside blockquotes |
<ul><li> |
List Bullet |
Nested: List Bullet 2, List Bullet 3 |
<ol><li> |
List Number |
Nested: List Number 2, List Number 3 |
<pre><code> |
(none) | Monospace font with grey shading |
<code> (inline) |
(none) | Monospace font on the run |
<table> |
(none) | Standard DOCX table |
Fallback behavior:
| Condition | Result |
|---|---|
No docx_wrapper in template config |
No wrapping (normal rendering) |
| No wrapper path resolvable (neither template nor system config) | Warning logged, unwrapped output returned |
| Filename pattern references a missing context variable | Warning logged, unwrapped output returned |
| Resolved wrapper file does not exist on disk | Warning logged, unwrapped output returned |
Dev-mode debugging:
When running in development mode (devel: true), an intermediate copy of the rendered subdoc is saved to the docx_wrapper work directory (under VIBE's data directory) for troubleshooting.
CLI testing:
Use --format docx with vibe test to generate DOCX output from Markdown templates:
Defined Terms (term_definitions)¶
The defined-terms system automatically highlights terms from a "Definitions" section in the live preview (with hover tooltips) and optionally validates that every defined term is used in the document body and that every capitalized mid-sentence term has a definition.
| Key | Type | Default | Description |
|---|---|---|---|
enable |
boolean | false |
Enable tooltip injection in the live preview. Required for all other features. |
validate |
boolean | false |
Enable validation warnings. Runs both at startup (vibe validate) and during the live preview. Requires enable: true. |
heading |
string | (locale-dependent) | The heading text that identifies the Definitions section. Defaults to the locale's native word: "Definitions" (en), "Definitioner" (sv), "Definitionen" (de), "Définitions" (fr), "Definiciones" (es). |
whitelist |
list | [] |
Proper nouns that look like defined terms but should be ignored by the forward check (case-insensitive). Example: ["United Nations", "European Union"]. |
additional_word_headings |
list | [] |
Extra Word paragraph style names to treat as headings when extracting text from DOCX templates. Each style is rendered as ## (h2). Example: ["Beslutsmening", "Avdelningsrubrik"]. |
# Example: enable tooltips + validation for a Swedish template
locale: sv
term_definitions:
enable: true
validate: true
whitelist:
- Europeiska Unionen
- Förenta Nationerna
How the Definitions section is recognized: VIBE scans for ATX headings (# through ######) or Word heading styles whose text matches the configured heading (case-insensitive). Each subsequent paragraph or list item whose content starts with **bold text** is treated as a definition entry, where the bold text is the term and the full line is the definition.
Validation checks:
- Forward check (non-German locales): title-cased words or phrases appearing mid-sentence in the document body that have no corresponding definition produce a warning.
- Reverse check (all locales): every term in the Definitions section that doesn't appear anywhere in the document body (in any inflected form) produces a warning.
- German exception: German capitalizes all nouns, so the forward check is disabled for
locale: de. Only the reverse check runs.
For full details on inflection rules and locale-specific behavior, see Linguistic Features — Defined Terms.
Template Extensions (templatefunctions.py / templatefilters.py)¶
Template authors can place templatefunctions.py and/or templatefilters.py in the template root to add custom Jinja globals and filters. The framework injects a thread-safe ctx proxy for accessing interview state. Custom filenames can be configured via the template_functions and template_filters config keys.
For full details — controlling exports, the ctx proxy, reserved names, and examples — see Template Extensions.
Session Context Requirements (uses)¶
Templates can declare that they require certain external data to be provided at session start. This data typically comes from a PASETO token (in production) or from dev_settings (during development).
Declaring Requirements:
The uses key is a list of references to definition-only components. Each item can be:
- A simple string (component ID and alias are the same):
- organization - A mapping for aliasing:
- ramavtal: framework(component "ramavtal" is aliased as "framework" in the template)
# Template config.yml
uses:
- organization # Use component "organization" as "organization"
- ramavtal: framework # Use component "ramavtal" as "framework"
questions:
contract_title:
type: text
label: Contract Title
Definition-Only Components:
A definition-only component provides data structure definitions without a template file. Create one by adding definition_only: true to its component.yml:
# components/organization/component.yml
definition_only: true
definitions:
namn:
type: text
label: Organization Name
required: true
orgnr:
type: text
label: Organization Number
required: true
settings:
type: structured
fields:
feature_enabled:
type: bool
required: false
default: false
Using Session Context in Templates:
Once declared, session context values are available directly in your template:
# Contract for {{ organization.namn }}
Organization number: {{ organization.orgnr }}
{% if organization.settings.feature_enabled %}
Premium features are enabled.
{% endif %}
Validation:
At session start, VIBE validates that all required session context values are present and correctly typed. If validation fails, the user sees a 400 error explaining which values are missing or invalid.
Type Coercion:
Session context values from PASETO tokens are strings. VIBE automatically coerces them to the correct type based on the definition:
bool: "true"/"false" →True/Falsenumber: "42" or "3.14" →intorfloattext: Passed through as-is
Component Configuration (component.yml)¶
This file is located inside a component's directory. It defines a component's interface (inputs), its internal logic (questions, computables), and its relationship to other data structures (uses).
Collection Configuration (collection.yml)¶
This file is optionally located inside a file-drop component's directory (alongside the component template file). It provides a lightweight way to declare inputs and questions for simple file-drop components without requiring a full component.yml configuration.
Legacy note:
defaults.ymlis still supported as a fallback filename. If both files exist,collection.ymltakes precedence. New components should usecollection.yml.
| Key | Type | Required | Description |
|---|---|---|---|
inputs |
mapping | No | Declares the data the file-drop component expects to receive. Each input follows the same field definition syntax as component.yml inputs. |
questions |
mapping | No | Defines questions that are internal to this component (same syntax as component.yml questions). |
include |
string | list | No | Inherit from base config files. See Config Inheritance below. |
At least one of inputs or questions should be present.
Purpose and Usage:
- Documentation: Clearly documents which variables a file-drop component expects from its host template
- Validation: Enables VIBE to validate that required inputs are provided when the component is used
- Component Defaults Integration: Inputs declared here can automatically receive values from the host template's
component_defaultsconfiguration - Optional Input Handling: Allows marking specific inputs as optional using
required: false - Component-scoped questions: Questions defined here become relevant only when the component is inserted, keeping the host template's interview focused
Input Field Options:
Each input in the inputs mapping can include:
required(boolean): Whether this input must be provided. Defaults totrue.type(string): The expected data type (text, number, bool, etc.). Optional but recommended for validation.description(string): Human-readable description of the input's purpose.
# Example collection.yml in components/signature_block/
inputs:
# Required inputs that must be provided by host
signer_name:
type: text
description: Full name of the person signing the document
signer_title:
type: text
description: Job title or role of the signer
# Optional input with explicit marking
signing_date:
type: date
required: false
description: Date of signing (optional, can be filled later)
questions:
# Component-scoped question — only asked when this component is inserted
include_witness:
type: bool
label: Include witness signature line?
default: false
Integration with Component Defaults:
Inputs declared in collection.yml automatically integrate with the host template's component_defaults. If a component default exists with a matching key, it will be used as the input value unless explicitly overridden in the insert() call.
Validation Behavior:
- Required inputs (default) must either be provided in the
insert()call or available through component defaults - Optional inputs (
required: false) can be omitted without causing validation errors - Type validation is performed if a
typeis specified for the input
Config Inheritance (include)¶
Any component or collection configuration file (component.yml, collection.yml, defaults.yml) can inherit from one or more base files using the include key. This eliminates repetition when many components share the same inputs.
| Key | Type | Required | Description |
|---|---|---|---|
include |
string | list | No | Path (or list of paths) to YAML files whose contents should be merged into this config. Paths are relative to the file containing the include key. |
Merge behavior:
- Included files are loaded left-to-right (when a list). Each successive file overlays the previous.
- The current file's own keys overlay the accumulated base (current file wins).
- Nested mappings are merged recursively (deep merge). Scalars, lists, and
nullvalues replace entirely. - The
includekey itself is stripped from the final result. - Included files may themselves contain
includekeys (transitive includes). Circular chains are detected and reported as validation errors.
Example — shared inputs for a clause library:
components/
└── clauses/
├── common-inputs.yml <-- Shared base
├── confidentiality/
│ ├── collection.yml <-- include: ../common-inputs.yml
│ └── mutual_nda.md
└── dispute/
├── collection.yml <-- include: ../common-inputs.yml
└── arbitration.md
clauses/common-inputs.yml
clauses/confidentiality/collection.yml
include: ../common-inputs.yml
# Additional inputs specific to this collection
inputs:
ConfidentialityPeriod:
type: text
questions:
mutual:
label: Mutual NDA?
type: bool
The resolved config merges PartyA, PartyB, and GoverningLaw from the base with ConfidentialityPeriod from the overlay.
Error handling:
- Missing included file: validation error, template loads in degraded/invalid state.
- Invalid
includevalue (not a string or list of strings): validation error. - Circular include chain: validation error with the full chain in the message.
| Key | Type | Required | Description |
|---|---|---|---|
definition_only |
boolean | No | When true, marks this as a definition-only component that provides data structure definitions for session context validation. These components don't require a template file. |
label |
string | No | A human-readable label for the component. Especially important for appendices. |
description |
string | No | A brief description of the component's purpose. |
uses |
string | No | The ID of a definition from the host template. The component inherits all fields from this definition as its inputs. See Reuse with Components. |
inputs |
mapping | No | Declares the data the component expects to receive. Each input is a field definition (like a mini-question). |
questions |
mapping | No | Defines questions that are internal to this component and only become relevant when it is inserted. |
computables |
mapping | No | Defines computed variables that are scoped to this component. |
output |
string | No | If present, marks this component as an Appendix. The string is a Jinja template for the output filename. See Generating Appendices and Annexes. |
encapsulation |
string | No | Controls host variable visibility. strict: component only sees declared inputs, insert() kwargs, and component_defaults — host variables are not passed through. Default (omit or null): host variables are passed through automatically. Session context variables (uses:) are always available regardless of this setting. See Encapsulation. |
# Example component.yml in components/contact_card/
# This component links to a data structure defined in the host template
uses: person_definition
# It adds one additional input field of its own
inputs:
department:
type: text
label: Department
description: The contact's department, e.g., 'Sales'.
required: false
# It also has its own internal question
questions:
show_department:
label: Show department on the contact card?
type: bool
default: true
required: false
# Example appendix component.yml in components/pricing_schedule/
# Marks this as an appendix and defines the output filename pattern
output: "Appendix-{{ ref.numbering }}-{{ ref.label|slugify }}.docx"
label: Pricing Schedule
description: A detailed breakdown of pricing for all services.
# Defines questions that will appear in the UI when this appendix is included
questions:
unit_price:
type: number
label: Price per unit
min: 0
currency:
type: select
label: Currency
options:
- USD
- EUR
- GBP
default: USD