Skip to content

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

  1. System Configuration (config.yml)
    • Core application and web server settings.
  2. Template Configuration (config.yml)
    • Defines the questions, logic, and metadata for a single interview template.
  3. 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:

template_sources:
  nda_template:
    path: ./templates/nda

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:

template_sources:
  my_templates:
    include: ./templates

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:

template_sources:
  external:
    include: ./external-templates
    recursive: true

With a directory structure like:

external-templates/
    contracts/
        nda/
            config.yml
        employment/
            config.yml
    forms/
        intake/
            config.yml

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 include discovers a template ID that is already registered (by an explicit path entry or by another include), VIBE raises an error at startup naming both sources.
  • path and include are 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 named default.
  • 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:

  • null means 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: ...})
  • The provider auto-generates tool-call IDs and follows the order of the list, matching the behavior of COMPLETE_WORKFLOW_RESPONSES (see tests/assistant/integration/browser.py for 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 when chunk_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). Set false for plain text interactions.
  • remove_empty_content – Controls handling of empty content in assistant messages with tool calls. When true (default), omits the content field entirely for OpenAI/Mistral compatibility. When false, includes content: null for third-party providers that require the field to be present. Only relevant when using tools.
  • max_tokens – Upper bound for generated tokens (max_output_tokens when using Responses models).
  • temperature – Sampling temperature. Forwarded only when tools are disabled; omit it for Responses-first models where reasoning.effort is preferred.
  • reasoning_effort – Sets reasoning.effort (low, medium, or high) on Responses requests. Defaults to medium when omitted.
  • text_verbosity – Sets text.verbosity (low, medium, or high) for Responses models. Defaults to medium and 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 their review.embedding setting.
  • 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 their review.reranking setting.
  • 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:

  1. Docker must be installed and running
  2. Tesseract container must be running:
    docker compose up -d tesseract
    

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:

  1. Docker must be installed and running
  2. LibreOffice container must be running:
    docker compose up -d libreoffice
    

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:

  1. When a user starts an interview, VIBE checks for a PASETO token first.
  2. If no token is found and debug: true is set, VIBE uses dev_settings instead.
  3. 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:

ui:
  templates: ui
  css: ui/theme.css

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:

  1. A template opts in by declaring docx_wrapper in its own config.yml with a filename pattern.
  2. At render time, VIBE resolves the pattern against the current interview state, which includes any session context variables and user answers.
  3. 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.
  4. 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):

# config.yml (system)
docx_wrapper:
  path: /data/wrapper_files

Template config (authoring concern -- opt-in per template):

# templates/my-template/config.yml
docx_wrapper:
  filename: "{organization_id}.docx"

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:

  1. docx_wrapper.path in the template config (relative to template bundle directory)
  2. docx_wrapper.path in the system config

Wrapper file requirements:

  • Must be a valid .docx file.
  • 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:

vibe test my-template -s "My scenario" --save . --format docx

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/False
  • number: "42" or "3.14" → int or float
  • text: 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.yml is still supported as a fallback filename. If both files exist, collection.yml takes precedence. New components should use collection.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_defaults configuration
  • 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 to true.
  • 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 type is 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 null values replace entirely.
  • The include key itself is stripped from the final result.
  • Included files may themselves contain include keys (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

inputs:
  PartyA:
    type: text
  PartyB:
    type: text
  GoverningLaw:
    type: text

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 include value (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