"""Declarative registry of the eight built-in agent CLIs.
This module is the single source of truth for the agents that Ralph Workflow
ships with out of the box. Each entry is a :class:`~ralph.agents.builtin_spec.BuiltinAgentSpec`
declaratively describing one CLI: the transport, the parser/strategy pair,
the JSON parsing mode, the executable, the flags used for unattended
("yolo") invocation, resume/session support, and whether the agent is allowed
to author commits.
The eight built-in agents are:
- ``claude`` (Claude Code interactive / PTY transport)
- ``claude-headless`` (Claude Code headless JSON-stream transport)
- ``codex`` (Codex CLI)
- ``opencode`` (OpenCode CLI)
- ``nanocoder`` (Nanocoder CLI)
- ``agy`` (AGY CLI; binary overridable via ``RALPH_AGY_BINARY``)
- ``pi`` (Pi.dev CLI)
- ``cursor`` (Cursor Agent CLI; binary overridable via ``RALPH_CURSOR_BINARY``)
Adding a new built-in agent requires editing this module only; the catalog
picks the entries up via :func:`builtin_supports`. Custom agents configured
via ``.agent/agents.toml`` are layered on top by the catalog and do not need
to be declared here.
Side effects: none at import time. The agent supports are returned as a
fresh tuple on each call to :func:`builtin_supports` so callers can iterate
without sharing state.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
from ralph.agents.builtin_spec import BuiltinAgentSpec
from ralph.agents.execution_state._factory import (
_make_agy_strategy,
_make_cursor_strategy,
_make_pi_strategy,
)
from ralph.agents.execution_state.claude_execution_strategy import ClaudeExecutionStrategy
from ralph.agents.execution_state.claude_interactive_execution_strategy import (
ClaudeInteractiveExecutionStrategy,
)
from ralph.agents.execution_state.generic_execution_strategy import GenericExecutionStrategy
from ralph.agents.execution_state.opencode_execution_strategy import OpenCodeExecutionStrategy
from ralph.agents.parsers.agy import AgyParser
from ralph.agents.parsers.claude import ClaudeParser
from ralph.agents.parsers.claude_interactive import ClaudeInteractiveParser
from ralph.agents.parsers.codex import CodexParser
from ralph.agents.parsers.cursor import CursorParser
from ralph.agents.parsers.nanocoder import NanocoderParser
from ralph.agents.parsers.opencode import OpenCodeParser
from ralph.agents.parsers.pi import PiParser
from ralph.config.enums import AgentTransport, JsonParserType
if TYPE_CHECKING:
from ralph.agents.support import AgentSupport
_BUILTIN_AGENT_SUPPORTS: tuple[AgentSupport, ...] = (
BuiltinAgentSpec(
transport=AgentTransport.CLAUDE_INTERACTIVE,
parser_factory=ClaudeInteractiveParser,
strategy_factory=ClaudeInteractiveExecutionStrategy,
json_parser=JsonParserType.CLAUDE,
cmd="claude",
yolo_flag="--dangerously-skip-permissions",
verbose_flag="--verbose",
can_commit=True,
session_flag="--resume {}",
interactive=True,
).to_support("claude"),
BuiltinAgentSpec(
transport=AgentTransport.CLAUDE,
parser_factory=ClaudeParser,
strategy_factory=ClaudeExecutionStrategy,
json_parser=JsonParserType.CLAUDE,
cmd="claude -p",
output_flag="--output-format=stream-json",
yolo_flag="--permission-mode auto",
verbose_flag="--verbose",
can_commit=True,
print_flag="--print",
streaming_flag="--include-partial-messages",
session_flag="--resume {}",
).to_support("claude-headless"),
BuiltinAgentSpec(
transport=AgentTransport.CODEX,
parser_factory=CodexParser,
strategy_factory=GenericExecutionStrategy,
json_parser=JsonParserType.CODEX,
cmd="codex exec",
output_flag="--json",
yolo_flag="--dangerously-bypass-approvals-and-sandbox",
can_commit=True,
).to_support("codex"),
BuiltinAgentSpec(
transport=AgentTransport.OPENCODE,
parser_factory=OpenCodeParser,
strategy_factory=OpenCodeExecutionStrategy,
json_parser=JsonParserType.OPENCODE,
cmd="opencode",
output_flag="--json-stream",
can_commit=False,
session_flag="--session {}",
).to_support("opencode"),
BuiltinAgentSpec(
transport=AgentTransport.NANOCODER,
parser_factory=NanocoderParser,
strategy_factory=GenericExecutionStrategy,
json_parser=JsonParserType.GENERIC,
cmd="nanocoder",
can_commit=False,
interactive=True,
no_default_session_flag=True,
).to_support("nanocoder"),
BuiltinAgentSpec(
transport=AgentTransport.AGY,
parser_factory=AgyParser,
strategy_factory=_make_agy_strategy,
json_parser=JsonParserType.GENERIC,
cmd="agy",
yolo_flag="--dangerously-skip-permissions",
print_flag="--print",
can_commit=False,
interactive=True,
no_default_session_flag=True,
).to_support("agy"),
BuiltinAgentSpec(
transport=AgentTransport.PI,
parser_factory=PiParser,
strategy_factory=_make_pi_strategy,
json_parser=JsonParserType.PI,
cmd="pi",
output_flag="--mode json",
yolo_flag="--approve",
session_flag="--session {}",
can_commit=True,
display_name="Pi",
).to_support("pi"),
BuiltinAgentSpec(
transport=AgentTransport.CURSOR,
parser_factory=CursorParser,
strategy_factory=_make_cursor_strategy,
json_parser=JsonParserType.GENERIC,
cmd="agent",
output_flag="--output-format stream-json",
yolo_flag="--yolo",
print_flag="--print",
streaming_flag="--stream-partial-output",
session_flag="--resume {}",
can_commit=True,
display_name="Cursor",
).to_support("cursor"),
)
[docs]
def builtin_supports() -> tuple[AgentSupport, ...]:
"""Return a fresh copy of the built-in agent supports."""
return tuple(_BUILTIN_AGENT_SUPPORTS)