okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
caedaa4
main
Extensions
Extensions are basically bundles that provide capabilities to the harness such as oauth, tools, compaction strategies, ways to inject context to the agent, and more. Each extension has a name, description, a list of extensions it depends on, a list of plugins that the extension's capabiltiies fit into, and an initializer.
Extensions can be installed and yet be optional. They can also be toggable as a global default or turned on/off per session.
For a list of built in extensions, see src/albedo/harenss/extensions/
Plugins
Plugins are typed contribution points and an extension can provide several kinds:
- context: load text for the harness’s model context.
- tools: add model-callable tools, Python modules, and host RPC routes.
- managed: prepare session-specific contributions that depend on the sqlite db and observe session events.
- commands: provide commands shared by the CLI and the Python kernel callable by the model.
- compaction / folds: provide compaction strategies and stored folds (previous compactions).
- models / model provider: provide catalog data for an inference provider or bridges for oauth from providers such as Claude and Codex
- login: provide a browser-based sign-in flow, often depended on by model provider extensions.
- service: mount daemon HTTP routes under the extension’s path.
- migration: contribute schema setup or data upgrades.
On installation/startup the host calls each extension’s initializer and applies schema migrations. When a session’s enabled extensions are composed, their plugins supply the context, tools, commands, strategies, and other session-facing capabilities. Services and model-provider capabilities are used by daemon-level code rather than being ordinary per-session tools.
Activation and reload
For implementation and review rules, see extension boundaries.
Each extension activates as a complete bundle. A failed context loader, managed preparation, or capability collision removes all of that extension's contributions. Extensions that require it also become inactive. The runtime closes rejected managed resources; unrelated extensions keep working.
Saving preferences changes the desired selection. Reload applies it to the session. If application fails, the desired choice remains saved for retry. A matching Python module set keeps the current kernel and rebinds its routes; a changed set stages a replacement and restores its namespace before retiring the old kernel. Failures before shutdown retain the old kernel. Failures after shutdown clear its handle instead of claiming rollback.
Host routes accept a host.Context and request string. The context contains the store, session ID, and search providers from the loaded active composition. Global HTTP services use globally enabled extensions instead of session overrides. Search preferences rank or exclude eligible providers without enabling an inactive extension.
Managed Plugins
A managed plugin has a prepare function that receives the store (the daemon’s durable SQLite-backed store), session id, and workspace, and it returns a Managed value. That value can contribute context, instructions, tools, Python modules, routes, commands, and warnings, plus an event observer and a close callback.
The observer can receive session events such as provider calls, turn completions, compaction, and session changes. It runs inside the session actor, so it must send and return rather than block or do lengthy work. The Session capability exposed to managed extensions can make a background provider call, but that call is exclusive work and fails if another run is active or the kernel is released
Example of creating an extension
A very small existing extension is run. It contributes a tool plugin: instructions for the model, a Python module named run, and a host route named jobs.
pub fn extension () -> harness_extension . Extension { harness_extension . Extension ( "run" , "Start supervised programs from Python, without a shell." , [ "python" ], [ harness_extension . ToolPlugin ( instructions , [], [ "run" ], [ #( "jobs" , fn ( context : host . Context , request ) { route ( context . store , context . session , request ) }), ]), ], harness_extension . no_initialise , ) }
To wire this in for now, import its module and add the extension to the extensions list in harness/extensions.gleam. In the future, there'll be an easier way to load extensions in.
An example of a managed plugin
Scheudle is a builtin managed plugin. It prepares a session-specific /schedule command using that session’s store and id. It’s managed because the command needs session-specific state
pub fn extension () -> extension . Extension { extension . Extension ( "schedule" , "Durable session prompts, recurring reminders, and idle heartbeats." , [ "python" ], [ extension . ManagedPlugin ( fn ( db , session , _ ) { Ok ( extension . Managed ( .. extension . empty (), commands : [ command ( db , session )], ), ) }), ], ledger . initialise , ) }
The prepare callback here receives db (the store), session (the session id), and the workspace (unused, hence _). It returns a Managed value with the command wired to that session. The extension’s initializer sets up the schedule ledger.
1# Extensions 2Extensions are basically bundles that provide capabilities to the harness such as oauth, tools, compaction strategies, ways to inject context to the agent, and more. Each extension has a name, description, a list of extensions it depends on, a list of plugins that the extension's capabiltiies fit into, and an initializer. 3 4Extensions can be installed and yet be optional. They can also be toggable as a global default or turned on/off per session. 5 6For a list of built in extensions, see src/albedo/harenss/extensions/ 7 8# Plugins 9Plugins are typed contribution points and an extension can provide several kinds: 10- context: load text for the harness’s model context. 11- tools: add model-callable tools, Python modules, and host RPC routes. 12- managed: prepare session-specific contributions that depend on the sqlite db and observe session events. 13- commands: provide commands shared by the CLI and the Python kernel callable by the model. 14- compaction / folds: provide compaction strategies and stored folds (previous compactions). 15- models / model provider: provide catalog data for an inference provider or bridges for oauth from providers such as Claude and Codex 16- login: provide a browser-based sign-in flow, often depended on by model provider extensions. 17- service: mount daemon HTTP routes under the extension’s path. 18- migration: contribute schema setup or data upgrades. 19 20On installation/startup the host calls each extension’s initializer and applies schema migrations. When a session’s enabled extensions are composed, their plugins supply the context, tools, commands, strategies, and other session-facing capabilities. Services and model-provider capabilities are used by daemon-level code rather than being ordinary per-session tools. 21 22## Activation and reload 23 24For implementation and review rules, see [extension boundaries](../robot-docs/extensions.md#boundaries-to-preserve). 25 26Each extension activates as a complete bundle. A failed context loader, managed preparation, or capability collision removes all of that extension's contributions. Extensions that require it also become inactive. The runtime closes rejected managed resources; unrelated extensions keep working. 27 28Saving preferences changes the desired selection. Reload applies it to the session. If application fails, the desired choice remains saved for retry. A matching Python module set keeps the current kernel and rebinds its routes; a changed set stages a replacement and restores its namespace before retiring the old kernel. Failures before shutdown retain the old kernel. Failures after shutdown clear its handle instead of claiming rollback. 29 30Host routes accept a `host.Context` and request string. The context contains the store, session ID, and search providers from the loaded active composition. Global HTTP services use globally enabled extensions instead of session overrides. Search preferences rank or exclude eligible providers without enabling an inactive extension. 31 32## Managed Plugins 33A managed plugin has a prepare function that receives the store (the daemon’s durable SQLite-backed store), session id, and workspace, and it returns a `Managed` value. That value can contribute context, instructions, tools, Python modules, routes, commands, and warnings, plus an event observer and a close callback. 34 35The observer can receive session events such as provider calls, turn completions, compaction, and session changes. It runs inside the session actor, so it must send and return rather than block or do lengthy work. The Session capability exposed to managed extensions can make a background provider call, but that call is exclusive work and fails if another run is active or the kernel is released 36 37## Example of creating an extension 38A very small existing extension is run. It contributes a tool plugin: instructions for the model, a Python module named run, and a host route named jobs. 39 40``` gleam 41pub fn extension () -> harness_extension . Extension { 42harness_extension . Extension ( 43"run" , 44"Start supervised programs from Python, without a shell." , 45[ "python" ], 46[ 47harness_extension . ToolPlugin ( instructions , [], [ "run" ], [ 48#( "jobs" , fn ( context : host . Context , request ) { 49route ( context . store , context . session , request ) 50}), 51]), 52], 53harness_extension . no_initialise , 54) 55} 56``` 57 58To wire this in for now, import its module and add the extension to the extensions list in harness/extensions.gleam. In the future, there'll be an easier way to load extensions in. 59 60## An example of a managed plugin 61Scheudle is a builtin managed plugin. It prepares a session-specific /schedule command using that session’s store and id. It’s `managed` because the command needs session-specific state 62 63``` gleam 64pub fn extension () -> extension . Extension { 65extension . Extension ( 66"schedule" , 67"Durable session prompts, recurring reminders, and idle heartbeats." , 68[ "python" ], 69[ 70extension . ManagedPlugin ( fn ( db , session , _ ) { 71Ok ( 72extension . Managed ( 73.. extension . empty (), 74commands : [ command ( db , session )], 75), 76) 77}), 78], 79ledger . initialise , 80) 81} 82``` 83 84The prepare callback here receives db (the store), session (the session id), and the workspace (unused, hence _). It returns a Managed value with the command wired to that session. The extension’s initializer sets up the schedule ledger.