Native integrations¶
octomate_cli.tentacles.hooks ¶
What every agent's hook installer shares: the check that the credential the hooks will carry — a server-issued API token — actually resolves, and the scripts the installed hooks run.
announce_secret ¶
Warn when hooks were just installed against a credential that resolves to nothing: the install reports success, and every turn after it 401s.
Source code in cli/octomate_cli/tentacles/hooks.py
octomate_cli.tentacles.mcp ¶
Octomate's static MCP client config — the three facts every octomate
<runtime> mcp install writes: where the server is, the credential, and which
runtime the calls are from.
Owned here so the runtimes' installers cannot drift apart. The server holds the
same literals (octomate.mcp.server, octomate.mcp.gateway,
octomate.types.threads); the CLI cannot import that half, so the tests are what
hold the two together. Unlike the hook commands — whose scripts resolve the
address and credential from the environment when each hook fires — a static MCP
entry is read by the runtime itself, so both are resolved once, at install time,
and written into the file: the file holds the literal credential, and rotating it
means re-running install.
octomate_url ¶
The full /octomate/mcp URL an install writes, from the pinned base or the
client's own resolution — refused when nothing names an address, since a
static entry pointing nowhere would fail every session's tool listing.
Source code in cli/octomate_cli/tentacles/mcp.py
octomate_secret ¶
The credential an install embeds in the entry's Authorization header — refused when nothing resolves, since the entry would 401 on every call.
Source code in cli/octomate_cli/tentacles/mcp.py
octomate_cli.tentacles.claude.hooks ¶
Install and manage the claude tentacle's native hooks.
HandledHookEvent
module-attribute
¶
HandledHookEvent = Literal[
"UserPromptSubmit",
"Stop",
"SessionEnd",
"SubagentStart",
"SubagentStop",
]
HANDLED_HOOK_EVENTS
module-attribute
¶
HANDLED_HOOK_EVENTS: tuple[HandledHookEvent, ...] = (
"UserPromptSubmit",
"Stop",
"SessionEnd",
"SubagentStart",
"SubagentStop",
)
hooks_typer
module-attribute
¶
hooks_typer = typer.Typer(
help="Manage the Claude Code hook pipe into Octomate.",
no_args_is_help=True,
)
ScopeOption
module-attribute
¶
ScopeOption = Annotated[
Scope,
typer.Option(
help="Which settings file to touch: 'user' (~/.claude) or 'project' (./.claude)."
),
]
SettingsOption
module-attribute
¶
SettingsOption = Annotated[
Path | None,
typer.Option(
help="Explicit settings.json path; overrides --scope when given."
),
]
Scope ¶
settings_file ¶
claude_emit_handler ¶
One forwarding command hook: emit.py carries the event body from stdin to
the hook router, reading the credential — and, unless url pins one, the router's
address (OCTOMATE_CLI_URL) — from the environment at fire time. A command rather
than a native http handler so the settings file stays free of hosts and
credentials both: the same install serves whichever server the environment names.
Synchronous either way, which is what guarantees delivery before a short-lived
claude -p exits.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
stream_url_for ¶
The stream endpoint the hook URL implies: same host, ws(s) for http(s).
Source code in cli/octomate_cli/tentacles/claude/hooks.py
claude_launch_handler ¶
The launcher command hook: spawns octomate claude tail for the session,
detached (launch.py) — the forwarding hooks reach Octomate but can start nothing
on this machine, and the stream needs a local process. The command pins this
installer's own interpreter and octomate script by absolute path, so it works from
whatever shell Claude runs hooks in; the stream address is pinned only when the
install pinned --url, and otherwise resolved from OCTOMATE_CLI_URL at fire time,
like the credential always is.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
is_octomate_hook ¶
A handler this installer wrote: a command carrying Octomate's hook path
(which the stream path extends, so pinned launchers of every age match too), or
the http handler an older install pointed at it. Matched by path, not the exact
command, so a re-install replaces a stale handler whatever its host, port,
interpreter, or script location — every generation back to the http ones.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
install ¶
install(url: Annotated[str | None, Option(help=f'Full hook URL to pin. Without it, hooks resolve ${env('url')} from each session's environment at fire time.')] = None, scope: ScopeOption = Scope.user, settings: SettingsOption = None) -> None
Point native Claude Code sessions at Octomate's hook router.
The transcript-stream launcher (a command hook on UserPromptSubmit) installs unconditionally, the machine Octomate itself runs on included: the stream is the only assembler — the server never reads a transcript from disk — so a session without a tail keeps only the hooks' sketch. Merges into the settings file: other hooks are preserved, and re-running replaces a stale Octomate handler in place rather than stacking another.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
uninstall ¶
Remove Octomate's hook handlers from a Claude settings file, leaving any other hooks untouched.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
show ¶
Show the Octomate hook handlers currently installed in a Claude settings file.
Source code in cli/octomate_cli/tentacles/claude/hooks.py
octomate_cli.tentacles.claude.mcp ¶
Install and manage the claude tentacle's MCP configuration.
mcp_typer
module-attribute
¶
mcp_typer = typer.Typer(
help="Manage the Octomate MCP entry for native Claude Code sessions.",
no_args_is_help=True,
)
McpScopeOption
module-attribute
¶
McpScopeOption = Annotated[
McpScope,
typer.Option(
help="Where the entry lives: 'local' (~/.claude.json, this project only), 'user' (~/.claude.json, every project), or 'project' (./.mcp.json)."
),
]
McpFileOption
module-attribute
¶
McpFileOption = Annotated[
Path | None,
typer.Option(
"--file",
help="Explicit config path; replaces the file --scope implies, while the scope keeps deciding where in it the entry lives.",
),
]
McpScope ¶
Bases: str, Enum
Claude's three MCP config placements. local — the default, since the entry
embeds a credential — is Claude's per-project slot inside ~/.claude.json
(projects.<cwd>.mcpServers, the shape claude mcp add --scope local writes):
scoped to this directory without putting a secret-bearing file in the repo.
Source code in cli/octomate_cli/tentacles/claude/mcp.py
mcp_config_file ¶
mcp_install ¶
mcp_install(url: Annotated[str | None, Option(help=f'Octomate's base URL (http://host:port) to write; defaults to ${env('url')}, then cli.toml.')] = None, scope: McpScopeOption = McpScope.local, file: McpFileOption = None) -> None
Point native Claude Code sessions at the served MCP server.
Writes the entry — the server's URL, the bearer, and the runtime attribution header — resolved once, now: unlike the hooks, a static entry is read by Claude itself, so the file holds the literal credential and rotating it means re-running install. Everything else in the file is kept, and re-running replaces the entry in place.
Source code in cli/octomate_cli/tentacles/claude/mcp.py
mcp_uninstall ¶
Remove the Octomate MCP entry, leaving every other server and setting.
Source code in cli/octomate_cli/tentacles/claude/mcp.py
mcp_show ¶
Show the Octomate MCP entry, credential masked.
Source code in cli/octomate_cli/tentacles/claude/mcp.py
octomate_cli.tentacles.codex.hooks ¶
Install and manage the codex tentacle's native hooks.
HANDLED_HOOK_EVENTS
module-attribute
¶
HANDLED_HOOK_EVENTS = (
"SessionStart",
"UserPromptSubmit",
"Stop",
"SubagentStart",
"SubagentStop",
)
LAUNCHER_HOOK_EVENTS
module-attribute
¶
hooks_typer
module-attribute
¶
hooks_typer = typer.Typer(
help="Manage the Codex hook pipe into Octomate.",
no_args_is_help=True,
)
Scope ¶
hooks_file ¶
is_octomate_handler ¶
A command hook aimed at Octomate's Codex hook path (which the stream path
extends, so pinned launchers match too) — matched by path, not the exact command,
so a re-install replaces a stale handler whatever its host, port, or interpreter,
including ones written by versions that ran codex hooks emit.
Source code in cli/octomate_cli/tentacles/codex/hooks.py
stream_url_for ¶
The stream endpoint the hook URL implies: same host, ws(s) for http(s).
Source code in cli/octomate_cli/tentacles/codex/hooks.py
codex_launch_handler ¶
The launcher command hook: spawns octomate codex tail for the session,
detached (launch.py) — the forwarding hooks reach Octomate but can start
nothing on this machine, and the stream needs a local process. The command pins
this installer's own interpreter and octomate script by absolute path, so it
works from whatever shell Codex runs hooks in; the stream address is pinned only
when the install pinned --url, and otherwise resolved from OCTOMATE_CLI_URL at
fire time, like the credential always is.
Source code in cli/octomate_cli/tentacles/codex/hooks.py
install ¶
install(url: Annotated[str | None, Option(help=f'Full hook URL to pin. Without it, hooks resolve ${env('url')} from each session's environment at fire time.')] = None, scope: Annotated[Scope, Option()] = Scope.user, path: Annotated[Path | None, Option('--hooks-file')] = None) -> None
Install observing command hooks without replacing the operator's hooks.
The transcript-stream launcher installs unconditionally, the machine Octomate itself runs on included: the stream is the only assembler — the server never reads a rollout from disk — so a session without a tail keeps only the hooks' sketch. Re-running replaces a stale Octomate handler in place rather than stacking another.
Source code in cli/octomate_cli/tentacles/codex/hooks.py
uninstall ¶
uninstall(
scope: Annotated[Scope, Option()] = Scope.user,
path: Annotated[
Path | None, Option("--hooks-file")
] = None,
) -> None
Source code in cli/octomate_cli/tentacles/codex/hooks.py
octomate_cli.tentacles.codex.mcp ¶
Install and manage the codex tentacle's MCP configuration.
mcp_typer
module-attribute
¶
mcp_typer = typer.Typer(
help="Manage the Octomate MCP entry for native Codex sessions.",
no_args_is_help=True,
)
McpConfigOption
module-attribute
¶
McpConfigOption = Annotated[
Path | None,
typer.Option(
"--config-file",
help="Explicit config.toml path; defaults to ~/.codex/config.toml.",
),
]
mcp_config_file ¶
load_toml ¶
The whole document, comments and all — tomlkit's round-trip is what keeps the operator's file theirs.
Source code in cli/octomate_cli/tentacles/codex/mcp.py
mcp_install ¶
mcp_install(url: Annotated[str | None, Option(help=f'Octomate's base URL (http://host:port) to write; defaults to ${env('url')}, then cli.toml.')] = None, config_file: McpConfigOption = None) -> None
Point native Codex sessions at the served MCP server.
Writes the mcp_servers.octomate table — the server's URL, the bearer,
the runtime attribution header, and teleport's approval requirement — preserving
the operator's comments and every other table. The credential is embedded;
rotating means re-running install. Driven sessions disable inherited MCP servers
and supply their caller's connection separately.
Source code in cli/octomate_cli/tentacles/codex/mcp.py
mcp_uninstall ¶
Remove the Octomate MCP entry, leaving the operator's comments and every other server.
Source code in cli/octomate_cli/tentacles/codex/mcp.py
mcp_show ¶
Show the Octomate MCP entry, credential masked.
Source code in cli/octomate_cli/tentacles/codex/mcp.py
octomate_cli.tentacles.deepseek.hooks ¶
Install and manage the deepseek tentacle's native hooks.
hooks_typer
module-attribute
¶
hooks_file ¶
bridge_link ¶
emit_handler ¶
The forwarding command hook: emit.py carries the event body from
stdin to the hook router, reading the credential — and, unless url pins
one, the router's address — from the environment at fire time.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
stream_url_for ¶
The stream endpoint the hook URL implies: same host, ws(s) for http(s).
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
launch_handler ¶
The launcher command hook: spawns octomate deepseek tail for the
session, detached (launch.py) — the forwarding hook reaches Octomate but
can start nothing on this machine, and the stream needs a local process to
read the gateway. Pins this installer's own interpreter and octomate
script by absolute path; the stream address is pinned only when the
install pinned --url, and otherwise resolved from OCTOMATE_CLI_URL at fire
time, like the credential always is.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
hooks_document ¶
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
patch_block ¶
The marker-delimited patch entry mounting the bridge over our hooks
file. Textual rather than parsed YAML: the user's patch file carries their
comments and !!js expressions, which a parse-and-rewrite would destroy.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
link_bridge ¶
Symlink the bridge package into dsh's flat module fallback, where every profile resolves plugins from. Validated first: the wrong directory here would fail every dsh boot, not just the hooks.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
install ¶
install(url: Annotated[str | None, Option(help=f'Full hook URL to pin. Without it, hooks resolve ${env('url')} from each session's environment at fire time.')] = None, home: DshHomeOption = None, bridge: Annotated[Path | None, Option(help="Path of the dsh-hooks-claude-code package to link into dsh's module fallback (e.g. <harness checkout>/packages/experimental/hooks-claude-code). The bridge ships outside dsh's own bundle, so the first install needs this once.")] = None) -> None
Point native dsh sessions at Octomate's hook router.
Writes Octomate's own hooks file (never a merge — an operator's dsh hooks
live in their own file, mounted by their own patch row) and a
marker-delimited row in $DSH_HOME/cordis.patch.yml mounting the
dsh-hooks-claude-code bridge over it. Re-running replaces both in place.
Restart dsh processes for the composition change to take.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
uninstall ¶
Remove Octomate's hooks file, patch row, and bridge link from a dsh home, leaving everything else in the patch file untouched.
Source code in cli/octomate_cli/tentacles/deepseek/hooks.py
octomate_cli.tentacles.deepseek.mcp ¶
Install and manage the deepseek tentacle's MCP configuration.
mcp_typer
module-attribute
¶
mcp_typer = typer.Typer(
help="Manage the Octomate MCP row for native dsh sessions.",
no_args_is_help=True,
)
LEGACY_MCP_MARK_BEGIN
module-attribute
¶
mcp_patch_block ¶
The marker-delimited row mounting dsh's MCP client on the served server —
serverName: octomate, so the model sees mcp__octomate__<tool>, the same
names Claude and Codex read. Header values are JSON-quoted, which YAML reads
as flow scalars: the credential is hand-written and need not be YAML-safe.
Source code in cli/octomate_cli/tentacles/deepseek/mcp.py
mcp_install ¶
mcp_install(url: Annotated[str | None, Option(help=f'Octomate's base URL (http://host:port) to write; defaults to ${env('url')}, then cli.toml.')] = None, home: DshHomeOption = None) -> None
Point native dsh sessions at the served MCP server.
Writes a marker-delimited row in $DSH_HOME/cordis.patch.yml mounting
@deepseek-ai/dsh-mcp-client on the served MCP server, the credential and the
runtime attribution embedded — resolved once, now: the file holds the
literal credential, and rotating it means re-running install. Re-running
replaces the row in place; restart dsh processes for the change to take.
Source code in cli/octomate_cli/tentacles/deepseek/mcp.py
mcp_uninstall ¶
Remove the Octomate MCP row, leaving the hooks row and everything else in the patch file untouched.
Source code in cli/octomate_cli/tentacles/deepseek/mcp.py
mcp_show ¶
Show the Octomate MCP row, credential masked.