TermAl

Feature Brief: Agent Slash Commands

Backlog source: docs/bugs.md

Status

Implemented for discovery and backend-owned execution. GET /api/sessions/{id}/agent-commands now serves:

The slash palette shows those commands alongside the existing session-control commands, including the catalog-gated Codex /fast Standard/Fast selector. Codex /mcp is also shown there, but it is a dedicated client-side status surface backed by mcpServerStatus/list, not an agent command and not a prompt sent to the model. Native Claude commands are sent as slash prompts such as /review, while markdown templates are resolved through POST /api/sessions/{id}/agent-commands/{name}/resolve. The frontend passes arguments and optional note; the backend applies $ARGUMENTS, appends any note as a standard user-note block, and returns the resolved prompt plus any trusted delegation defaults. Regular session sends and delegated sends use the same resolver.

See slash-commands.md for the existing session-control implementation.

Problem

Claude exposes two useful command surfaces:

TermAl supports filesystem prompt templates for local sessions and merges live native-command metadata for Claude sessions when available. This brief remains useful as the design record for that work.

Goals

Non-goals for v1

Implemented architecture

1. Backend: command discovery endpoint

GET /api/sessions/{id}/agent-commands

Response:

{
  "commands": [
    {
      "name": "review-code",
      "description": "Review staged and unstaged changes using multiple specialized reviewers.",
      "content": "Review staged and unstaged changes using...\n\n## Step 1: ...",
      "source": ".claude/commands/review-code.md"
    },
    {
      "name": "fix-bug",
      "description": "Fix a bug from docs/bugs.md by number.",
      "content": "Fix a bug from `docs/bugs.md`...\n\n$ARGUMENTS\n...",
      "source": ".claude/commands/fix-bug.md"
    }
  ]
}

Implementation:

1a. Backend: command/skill resolution endpoint

Target contract:

POST /api/sessions/{id}/agent-commands/{name}/resolve

Request:

{
  "arguments": "1024",
  "note": "Please add integration tests for Connectivity class.",
  "cwd": "C:\\github\\Personal\\TermAl",
  "intent": "delegate"
}

intent is "send" for a normal session turn and "delegate" for child-session delegation. The resolver must use the same template expansion rules for both intents, but may return different execution defaults for delegation.

cwd is optional and delegation-only. It lets MCP-based delegation resolve a slash command against the intended child session working directory before the child exists. Requests with cwd and intent: "send" are rejected. For project-scoped sessions the canonicalized cwd must stay inside the local project root; non-project sessions may resolve against any local directory the backend process can read. Remote-backed projects return NOT_IMPLEMENTED in Phase 1. The value is capped at 4,096 Unicode code points. Callers should pass absolute paths; relative paths follow the server-side session workdir resolution rules.

Response:

{
  "name": "fix-bug",
  "source": ".claude/commands/fix-bug.md",
  "kind": "promptTemplate",
  "visiblePrompt": "/fix-bug 1024",
  "expandedPrompt": "Fix a bug from docs/bugs.md...\n\n1024\n\n## Additional User Note\n\nPlease add integration tests for Connectivity class.",
  "title": "Fix bug 1024"
}

Delegating a prompt-template command with trusted command-owned defaults returns delegation only for intent: "delegate". This is the trusted-source response shape; project-local .claude/commands/*.md templates are not trusted today and do not return delegation defaults:

{
  "name": "review-code",
  "source": ".claude/commands/review-code.md",
  "kind": "promptTemplate",
  "visiblePrompt": "/review-code",
  "expandedPrompt": "Review staged and unstaged changes...",
  "title": "Review staged and unstaged changes using multiple specialized reviewers.",
  "delegation": {
    "title": "Review staged and unstaged changes using multiple specialized reviewers.",
    "mode": "reviewer",
    "writePolicy": { "kind": "isolatedWorktree", "ownedPaths": [] }
  }
}

Resolution rules:

1b. Command/skill frontmatter metadata

Command templates and future SKILL.md files may declare TermAl execution metadata under metadata.termal. This follows the Claude skill model: YAML frontmatter is the always-loaded discovery layer, while the Markdown body remains the prompt/instruction payload. TermAl strips recognized frontmatter before sending the template to an agent and uses description: as the command palette description when present.

TermAl parses prompt-template command frontmatter for resolver metadata today. Project-local .claude/commands/*.md metadata may drive title generation after passing the source/name gate, but delegation defaults that affect mode or write policy are ignored. No production command source is marked trusted yet; future TermAl-owned command or SKILL.md support should reuse the same metadata.termal shape and set the trusted-source marker only for those TermAl-owned files.

Metadata contract:

---
name: review-code
description: Review staged and unstaged changes using multiple specialized reviewers.
metadata:
  termal:
    title:
      strategy: default
    delegation:
      enabled: true
      mode: reviewer
      writePolicy:
        kind: readOnly
---

Title strategies:

Delegation metadata:

Trust rules:

Example user intent:

/fix-bug 1024 -- Please add integration tests for Connectivity class.

The UI can parse this into arguments: "1024" and note: "Please add integration tests for Connectivity class.", then call the resolver. Without an unambiguous separator or metadata, the whole tail should be sent as arguments, with note omitted.

2. Frontend: agent command type

Extend the slash palette to support agent commands.

// New palette item kind
type SlashPaletteItem =
  | { kind: "command"; ... }      // existing: session control (expands text)
  | { kind: "choice"; ... }       // existing: setting value (applies immediately)
  | { kind: "agent-command";      // new: agent slash command
      key: string;
      command: string;            // "/review-code"
      label: string;             // "/review-code"
      detail: string;            // first line of .md file
      content: string;           // full .md template content for display/compatibility
      hasArguments: boolean;     // true if content contains $ARGUMENTS
    };

3. Frontend: command fetching

// api.ts
export function fetchAgentCommands(sessionId: string): Promise<AgentCommandsResponse> {
  return request<AgentCommandsResponse>(
    `/api/sessions/${encodeURIComponent(sessionId)}/agent-commands`
  );
}

Fetch agent commands:

4. Frontend: palette integration

Modify buildSlashPaletteState to include agent commands:

User types "/"
  → Show two sections:
    ┌─────────────────────────────────────┐
    │ Agent Commands                      │
    │   /review-code  Review staged...   │
    │   /fix-bug       Fix a bug from...  │
    │ Session Controls                    │
    │   /model         Change the model   │
    │   /mode          Change the mode    │
    │   /effort        Change effort      │
    └─────────────────────────────────────┘

User types "/rev"
  → Filter to matching commands:
    ┌─────────────────────────────────────┐
    │ Agent Commands                      │
    │   /review-code  Review staged...   │
    └─────────────────────────────────────┘

5. Frontend: command execution

When an agent command is selected:

Without arguments (hasArguments: false):

With arguments (hasArguments: true):

Delegation:

6. Argument substitution and notes

Claude Code’s convention:

UI plan

Composer slash menu changes

Loading and error states

Refresh

API plan

Discovery endpoint:

Method Path Purpose
GET /api/sessions/{id}/agent-commands Discover agent commands for session’s project

Resolution endpoint:

Method Path Purpose
POST /api/sessions/{id}/agent-commands/{name}/resolve Resolve a command template/native command into the prompt and execution defaults for a regular send or delegation

The discovery response may continue to include command content for display and compatibility, but frontend execution should use the resolver as the source of truth. This keeps command/skill parsing, $ARGUMENTS, optional notes, and delegation policy on the backend.

Implementation phases

Phase 1: backend discovery

Phase 2: frontend palette integration

Phase 3: command execution

Phase 4: polish

Testing plan

Backend:

Backend resolver:

Frontend:

Acceptance criteria