Where Agent Capabilities Are Defined in Nodeterm: Inside `src/shared/agents/config.ts`

TLDR: In the eneskirca/nodeterm repository, all agent capabilities for Nodeterm are defined centrally inside src/shared/agents/config.ts, which exports agent IDs, a static AGENT_CONFIG, capability membership arrays, and predicate helper functions such as canResume(), hasHooks(), and canControlCanvas() that the rest of the codebase imports to gate features.

Nodeterm is an open-source terminal-based agent launcher that supports multiple AI coding agents like Claude, Codex, Gemini, and Grok. Because each agent has different abilities — hook support, resume capability, usage tracking, or canvas control — Nodeterm centralizes every agent capability definition in a single module. According to the Nodeterm source code, that authoritative module lives at [src/shared/agents/config.ts](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/config.ts), and every UI feature, launch-line builder, and process manager pulls capability checks from it.

Nodeterm: The Single Source of Truth for Agent Capabilities

The design principle behind Nodeterm's agent capability system is centralization: one file defines what each agent can do, and everywhere else simply consumes those definitions. This guarantees consistent behavior across the desktop, server, and mobile surfaces — and makes adding a new capability a one-file change.

In src/shared/agents/config.ts, you'll find:

  • Agent identifiers — a generic AgentId type plus built-in IDs (claude, codex, gemini, opencode, grok, copilot)
  • Static configuration — the AGENT_CONFIG map holding launch commands, color associations, and prompt-injection modes per agent
  • Capability membership lists — a series of const ... = [...] as const arrays, each representing the set of agents that support a given capability (e.g., USAGE_CAPABLE, CANVAS_CONTROL_CAPABLE, RESUMABLE_AGENTS)
  • Predicate helpers — small functions like hasHooks(id), canResume(id), and canControlCanvas(id) that resolve capability for built-in and custom agents alike
  • Inheritance utilities — setCustomAgentBaseResolver, baseAgentOf, and capabilityAgentId, which let custom agents inherit capability sets from a built-in agent harness

What the Central Config Module Defines

Let's unpack each layer of the config file to see exactly where agent capabilities are defined.

Agent Identifiers in Nodeterm

The module exports a generic AgentId type that unions all supported agent identifiers with a fallback for custom agents. The built-in IDs defined in the source are:

  • claude
  • codex
  • gemini
  • opencode
  • grok
  • copilot

Because AgentId is exported from config.ts, any other module — from the PTY manager in src/main/ to the React renderer in src/renderer/ — can reference agents without importing each agent's implementation.

Static Configuration: AGENT_CONFIG

The constant AGENT_CONFIG is a per-agent object map that stores startup metadata:

  • launchCmd — the command used to boot the agent
  • Color associations for UI badges
  • Prompt-injection modes and related settings

Any component that constructs a launch command, such as the code in src/shared/agents/config.ts used across the app, reads from AGENT_CONFIG and falls back to something like 'node' for unknown custom agents.

Capability Lists (Membership Arrays)

The core of the capability system lives in a series of const arrays with as const assertions. Each array is a membership list: "these agent IDs support the following capability."

Capability lists defined in the file include:

  • AGENT_HOOK_TARGETS — agents that support hook execution
  • RESUMABLE_AGENTS — agents that can be resumed after a restart
  • USAGE_CAPABLE — agents that report usage metrics
  • CANVAS_CONTROL_CAPABLE — agents that support the canvas-control skill

Because these lists are the literal source of truth, adding a new capability to Nodeterm only requires adding (or removing) an agent ID in the appropriate array. No other file has to be updated.

Predicate Helpers: Resolving Capabilities at Runtime

Rather than checking the arrays directly, the rest of the codebase calls exported predicate functions that wrap those arrays:

  • hasHooks(agentId) — does the agent receive hook callback events?
  • canResume(agentId) — can the agent be resumed after termination?
  • canRename(agentId) — does the agent support renaming?
  • canChat(agentId) — does the agent support chat interaction?
  • canControlCanvas(agentId) — does the agent expose canvas control?

Each predicate is smart: for built-in agents it checks the corresponding list; for custom agents it first resolves the inherited harness via baseAgentOf() and then checks that agent's capability set. That is how a custom agent at launch is treated as "a Codex but with X"—by inheriting the capability list of a built-in base agent.

Custom Agent Inheritance Utilities

Optional custom agents need a way to map their custom@ identifier to a built-in harness. For this, config.ts exports:

  • setCustomAgentBaseResolver(resolverFn) — registers a function that maps a custom agent ID to its base agent ID
  • baseAgentOf(customAgentId) — resolves the base ID (defaulting to the agent itself)
  • capabilityAgentId(agentId) — returns the effective ID used for capability checks (either the custom ID or its base)

These utilities guarantee that any feature gating (permission-mode UI, canvas-control skill, copy feedback) behaves consistently for both built-in and custom agents.

How the Codebase Consumes Agent Capability Predicates

Every module that needs to know what an agent can do imports the capability predicates from src/shared/agents/config.ts, ensuring one consistent query path.

File Role
[src/shared/agents/config.ts](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/config.ts) Defines AgentId, static AGENT_CONFIG, all capability arrays (USAGE_CAPABLE, CANVAS_CONTROL_CAPABLE, etc.) and the predicate helpers
[src/shared/agents/approval-mode.ts](https://github.com/eneskirca/nodeterm/blob/main/src/shared/agents/approval-mode.ts) Maps high-level permission-mode values to CLI flags for agents that support PERMISSION_MODE_CAPABLE
[src/renderer/state/agent-status.ts](https://github.com/eneskirca/nodeterm/blob/main/src/renderer/state/agent-status.ts) Imports the capability predicates to drive UI badges, restart actions, and permission-mode UI
[src/main/pty-manager.ts](https://github.com/eneskirca/nodeterm/blob/main/src/main/pty-manager.ts) Uses hasHooks and canResume when spawning a new terminal session

Practical Examples: Using Agent Capability Predicates

Here's a look at how Nodeterm's own code — and your extensions — would query agent capabilities.

import {
  hasHooks,
  canResume,
  canControlCanvas,
  canRename,
  canChat,
  AGENT_CONFIG,
} from '@/shared/agents/config'

// Example: decide whether to show the "Restart Agent" menu item
function shouldShowRestart(agentId: AgentId): boolean {
  return canResume(agentId) && hasHooks(agentId)
}
// Example: build a launch command with the correct permission-mode flag
import { permissionModeFlag, resolvePermissionMode } from '@/shared/agents/config'

function buildLaunch(agentId: AgentId, project: Project | undefined, settings: Settings): string {
  const base = AGENT_CONFIG[agentId as BuiltinAgentId]?.launchCmd ?? 'node' // fallback for custom agents
  const mode = resolvePermissionMode(project, settings)
  const flags = permissionModeFlag(mode)   // [] for 'manual', otherwise ["--permission-mode","auto"]
  return `${base} ${flags.join(' ')}`.trim()
}

Canvas-control is a UI-heavy capability, so the renderer checks it before exposing the corresponding skill:

// Example: checking canvas-control capability before exposing the skill
if (canControlCanvas(agentId)) {
  // register the "manage-nodeterm-canvas" skill for this agent
}

These examples mirror the actual code patterns found in src/renderer/state/agent-status.ts and src/shared/agents/approval-mode.ts.

What Happens When You Add a New Agent Capability to Nodeterm

To add a new capability to Nodeterm's agent model, you normally only edit one file:

  1. Open src/shared/agents/config.ts.
  2. Define a new membership array or a new predicate helper that reads it.
  3. Optionally, add the feature logic in the renderer or main process that guards by that predicate.

Because the rest of the codebase always imports from this module, the new capability will automatically propagate to the PTY manager, the approval-mode mapper, and the UI badge system. Nodeterm's architecture was designed so that the capability model at config.ts is the only place you need to touch for most agent support changes.

Summary

  • All Nodeterm agent capabilities are defined in a single file: src/shared/agents/config.ts.
  • The file exports capability arrays (RESUMABLE_AGENTS, USAGE_CAPABLE, CANVAS_CONTROL_CAPABLE, AGENT_HOOK_TARGETS) plus predicate helpers like hasHooks(), canResume(), canControlCanvas().
  • Custom agents can inherit a built-in agent's capabilities via baseAgentOf() and setCustomAgentBaseResolver().
  • UI indicators, launch-line construction, and PTY spawning all import these predicates, guaranteeing one source of truth.

Frequently Asked Questions

What is the agent capability definition file in Nodeterm?

The agent capability definitions in Nodeterm live in src/shared/agents/config.ts. This file exports the AgentId type, the AGENT_CONFIG map, capability membership arrays, and predicate helpers like canResume() and canControlCanvas().

How do I add a new capability to an agent in Nodeterm?

You add the capability in the single configuration module: update src/shared/agents/config.ts to include a new capability list and predicate. Since every other module imports capability checks from this file, your new capability automatically flows to the PTY manager, approval mode, and renderer.

Can custom agents in Nodeterm inherit capabilities from built-in agents?

Yes. The custom agent mechanism lets you map an agent ID to a built-in base agent with setCustomAgentBaseResolver and baseAgentOf. Custom agents then reuse the capability queries of the base harness — for example, a custom agent treated as a Codex automatically gains canResume, hasHooks, and canvas-control until overridden.

Which features in Nodeterm depend on agent capability predicates?

Several: the Restart Agent menu (uses canResume and hasHooks), permission-mode UI (uses permissionModeFlag and resolvePermissionMode), copy-feedback, the canvas-control skill and agent status badges in src/renderer/state/agent-status.ts— plus their spawning loop in src/main/pty-manager.ts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →