turbovault_plugin_api/lib.rs
1//! Stable contracts for compiled-in TurboVault plugins.
2//!
3//! This crate is intentionally smaller than TurboVault's internal API. A
4//! plugin receives a curated [`VaultApi`] facade and an advisory [`HookBus`],
5//! never a raw vault manager or MCP server.
6//!
7//! Plugins are compiled into the host behind default-off Cargo features. The
8//! host mounts each plugin under [`PluginDescriptor::id`] and namespaces all
9//! three MCP primitives, so in the `tasks` plugin a local tool `list` is
10//! advertised as `tasks_list`, a prompt `review` as `tasks_review`, and a
11//! resource `index/stats.json` as `tasks://index/stats.json`. A plugin names
12//! only the local half.
13//!
14//! # Trust model
15//!
16//! Plugins are statically linked into the TurboVault process. **This API is a
17//! contract, not a sandbox.** A compiled-in plugin runs with the host's full
18//! privileges: it can open files, spawn threads, and reach the network
19//! regardless of what it declares here. The boundary exists to keep plugins
20//! decoupled from TurboVault's internals, to make what a plugin touches
21//! reviewable, and to stop *accidental* over-reach — not to contain hostile
22//! code. Only compile in plugins you would accept as a dependency.
23//!
24//! Within that model the host does enforce real invariants: capabilities are
25//! per-plugin and declared up front, writes carry mandatory preconditions,
26//! event attribution is host-stamped, and a plugin's tool calls are bounded in
27//! time and isolated from panics.
28//!
29//! # Compatibility
30//!
31//! Public types are `#[non_exhaustive]` and built through constructors and
32//! builder setters, so this crate can gain fields, variants, and trait methods
33//! (always with defaults) without a breaking release. Construct types via
34//! their `new` functions rather than struct literals.
35
36#![deny(missing_docs)]
37#![forbid(unsafe_code)]
38
39mod completion;
40mod error;
41mod hooks;
42mod lifecycle;
43mod provider;
44mod storage;
45mod vault;
46
47pub use completion::{Completion, CompletionRequest, CompletionTarget};
48pub use error::{PluginError, PluginErrorCode, PluginResult};
49pub use hooks::{
50 EventAttribution, EventCursor, HookBus, HookEvent, HookLifecycle, HookRecvError,
51 HookSubscription, PublishError, VaultEventEnvelope, WriteProvenance,
52};
53pub use lifecycle::{ShutdownSignal, ShutdownTrigger};
54pub use provider::{
55 MCP_TOOL_NAME_MAX_LEN, Plugin, PluginCapabilities, PluginContext, PluginDescriptor,
56 PluginProvider, PluginRequestContext, namespaced_prompt_name, namespaced_resource_template,
57 namespaced_resource_uri, namespaced_tool_name, validate_mcp_tool_name, validate_plugin_id,
58};
59pub use storage::{PluginStorage, PluginStore};
60pub use turbomcp_types::{
61 Prompt, PromptResult, Resource, ResourceResult, ResourceTemplate, Tool, ToolResult,
62};
63pub use vault::{
64 NoteListing, NoteSnapshot, PluginIdentity, VaultApi, VaultDescriptor, VaultHost,
65 WriteNoteRequest, WritePrecondition, WriteReceipt,
66};
67
68/// Compiles the README's examples as doctests.
69///
70/// The README is a plugin author's first contact with this crate, so its code
71/// has to keep working as the contract changes rather than quietly rotting.
72#[cfg(doctest)]
73#[doc = include_str!("../README.md")]
74struct ReadmeExamples;