pub struct Client {
pub commit_author_name: String,
pub commit_author_email: String,
/* private fields */
}Expand description
On-disk layout root + state selection.
<dir> default: ~/.objectiveai
├── bin/ ── shared across states ──
│ ├── objectiveai[.exe] (+ -api, -viewer, -mcp, -db)
│ ├── pg-bin/ postgres install (objectiveai-db)
│ ├── plugins/<owner>/<name>/<version>/
│ └── tools/<owner>/<name>/<version>/
└── state/<state>/ default state: "default"
├── config.json
├── db/ .pgpass db.lock (cluster, per state)
├── logs/
└── instances/agents/Binaries, the postgres install, plugins and tools are
machine-wide (Self::bin_dir); everything else is per-state
(Self::state_dir), so independent states coexist under one
install by switching OBJECTIVEAI_STATE.
Fields§
Implementations§
Source§impl Client
impl Client
Sourcepub fn new(
dir: Option<impl Into<PathBuf>>,
state: Option<impl Into<String>>,
commit_author_name: Option<impl Into<String>>,
commit_author_email: Option<impl Into<String>>,
) -> Self
pub fn new( dir: Option<impl Into<PathBuf>>, state: Option<impl Into<String>>, commit_author_name: Option<impl Into<String>>, commit_author_email: Option<impl Into<String>>, ) -> Self
Resolution per field: explicit arg → env (OBJECTIVEAI_DIR /
OBJECTIVEAI_STATE, feature env) → default
(~/.objectiveai / "default").
Panics when the state name doesn’t match [A-Za-z0-9_-]+ —
state names become directory names under <dir>/state/, so
separators, dot-segments, and empty names are rejected
outright.
Sourcepub fn dir(&self) -> &PathBuf
pub fn dir(&self) -> &PathBuf
The layout root (OBJECTIVEAI_DIR). Forward this (with
Self::state) to child processes so they resolve the same
tree.
Sourcepub fn bin_dir(&self) -> PathBuf
pub fn bin_dir(&self) -> PathBuf
<dir>/bin — binaries, the postgres install, plugins, tools.
Shared across every state.
Sourcepub fn state_dir(&self) -> PathBuf
pub fn state_dir(&self) -> PathBuf
<dir>/state/<state> — config, database cluster, logs, agent
registry. Per state.
Sourcepub fn config_path(&self) -> PathBuf
pub fn config_path(&self) -> PathBuf
Per-state config: <dir>/state/<state>/config.json.
Sourcepub fn global_config_path(&self) -> PathBuf
pub fn global_config_path(&self) -> PathBuf
Machine-wide (global) config: <dir>/bin/config.json — lives
with the other machine-wide artifacts.
pub fn logs_dir(&self) -> PathBuf
Source§impl Client
impl Client
pub async fn read_config(&self) -> Result<Config, Error>
pub async fn write_config(&self, config: &Config) -> Result<(), Error>
Sourcepub async fn read_config_at(&self, scope: SetScope) -> Result<Config, Error>
pub async fn read_config_at(&self, scope: SetScope) -> Result<Config, Error>
Read the config file a MUTATION targets — no merging, ever:
--global edits <dir>/bin/config.json, --state edits
<dir>/state/<state>/config.json. Missing file = defaults.
Sourcepub async fn write_config_at(
&self,
scope: SetScope,
config: &Config,
) -> Result<(), Error>
pub async fn write_config_at( &self, scope: SetScope, config: &Config, ) -> Result<(), Error>
Write back the file Self::read_config_at selected.
Sourcepub async fn read_config_view(&self, scope: GetScope) -> Result<Config, Error>
pub async fn read_config_view(&self, scope: GetScope) -> Result<Config, Error>
Read the config VIEW a get targets: --global and
--state return their file verbatim; --final joins them —
the global (root) config is the base and the per-state config
is layered on top, winning every conflict (recursively: maps
like api.mcp_authorization union per key with the per-state
entry overwriting the global one).
Source§impl Client
impl Client
Sourcepub fn plugins_dir(&self) -> PathBuf
pub fn plugins_dir(&self) -> PathBuf
The plugins directory: <bin_dir>/plugins — installed
plugins are machine-wide, shared by every state.
Sourcepub fn plugin_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
pub fn plugin_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
The directory that holds a plugin’s installed artifacts:
<plugins_dir>/<owner>/<name>/<version>/. Contains the
manifest objectiveai.json, the cli/ exec working
directory, and an optional viewer/ bundle.
Sourcepub fn plugin_cli_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
pub fn plugin_cli_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
A plugin’s cli working directory: <plugin_dir>/cli/. The
manifest’s exec runs with this as CWD; cli_zip extracts
into it at install time.
Sourcepub async fn resolve_plugin(
&self,
owner: &str,
name: &str,
version: &str,
) -> Option<(Vec<String>, PathBuf)>
pub async fn resolve_plugin( &self, owner: &str, name: &str, version: &str, ) -> Option<(Vec<String>, PathBuf)>
Resolve a plugin coordinate to its (exec_vector, cli_dir)
for the current platform — the same contract
Client::resolve_tool
has, with the plugin’s cli/ folder as the working directory.
exec_vector may be empty when the manifest declares no
command for this platform (viewer-only plugins; the caller
treats that as an error). None when the manifest is
missing/malformed/invalid.
Sourcepub async fn get_plugin(
&self,
owner: &str,
name: &str,
version: &str,
) -> Option<ManifestWithNameAndSource>
pub async fn get_plugin( &self, owner: &str, name: &str, version: &str, ) -> Option<ManifestWithNameAndSource>
Look up a single plugin manifest by coordinate. Reads
<base_dir>/plugins/<owner>/<name>/<version>/objectiveai.json.
Returns None if the file is missing, unreadable, malformed, or
invalid.
Sourcepub async fn list_plugins(
&self,
offset: usize,
limit: usize,
) -> Vec<ManifestWithNameAndSource>
pub async fn list_plugins( &self, offset: usize, limit: usize, ) -> Vec<ManifestWithNameAndSource>
Enumerate plugin manifests by walking the
plugins/<owner>/<name>/<version>/objectiveai.json tree. Every
failure mode — missing dir, unreadable file, malformed JSON,
missing required field — is silently skipped; the return type is
plain Vec rather than Result to reflect that.
Results are sorted by manifest mtime descending (most recently
modified first), then skip(offset).take(limit) is applied —
matching the convention of the logs list endpoints. Pass
(0, usize::MAX) for an unbounded list.
The directory walk is sequential but per-file read+parse runs
concurrently via futures::future::join_all.
Source§impl Client
impl Client
Sourcepub async fn install_plugin(
&self,
owner: &str,
repository: &str,
commit_sha: Option<&str>,
headers: Option<&IndexMap<String, String>>,
upgrade: bool,
) -> Result<bool, Error>
pub async fn install_plugin( &self, owner: &str, repository: &str, commit_sha: Option<&str>, headers: Option<&IndexMap<String, String>>, upgrade: bool, ) -> Result<bool, Error>
Install a plugin from a GitHub repository.
- Fetches
objectiveai.jsonfromraw.githubusercontent.comat the suppliedcommit_sha(or the default branch viaHEADwhen none). - Parses it as a
Manifest. - Downloads the declared release assets from
https://github.com/<owner>/<repository>/releases/download/v<version>/<asset>:cli_zip(when declared) extracts into<plugin dir>/cli/,viewer_zipinto…/viewer/. Neither is required — a manifest whose exec invokes PATH-resolved programs installs with just the manifest.
headers is an optional IndexMap<String, String> that gets
attached to every HTTP request (e.g. Authorization for
private repos / higher rate limits). The cli always passes
None.
Failures are returned as super::InstallError wrapped by
super::super::Error::Install. The bool is retained for
wire compatibility and is always true on success — the
platform gate that used to yield Ok(false) died with the
per-platform binaries map (per-OS support is now expressed by
the exec vectors themselves).
Sourcepub async fn fetch_plugin_manifest(
&self,
owner: &str,
repository: &str,
commit_sha: Option<&str>,
headers: Option<&IndexMap<String, String>>,
) -> Result<Manifest, Error>
pub async fn fetch_plugin_manifest( &self, owner: &str, repository: &str, commit_sha: Option<&str>, headers: Option<&IndexMap<String, String>>, ) -> Result<Manifest, Error>
Step 1 of install_plugin: fetch <owner>/<repo>/<ref>/objectiveai.json
from raw.githubusercontent.com and parse it as a Manifest.
Exposed publicly so callers can inspect the manifest before
committing to an install (e.g. for whitelist checks).
Sourcepub async fn install_plugin_from_manifest(
&self,
owner: &str,
repository: &str,
manifest: &Manifest,
source: &str,
headers: Option<&IndexMap<String, String>>,
upgrade: bool,
) -> Result<bool, Error>
pub async fn install_plugin_from_manifest( &self, owner: &str, repository: &str, manifest: &Manifest, source: &str, headers: Option<&IndexMap<String, String>>, upgrade: bool, ) -> Result<bool, Error>
Step 2 of install_plugin: given an already-parsed manifest,
download its declared release assets (cli_zip → cli/,
viewer_zip → viewer/) and persist the manifest.
Source§impl Client
impl Client
Sourcepub fn resolve_head(
&self,
kind: Kind,
owner: &str,
repository: &str,
) -> Result<String, Error>
pub fn resolve_head( &self, kind: Kind, owner: &str, repository: &str, ) -> Result<String, Error>
Resolves the HEAD commit SHA for a repository.
Sourcepub async fn read_json<T: DeserializeOwned>(
&self,
kind: Kind,
owner: &str,
repository: &str,
commit: Option<&str>,
) -> Result<Option<(T, String)>, Error>
pub async fn read_json<T: DeserializeOwned>( &self, kind: Kind, owner: &str, repository: &str, commit: Option<&str>, ) -> Result<Option<(T, String)>, Error>
Reads and deserializes a kind’s JSON file from a repository.
commit = Some reads from that specific git commit; commit = None
reads the working tree and resolves HEAD for the reported commit.
Returns Ok(None) if the repository or file does not exist.
Sourcepub async fn list(
&self,
kind: Kind,
) -> Pin<Box<dyn Stream<Item = RemotePath> + Send>>
pub async fn list( &self, kind: Kind, ) -> Pin<Box<dyn Stream<Item = RemotePath> + Send>>
Streams every valid repository of kind under state_dir/<kind>.
The outer stream lists the <owner> directories; each owner is then
flat-mapped into an inner stream listing its <repository>
directories, and each repo resolves to a Client remote path by
reading HEAD and parsing the kind’s JSON. Repos whose HEAD or JSON
fails are skipped. Nothing is buffered into a Vec: directories are
walked lazily as the stream is polled.
Source§impl Client
impl Client
Sourcepub fn tool_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
pub fn tool_dir(&self, owner: &str, name: &str, version: &str) -> PathBuf
A tool’s version directory:
<base_dir>/tools/<owner>/<name>/<version>.
Sourcepub async fn resolve_tool(
&self,
owner: &str,
name: &str,
version: &str,
) -> Option<(Vec<String>, PathBuf)>
pub async fn resolve_tool( &self, owner: &str, name: &str, version: &str, ) -> Option<(Vec<String>, PathBuf)>
Resolve a tool coordinate to its (exec_vector, cwd) for the
current platform. cwd is the version folder; exec_vector is
the manifest’s per-OS command (possibly empty when the tool
declares no command for this platform — the caller treats that
as an error). None when the manifest is missing/malformed.
Sourcepub async fn get_tool(
&self,
owner: &str,
name: &str,
version: &str,
) -> Option<ManifestWithNameAndSource>
pub async fn get_tool( &self, owner: &str, name: &str, version: &str, ) -> Option<ManifestWithNameAndSource>
Look up a single tool manifest by coordinate. Reads
<base_dir>/tools/<owner>/<name>/<version>/objectiveai.json.
None on missing / unreadable / malformed files.
Sourcepub async fn list_tools(
&self,
offset: usize,
limit: usize,
) -> Vec<ManifestWithNameAndSource>
pub async fn list_tools( &self, offset: usize, limit: usize, ) -> Vec<ManifestWithNameAndSource>
Enumerate tool manifests by walking the
tools/<owner>/<name>/<version>/objectiveai.json tree. Every
failure mode — missing dir, unreadable file, malformed JSON — is
silently skipped.
Results are sorted by manifest mtime descending, then
skip(offset).take(limit) is applied — matching list_plugins.
Pass (0, usize::MAX) for an unbounded list.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Client
impl RefUnwindSafe for Client
impl Send for Client
impl Sync for Client
impl Unpin for Client
impl UnsafeUnpin for Client
impl UnwindSafe for Client
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,
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