Skip to main content

rig_compose/
skill.rs

1//! [`Skill`] — a stateless, composable reasoning unit.
2//!
3//! Skills are the K4 (Investigative Knowledge) primitive: deterministic Rust
4//! code that operates on an [`InvestigationContext`] using the agent's
5//! [`super::ToolRegistry`] slice. They are stateless so the same instance
6//! can be assigned to any number of agents simultaneously.
7
8use async_trait::async_trait;
9
10use crate::context::{InvestigationContext, NextAction};
11use crate::registry::{KernelError, ToolRegistry};
12
13/// Stable identifier for a skill (e.g. `"recon.high_fanout"`,
14/// `"general.baseline_compare"`).
15pub type SkillId = String;
16
17/// What a skill produced for one execution. The agent loop folds these
18/// outcomes into the shared [`InvestigationContext`].
19#[derive(Debug, Clone, Default)]
20pub struct SkillOutcome {
21    /// Confidence delta to apply (positive raises threat probability,
22    /// negative lowers). The agent clamps the running confidence after
23    /// folding the delta in.
24    pub confidence_delta: f32,
25    /// Hints for subsequent skills.
26    pub next_actions: Vec<NextAction>,
27}
28
29impl SkillOutcome {
30    pub fn noop() -> Self {
31        Self::default()
32    }
33
34    pub fn with_delta(mut self, d: f32) -> Self {
35        self.confidence_delta = d;
36        self
37    }
38
39    pub fn with_next(mut self, a: NextAction) -> Self {
40        self.next_actions.push(a);
41        self
42    }
43}
44
45/// A composable, stateless reasoning unit.
46///
47/// Implementations MUST be safe to share across agents: no mutable state in
48/// the skill itself. Per-investigation state lives in [`InvestigationContext`].
49#[async_trait]
50pub trait Skill: Send + Sync {
51    fn id(&self) -> &str;
52
53    fn description(&self) -> &str {
54        ""
55    }
56
57    /// Whether this skill is willing to run given the current context.
58    /// Default: always applicable. Specialist skills typically gate on
59    /// signal presence or evidence already collected.
60    fn applies(&self, _ctx: &InvestigationContext) -> bool {
61        true
62    }
63
64    /// Execute the skill. Implementations may inspect and mutate `ctx`
65    /// directly (appending evidence/signals) and/or return non-evidence
66    /// adjustments via [`SkillOutcome`].
67    async fn execute(
68        &self,
69        ctx: &mut InvestigationContext,
70        tools: &ToolRegistry,
71    ) -> Result<SkillOutcome, KernelError>;
72}