Project environments
A project-environment provider creates and operates one kind of environment for a Terminay project. The host renders its declarative forms and calls its typed runtime; extension code never renders UI directly.
Manifest contribution
Declare the provider in contributes.projectEnvironments, then register its runtime during activation.
| Field | Meaning |
|---|---|
id | Provider identity, namespaced by the immutable extension ID. |
displayName, description, icon | Host-rendered provider metadata. Icons are limited to Terminay’s named icon allowlist. |
capabilities | Environment services this provider makes available; listed below. |
profileSave | Optional { createEnvironment: true }. Without it, saving a profile does not create an environment. |
dependencyOperations | Optional allowlist of public operation names that compatible extension dependencies may call. |
| Capability | Environment service |
|---|---|
terminal | Terminal access routed through this environment. |
filesystem, filesystem-observation | Filesystem access or bounded filesystem observation. |
git | Git integration. |
process-observation, agent-journal | Bounded process facts and agent-journal observation. |
mcp-bridge, infrastructure, shell-discovery | MCP bridging, infrastructure operations, and shell discovery. |
Register a provider
import { defineExtension } from '@terminay/extension-api';
export default defineExtension({
activate(context) {
context.registerProjectEnvironmentProvider({
definition: {
providerId: 'acme-cloud',
displayName: 'Acme Cloud',
capabilities: ['terminal', 'filesystem', 'agent-journal'],
},
runtime: {
async testProfile({ values }) {
return values.token ? [] : [{
fieldId: 'token', code: 'required', message: 'Add an API token.',
}];
},
async resolveOptions() { return { options: [] }; },
async createEnvironment(request) {
return {
state: 'ready',
providerState: { instanceId: request.environmentId },
status: { state: 'available', revision: 1 },
};
},
async resumeOperation() { throw new Error('No pending operations.'); },
async getStatus({ providerState }) {
return { state: 'available', revision: 1, card: {
id: 'instance', title: 'Acme Cloud', summary: String(providerState),
}};
},
async invokeAction(request) {
return { state: 'complete', providerState: request.providerState,
status: { state: 'available', revision: 1 } };
},
},
});
},
}); registerProjectEnvironmentProvider() receives a definition, a
required runtime, and optionally dependencyOperations: a handler
for the operations declared in the manifest.
| Provider definition | Type |
|---|---|
providerId, displayName, description?, icon? | Provider identity and host-rendered metadata. |
capabilities | Required EnvironmentCapability[]; it must match the declared provider. |
profileForm?, createForm? | Optional declarative forms for saved profiles and environment creation. |
Declarative forms and presentation
A form has id, title, optional description, ordered
sections, and submitLabel. A section has id,
title, optional description, disclosure (always,
expanded, or collapsed), and fields.
| Field type | Additional fields |
|---|---|
| All fields | id, label, optional description, required, disabled reason, default value, and visibleWhen (equals / notEquals). |
text, url, secret, textarea | Placeholder, length bounds, pattern, or an asynchronous suggestion source and label. |
number | Minimum, maximum, and step. |
checkbox, switch | Boolean controls. |
select | Static options or optionSource, searchable and multiple selection flags. |
preset-cards | Static options with an optional allowed icon, or optionSource. |
Runtime responses may provide field ValidationIssues, status cards, guarded HTTPS links,
actions (including an ordinary or destructive confirmation), and resumable progress stages.
Runtime methods
| Method | Request and result |
|---|---|
testProfile | { profileId?, values } → ValidationIssue[]. |
resolveOptions | { sourceId, profileId?, query?, cursor?, values } → select options and optional next cursor. |
createEnvironment | { environmentId, displayName, profileId?, values } → ready status or a pending resumable operation. |
resumeOperation | Environment state and operationId → ready status or a still-pending operation. |
getStatus | { environmentId, profileId?, providerState } → availability, message, root, card/progress, and revision. |
invokeAction | Environment state, actionId, and optional values → complete or pending action result. |
invokeService? | Optional, environment-bound call with one declared capability, operation, project ID, revision, and JSON input. |
updateEnvironment? | Optional environment state plus new values → complete or pending action result. |
deleteEnvironment? | Optional environment state → complete or pending action result. |
Every method receives ProviderCallContext: an absolute deadlineAt,
cancellation signal, retry-stable idempotencyKey?, optimistic
expectedRevision?, and scoped profiles, secrets, SSH-agent, and dependency brokers.
See scoped brokers.
Boundaries
Provider output is declarative and bounded: no custom React, HTML, CSS, routes, or raw application-protocol handlers. The server owns project bindings, environment revisions, confirmation, cancellation, and lifecycle policy.