Skip to main content

systemprompt_models/bridge/manifest/
entries.rs

1//! Catalogue entries carried inside a [`super::SignedManifest`]: plugins,
2//! skills, rules, agents, hooks and library artifacts.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use serde::{Deserialize, Serialize};
8
9use crate::bridge::ids::Sha256Digest;
10use crate::hooks::{HookCategory, HookEvent};
11use crate::plugin::{PluginComponentRef, PluginHooksRef};
12use systemprompt_identifiers::{
13    AgentId, AgentName, HookId, LibraryArtifactId, MarketplaceRuleId, ModelId, PluginId,
14    ProviderId, RuleName, SkillId, SkillName,
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct PluginEntry {
19    pub id: PluginId,
20    pub version: String,
21    pub sha256: Sha256Digest,
22    pub files: Vec<PluginFile>,
23    #[serde(default)]
24    pub hooks: PluginHooksRef,
25    #[serde(default, skip_serializing_if = "Option::is_none")]
26    pub publication: Option<ManagedPublicationRef>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct PluginFile {
31    pub path: String,
32    pub sha256: Sha256Digest,
33    pub size: u64,
34}
35
36/// A Cowork-native library document (raw HTML in the desktop app's Artifacts
37/// library) — not one of the in-chat MCP artifacts in [`crate::artifacts`].
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct ArtifactEntry {
40    pub id: LibraryArtifactId,
41    pub name: String,
42    pub description: String,
43    pub version: String,
44    pub mcp_tools: Vec<String>,
45    pub content: String,
46    pub starred: bool,
47    pub sha256: Sha256Digest,
48    #[serde(default, skip_serializing_if = "Vec::is_empty")]
49    pub plugins: Vec<PluginId>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct SkillEntry {
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    pub publication: Option<ManagedPublicationRef>,
56    pub id: SkillId,
57    pub name: SkillName,
58    pub description: String,
59    pub file_path: String,
60    #[serde(default)]
61    pub tags: Vec<String>,
62    pub sha256: Sha256Digest,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub instructions: Option<String>,
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub source: Option<SkillSource>,
67    #[serde(default, skip_serializing_if = "Vec::is_empty")]
68    pub hosts: Vec<String>,
69    #[serde(default, skip_serializing_if = "Vec::is_empty")]
70    pub plugins: Vec<PluginId>,
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub frontmatter: Option<serde_yaml::Mapping>,
73}
74
75/// Where a plugin-delivered skill's `SKILL.md` sits: `path` is an entry of
76/// that plugin's [`PluginEntry::files`].
77#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78pub struct SkillSource {
79    pub plugin_id: PluginId,
80    pub path: String,
81}
82
83/// Exact signed publication identity of a managed skill, plugin or rule,
84/// shared by every host projection. This is distribution evidence, not proof
85/// that a host installed or invoked the resource.
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct ManagedPublicationRef {
88    pub publication_id: systemprompt_identifiers::PublicationId,
89    pub resource_id: systemprompt_identifiers::ManagedResourceId,
90    pub revision_id: systemprompt_identifiers::ResourceRevisionId,
91    pub generation: i64,
92    pub bundle_digest: Sha256Digest,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct RuleEntry {
97    pub id: MarketplaceRuleId,
98    pub name: RuleName,
99    pub description: String,
100    pub file_path: String,
101    #[serde(default)]
102    pub tags: Vec<String>,
103    pub sha256: Sha256Digest,
104    pub instructions: String,
105    #[serde(default, skip_serializing_if = "Vec::is_empty")]
106    pub hosts: Vec<String>,
107    #[serde(default, skip_serializing_if = "Vec::is_empty")]
108    pub plugins: Vec<PluginId>,
109    #[serde(default, skip_serializing_if = "Option::is_none")]
110    pub publication: Option<ManagedPublicationRef>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct AgentEntry {
115    pub id: AgentId,
116    pub name: AgentName,
117    pub display_name: String,
118    pub description: String,
119    pub version: String,
120    pub endpoint: String,
121    pub enabled: bool,
122    pub is_default: bool,
123    pub is_primary: bool,
124    #[serde(default)]
125    pub provider: Option<ProviderId>,
126    #[serde(default)]
127    pub model: Option<ModelId>,
128    #[serde(default)]
129    pub mcp_servers: PluginComponentRef,
130    #[serde(default)]
131    pub skills: PluginComponentRef,
132    #[serde(default)]
133    pub tags: Vec<String>,
134    #[serde(default)]
135    pub system_prompt: Option<String>,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub struct HookEntry {
140    pub id: HookId,
141    pub name: String,
142    pub description: String,
143    pub version: String,
144    pub event: HookEvent,
145    pub matcher: String,
146    pub command: String,
147    #[serde(default)]
148    pub is_async: bool,
149    #[serde(default, skip_serializing_if = "Option::is_none")]
150    pub timeout: Option<u32>,
151    pub category: HookCategory,
152    #[serde(default)]
153    pub tags: Vec<String>,
154    pub sha256: Sha256Digest,
155}