Skip to content

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.

[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"
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);

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.

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.

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.