Skip to main content

evolve_adapters/
traits.rs

1//! The [`Adapter`] trait: one implementor per supported tool.
2
3use crate::signals::{ParsedSignal, SessionLog};
4use async_trait::async_trait;
5use evolve_core::agent_config::AgentConfig;
6use evolve_core::ids::AdapterId;
7use std::path::Path;
8use thiserror::Error;
9
10/// Errors common to all adapters.
11#[derive(Debug, Error)]
12pub enum AdapterError {
13    /// I/O error reading or writing adapter files.
14    #[error("io: {0}")]
15    Io(#[from] std::io::Error),
16    /// JSON error parsing or writing settings/transcript.
17    #[error("json: {0}")]
18    Json(#[from] serde_json::Error),
19    /// Adapter was asked to operate on a root that it does not recognize.
20    #[error("adapter not applicable at {path}")]
21    NotApplicable {
22        /// Path the caller asked the adapter to operate on.
23        path: String,
24    },
25    /// Adapter-specific parse failure (bad transcript line, etc.).
26    #[error("parse: {0}")]
27    Parse(String),
28}
29
30/// What [`Adapter::detect`] found in a target directory.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum AdapterDetection {
33    /// Strong signal the tool is in use here (config files, binaries, etc.).
34    Detected,
35    /// Nothing conclusive found.
36    NotDetected,
37}
38
39/// Per-tool integration contract. See design doc section 4.4.
40#[async_trait]
41pub trait Adapter: Send + Sync {
42    /// Stable identifier (e.g., "claude-code", "cursor", "aider").
43    fn id(&self) -> AdapterId;
44
45    /// Detect whether the tool is in use at `root` (or in the user's home).
46    fn detect(&self, root: &Path) -> AdapterDetection;
47
48    /// Install hooks/config so the tool reports sessions back to Evolve. Idempotent.
49    async fn install(&self, root: &Path, config: &AgentConfig) -> Result<(), AdapterError>;
50
51    /// Write the given config into the tool's files (inside managed-section markers).
52    async fn apply_config(&self, root: &Path, config: &AgentConfig) -> Result<(), AdapterError>;
53
54    /// Parse a session log into fitness signals.
55    async fn parse_session(&self, log: SessionLog) -> Result<Vec<ParsedSignal>, AdapterError>;
56
57    /// Remove everything this adapter installed, restoring the pre-evolve state.
58    async fn forget(&self, root: &Path) -> Result<(), AdapterError>;
59}