Skip to main content

kernel/event/record/
skill.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! What shelving a skill and auditing it record
7//! (`crates/kernel/spec/Event/Record.lean` D23).
8//!
9//! The line is record-only: what an auditor said about a skill decides
10//! no byte of a model request. A skill's use is not recorded here; the
11//! `tool_called` lines that read it already say so.
12
13use serde::{Deserialize, Serialize};
14
15use crate::B3Hash;
16
17/// `skill_audited`: one audit of one version of a skill.
18///
19/// The digest binds the verdict to the bytes it judged: once the skill's
20/// content changes, its digest changes and this line no longer speaks
21/// for it.
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
24pub struct SkillAudited {
25    pub skill: String,
26    pub digest: B3Hash,
27    pub source: AuditSource,
28    /// The auditor's own version or name; for skills.sh, the partner,
29    /// such as `socket`.
30    pub scanner: String,
31    pub verdict: AuditVerdict,
32    /// The risk level in the auditor's own word.
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub risk: Option<String>,
35    /// When the auditor says it audited, in its own spelling.
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub audited_at: Option<String>,
38    /// Where a person reads the audit when the city could not fetch it.
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub link: Option<String>,
41}
42
43/// `skill_shelved`: one version of a skill landed on a shelf through the
44/// city's install door.
45///
46/// Written only when bytes actually landed: a reinstall of the same
47/// content changes nothing and writes nothing. `digest` is the value the
48/// audit binds to, so a version, its shelving and its audits meet on one
49/// digest.
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
51#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
52pub struct SkillShelved {
53    pub skill: String,
54    pub digest: B3Hash,
55    pub source: ShelvedFrom,
56}
57
58/// Where a shelved version came from.
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60#[serde(tag = "kind", rename_all = "snake_case")]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62pub enum ShelvedFrom {
63    /// A directory or document on this machine.
64    Path,
65    /// A clone of an `https://` repository at a revision.
66    Git { url: String, rev: Option<String> },
67    /// A skill skills.sh names as `<owner>/<repo>/<skill>`.
68    SkillsSh { name: String },
69    /// One of the skills the binary carries.
70    Shipped,
71    /// Text written on the shelf page.
72    Page,
73}
74
75/// Who audited.
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
77#[serde(rename_all = "snake_case")]
78#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
79pub enum AuditSource {
80    /// The partner audits skills.sh publishes for a skill.
81    SkillsSh,
82    /// The SkillSpector scanner run on this machine.
83    SkillSpector,
84}
85
86/// What the audit concluded.
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
90pub enum AuditVerdict {
91    Pass,
92    Warn,
93    Fail,
94    /// An auditor applied and no audit could be had: skills.sh did not
95    /// answer or refused, or SkillSpector exited with neither verdict code.
96    /// Shelving goes ahead, and the audit state never counts this line as
97    /// an audit. When no auditor applies - a local or shipped skill and no
98    /// SkillSpector on the PATH - no line is written at all (city D19).
99    Unreachable,
100}