SuperPi.Harness behaviour (super_pi v0.1.0)

Copy Markdown View Source

Pluggable agent harness specification and registry (REQ-HARNESS-01).

A harness is a named persona: a plugin set plus pi.agent defaults. Three showcase harnesses and one safety harness ship with Super-Pi-BEAM:

IdModuleDistinct because
super-pi-codeSuperPi.Harness.CodeMutates a repository, reversibly (checkpoints, optional auto-commit).
super-pi-assistantSuperPi.Harness.AssistantWorks with a human present, reaches the web and third-party services over MCP, has no filesystem.
super-pi-librarianSuperPi.Harness.LibrarianRuns with no human present (scheduler) and remembers across sessions (memory).
super-pi-plannerSuperPi.Harness.PlannerCannot write.

The ids of earlier releases (super-pi-agent, -fast, -workspace, -auto, -interactive) still resolve, to Code or Assistant, but list/0 no longer shows them.

Declaring a harness

defmodule MyApp.Harness.Triage do
  alias SuperPi.Plugins

  use SuperPi.Harness,
    id: "my-triage",
    name: "Triage",
    description: "Sorts incoming tickets",
    effort: "low",
    mode: "accept-edits",
    max_mode: "accept-edits",
    workspace: %{"kind" => "none"},
    tools: {:only, ["todo"]},
    prompt: "You triage tickets.",
    plugins: [Plugins.Todo, Plugins.Permissions]
end

The macro defines id/0, name/0, description/0, capabilities/0, extensions/1 and agent_defaults/1, all overridable. Register the module with config :super_pi, extra_harnesses: [MyApp.Harness.Triage].

OptionMeaning
:id, :name, :descriptionRequired. Metadata for model listings and discovery.
:pluginsPlugin specs (Module or {Module, opts}). Order matters for before_compact: the first plugin that does not answer :default ends the chain.
:effort, :mode, :modelDefaults for pi.agent. See SuperPi.Harness.Defaults.
:max_modeHighest executionMode the harness allows ("plan", "accept-edits" or "auto"). Permissions enforces it. Defaults to :mode.
:workspace:local (default), :knowledge_paths or a "workspace" map such as %{"kind" => "none"}.
:tools:all, {:only, names} or {:except, names}.
:promptCore system prompt.

Summary

Callbacks

Default document configuration for the conversation agent

Machine-readable summary of the harness: id, plugins, tool loadout, workspace kind and modes. Interfaces that must describe a harness to a client (ACP initialize, workspace.metadata, GET /v1/models) call it through capabilities/1, which tolerates harnesses without it.

Short description for model listings and discovery

List of SuperPi.Extension modules active in this harness

Unique string identifier for the harness (e.g., 'super-pi-code')

Human-readable name

Functions

Capability summary of harness. A harness without capabilities/0 gets one built from its metadata, so external :extra_harnesses modules keep working.

Default harness for entry points that receive no harness name (Gateway, RPC, MCP, CLI).

Strict form of resolve/1. An unknown name is an error, not a silent default.

Returns true if the given model name or ID corresponds to a registered harness.

Lists the harness modules to show to users: the four built-in ones and any configured via :extra_harnesses. Resolution (resolve/1, harness?/1) is wider than this list: it also accepts the ids of earlier releases.

Extensions of harness for a caller that is not the local user (Gateway, RPC, MCP, subagents).

Resolves a model name, alias, module, or harness ID to its corresponding Harness module. Falls back to default/0 if unknown.

Callbacks

agent_defaults(opts)

@callback agent_defaults(opts :: keyword()) :: map()

Default document configuration for the conversation agent

capabilities()

(optional)
@callback capabilities() :: map()

Machine-readable summary of the harness: id, plugins, tool loadout, workspace kind and modes. Interfaces that must describe a harness to a client (ACP initialize, workspace.metadata, GET /v1/models) call it through capabilities/1, which tolerates harnesses without it.

description()

@callback description() :: String.t()

Short description for model listings and discovery

extensions(opts)

@callback extensions(opts :: keyword()) :: [module() | {module(), term()}]

List of SuperPi.Extension modules active in this harness

id()

@callback id() :: String.t()

Unique string identifier for the harness (e.g., 'super-pi-code')

name()

@callback name() :: String.t()

Human-readable name

Functions

capabilities(harness)

@spec capabilities(module()) :: map()

Capability summary of harness. A harness without capabilities/0 gets one built from its metadata, so external :extra_harnesses modules keep working.

default()

@spec default() :: module()

Default harness for entry points that receive no harness name (Gateway, RPC, MCP, CLI).

Configure it with config :super_pi, default_harness: "<harness id>". The default is super-pi-code, which carries the permission and safety plugins.

fetch(name)

@spec fetch(String.t() | module()) ::
  {:ok, module()} | {:error, {:unknown_harness, term()}}

Strict form of resolve/1. An unknown name is an error, not a silent default.

A deployment that wants a fallback can set config :super_pi, fallback_harness: "<id>".

harness?(module)

Returns true if the given model name or ID corresponds to a registered harness.

list()

Lists the harness modules to show to users: the four built-in ones and any configured via :extra_harnesses. Resolution (resolve/1, harness?/1) is wider than this list: it also accepts the ids of earlier releases.

remote_extensions(harness)

@spec remote_extensions(module()) :: [module() | {module(), keyword()}]

Extensions of harness for a caller that is not the local user (Gateway, RPC, MCP, subagents).

InlineBash runs !{...} shell commands from user input with no permission check, so a remote caller must not get it. No built-in harness carries it, but a harness from :extra_harnesses may. Use this instead of harness.extensions([]) on those paths.

resolve(module)

Resolves a model name, alias, module, or harness ID to its corresponding Harness module. Falls back to default/0 if unknown.