Extension manifest

The manifest is the closed terminay object in your package's package.json. Terminay validates it before importing your extension. Its type is TerminayExtensionManifest.

Example

JSON
{
  "name": "terminay-example-session-source",
  "version": "1.0.0",
  "type": "module",
  "exports": { ".": "./extension.js" },
  "peerDependencies": { "@terminay/extension-api": "^3.0.0" },
  "terminay": {
    "manifestVersion": 1,
    "id": "com.example.agent",
    "displayName": "Example Agent",
    "description": "Shows Example Agent sessions in Terminay and registers the Terminay MCP server with it.",
    "api": "^3.0.0",
    "engines": { "terminay": ">=1.0.0", "node": ">=24" },
    "entrypoint": "extension.js",
    "platforms": ["darwin", "linux"],
    "permissions": ["agent-observation", "mcp-registration"],
    "contributes": {
      "agentSessionSources": [{
        "id": "com.example.agent/sessions",
        "displayName": "Example Agent",
        "harnesses": [{ "id": "example-agent", "displayName": "Example Agent" }],
        "environmentVariables": ["EXAMPLE_AGENT_HOME"]
      }],
      "mcpInstallTargets": [{
        "id": "com.example.agent/example-agent",
        "displayName": "Example Agent"
      }]
    }
  }
}

name, version, and an exports entry for the entrypoint are package requirements. Package name and extension id are deliberately separate.

Top-level fields

FieldRequiredMeaning
manifestVersionYesManifest format. Use 1.
idYesImmutable extension identity: lowercase letters, digits, dots, and hyphens, starting and ending with a letter or digit, at most 128 characters.
displayNameYesHuman-readable name, at most 96 characters.
descriptionNoShort description shown by Terminay, at most 1,024 characters.
apiYesExtension API range. See range syntax.
enginesYesExactly terminay and node ranges.
entrypointYesRelative, forward-slash path ending in .js, with no .. segment. It must also appear in the package's exports.
platformsNoNon-empty list of darwin, linux, or win32.
permissionsYesRequested host capabilities, possibly empty. See Permissions.
extensionDependenciesNoUp to 32 other extensions: extensionId, apiRange, and optional boolean optional.
contributesYesThe contribution arrays below. At least one is required, and a declared array cannot be empty.

contributes.agentSessionSources

Each item declares a machine-wide agent session source. Declaring one requires the agent-observation permission.

FieldMeaning
idRequired. <extensionId>/<local-id>, where the local ID is lowercase kebab-case.
displayNameRequired label.
description, platformsOptional metadata and OS restriction.
harnessesRequired. One to 16 objects with a unique kebab-case id and a displayName. Each is one agent the source can report, with its own switch in Settings.
environmentVariablesOptional. Up to 32 server environment variable names the extension process should receive when they are set.

contributes.mcpInstallTargets

Each item declares one client the Terminay MCP server can be registered with. Declaring one requires the mcp-registration permission. At most 16.

FieldMeaning
idRequired. Namespaced by the extension ID.
displayNameRequired. The client's name as the install surface shows it.

contributes.languageServers

Each item declares one language server. No permission is required. At most 8.

FieldMeaning
idRequired. Extension-local kebab-case ID such as typescript. It is not namespaced.
displayNameRequired label.
descriptionOptional.
languageIdsRequired. One to 32 unique language IDs such as typescriptreact.
fileExtensionsRequired. One to 32 unique lowercase extensions with the leading dot, such as .tsx.
runtimeNotesOptional text shown in Settings.

contributes.worktreeInsights

Each item declares one worktree insight source. Declaring one requires the worktree-observation permission and API ^3.1.0. At most 8.

FieldMeaning
idRequired. Namespaced by the extension ID.
displayNameRequired label.
descriptionOptional.

Validation

validateExtensionManifest(value) returns either the manifest or a list of issues, each with a path, code, and message. parseExtensionManifest(value) throws ExtensionSchemaError instead.

CodeCause
unknown_fieldA field the schema does not define, at any level.
unsupported_versionmanifestVersion is not 1.
invalid_id, invalid_namespaceA malformed ID, or a contribution ID not prefixed by the extension ID.
unsafe_entrypointAn absolute, escaping, backslash, or non-.js entrypoint.
unknown_permission, missing_permissionAn unrecognized permission, or a contribution without the permission it requires.
missing_contributioncontributes declares no supported array.
duplicateA repeated permission, contribution ID, harness ID, or dependency.
invalid_language_id, invalid_file_extensionA malformed language server selector.
missing_exports, entrypoint_not_exportedThe package does not export the entrypoint.

Before import, the host also rejects an entrypoint that is a symbolic link or not a regular file inside the package.