Extension anatomy

A Terminay extension is one npm package, one immutable extension ID, one ESM entrypoint, and at least one declared contribution. The manifest describes its public contract before code runs.

The manifest lives in package.json

JSON
"terminay": {
  "manifestVersion": 1,
  "id": "com.example.agent",
  "displayName": "Example Agent",
  "api": "^3.0.0",
  "engines": { "terminay": ">=1.0.0", "node": ">=24" },
  "entrypoint": "extension.js",
  "permissions": ["agent-observation"],
  "contributes": {
    "agentSessionSources": [{
      "id": "com.example.agent/sessions",
      "displayName": "Example Agent",
      "harnesses": [{ "id": "example-agent", "displayName": "Example Agent" }]
    }]
  }
}
FieldWhy it matters
idImmutable extension identity. Package name and extension ID are separate.
apiThe supported Terminay Extension API range. A major version is breaking; a minor is additive.
enginesRequired Terminay and Node versions.
entrypointA relative .js ESM file that the package also lists in exports.
permissionsExplicit host capabilities, such as agent-observation.
contributesOne or more of agentSessionSources, mcpInstallTargets, languageServers, and worktreeInsights.

The manifest is data only. See the manifest reference for every field.

Activation is small and explicit

Default-export the value returned by defineExtension(). There is no global Terminay object: everything the host grants arrives on context or on a callback argument.

TypeScript
import { defineExtension } from '@terminay/extension-api';
import { exampleSessionSource } from './example-agent.js';

export default defineExtension({
  activate(context) {
    context.subscriptions.add(
      context.agents.registerSessionSource(
        'com.example.agent/sessions',
        exampleSessionSource,
      ),
    );
  },
});
Context surfaceUse it for
context.agents.registerSessionSource()Register the runtime for a declared agent session source.
context.mcp.registerInstallTarget()Register the runtime for a declared MCP install target.
context.registerLanguageServerProvider()Register the launch callback for a declared language server.
context.worktrees.registerInsightSource()Register the runtime for a declared worktree insight source.
context.subscriptionsGive Terminay disposables to clean up when the activation ends.
context.pathsFind the extension's own configuration, data, and cache directories.

A registration is accepted only for an ID the manifest declares. An undeclared ID or a second registration of the same ID throws.

Contributions

Agent session sources

A session source reports every live coding-agent session of its harnesses on the server's machine, however the session was started. It publishes bounded snapshots. Terminay decides which project a session belongs to and which terminal, if any, it binds to. See Agent session sources.

MCP install targets

An install target owns one client's Terminay MCP registration. It reports status and writes or removes the host-supplied server command in that client's configuration file. See MCP install targets.

Language servers

A language server contribution declares the languages and file extensions it serves and returns a launch command for a project root. Terminay spawns the server and speaks the Language Server Protocol to it. See Language servers.

Worktree insight sources

An insight source receives the repositories of open projects and publishes a pull request and checks summary per worktree. Terminay renders them. See Worktree insights.

Keep the boundary clear

  • Extensions can use public Node modules and declared npm dependencies.
  • They cannot import private Terminay packages, Electron APIs, or host bridges.
  • They cannot add renderer components, routes, themes, menus, or raw terminal access.
  • They run as trusted server-side code, so administrators review permissions before installing them.

Continue building

Create an agent extension