Static, serializable agent definition.
An AgentSpec is the shape used both by team members loaded from disk (via
Planck.Agent.Team) and by the orchestrator's spawn_agent tool when it
creates workers at runtime. It contains only serializable fields — no
execute_fn. Tool wiring is merged in programmatically before starting the
agent.
Member-entry JSON schema
This is the format for a single entry in a team's members list:
{
"type": "builder",
"name": "Builder Joe",
"description": "Writes and edits code.",
"provider": "anthropic",
"model_id": "claude-sonnet-4-6",
"system_prompt": "You are an expert builder.",
"opts": { "temperature": 0.7 },
"tools": ["read", "write", "edit", "bash"],
"skills": ["code_review", "refactor"]
}Required fields are type, provider, model_id. Valid providers are
derived from Planck.AI.Model.providers/0.
system_prompt is either inline text or a path to a .md/.txt file
resolved relative to a caller-provided base_dir. tools and skills
are lists of names resolved against caller-provided pools at start time
(see to_start_opts/2). When skills is non-empty, their descriptions
are appended to the system prompt via Planck.Agent.Skill.system_prompt_section/1.
Construction
iex> AgentSpec.from_map(%{
...> "type" => "builder",
...> "provider" => "ollama",
...> "model_id" => "llama3.2",
...> "system_prompt" => "Build things."
...> })
{:ok, %AgentSpec{...}}
iex> AgentSpec.from_list(list_of_maps, base_dir: "/path/to/team")
[%AgentSpec{...}, ...]
Summary
Functions
Convert a list of maps (as decoded from JSON) into a list of AgentSpec structs.
Convert a single map into an AgentSpec struct.
Build an AgentSpec from a keyword list of validated fields.
Convert an AgentSpec to keyword options suitable for Planck.Agent.start_link/1.
Types
@type t() :: %Planck.Agent.AgentSpec{ base_url: String.t() | nil, compactor: String.t() | nil, description: String.t() | nil, model_id: String.t(), name: String.t(), opts: keyword(), provider: atom(), skills: [String.t()], system_prompt: String.t(), tools: [String.t()], type: String.t() }
:type— role identifier used for registry lookups and tool targeting (e.g."builder"):name— human-readable label shown to other agents vialist_team; defaults totypewhen not provided or empty:description— one-line purpose shown to other agents vialist_team:provider— LLM provider atom (e.g.:anthropic,:ollama):model_id— model identifier within the provider (e.g."claude-sonnet-4-6"):system_prompt— system prompt text sent to the model at the start of every turn:opts— provider-specific options forwarded to the LLM call (e.g.temperature:):tools— tool names to resolve from atool_pool:at start time (e.g.["read", "bash"]):skills— skill names to resolve from askill_pool:at start time; when non-empty, their descriptions are appended tosystem_promptinto_start_opts/2:base_url— base URL of the model server for local providers that run multiple instances (e.g."http://localhost:11434"for a specific Ollama server). Whennil, the provider's default URL is used.:compactor— fully-qualified module name of a sidecar compactor for this agent, e.g."MySidecar.Compactors.Builder". The module must implementcompact/2. planck_headless resolves this viaPlanck.Agent.Sidecar.compactor_for/1when materialising the agent.nilmeans the default compactor is used.
Functions
Convert a list of maps (as decoded from JSON) into a list of AgentSpec structs.
Invalid entries are skipped with a warning; the rest are returned. Accepts
base_dir: for resolving relative system_prompt file paths. Defaults to
File.cwd!().
Convert a single map into an AgentSpec struct.
Returns {:ok, spec} or {:error, reason}. system_prompt values ending in
.md or .txt are treated as file paths and read from disk relative to
base_dir.
Build an AgentSpec from a keyword list of validated fields.
name defaults to type when not provided or empty — every agent has a
human-readable label, and teams with multiple members of the same type are
forced to assign explicit names (via Team.load/1's name-uniqueness check).
Convert an AgentSpec to keyword options suitable for Planck.Agent.start_link/1.
Accepts optional overrides: tools:, tool_pool:, skill_pool:, team_id:,
session_id:, available_models:, on_compact:.
Tool resolution
When spec.tools is non-empty, tool names are resolved against tool_pool: (a list
of Tool.t() structs). Unknown names are silently ignored. Any tools passed via
tools: are appended after the resolved ones. When spec.tools is empty, tools:
is used directly.
Skill resolution
When spec.skills is non-empty, skill names are resolved against skill_pool: (a
list of Skill.t() structs). The resolved skills' descriptions are appended to
spec.system_prompt via Planck.Agent.Skill.system_prompt_section/1. Unknown
names are silently ignored. When spec.skills is empty, system_prompt passes
through unchanged.
Examples
iex> AgentSpec.to_start_opts(spec, tool_pool: [read_tool, bash_tool], team_id: "team-1")
[id: "...", type: "builder", tools: [read_tool], ...]