calternal-plugin
Plugin contracts and the runtime registry.
Core plugins register factories in the distributed slice. The registry validates IDs, sorts plugins and merges their Home-path declarations before it exposes routes or metadata, so linker order cannot affect shared views. Request timing exposes selected operations without User data (#549).
Source: crates/calternal-plugin/src/lib.rs
Modules
Section titled “Modules”| Module | Summary |
|---|---|
changes |
One durable change sequence per User (DESIGN §§24, 58; #668). |
media_sandbox |
Process controls shared by Plugins that decode untrusted media. |
notes_writer |
Shared Home writer identity for Notes and durable Tag operations (#1110, #1111). |
http_cache |
Authorized conditional HTTP reads with strong representation ETags (#665). |
outbound |
Validate and pin public endpoints used by Plugin provider clients. |
query |
URL query parsing that preserves repeated keys for AND Tag filters (#1109, DESIGN §33). |
raster_transport |
One bounded transport for public images, Mail fonts and Notes page metadata (#766, #726, #1151; DESIGN §§9, 21, 45, 53). |
timing |
Cheap request phase timing for Calendar, Notes and Files (#549). |
user_settings |
Per-User preferences in <home>/.calternal/settings.json. |
zone |
The user’s time zone and local-day arithmetic (#141). |
mcp_events |
Trusted webhook producer bus (DESIGN §55, #491). |
Re-exports
Section titled “Re-exports”pub use linkme::distributed_slice
Structs
Section titled “Structs”AgentTurnFileMutation
Section titled “AgentTurnFileMutation”pub struct AgentTurnFileMutationA file change produced by an Agent request. The Files plugin creates this only after its normal Index writer has committed the matching feed row.
Fields
pub owner_id: String: Home that owns the changed item.pub cursor: i64: Durable cursor in the Files change feed.pub operation: String: Files change-feed operation.pub path: String: Current owner-relative path.pub old_path: Option<String>: Previous owner-relative path for moves.pub item_id: String: Stable Files item identity.pub content_hash: Option<String>: Hash after the mutation, when the item remains present.pub prior_version: Option<String>: Version name containing the content before an overwrite.pub prior_hash: Option<String>: Hash of the content stored inprior_version.pub trash_name: Option<String>: Trash entry name when the Agent moved an item to Trash.
Implements: Clone, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:534
AgentTurnScope
Section titled “AgentTurnScope”pub struct AgentTurnScopeAuth-validated context that tags writes made by a data-scope Agent token.
Fields
pub turn_id: String: Stable Agent turn identity.pub user_id: String: User who owns the turn.pub request_cursor: i64: Files change-feed cursor captured before this authenticated request.
Implements: Clone
AgentTurnScope::new
Section titled “AgentTurnScope::new”pub fn new( turn_id: String, user_id: String, request_cursor: i64, recorder: Arc<dyn AgentTurnMutationRecorder>, ) -> SelfBind a trusted turn identity to its AI plugin mutation writer.
AgentTurnScope::record
Section titled “AgentTurnScope::record”pub async fn record(&self, mutation: AgentTurnFileMutation) -> Result<(), String>Record one mutation through the turn’s durable writer.
AgentTurnScope::record_data_file_write
Section titled “AgentTurnScope::record_data_file_write”pub async fn record_data_file_write( &self, owner_id: &str, path: &str, before: Option<calternal_fs::FileFingerprint>, ) -> Result<(), String>Record one Markdown write through the Files Index single writer.
AgentTurnScope::record_data_file_move
Section titled “AgentTurnScope::record_data_file_move”pub async fn record_data_file_move( &self, owner_id: &str, old_path: &str, new_path: &str, ) -> Result<(), String>Record one Markdown move through the Files Index single writer.
Source: crates/calternal-plugin/src/lib.rs:592
ConnectionLease
Section titled “ConnectionLease”pub struct ConnectionLeaseKeep the accepted TCP connection’s resource permit alive in an upgraded protocol task after Hyper hands the socket to that task.
Implements: Clone, std::fmt::Debug
ConnectionLease::new
Section titled “ConnectionLease::new”pub fn new<T: Send + Sync + 'static>(owner: T) -> SelfKeep owner alive until every clone of this lease is dropped.
Source: crates/calternal-plugin/src/lib.rs:336
FileTypeHandler
Section titled “FileTypeHandler”pub struct FileTypeHandlerA file type which a plugin can handle in a future preview flow.
Fields
pub id: String: Stable handler identifier within the plugin.pub mime_types: Vec<String>: MIME types accepted by this handler.pub extensions: Vec<String>: Filename extensions accepted by this handler, without a leading dot.
Implements: Clone, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:755
IndexPluginState
Section titled “IndexPluginState”pub struct IndexPluginStatePersisted enablement overrides with a request-path memory cache.
Implements: PluginState
IndexPluginState::load
Section titled “IndexPluginState::load”pub async fn load(db: Db, root: Root) -> Result<Self, PluginStateError>Load all persisted overrides before the router and workers start.
Source: crates/calternal-plugin/src/state.rs:16
InMemoryPluginState
Section titled “InMemoryPluginState”pub struct InMemoryPluginStateIn-memory state for tests and contract-only server builds.
Implements: Default, PluginState
Source: crates/calternal-plugin/src/lib.rs:1027
JobContext
Section titled “JobContext”pub struct JobContextInput passed to a plugin job handler by a future queue adapter.
Fields
pub job_id: String: Stable job identifier supplied by the queue.pub payload: Value: Serialized job payload.
Implements: Clone, Debug
Source: crates/calternal-plugin/src/lib.rs:703
JobError
Section titled “JobError”pub struct JobErrorA safe error returned by a job handler.
Fields
pub message: String: Short error text for the queue and logs.
Implements: Clone, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:712
JobRegistration
Section titled “JobRegistration”pub struct JobRegistrationA plugin paired with one of its job handlers.
Fields
pub plugin_id: String: Owning plugin ID.pub handler: Arc<dyn JobHandler>: Handler supplied by the plugin.
Source: crates/calternal-plugin/src/lib.rs:1227
NotificationDraft
Section titled “NotificationDraft”pub struct NotificationDraftA typed event for the Notifications Plugin to persist.
Fields
pub user_id: String: Immutable ID of the User who can see this notification.pub kind: NotificationKind: Stable notification category.pub title: String: Short inbox and push title.pub body: Option<String>: Optional inbox and push detail.pub link: Option<String>: Stable UI link, when this event has a navigable target.pub dedupe_key: String: Stable producer identity used to make retries idempotent.
Implements: Clone, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:181
NotificationPublisherInstallError
Section titled “NotificationPublisherInstallError”pub struct NotificationPublisherInstallError;Error returned when another sink is already installed in this process.
Implements: Clone, Copy, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:205
OwnedPathRegistry
Section titled “OwnedPathRegistry”pub struct OwnedPathRegistryShared, immutable view of the Home paths declared by registered Plugins.
The registry merges declarations once when Plugins are built. Route handlers can then identify Plugin storage without maintaining local path lists (#606, Calendar Activity #662).
Implements: Clone, Debug, Default
OwnedPathRegistry::iter
Section titled “OwnedPathRegistry::iter”pub fn iter(&self) -> impl Iterator<Item = OwnedPath> + '_Return the stable, de-duplicated Plugin path declarations.
OwnedPathRegistry::owns
Section titled “OwnedPathRegistry::owns”pub fn owns(&self, candidate: &str) -> boolReturn true when any registered Plugin owns this Home-relative path.
Source: crates/calternal-plugin/src/lib.rs:815
PluginContext
Section titled “PluginContext”pub struct PluginContextStable instance data available when the host builds plugin routes.
Fields
pub instance_name: String: Display name for this instance.pub live_instance_name: Option<Arc<RwLock<String>>>: Live instance name, when the server owns a hot-reloaded config file.pub data: Option<PluginData>: Live filesystem and Index handles. Absent while building the static contract.
Implements: Clone, Debug
Source: crates/calternal-plugin/src/lib.rs:923
PluginData
Section titled “PluginData”pub struct PluginDataServer-owned handles shared with compiled Plugins during live routing.
Fields
pub root: calternal_fs::Root: The confined data directory.pub db: calternal_db::Db: The Index, with one SQLite writer.
Implements: Clone, std::fmt::Debug
Source: crates/calternal-plugin/src/lib.rs:934
PluginEvent
Section titled “PluginEvent”pub struct PluginEventAn invalidation that plugins publish after a durable mutation. path is a
Home-relative path for file-backed plugins; provider-backed plugins may use
a documented virtual scope such as Mail’s folders. A global Files
reconciliation notice uses an empty User and path scope (#470, #771).
Fields
pub user_id: String: Immutable User ID; empty only for the global Files reconciliation notice.pub plugin_id: String: Plugin that owns the changed object, orfsfor Files invalidations.pub path: String: Changed Home path or documented plugin scope; empty only for global Files reconciliation.pub kind: String: Short mutation kind, such ascreated,updated, orreconciled.
Implements: Clone, Debug
PluginEvent::files_reconciled
Section titled “PluginEvent::files_reconciled”pub fn files_reconciled() -> SelfMark that Files adopted every Home after a full scan. The empty scope means each consumer must reconcile its derived data once; this is not an item change. One bus message avoids a per-file startup storm (#470, DESIGN §2–3).
PluginEvent::is_files_reconciled
Section titled “PluginEvent::is_files_reconciled”pub fn is_files_reconciled(&self) -> boolIdentify the global completion notice emitted after Files scans all Homes. Subscribers must handle it before applying User or path filters (#470).
Source: crates/calternal-plugin/src/lib.rs:60
PluginRegistry
Section titled “PluginRegistry”pub struct PluginRegistryValidated plugin set with stable ordering and enablement-aware views.
PluginRegistry::new
Section titled “PluginRegistry::new”pub fn new( plugins: Vec<Arc<dyn Plugin>>, state: Arc<dyn PluginState>, ) -> Result<Self, RegistryError>Build a registry and validate all plugin IDs.
PluginRegistry::from_core_plugins
Section titled “PluginRegistry::from_core_plugins”pub fn from_core_plugins(state: Arc<dyn PluginState>) -> Result<Self, RegistryError>Build a registry from the compile-time core plugin slice.
PluginRegistry::all
Section titled “PluginRegistry::all”pub fn all(&self) -> &[Arc<dyn Plugin>]Return all registered plugins in stable ID order.
PluginRegistry::manifest
Section titled “PluginRegistry::manifest”pub fn manifest(&self, plugin_id: &str) -> Option<PluginManifest>Return a registered manifest by its stable ID.
PluginRegistry::owned_paths
Section titled “PluginRegistry::owned_paths”pub fn owned_paths(&self) -> &OwnedPathRegistryReturn the shared Home path declarations from all registered Plugins.
PluginRegistry::is_instance_enabled
Section titled “PluginRegistry::is_instance_enabled”pub fn is_instance_enabled(&self, plugin_id: &str) -> boolCheck whether the Instance has enabled one plugin.
PluginRegistry::is_enabled
Section titled “PluginRegistry::is_enabled”pub fn is_enabled(&self, plugin_id: &str, user_id: Option<&str>) -> boolCheck whether a plugin is enabled for one optional User.
PluginRegistry::default_user_enabled
Section titled “PluginRegistry::default_user_enabled”pub fn default_user_enabled(&self, plugin_id: &str) -> boolReturn a registered Plugin’s per-User default, or the historical visible default for an absent ID.
PluginRegistry::set_instance_enabled
Section titled “PluginRegistry::set_instance_enabled”pub async fn set_instance_enabled( &self, plugin_id: &str, enabled: bool, cascade: bool, ) -> Result<Vec<String>, PluginStateError>Apply an Instance toggle and its dependency changes atomically.
PluginRegistry::set_user_enabled
Section titled “PluginRegistry::set_user_enabled”pub async fn set_user_enabled( &self, plugin_id: &str, user_id: &str, enabled: bool, ) -> Result<(), PluginStateError>Apply a user’s mode toggle for one registered plugin.
PluginRegistry::enabled
Section titled “PluginRegistry::enabled”pub fn enabled(&self, user_id: Option<&str>) -> impl Iterator<Item = &Arc<dyn Plugin>>Return enabled plugins in stable ID order.
PluginRegistry::catalog
Section titled “PluginRegistry::catalog”pub fn catalog(&self, user_id: Option<&str>) -> PluginCatalogBuild the catalog for all plugins and the state visible to one user.
PluginRegistry::router
Section titled “PluginRegistry::router”pub fn router(&self, context: &PluginContext) -> RouterMount plugin routers below /api/v1/<plugin-id>.
The enablement and scope guard runs for every request. This keeps state changes effective without rebuilding the server router.
PluginRegistry::public_router
Section titled “PluginRegistry::public_router”pub fn public_router(&self, context: &PluginContext) -> RouterMount Plugin capability routes at their declared root paths.
Unlike router, this does not require a User or scope. Each Plugin
must authenticate its own bearer capability and limit access to the
referenced owner data. Instance-level Plugin disablement still applies.
PluginRegistry::openapi_documents
Section titled “PluginRegistry::openapi_documents”pub fn openapi_documents(&self) -> impl Iterator<Item = OpenApi> + '_Return OpenAPI documents from every compiled plugin, including disabled plugins.
The checked-in contract describes the complete binary. Runtime routing still uses only enabled plugins.
PluginRegistry::job_handlers
Section titled “PluginRegistry::job_handlers”pub fn job_handlers(&self, user_id: Option<&str>) -> Vec<JobRegistration>Return job handlers from enabled plugins.
PluginRegistry::all_job_handlers
Section titled “PluginRegistry::all_job_handlers”pub fn all_job_handlers(&self) -> Vec<JobRegistration>Return job handlers for every registered plugin.
The server uses this list to register stable kinds once. The Worker checks the live Instance state before each claim, so later toggles do not require rebuilding its handler table.
PluginRegistry::search_providers
Section titled “PluginRegistry::search_providers”pub fn search_providers(&self, user_id: Option<&str>) -> Vec<SearchRegistration>Return search providers from enabled plugins.
PluginRegistry::file_type_handlers
Section titled “PluginRegistry::file_type_handlers”pub fn file_type_handlers(&self, user_id: Option<&str>) -> Vec<RegisteredFileTypeHandler>Return file-type handlers from enabled plugins.
PluginRegistry::settings_schemas
Section titled “PluginRegistry::settings_schemas”pub fn settings_schemas(&self, user_id: Option<&str>) -> Vec<RegisteredSettingsSchema>Return settings schemas from enabled plugins.
Source: crates/calternal-plugin/src/lib.rs:1294
PluginRequestContext
Section titled “PluginRequestContext”pub struct PluginRequestContextAuthenticated authority attached to an API request by the server.
The auth adapter must create this extension after validating the session. The plugin host never reads identity or scopes from request headers.
Fields
pub user_id: Option<String>: Immutable user ID, if this request belongs to a user.pub allowed_roots: Vec<String>: Auth-validated Home and Share roots available to the request.pub scopes: Vec<String>: Scopes granted to the current session.pub role: Option<String>: Current instance role.pub resource_scope: Option<Value>: Auth-validated resource boundary carried to Plugin routes.pub session_actor: SessionActor: Who holds the session, as the auth layer recorded it at issuance.
Implements: Clone, Debug, Default, PartialEq, Eq
PluginRequestContext::data_user
Section titled “PluginRequestContext::data_user”pub fn data_user(&self) -> Option<&str>The caller’s own User ID when the session has the data scope and no
resource scope that names another User; None otherwise.
Per-User projections authorise through this one check, so a request can only ever name its own data (cross-user isolation, #331, #435).
Source: crates/calternal-plugin/src/lib.rs:485
PluginRequestFreshness
Section titled “PluginRequestFreshness”pub struct PluginRequestFreshness(pub bool);Recent passkey assertion state attached by the authenticated server layer.
Implements: Clone, Copy, Debug, Default, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:529
PluginRequestSession
Section titled “PluginRequestSession”pub struct PluginRequestSession(pub Vec<u8>);Exact authenticated session identity for revocable Installation delivery (#759, DESIGN §57). This is a hash-only Index key, never a bearer credential. App Passwords do not carry it.
Implements: Clone
Source: crates/calternal-plugin/src/lib.rs:525
RegisteredFileTypeHandler
Section titled “RegisteredFileTypeHandler”pub struct RegisteredFileTypeHandlerA file-type handler paired with the plugin that owns it.
Fields
pub plugin_id: String: Owning plugin ID.pub handler: FileTypeHandler: Handler contribution.
Source: crates/calternal-plugin/src/lib.rs:1243
RegisteredSettingsSchema
Section titled “RegisteredSettingsSchema”pub struct RegisteredSettingsSchemaA settings schema paired with the plugin that owns it.
Fields
pub plugin_id: String: Owning plugin ID.pub schema: Value: JSON Schema for the plugin settings.
Source: crates/calternal-plugin/src/lib.rs:1251
SearchContext
Section titled “SearchContext”pub struct SearchContextAuthority data a provider must use when filtering search results.
Authentication will populate this value when its crate is integrated. The host passes an empty, anonymous context until then; a provider must not infer access from a query or result identifier.
Fields
-
pub user_id: Option<String>: Immutable user ID, if the request has an authenticated user. -
pub allowed_roots: Vec<String>: Auth-validated Home and Share roots the provider may search.Each value is a data-directory-relative path. An empty list grants no access. Providers must still validate each root before using it.
-
pub scopes: Vec<String>: Granted session scopes. -
pub role: Option<String>: The current instance role, if one is available. -
pub timezone: Option<String>: The user’s IANA zone for day-relative operators (date:today), as the host resolved it (zone::resolve_zone).Nonemeans UTC.
Implements: Clone, Debug, Default, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:440
SearchRegistration
Section titled “SearchRegistration”pub struct SearchRegistrationA plugin paired with one of its search providers.
Fields
pub plugin_id: String: Owning plugin ID.pub provider: Arc<dyn SearchProvider>: Provider supplied by the plugin.
Source: crates/calternal-plugin/src/lib.rs:1235
StreamPermit
Section titled “StreamPermit”pub struct StreamPermitHolds one stream slot. Dropping it frees the slot, including when the stream task ends by panic or cancellation.
Implements: Debug, Drop
Source: crates/calternal-plugin/src/lib.rs:275
NotificationKind
Section titled “NotificationKind”pub enum NotificationKindA notification kind that a server-side producer can publish.
The variant set is intentionally small. Producers send domain events after their own durable mutation; the Notifications Plugin owns persistence, inbox visibility, push delivery, and user-facing copy.
Variants
ShareReceived: A Share was granted to this User.AgentTurnFinished: An autonomous Agent turn completed.AgentApprovalNeeded: An autonomous Agent turn requires User approval.SyncConflict: A sync client found a conflict.CalendarReminder: A calendar reminder trigger became due.LogReminder: A Log entry reminder trigger became due.BlockReminder: A block reminder trigger became due.
Implements: Clone, Copy, Debug, PartialEq, Eq
NotificationKind::as_str
Section titled “NotificationKind::as_str”pub const fn as_str(self) -> &'static strStable identifier stored in the Index and sent to clients.
Source: crates/calternal-plugin/src/lib.rs:147
NotificationPublishError
Section titled “NotificationPublishError”pub enum NotificationPublishErrorError returned when the Notifications Plugin cannot persist an event.
Variants
Storage: The notification could not be written to the Index.
Implements: Clone, Copy, Debug, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:198
OwnedPath
Section titled “OwnedPath”pub enum OwnedPathOne path below a User’s Home that a Plugin owns (#606, used by Calendar #662).
A directory declaration owns the directory and its descendants. A file declaration owns one exact path. Declarations are compiled Plugin data, so request paths never enter the registry.
Variants
File(&'static str): One exact file path relative to a User’s Home.Directory(&'static str): A directory path and every descendant relative to a User’s Home.
Implements: Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd
OwnedPath::file
Section titled “OwnedPath::file”pub const fn file(path: &'static str) -> SelfDeclare one exact Plugin-owned file path below Home.
OwnedPath::directory
Section titled “OwnedPath::directory”pub const fn directory(path: &'static str) -> SelfDeclare a Plugin-owned directory tree below Home.
OwnedPath::path
Section titled “OwnedPath::path”pub const fn path(self) -> &'static strReturn the Home-relative path declared by this Plugin.
OwnedPath::owns
Section titled “OwnedPath::owns”pub fn owns(self, candidate: &str) -> boolReturn true when this declaration owns the supplied Home-relative path.
Source: crates/calternal-plugin/src/lib.rs:770
PluginStateError
Section titled “PluginStateError”pub enum PluginStateErrorError returned when an enablement change violates state or manifest rules.
Variants
UnknownPlugin: The requested plugin is not registered.CorePlugin: A Core plugin cannot be disabled.RequiredBy(Vec<String>): Enabled plugins require the requested plugin.UserToggleNotAllowed: This plugin does not allow per-user enablement changes.Storage: The Index could not commit the change.
Implements: Clone, Debug, PartialEq, Eq, std::fmt::Display, std::error::Error
Source: crates/calternal-plugin/src/lib.rs:996
RegistryError
Section titled “RegistryError”pub enum RegistryErrorFailures found while constructing a plugin registry.
Variants
InvalidPluginId(String): Plugin IDs must be lowercase path-safe identifiers.DuplicatePluginId(String): More than one plugin declared this ID.MissingDependency { plugin_id: String, required_id: String, }: A plugin requires an ID that is not registered.DependencyCycle(String): Plugin requirements contain a cycle.
Implements: Clone, Debug, PartialEq, Eq, std::fmt::Display, std::error::Error
Source: crates/calternal-plugin/src/lib.rs:1260
SessionActor
Section titled “SessionActor”pub enum SessionActorWho holds the session behind a request (#980).
The auth layer sets this from the stored session row. It is not derived
from scopes: an Agent container token has the same data scope as the
User’s own session, but it must not reach routes that act on the User’s
behalf at a higher level, such as starting AI turns or reading AI history.
The default is SessionActor::Unclassified so a context that the auth
layer did not classify fails closed on every route that requires
SessionActor::User.
Variants
Unclassified: Not classified by the auth layer; routes that check the actor refuse it.User: The User’s own session: browser cookie, human Installation token (CLI) or app password.Agent: An Agent turn’s container token.Ask: An Ask turn’s read-only container token.
Implements: Clone, Copy, Debug, Default, PartialEq, Eq
Source: crates/calternal-plugin/src/lib.rs:467
Traits
Section titled “Traits”AgentTurnMutationRecorder
Section titled “AgentTurnMutationRecorder”pub trait AgentTurnMutationRecorder: Send + SyncDurable writer installed by the AI plugin for the lifetime of one turn.
AgentTurnMutationRecorder::record
Section titled “AgentTurnMutationRecorder::record”fn record<'a>( &'a self, turn_id: &'a str, mutation: AgentTurnFileMutation, ) -> AgentTurnMutationFuture<'a>;Attach one Files change-feed row to its active turn.
AgentTurnMutationRecorder::record_data_file_write
Section titled “AgentTurnMutationRecorder::record_data_file_write”fn record_data_file_write<'a>( &'a self, turn_id: &'a str, owner_id: &'a str, path: &'a str, before: Option<calternal_fs::FileFingerprint>, ) -> AgentTurnMutationFuture<'a>;Attach a Markdown write made by the Notes single writer. Files supplies the stable item ID, Version and change-feed cursor for the write.
AgentTurnMutationRecorder::record_data_file_move
Section titled “AgentTurnMutationRecorder::record_data_file_move”fn record_data_file_move<'a>( &'a self, turn_id: &'a str, owner_id: &'a str, old_path: &'a str, new_path: &'a str, ) -> AgentTurnMutationFuture<'a>;Attach a Markdown move made by the Notes single writer.
Source: crates/calternal-plugin/src/lib.rs:562
JobHandler
Section titled “JobHandler”pub trait JobHandler: Send + SyncA plugin-owned asynchronous job kind.
JobHandler::kind
Section titled “JobHandler::kind”fn kind(&self) -> &'static str;Kind name stored in the queue.
JobHandler::display_name
Section titled “JobHandler::display_name”fn display_name(&self) -> &'static strHuman-readable label shown in the instance Jobs view.
JobHandler::description
Section titled “JobHandler::description”fn description(&self) -> &'static strOne-line explanation shown with the registered kind in Admin Jobs.
JobHandler::max_concurrency
Section titled “JobHandler::max_concurrency”fn max_concurrency(&self) -> usizeMaximum number of concurrent jobs of this kind. The host applies this limit in addition to any shared resource semaphore a Plugin uses.
JobHandler::run
Section titled “JobHandler::run”fn run<'a>(&'a self, context: JobContext) -> JobFuture<'a>;Run one job. Queue leases, retries, and persistence stay outside this crate.
JobHandler::run_controlled
Section titled “JobHandler::run_controlled”fn run_controlled<'a>( &'a self, context: JobContext, _control: calternal_db::JobControl, ) -> JobFuture<'a>Run one job with queue control for progress updates and safe stop checkpoints. Existing handlers remain valid and can adopt checkpoints when they have bounded units of work.
Source: crates/calternal-plugin/src/lib.rs:718
NotificationPublisher
Section titled “NotificationPublisher”pub trait NotificationPublisher: Send + SyncDurable sink installed by the Notifications Plugin during server startup.
NotificationPublisher::publish
Section titled “NotificationPublisher::publish”fn publish<'a>(&'a self, event: NotificationDraft) -> NotificationPublishFuture<'a>;Persist one event and make it available to the User’s inbox.
Source: crates/calternal-plugin/src/lib.rs:212
Plugin
Section titled “Plugin”pub trait Plugin: Send + SyncA plugin and all server-side contributions it owns.
Plugin::manifest
Section titled “Plugin::manifest”fn manifest(&self) -> PluginManifest;Return the public manifest declared by this plugin.
Plugin::owned_paths
Section titled “Plugin::owned_paths”fn owned_paths(&self) -> &'static [OwnedPath]Return Home-relative paths owned by this Plugin.
Shared views use this registry to exclude Plugin storage while leaving direct Files access unchanged (#606).
Plugin::default_user_enabled
Section titled “Plugin::default_user_enabled”fn default_user_enabled(&self) -> boolSet the initial per-User mode state when no saved choice exists.
The default preserves the historical visible-by-default behavior. A Plugin may opt out until its onboarding flow exists; persisted choices always take precedence over this fallback (DESIGN §34, #34).
Plugin::router
Section titled “Plugin::router”fn router(&self, _context: &PluginContext) -> RouterReturn routes mounted below /api/v1/<plugin-id>.
Plugin::public_router
Section titled “Plugin::public_router”fn public_router(&self, _context: &PluginContext) -> RouterReturn read-only routes outside the authenticated API prefix.
Public capability URLs (issue #431) need a stable root path and do not require a session. The Registry still checks that the owning Plugin is enabled for the Instance before it dispatches these routes.
Plugin::change_projection
Section titled “Plugin::change_projection”fn change_projection<'a>( &'a self, _principal: &'a PluginRequestContext, _record: &'a changes::Record, ) -> changes::ProjectionFuture<'a>Project one changed ID after checking current access (#668, DESIGN §58). The default fails closed until the owning adoption issue adds an adapter.
Plugin::openapi
Section titled “Plugin::openapi”fn openapi(&self) -> Option<OpenApi>Return the OpenAPI fragment contributed by this plugin.
Plugin::job_handlers
Section titled “Plugin::job_handlers”fn job_handlers(&self) -> Vec<Arc<dyn JobHandler>>Return job handlers. The registry keeps this hook decoupled from the job queue.
Plugin::search_providers
Section titled “Plugin::search_providers”fn search_providers(&self) -> Vec<Arc<dyn SearchProvider>>Return server-side search providers.
Plugin::file_type_handlers
Section titled “Plugin::file_type_handlers”fn file_type_handlers(&self) -> Vec<FileTypeHandler>Return file-type handlers for a later preview flow.
Plugin::settings_schema
Section titled “Plugin::settings_schema”fn settings_schema(&self) -> Option<Value>Return the JSON Schema for this plugin’s settings, if it has settings.
Plugin::ui_entry_points
Section titled “Plugin::ui_entry_points”fn ui_entry_points(&self) -> PluginUiEntryPointsReturn client entry points exposed by the plugin catalog.
Source: crates/calternal-plugin/src/lib.rs:845
PluginState
Section titled “PluginState”pub trait PluginState: Send + SyncState interface for instance and per-user plugin enablement.
PluginState::is_enabled
Section titled “PluginState::is_enabled”fn is_enabled( &self, manifest: &PluginManifest, default_user_enabled: bool, user_id: Option<&str>, ) -> bool;Check if a plugin is enabled for an optional user, using its declared per-User default when no persisted choice exists.
PluginState::is_instance_enabled
Section titled “PluginState::is_instance_enabled”fn is_instance_enabled(&self, manifest: &PluginManifest) -> bool;Check the instance-wide state without applying a user’s mode preference.
PluginState::is_user_enabled
Section titled “PluginState::is_user_enabled”fn is_user_enabled( &self, manifest: &PluginManifest, default_user_enabled: bool, user_id: &str, ) -> bool;Return one User’s mode state, using the Plugin’s declared default when no choice is saved.
PluginState::set_instance_enabled
Section titled “PluginState::set_instance_enabled”fn set_instance_enabled<'a>( &'a self, manifests: &'a [PluginManifest], plugin_id: &'a str, enabled: bool, cascade: bool, ) -> PluginStateFuture<'a, Vec<String>>;Apply an instance change with its dependency rules as one serialized operation. The returned IDs are the plugins whose state changed.
PluginState::set_user_enabled
Section titled “PluginState::set_user_enabled”fn set_user_enabled<'a>( &'a self, manifest: &'a PluginManifest, user_id: &'a str, enabled: bool, ) -> PluginStateFuture<'a, ()>;Set one user’s plugin state when the manifest allows it.
Source: crates/calternal-plugin/src/lib.rs:953
SearchProvider
Section titled “SearchProvider”pub trait SearchProvider: Send + SyncA search provider contributed by a plugin.
SearchProvider::search
Section titled “SearchProvider::search”fn search<'a>( &'a self, context: &'a SearchContext, query: &'a str, limit: usize, ) -> SearchFuture<'a>;Search objects visible to context and return at most limit hits.
SearchProvider::search_keyword
Section titled “SearchProvider::search_keyword”fn search_keyword<'a>( &'a self, context: &'a SearchContext, query: &'a str, limit: usize, ) -> SearchFuture<'a>Search the keyword index without waiting for semantic retrieval.
Providers without a separate semantic stage keep their normal result path. Search overrides this hook so the palette can show keyword hits first, then replace them with its fused results when semantic search completes.
Source: crates/calternal-plugin/src/lib.rs:409
Type aliases
Section titled “Type aliases”AgentTurnMutationFuture
Section titled “AgentTurnMutationFuture”pub type AgentTurnMutationFuture<'a> = Pin<Box<dyn Future<Output = Result<(), String>> + Send + 'a>>;Result type returned by the Agent mutation persistence hook.
Source: crates/calternal-plugin/src/lib.rs:558
JobFuture
Section titled “JobFuture”pub type JobFuture<'a> = Pin<Box<dyn Future<Output = Result<(), JobError>> + Send + 'a>>;A job handler future. This hook does not depend on a queue or database.
Source: crates/calternal-plugin/src/lib.rs:699
NotificationPublishFuture
Section titled “NotificationPublishFuture”pub type NotificationPublishFuture<'a> = Pin<Box<dyn Future<Output = Result<(), NotificationPublishError>> + Send + 'a>>;Future returned by one typed notification publish hook.
Source: crates/calternal-plugin/src/lib.rs:208
PluginFactory
Section titled “PluginFactory”pub type PluginFactory = fn() -> Arc<dyn Plugin>;A constructor for one compiled core plugin.
Source: crates/calternal-plugin/src/lib.rs:49
PluginStateFuture
Section titled “PluginStateFuture”pub type PluginStateFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, PluginStateError>> + Send + 'a>>;One serialized state mutation. State changes are asynchronous because the production adapter commits them to the Index before invalidating its cache.
Source: crates/calternal-plugin/src/lib.rs:949
SearchFuture
Section titled “SearchFuture”pub type SearchFuture<'a> = Pin<Box<dyn Future<Output = Vec<SearchHit>> + Send + 'a>>;A search provider future. The boxed future keeps the provider hook object-safe.
Source: crates/calternal-plugin/src/lib.rs:406
Functions
Section titled “Functions”client_stream_permit
Section titled “client_stream_permit”pub fn client_stream_permit(ip: IpAddr) -> Option<StreamPermit>Reserve one of MAX_STREAMS_PER_CLIENT_IP long-lived stream slots for
one resolved client IP.
Source: crates/calternal-plugin/src/lib.rs:315
client_stream_permit_with_limit
Section titled “client_stream_permit_with_limit”pub fn client_stream_permit_with_limit(ip: IpAddr, limit: usize) -> Option<StreamPermit>Reserve one stream slot for a resolved client IP. The server resolves
forwarded addresses before calling this function. A custom limit supports
small deterministic tests; production uses client_stream_permit.
Source: crates/calternal-plugin/src/lib.rs:309
current_agent_turn_scope
Section titled “current_agent_turn_scope”pub fn current_agent_turn_scope() -> Option<AgentTurnScope>Read the current turn scope inside a writer request.
Source: crates/calternal-plugin/src/lib.rs:664
drain_oversized_json
Section titled “drain_oversized_json”pub async fn drain_oversized_json(request: Request<Body>, next: Next) -> ResponseDrain a known oversized request before sending 413. This lets HTTP/1.1 clients that are still writing a large JSON body receive the status instead of a reset connection. The extractor retains the per-route allocation cap.
Source: crates/calternal-plugin/src/lib.rs:358
event_bus
Section titled “event_bus”pub fn event_bus() -> &'static tokio::sync::broadcast::Sender<PluginEvent>Process-wide event bus shared by compiled plugins. Lagged receivers must reconcile from the Index; events are invalidations, not durable records.
Source: crates/calternal-plugin/src/lib.rs:136
install_notification_publisher
Section titled “install_notification_publisher”pub fn install_notification_publisher( publisher: Arc<dyn NotificationPublisher>,) -> Result<(), NotificationPublisherInstallError>Install the Notifications Plugin’s durable event sink once during startup.
A process has one Index and one Notifications Plugin. Refusing replacement prevents one Plugin instance from silently stealing another’s event hook.
Source: crates/calternal-plugin/src/lib.rs:226
is_change_event
Section titled “is_change_event”pub fn is_change_event(kind: ¬ify::EventKind) -> boolWhether a data-directory watcher event can mean that a file changed. Every server-side watcher of Homes filters its events with this.
The inotify backend also reports opens and read-only closes (notify’s
Access kind). A read is not a change. Forwarding reads made every
download, thumbnail job, video playback and EXIF read look like an edit,
and each one rebuilt the Photos index of the whole library. In the search
indexer it was a loop: indexing a file reads it, the read was an event,
and the event queued the file again, so the indexer never went idle and a
steady stream of reads kept new changes waiting (#122). A close after
writing does end a write, so it still counts.
Source: crates/calternal-plugin/src/lib.rs:124
migrations
Section titled “migrations”pub fn migrations() -> MigrationSetPlugin enablement is owned by this crate, so its migration has its own namespace and never changes another crate’s migration numbers.
Source: crates/calternal-plugin/src/state.rs:193
publish_notification
Section titled “publish_notification”pub async fn publish_notification( event: NotificationDraft,) -> Result<(), NotificationPublishError>Persist one notification when the Notifications Plugin is installed.
Startup code may omit the sink in contract-only/static contexts. Producers can still complete their own durable mutation in that case.
Source: crates/calternal-plugin/src/lib.rs:243
record_current_agent_data_file_move
Section titled “record_current_agent_data_file_move”pub async fn record_current_agent_data_file_move( owner_id: &str, old_path: &str, new_path: &str,) -> Result<(), String>Record a Markdown move when the authenticated request carries an Agent turn scope. Ordinary Notes moves remain unchanged.
Source: crates/calternal-plugin/src/lib.rs:683
record_current_agent_data_file_write
Section titled “record_current_agent_data_file_write”pub async fn record_current_agent_data_file_write( owner_id: &str, path: &str, before: Option<calternal_fs::FileFingerprint>,) -> Result<(), String>Record a Markdown write when the authenticated request carries an Agent turn scope. Ordinary Notes and Task writes remain unchanged.
Source: crates/calternal-plugin/src/lib.rs:670
stream_permit
Section titled “stream_permit”pub fn stream_permit(user: &str) -> Option<StreamPermit>Reserve one stream slot for user, or None when the User already holds
MAX_STREAMS_PER_USER streams. Callers answer None with 429 before
they upgrade or start the stream.
Source: crates/calternal-plugin/src/lib.rs:302
with_agent_turn_scope
Section titled “with_agent_turn_scope”pub async fn with_agent_turn_scope<F: Future>(scope: AgentTurnScope, future: F) -> F::OutputRun an authenticated Agent request with a server-created turn scope.
Source: crates/calternal-plugin/src/lib.rs:659
Constants
Section titled “Constants”MAX_STREAMS_PER_CLIENT_IP
Section titled “MAX_STREAMS_PER_CLIENT_IP”pub const MAX_STREAMS_PER_CLIENT_IP: usizeMaximum long-lived streams from one resolved client IP.
Source: crates/calternal-plugin/src/lib.rs:264
MAX_STREAMS_PER_USER
Section titled “MAX_STREAMS_PER_USER”pub const MAX_STREAMS_PER_USER: usizeMost long-lived streams (SSE and WebSocket) that one User may hold at the same time. Each stream holds a socket and a task, and SSE streams run a query on every wake-up, so an uncapped User could starve the Instance. A browser needs a few streams per tab; 64 leaves room for many tabs and installations.
Source: crates/calternal-plugin/src/lib.rs:261
Statics
Section titled “Statics”CORE_PLUGINS
Section titled “CORE_PLUGINS”pub static CORE_PLUGINS: [PluginFactory]Compile-time registration point for core plugin factories.