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