pub trait AgentAdapter {
Show 33 methods
// Required methods
fn id(&self) -> &'static str;
fn display_name(&self) -> &'static str;
fn dir_prefix(&self) -> &'static str;
fn mcp_config_relpath(&self) -> &'static str;
fn supported_agents(&self) -> &[&'static str];
fn hook_compatibility(&self) -> &'static CompatibilityMatrix;
fn hook_settings_relpath(&self) -> &'static str;
fn hook_settings_shape(&self) -> HookSettingsShape;
fn scaffold_hook_event(&self) -> &'static str;
fn detect(&self, repo_root: &Path) -> bool;
fn kinds_supported(&self) -> &[CapabilityType];
// Provided methods
fn hook_filename(&self) -> &'static str { ... }
fn hook_file_content(&self, hook_cfg: &HookConfig) -> Result<Vec<u8>> { ... }
fn render_standard_hook(
&self,
context: HookRenderContext<'_>,
) -> Result<HookRenderPlan> { ... }
fn command_hook_fragment(&self, native_event: &str, command: &str) -> Value { ... }
fn merge_hook_fragment(
&self,
existing: Option<&[u8]>,
fragment: &Value,
) -> Result<Vec<u8>> { ... }
fn remove_hook_settings(
&self,
repo_root: &Path,
managed_hooks: &[ManagedHook],
) -> Result<()> { ... }
fn supports(&self, capability_type: CapabilityType) -> bool { ... }
fn native_hook_event(&self, raw_event: &str) -> Result<&'static str> { ... }
fn canonical_hook_event(&self, raw_event: &str) -> Result<&'static str> { ... }
fn ensure_project_dir(&self, repo_root: &Path) -> Result<()> { ... }
fn mcp_env_reference(&self, var: &str) -> String { ... }
fn mcp_server_entry(&self, server: &McpServerConfig) -> Value { ... }
fn mcp_http_declares_type(&self) -> bool { ... }
fn plan(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn remove(
&self,
primitive_id: &str,
repo_root: &Path,
managed_hooks: &[ManagedHook],
) -> Result<()> { ... }
fn plan_skill(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn plan_tool(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn plan_hook(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn plan_native_hook(
&self,
capability: &ResolvedCapability,
native: &NativeHookConfig,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn plan_workflow(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn plan_mcp_server(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>> { ... }
fn remove_dir(
&self,
repo_root: &Path,
base: &str,
kind: &str,
primitive_id: &str,
) -> Result<()> { ... }
}Expand description
What a harness adapter declares, and what Tuff does with it.
An adapter is a declaration: where the harness keeps its files, which
hook events it has and how they map onto Tuff’s, the shape of its hook
settings file, and how to recognise a project that uses it. Everything
else, planning files, rendering hooks, merging into and removing from
the settings file, is a default method here, so there is one
implementation of each and an adapter overrides one only when its
harness genuinely differs (Cursor’s ${env:VAR} spelling, say).
Required Methods§
fn id(&self) -> &'static str
fn display_name(&self) -> &'static str
fn dir_prefix(&self) -> &'static str
fn mcp_config_relpath(&self) -> &'static str
fn supported_agents(&self) -> &[&'static str]
fn hook_compatibility(&self) -> &'static CompatibilityMatrix
fn hook_settings_relpath(&self) -> &'static str
Sourcefn hook_settings_shape(&self) -> HookSettingsShape
fn hook_settings_shape(&self) -> HookSettingsShape
How the settings file at hook_settings_relpath lays out its
registrations. This is the whole of what differs between harnesses
in hook handling; the merge and removal follow from it.
Sourcefn scaffold_hook_event(&self) -> &'static str
fn scaffold_hook_event(&self) -> &'static str
The native event tuff create registers a scaffolded hook under.
fn kinds_supported(&self) -> &[CapabilityType]
Provided Methods§
fn hook_filename(&self) -> &'static str
fn hook_file_content(&self, hook_cfg: &HookConfig) -> Result<Vec<u8>>
fn render_standard_hook( &self, context: HookRenderContext<'_>, ) -> Result<HookRenderPlan>
Sourcefn command_hook_fragment(&self, native_event: &str, command: &str) -> Value
fn command_hook_fragment(&self, native_event: &str, command: &str) -> Value
The hooks-only fragment that registers command under native_event.
Sourcefn merge_hook_fragment(
&self,
existing: Option<&[u8]>,
fragment: &Value,
) -> Result<Vec<u8>>
fn merge_hook_fragment( &self, existing: Option<&[u8]>, fragment: &Value, ) -> Result<Vec<u8>>
Merge a hooks-only fragment into the settings file’s current bytes.
Sourcefn remove_hook_settings(
&self,
repo_root: &Path,
managed_hooks: &[ManagedHook],
) -> Result<()>
fn remove_hook_settings( &self, repo_root: &Path, managed_hooks: &[ManagedHook], ) -> Result<()>
Take Tuff’s registrations out of the settings file, leaving the user’s own alone.
fn supports(&self, capability_type: CapabilityType) -> bool
fn native_hook_event(&self, raw_event: &str) -> Result<&'static str>
fn canonical_hook_event(&self, raw_event: &str) -> Result<&'static str>
fn ensure_project_dir(&self, repo_root: &Path) -> Result<()>
Sourcefn mcp_env_reference(&self, var: &str) -> String
fn mcp_env_reference(&self, var: &str) -> String
How this harness spells a reference to an environment variable inside
its MCP config. Claude Code and most stdio clients expand ${VAR}.
Sourcefn mcp_server_entry(&self, server: &McpServerConfig) -> Value
fn mcp_server_entry(&self, server: &McpServerConfig) -> Value
The mcpServers.<id> entry this harness needs for an external MCP
server. Secrets are emitted as env references, never values.
Sourcefn mcp_http_declares_type(&self) -> bool
fn mcp_http_declares_type(&self) -> bool
Whether this harness wants an explicit "type": "http" on a remote
server entry. Claude Code and Codex do; Cursor infers the transport
from url and has no type key for remote servers.
fn plan( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
fn remove( &self, primitive_id: &str, repo_root: &Path, managed_hooks: &[ManagedHook], ) -> Result<()>
fn plan_skill( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
fn plan_tool( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
fn plan_hook( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
fn plan_native_hook( &self, capability: &ResolvedCapability, native: &NativeHookConfig, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
fn plan_workflow( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
Sourcefn plan_mcp_server(
&self,
capability: &ResolvedCapability,
repo_root: &Path,
) -> Result<Vec<PlannedFile>>
fn plan_mcp_server( &self, capability: &ResolvedCapability, repo_root: &Path, ) -> Result<Vec<PlannedFile>>
Emit the canonical server.toml record. The JSON entry in the
harness’s MCP config is the artifact the harness reads; this file is
what gives the capability a tree to hash, so check/diff/delete
work exactly as they do for every other kind.
fn remove_dir( &self, repo_root: &Path, base: &str, kind: &str, primitive_id: &str, ) -> Result<()>
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".