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.my-agent",
  "displayName": "My agent",
  "api": "^1.2.0",
  "engines": { "terminay": ">=1.0.0", "node": ">=24" },
  "entrypoint": "dist/index.js",
  "permissions": ["agent-observation"],
  "contributes": { "agentProviders": [/* … */] }
}
FieldWhy it matters
idImmutable extension identity. Package name and extension ID are intentionally separate.
apiThe supported Terminay Extension API range. A major version is breaking; a minor is additive.
enginesRequired Terminay and Node versions.
entrypointA relative ESM file included in the packed package.
permissionsExplicit host capabilities, such as agent-observation.
contributesOne or more project-environment or agent-provider declarations.

Activation is small and explicit

Export defineExtension({ activate(context) { … } }) from the entrypoint. The context provides your extension ID, negotiated API version, private configuration/data/cache paths, a disposable subscription bag, and the two registration surfaces.

Context surfaceUse it for
context.agents.registerProvider()Register the runtime for a declared agent provider.
context.registerProjectEnvironmentProvider()Register a declared project-environment definition and runtime.
context.subscriptionsGive Terminay disposables to clean up during deactivation.
context.pathsFind the package’s own configuration, data, and cache directories.

Contributions

Agent providers

An agent provider matches a foreground process, receives a terminal-scoped observation context, and returns unavailable, not-bound, or a bound session. It can observe bounded process and file facts, follow an agent journal, and publish normalized lifecycle events. It cannot control the terminal or mutate Terminay’s agent store directly.

Project-environment providers

An environment provider declares host-rendered forms and environment capabilities, then implements the runtime methods that validate profiles, create or resume an environment, report its status, and run declared actions.

TypeScript
export default defineExtension({
  activate(context) {
    context.registerProjectEnvironmentProvider({
      definition: {
        providerId: 'com.example.host/ssh',
        displayName: 'Example host',
        capabilities: ['terminal', 'filesystem'],
      },
      runtime: {
        async testProfile() { return []; },
        async resolveOptions() { return { options: [] }; },
        async createEnvironment(request) { /* return ready or pending */ },
        async resumeOperation(request) { /* resume a pending operation */ },
        async getStatus(request) { /* return current status */ },
        async invokeAction(request) { /* return complete or pending */ },
      },
    });
  },
});

Provider calls include a deadline, cancellation signal, and (for mutations) idempotency and revision information. Profiles, secrets, SSH signing, and extension dependencies are only available through scoped brokers on that call context.

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 custom 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 →