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}