Rust Backend
Use a Rust backend when a plugin needs native filesystem access, outbound HTTP without browser CORS, secret handling, local process integration, long-running work, or privileged host operations.
Frontend-only plugins are acceptable for pure UI surfaces and simple panels that only consume public SDK hooks.
Cargo Setup
Section titled “Cargo Setup”[package]name = "hf-my-plugin"version = "0.1.0"edition = "2021"
[lib]crate-type = ["cdylib"]
[dependencies]haloforge-plugin-api = "0.2.13"serde_json = "1"Minimal Backend
Section titled “Minimal Backend”use haloforge_plugin_api::*;
pub struct MyPlugin;
impl MyPlugin { pub fn new() -> Self { Self }}
impl HaloForgePlugin for MyPlugin { fn metadata(&self) -> PluginMetadata { PluginMetadata { id: "dev.example.my-plugin".into(), name: "My Plugin".into(), version: "0.1.0".into(), description: "A sample HaloForge plugin".into(), author: "Example".into(), abi_version: PLUGIN_ABI_VERSION, } }
fn on_load( &mut self, _ctx: &dyn PluginContext, ipc: &mut dyn IpcRegistrar, ) -> Result<(), PluginError> { ipc.register("ping", Box::new(|args, _ctx| { Ok(serde_json::json!({ "ok": true, "echo": args })) }))?; Ok(()) }}
declare_plugin!(MyPlugin, MyPlugin::new);Command Naming
Section titled “Command Naming”Register short command names in Rust:
ipc.register("ping", Box::new(|args, _ctx| { Ok(serde_json::json!({ "ok": true, "echo": args }))}))?;Then call them from the frontend with:
await invokePlugin("ping", { value: 1 });Do not construct the final wire name manually. The SDK prefixes the command for the current plugin.
External HTTP
Section titled “External HTTP”When a plugin calls a user-configured API endpoint, prefer the Rust backend if:
- the browser would hit CORS
- an API key should not sit in frontend component state longer than needed
- request signing is required
- retries, timeouts, and response normalization matter
Declare network_http or a scoped network_http_domain permission when needed.
Logging
Section titled “Logging”Rust backends should use the PluginContext logger for operational diagnostics:
ctx.log(LogLevel::Info, "image request started request_id=hfis-123 model=gpt-image-2.0 size=1024x1024");ctx.log(LogLevel::Error, "image request failed request_id=hfis-123 status=502 elapsed_ms=1842");These records are written to the HaloForge app log at ~/.haloforge/logs/haloforge.log.YYYY-MM-DD. Use Info for lifecycle/start/success records, Warn for recoverable degradation, and Error for failed user actions. Debug and Trace are available when the app is launched with a matching RUST_LOG.
Do not log API keys, bearer tokens, full prompts, file contents, raw image bytes, or base64 payloads. Prefer request IDs, endpoint kind, model, size, status, elapsed time, and output counts.