Skip to content

File Types, Associations, and App Capabilities

Design the end-to-end experience for how files are previewed, opened, edited, and printed using a single, unified model:

  • fileTypes: define what a file “is” and how to match it.
  • apps[].capabilities: let apps declare what file types and verbs they can handle.
  • fileAssociations: centrally curate the UX (defaults, Open With, previews, and print).

What You'll Learn

  • Single source of truth for file type matching (fileTypes)
  • Clear separation of concerns: capability (app) vs UX (routing)
  • Deterministic precedence and selection per verb
  • Built-in preview providers configured centrally

Overview

  • fileTypes (registry):
    • Central registry of recognizable file kinds with a single match definition (e.g., “pdf”, “word-docs”).
    • Case-insensitive extension matching.
    • Optional defaultPreviewProvider for built-in previews.
  • App Capabilities (per-app):
    • Apps declare which fileTypes they support and how to invoke verbs (open/edit/print).
    • Capabilities do not by themselves determine UI; they provide launch details when chosen by file associations.
  • File Associations (central UX):
    • Rules per fileType that define which handlers are available for each verb, which one is default, and whether entries appear in Open With.
    • Associations can reference apps by appRef or specify targetPath directly.
    • Built-in preview providers live here (or on the fileType via defaultPreviewProvider).

Security gating

  • Any association entry that references an application requires an enabled application policy with action: "allow" that matches the executable. Otherwise, that entry is ignored.
  • Association rules do not expand discovery scope; applications must still be discoverable via Start Menu/Desktop shortcut scan.

File Types (Registry)

Centralize file type recognition to avoid scattered literal extension lists.

Structure

json
{
  "fileTypes": [
    {
      "id": "pdf",
      "displayName": "PDF",
      "match": { "extensions": ["pdf"] },
      "defaultPreviewProvider": "builtInPdf"
    },
    {
      "id": "word-docs",
      "displayName": "Word Documents",
      "match": { "extensions": ["doc", "docx"] }
    }
  ]
}

Fields

  • id (string, required): kebab-case; unique and stable within fileTypes.
  • displayName (string, required): shown in UI where applicable.
  • match (required): a single match object:
    • extensions (string[]): one or more file extensions (no leading dot). Case-insensitive (e.g., pdf, PDF).
  • defaultPreviewProvider (string, optional): "builtInPdf" | "builtInImage" | "builtInText"

Case sensitivity

  • Extensions are matched case-insensitively.

App Capabilities (Per-App Declaration)

Apps declare the file types and verbs they support. Capabilities describe "can do X with Y fileType" plus the invocation details (arguments and optional flags). UI/selection is controlled by fileAssociations.

Structure

json
{
  "id": "ms-word",
  "displayName": "Microsoft Word",
  "enabled": true,
  "priority": 200,
  "visibility": "hidden",
  "matchAll": [
    { "type": "targetPath", "pattern": ".*WINWORD\\.EXE$", "patternType": "regex" }
  ],
  "action": "allow",
  "capabilities": [
    {
      "fileTypeRef": "word-docs",
      "verbs": {
        "open":  { "arguments": "\"%1\"" },
        "edit":  { "arguments": "/e \"%1\"" },
        "print": { "arguments": "/p \"%1\"" }
      }
    }
  ]
}

Fields

  • capabilities[].fileTypeRef (string, required): references fileTypes[].id.
  • capabilities[].verbs (dictionary, optional): maps verb names to invocation details. Supports standard verbs (open, edit, print) and custom verbs (e.g., extract).
    • arguments (string, optional): command string; supports variable substitution (%1, %~dp1, %~n1, %~dpn1).
    • vmFlags (string[], deprecated): additional flags for this verb. Deprecated: use runtime instead for structured settings.
    • runtime (Runtime, optional): additional runtime settings for this verb. Replaces vmFlags.

Notes

  • Capabilities do not create context menu entries or defaults by themselves; fileAssociations curate the UX.
  • Security gating still applies at launch time (the app must be discoverable and allowed).

File Associations (Central UX)

Routing rules determine the user experience per fileType: which actions exist, which is default, and whether entries appear in context menus. Built-in previews are configured as actions.

Structure

json
{
  "fileAssociations": [
    {
      "id": "pdf-routing",
      "displayName": "PDF",
      "enabled": true,
      "priority": 250,
      "fileTypeRef": "pdf",
      "actions": [
        { "verb": "preview", "displayName": "Preview", "provider": "builtInPdf", "default": true },
        { "verb": "open", "displayName": "Open", "appRef": "google-chrome", "showInContextMenu": true }
      ]
    }
  ]
}

Action Entry Fields

  • verb (string, required): verb name (e.g., preview, open, edit, print, extract). Must match a verb in the app's capabilities (or be preview for built-in preview).
  • displayName (string, required): label shown in menus.
  • appRef (string): id of an application policy to launch for this verb. Required for non-preview actions.
  • provider (string): built-in preview provider (builtInPdf, builtInImage, builtInText). Required for preview verb only.
  • default (boolean): marks this action as the default for double-click.
  • showInContextMenu (boolean): show in main context menu (default: true).
  • showInOpenWith (boolean): include in Open With submenu (default: true).
  • match (optional): narrows the action within the fileType (e.g., split doc vs docx).

Action and Capability Resolution

When an action references an app via appRef, invocation details come from the app's capabilities for that verb:

  • arguments: Retrieved from apps[].capabilities[].verbs[verbName].arguments
  • vmFlags (deprecated): Retrieved from apps[].capabilities[].verbs[verbName].vmFlags
  • runtime: Retrieved from apps[].capabilities[].verbs[verbName].runtime

Boolean Logic

  • An association rule applies when its fileTypeRef matches the file’s fileType (see resolution).
  • Per-handler match (optional) further narrows the handler within the fileType context.
  • To express OR across file types, author multiple routing rules, each with its own fileTypeRef; for OR within a fileType, use match.extensions with multiple values or separate handler entries with different match filters.

Variable Substitution

The following variables are available in arguments:

VariableDescriptionExample (Given C:\Downloads\MyArchive.zip)
%1Full path to the fileC:\Downloads\MyArchive.zip
%~dp1Drive and Path onlyC:\Downloads\
%~n1File name without extensionMyArchive
%~dpn1Derived Destination Path (Path + Name)C:\Downloads\MyArchive\

Quote Escaping

  • When a variable appears inside quotes (e.g., "%1"), all backslashes in the substituted value are escaped (\\\).
  • When a variable appears outside quotes, backslashes are not escaped.
  • To include a literal % character, use %%.

Resolution Algorithm

  1. Determine fileType:

    • Match the file against fileTypes[].match. If multiple fileTypes match, select by:
      • Highest fileTypes array order? No — use a stable deterministic rule:
        • Prefer the fileType whose match is more specific when determinable (for example, a single-extension type over a broader multi-extension type that also includes the same extension); otherwise fall back to fileType id alphabetical.
      • Matching is case-insensitive for extensions.
    • If no fileType matches, associations do not apply.
  2. Gather routing rules:

    • Collect all enabled fileAssociations rules where fileTypeRef equals the selected fileType id.
  3. For the requested verb (open, edit, print, preview):

    • Aggregate all handlers for that verb from the collected routing rules.
  4. Choose the default handler:

    • Any handler with default: true.
    • Else highest routing rule priority (descending).
    • Else stable alphabetical tie-break by routing rule id (fallback to displayName when id is missing).
  5. Open With menu:

    • Include handlers where showInOpenWith: true.
  6. Security gating:

    • If a handler references an app (appRef or targetPath), it is only considered valid if at least one enabled application policy with action: "allow" matches the executable. Otherwise the handler is ignored.

Resolution flow

Mermaid Diagram

Print

  • The Print action is available only when at least one print handler exists in applicable routing rules for the fileType.
  • If no association rule provides verbs.print, the Print action is not offered.

::: note Device-level vs UI-level

  • UI-level: include or omit verbs.print in routing to control whether the Launcher offers the Print action for a file type.
  • Device-level: enforce printer availability and restrictions via runtime runtime.devices or vendor-specific runtime.extensions (global or per-app). See: Device-level Settings and Schema Reference :::

Examples

Hidden Word with centralized routing and split doc vs docx

json
{
  "fileTypes": [
    { "id": "word-docs", "displayName": "Word Documents", "match": { "extensions": ["doc", "docx"] } }
  ],
  "apps": [
    {
      "id": "ms-word",
      "displayName": "Microsoft Word",
      "enabled": true,
      "priority": 200,
      "visibility": "hidden",
      "matchAll": [
        { "type": "targetPath", "pattern": ".*WINWORD\\.EXE$", "patternType": "regex" }
      ],
      "action": "allow",
      "capabilities": [
        {
          "fileTypeRef": "word-docs",
          "verbs": {
            "open":  { "arguments": "\"%1\"" },
            "edit":  { "arguments": "/e \"%1\"" },
            "print": { "arguments": "/p \"%1\"" }
          }
        }
      ]
    }
  ],
  "fileAssociations": [
    {
      "id": "word-docs-routing",
      "displayName": "Word docs",
      "enabled": true,
      "priority": 300,
      "fileTypeRef": "word-docs",
      "actions": [
        { "verb": "open", "displayName": "Open", "appRef": "ms-word", "match": { "extensions": ["docx"] }, "default": true, "showInContextMenu": true },
        { "verb": "open", "displayName": "Open (Compatibility Mode)", "appRef": "ms-word", "match": { "extensions": ["doc"] }, "showInContextMenu": true },
        { "verb": "print", "displayName": "Print", "appRef": "ms-word", "default": true }
      ]
    }
  ]
}

PDF with built-in preview and hidden Chrome for context menu

json
{
  "fileTypes": [
    { "id": "pdf", "displayName": "PDF", "match": { "extensions": ["pdf"] }, "defaultPreviewProvider": "builtInPdf" }
  ],
  "apps": [
    {
      "id": "google-chrome",
      "displayName": "Google Chrome",
      "enabled": true,
      "priority": 150,
      "visibility": "hidden",
      "matchAll": [
        { "type": "targetPath", "pattern": ".*chrome\\.exe$", "patternType": "regex" }
      ],
      "action": "allow",
      "capabilities": [
        { "fileTypeRef": "pdf", "verbs": { "open": { "arguments": "\"%1\"" } } }
      ]
    }
  ],
  "fileAssociations": [
    {
      "id": "pdf-routing",
      "displayName": "PDF",
      "enabled": true,
      "priority": 250,
      "fileTypeRef": "pdf",
      "actions": [
        { "verb": "preview", "displayName": "Preview", "provider": "builtInPdf", "default": true },
        { "verb": "open", "displayName": "Open", "appRef": "google-chrome", "showInContextMenu": true }
      ]
    }
  ]
}

Image previews (built-in only)

json
{
  "fileTypes": [
    { "id": "images", "displayName": "Images", "match": { "extensions": ["png", "jpg", "jpeg", "gif"] }, "defaultPreviewProvider": "builtInImage" }
  ],
  "fileAssociations": [
    {
      "id": "images-routing",
      "displayName": "Images",
      "enabled": true,
      "priority": 200,
      "fileTypeRef": "images",
      "actions": [
        { "verb": "preview", "displayName": "Preview", "provider": "builtInImage", "default": true }
      ]
    }
  ]
}

Disable Print for PDFs (omit print actions)

json
{
  "fileTypes": [
    { "id": "pdf", "displayName": "PDF", "match": { "extensions": ["pdf"] }, "defaultPreviewProvider": "builtInPdf" }
  ],
  "fileAssociations": [
    {
      "id": "pdf-no-print",
      "displayName": "PDF (no printing)",
      "enabled": true,
      "priority": 250,
      "fileTypeRef": "pdf",
      "actions": [
        { "verb": "preview", "displayName": "Preview", "provider": "builtInPdf", "default": true }
      ]
    }
  ]
}

Route DOC/DOCX Print to Word

json
{
  "fileTypes": [
    { "id": "word-docs", "displayName": "Word Documents", "match": { "extensions": ["doc", "docx"] } }
  ],
  "apps": [
    {
      "id": "ms-word",
      "displayName": "Microsoft Word",
      "enabled": true,
      "priority": 200,
      "matchAll": [
        { "type": "targetPath", "pattern": ".*WINWORD\\.EXE$", "patternType": "regex" }
      ],
      "action": "allow",
      "capabilities": [
        { "fileTypeRef": "word-docs", "verbs": { "open": { "arguments": "\"%1\"" }, "print": { "arguments": "/p \"%1\"" } } }
      ]
    }
  ],
  "fileAssociations": [
    {
      "id": "word-docs-print",
      "displayName": "Word docs (print via Word)",
      "enabled": true,
      "priority": 300,
      "fileTypeRef": "word-docs",
      "actions": [
        { "verb": "open", "displayName": "Open", "appRef": "ms-word", "default": true, "showInContextMenu": true },
        { "verb": "print", "displayName": "Print", "appRef": "ms-word", "default": true }
      ]
    }
  ]
}

Developer source files → hidden editor via routing

json
{
  "fileTypes": [
    {
      "id": "source-files",
      "displayName": "Source files",
      "match": { "extensions": ["txt","md","json","yml","yaml","xml","ini","cfg","log","js","ts","jsx","tsx","css","scss","less","py","rb","go","rs","java","c","cpp","h","hpp","cs"] }
    }
  ],
  "apps": [
    {
      "id": "code-editor",
      "displayName": "Code Editor",
      "enabled": true,
      "priority": 190,
      "visibility": "hidden",
      "matchAll": [
        { "type": "targetPath", "pattern": ".*(Code|notepad\\+\\+|sublime_text)\\.exe$", "patternType": "regex" }
      ],
      "action": "allow",
      "capabilities": [
        { "fileTypeRef": "source-files", "verbs": { "open": { "arguments": "\"%1\"" } } }
      ]
    }
  ],
  "fileAssociations": [
    {
      "id": "source-files-routing",
      "displayName": "Source files",
      "enabled": true,
      "priority": 280,
      "fileTypeRef": "source-files",
      "actions": [
        { "verb": "open", "displayName": "Open", "appRef": "code-editor", "default": true, "showInContextMenu": true }
      ]
    }
  ]
}

RDP and VNC clients + routing

json
{
  "fileTypes": [
    { "id": "rdp", "displayName": "RDP", "match": { "extensions": ["rdp"] } },
    { "id": "vnc", "displayName": "VNC", "match": { "extensions": ["vnc"] } }
  ],
  "apps": [
    {
      "id": "rdp-client",
      "displayName": "Remote Desktop Connection",
      "enabled": true,
      "priority": 160,
      "matchAll": [ { "type": "targetPath", "pattern": ".*mstsc\\.exe$", "patternType": "regex" } ],
      "action": "allow",
      "capabilities": [ { "fileTypeRef": "rdp", "verbs": { "open": { "arguments": "\"%1\"" } } } ]
    },
    {
      "id": "vnc-viewer",
      "displayName": "VNC Viewer",
      "enabled": true,
      "priority": 160,
      "matchAll": [ { "type": "targetPath", "pattern": ".*vncviewer.*\\.exe$", "patternType": "regex" } ],
      "action": "allow",
      "capabilities": [ { "fileTypeRef": "vnc", "verbs": { "open": { "arguments": "\"%1\"" } } } ]
    }
  ],
  "fileAssociations": [
    {
      "id": "rdp-routing",
      "displayName": "RDP",
      "enabled": true,
      "priority": 260,
      "fileTypeRef": "rdp",
      "actions": [ { "verb": "open", "displayName": "Open", "appRef": "rdp-client", "default": true, "showInContextMenu": true } ]
    },
    {
      "id": "vnc-routing",
      "displayName": "VNC",
      "enabled": true,
      "priority": 260,
      "fileTypeRef": "vnc",
      "actions": [ { "verb": "open", "displayName": "Open", "appRef": "vnc-viewer", "default": true, "showInContextMenu": true } ]
    }
  ]
}

ZIP extraction with custom extract verb and system tar utility

json
{
  "fileTypes": [
    {
      "id": "zip-archive",
      "displayName": "Compressed (zipped) Folder",
      "match": { "extensions": ["zip"] }
    }
  ],
  "apps": [
    {
      "id": "system-tar",
      "displayName": "System Tar",
      "targetPath": "%SYSTEMROOT%\\System32\\cmd.exe",
      "enabled": true,
      "priority": 60,
      "visibility": "hidden",
      "action": "allow",
      "capabilities": [
        {
          "fileTypeRef": "zip-archive",
          "verbs": {
            "extract": { "arguments": "/c mkdir \"%~dpn1\" & tar -xf \"%1\" -k -C \"%~dpn1\"" }
          }
        }
      ]
    }
  ],
  "fileAssociations": [
    {
      "id": "zip-extraction-routing",
      "displayName": "Extract ZIP archives",
      "enabled": true,
      "priority": 100,
      "fileTypeRef": "zip-archive",
      "actions": [
        { "verb": "extract", "displayName": "Extract", "appRef": "system-tar", "default": true }
      ]
    }
  ]
}

File Policies (Files Tab)

Control which file operations are allowed. Defaults:

OperationDefaultDescription
listAllowShow files in the file browser (Files tab)
importAllowImport files into sandbox
exportDenyExport files from sandbox
openAllowOpen files with configured routing
deleteAllowDelete files in sandbox

Structure

Define the referenced file type in fileTypes[] (for example, an executable entry that matches installer/PE extensions).

json
{
  "id": "deny-import-executables",
  "displayName": "Block executable imports",
  "enabled": true,
  "priority": 1000,
  "operation": "import",
  "fileTypeRef": "executable",
  "action": "deny"
}

Match Semantics (File Policies)

  • fileTypeRef must reference an entry in fileTypes[].
  • Resolution uses the same fileType matching rules as associations: prefer more specific fileTypes; ties break by fileType id (alphabetical). Conflicts across file policies resolve by rule priority (descending), then id alphabetical (fallback to displayName when id is missing).

List Operation (Files Tab)

  • Controls visibility in the Files tab listing; does not execute a verb.
  • action: "allow" shows matching items; action: "deny" hides them.
  • Conflicts resolve by rule priority (descending), then rule id alphabetical, consistent with other file operations.

Example (hide temp/backup files)

json
{
  "id": "hide-temp-and-backups",
  "displayName": "Hide temporary/backup files",
  "enabled": true,
  "priority": 900,
  "operation": "list",
  "fileTypeRef": "temp-and-backups",
  "action": "deny"
}

Choosing What to Author Where

  • fileTypes: define once, reuse everywhere. If you add or change extensions, do it here.
  • App Capabilities: let each app declare what it can handle and how (per verb).
  • fileAssociations: curate the user experience per fileType. Defaults, Open With presence, previews, and print are chosen here.

Rule of thumb

  • If users should have a consistent experience (previews, Open With, defaults, print) across apps → configure fileAssociations for that fileType.
  • If a single app “owns” a type and you don’t need multiple choices, you can still use fileAssociations with a single handler. Capabilities simply supply the invocation details.

Next Steps