pub struct Manifest {
pub owner: String,
pub name: String,
pub version: String,
pub description: String,
pub exec: Exec,
pub cli_zip: CliZip,
pub viewer_zip: Option<String>,
pub viewer_url: Option<String>,
pub viewer_routes: Vec<ViewerRoute>,
pub mcp_servers: Vec<McpServer>,
}Expand description
Declarative metadata a plugin ships with — the on-disk
objectiveai.json at
<base_dir>/plugins/<owner>/<name>/<version>/objectiveai.json. The
CLI reads and writes this shape verbatim (install writes the fetched
manifest exactly as authored); the plugins get wire response is a
lean projection of it.
Fields§
§owner: StringGitHub <owner> segment of the source repo, written verbatim
from the fetched manifest (forks land on disk with whatever
owner they authored, not rewritten to the install coordinate).
name: StringThe plugin’s identifier (matches the <name> directory
segment).
version: StringVersion string. Semver convention is recommended but not enforced — the host just displays whatever’s here.
description: StringOne-line description of what the plugin does. Surfaced in
listings and the plugin’s --help-equivalent UI.
exec: ExecPer-OS exec command for the plugin’s cli side — the same shape
tools use. The current platform’s vector is the program plus
its leading arguments; the run’s args are appended, and the
whole thing runs with CWD = <plugin dir>/cli/. Relative
program paths resolve against that folder; bare names keep
PATH-lookup semantics. An empty per-OS vector means viewer-only
for that platform.
cli_zip: CliZipPer-OS cli bundle zip filenames. At install the current
platform’s entry (when present) is downloaded and extracted
into <plugin dir>/cli/ (the Self::exec working
directory), the same way Self::viewer_zip extracts to
viewer/. Required field; each per-OS entry is optional —
absent means the exec needs nothing on disk for that platform
(e.g. it invokes a PATH-resolved program, or the plugin is
viewer-only).
viewer_zip: Option<String>GitHub-release asset filename for the plugin’s viewer UI
bundle (a .zip whose root contains index.html plus
assets). When absent, the plugin has no viewer tab from this
source. Mutually exclusive with Self::viewer_url —
validated by Self::validate.
viewer_url: Option<String>Remote URL the viewer’s iframe loads directly, instead of an
on-disk bundle from Self::viewer_zip. The full URL is used
as the iframe src= verbatim — query string, path, port,
fragment all pass through. Must use https://, or http://
targeting localhost / 127.0.0.1 (development only).
Mutually exclusive with Self::viewer_zip. Self::viewer_routes
apply to remote-URL viewers the same way they apply to
zip-bundled viewers — the embedded axum server still hosts the
declared routes; the iframe still receives the same postMessage
protocol regardless of where its HTML/JS loaded from.
viewer_routes: Vec<ViewerRoute>HTTP routes the viewer exposes on behalf of this plugin.
Each entry registers a handler at
/plugin/<repository>/<path> on the viewer’s embedded axum
server; a hit emits a PluginRequest { type, value } event
to the React frontend, which dispatches to the plugin’s
iframe via the postMessage bridge.
mcp_servers: Vec<McpServer>MCP servers the plugin wants the host to expose. Each entry
has a name (the identifier agents reference via
objectiveai_sdk::agent::ClientObjectiveaiMcpPluginEntry::mcp_servers)
plus an authorization flag. Auth-requiring entries flag
authorization = true; credentials are resolved by the host
(env vars / config), not the manifest.
Implementations§
Source§impl Manifest
impl Manifest
Sourcepub fn has_viewer(&self) -> bool
pub fn has_viewer(&self) -> bool
Whether this plugin presents a viewer tab in the host. True
iff either viewer source field — Self::viewer_zip or
Self::viewer_url — is set.
Sourcepub fn validate(&self) -> Result<(), &'static str>
pub fn validate(&self) -> Result<(), &'static str>
Validate fields that can’t be enforced by serde alone:
viewer_zip and viewer_url are mutually exclusive, and
viewer_url (when present) must be https:// or http://
targeting localhost / 127.0.0.1. Called at every parse
boundary (remote-fetched install, on-disk read) so a broken
manifest can’t sneak through.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Manifest
impl<'de> Deserialize<'de> for Manifest
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl From<Manifest> for ResponseManifest
impl From<Manifest> for ResponseManifest
Source§impl JsonSchema for Manifest
impl JsonSchema for Manifest
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for Manifest
Auto Trait Implementations§
impl Freeze for Manifest
impl RefUnwindSafe for Manifest
impl Send for Manifest
impl Sync for Manifest
impl Unpin for Manifest
impl UnsafeUnpin for Manifest
impl UnwindSafe for Manifest
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more