dsl

package
v1.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package dsl provides the loom-mcp design-time DSL for declaring agents, toolsets, MCP servers, registries, and run policies. These functions augment Goa's standard service DSL and drive the loom-mcp code generators; they are not used at runtime.

Overview

The DSL enables design-first development of LLM-based agents. You declare your agent's capabilities, tools, and policies in Go code, then run `loom gen` to produce type-safe packages including:

  • Agent packages with workflow definitions and planner activities
  • Tool codecs, JSON schemas, and registry entries
  • MCP server adapters and client helpers
  • Agent-as-tool composition helpers

Import the DSL alongside Goa's standard DSL:

import (
    . "github.com/CaliLuke/loom/dsl"
    . "github.com/CaliLuke/loom-mcp/dsl"
)

Mental Model

Think of the DSL as declaring intent across three domains:

**Agents** define LLM-powered planners that orchestrate tool usage. Each agent belongs to a Goa service and declares which toolsets it consumes (Use) and exports (Export) for other agents.

**Toolsets** group related tools owned by services. Tools have typed schemas (Args/Return) and can be bound to service methods (BindTo) or implemented via custom executors. Toolsets can be sourced from local definitions, MCP servers, or remote registries.

**Policies** constrain agent behavior at runtime: caps on tool calls, time budgets, history management, and prompt caching. These policies become configuration that the runtime enforces.

DSL Structure

The DSL functions must be called in the appropriate context:

API("name", func() {})           // Top-level API definition (Goa)
DisableAgentDocs()               // Inside API - disable quickstart doc generation

var MyTools = Toolset("...", func() {...})  // Top-level toolset definition
var MCPTools = Toolset(FromMCP(...))        // MCP-backed toolset
var RegTools = Toolset(FromRegistry(...))   // Registry-backed toolset
var MyRegistry = Registry("...", func() {...})  // Registry definition

Service("name", func() {         // Goa service definition
    MCP("name", "version")       // Enable MCP for this service

    Agent("name", "desc", func() {   // Inside Service
        Use(MyTools)                 // Reference toolsets
        Export("tools", func() {...}) // Export toolsets
        RunPolicy(func() {           // Inside Agent
            DefaultCaps(...)         // Inside RunPolicy
            TimeBudget("5m")
            History(func() {...})
        })
    })

    Method("search", func() {    // Goa method definition
        Tool("search", "...")    // Mark as MCP tool (requires MCP enabled)
        Resource(...)            // Mark as MCP resource
    })
})

Key Functions by Category

Agent Functions:

  • Agent declares an LLM agent within a service
  • Use declares toolset consumption
  • Export declares toolset export for agent-as-tool
  • Workflow defines a deterministic workflow planner
  • DisableAgentDocs opts out of AGENTS_QUICKSTART.md generation
  • Passthrough forwards exported tools to service methods
  • AgentToolset references an exported toolset by coordinates
  • UseAgentToolset references and consumes an exported agent toolset

Workflow Functions:

  • Step adds a deterministic tool-call node
  • FinalMessage sets the completion message
  • Parallel marks enclosed steps as concurrently ready
  • Join declares a dependency barrier
  • RequestInput declares a schema-typed human input node
  • Loop declares a bounded repeated tool node
  • MaxIterations caps loop iterations
  • UntilJSONPath stops a loop when a JSONPath value matches
  • Branch declares deterministic branch selection
  • Case adds a branch case
  • BranchDefault adds the fallback branch target

Toolset Functions:

Tool Functions:

  • Tool declares a callable tool
  • Args defines input parameter schema
  • Return defines output result schema
  • ServerData defines typed server-only data emitted alongside results
  • FromMethodResultField sources server data from a bound method result field
  • Audience configures the server-data audience
  • AudienceTimeline marks server data for timeline/UI rendering
  • AudienceInternal marks server data for internal composition only
  • AudienceEvidence marks server data as provenance evidence
  • BindTo binds a tool to a service method
  • Inject marks fields as server-injected (hidden from LLM)
  • CallHintTemplate configures call display hint template
  • ResultHintTemplate configures result display hint template
  • BoundedResult marks result as a bounded view over larger data
  • Cursor declares which payload field carries a paging cursor (optional)
  • NextCursor declares which result field carries the next-page cursor (optional)
  • ResultReminder configures a static post-result system reminder
  • TerminalRun completes the run immediately after tool execution
  • Confirmation declares that a tool must be confirmed out-of-band before execution
  • PromptTemplate configures the confirmation prompt template
  • DeniedResultTemplate configures the result returned when confirmation is denied
  • Expose declares generated tool surfaces
  • MCPPlacement places a projected toolset tool in an MCP server
  • Idempotent marks an MCP method as safe to retry

Policy Functions:

Timing Functions (inside RunPolicy):

  • Timing groups timing configuration
  • Budget sets total wall-clock budget
  • Plan sets planner activity timeout
  • Tools sets default tool activity timeout

History Functions (inside History):

Cache Functions (inside Cache):

  • AfterSystem places cache checkpoint after system messages
  • AfterTools places cache checkpoint after tool definitions

MCP Functions:

Registry Functions:

Generated Artifacts

For each service with agents, `loom gen` produces:

  • gen/<service>/agents/<agent>/ - Agent package with workflow and activities
  • gen/<service>/agents/<agent>/specs/ - Tool specs, codecs, and JSON schemas
  • gen/<service>/agents/<agent>/specs/tool_schemas.json - Backend-agnostic tool catalog
  • gen/<service>/agents/<agent>/agenttools/ - Helpers for exported tools
  • AGENTS_QUICKSTART.md - Contextual guide (unless disabled)

For MCP-enabled services:

  • gen/mcp_<service>/ - MCP server adapter and protocol helpers
  • gen/mcp_<service>/client/ - Generated MCP client wrappers

Best Practices

Design first: Put all agent and tool schemas in the DSL. Add examples and validations to field definitions. Let codegen own schemas and codecs.

Use strong types: Define reusable Goa types (Type, ResultType) for complex tool payloads instead of inline anonymous schemas.

Keep descriptions concise: Tool descriptions are shown to LLMs. Write clear, actionable summaries that help the model choose the right tool.

Leverage BindTo: For service-backed tools, use BindTo to get generated transforms and keep tool schemas decoupled from method signatures.

Mark bounded results: Tools returning potentially large data should use BoundedResult() so the runtime can track truncation metadata. Bounded tools keep their semantic result shape domain-specific and return canonical bounds through planner.ToolResult.Bounds.

For complete documentation and examples, see docs/dsl.md in the repository.

Index

Constants

View Source
const (
	// AgentRuntime exposes a toolset tool to agent runtime registration.
	AgentRuntime = agentsexpr.ToolSurfaceAgentRuntime
	// MCPSurface exposes a method-backed toolset tool through a generated MCP adapter.
	MCPSurface = agentsexpr.ToolSurfaceMCP
)
View Source
const (
	// SkillPreloadNone leaves skill instructions unloaded until requested.
	SkillPreloadNone = agentsexpr.SkillPreloadNone
	// SkillPreloadOnStart preloads SKILL.md when the generated registration is built.
	SkillPreloadOnStart = agentsexpr.SkillPreloadOnStart
	// SkillReloadNever reuses loaded content until the registration is rebuilt.
	SkillReloadNever = agentsexpr.SkillReloadNever
	// SkillReloadPerCall reloads skill files for each load call.
	SkillReloadPerCall = agentsexpr.SkillReloadPerCall
)
View Source
const IconThemeDark = exprmcp.IconThemeDark

IconThemeDark marks an icon as designed for dark backgrounds.

View Source
const IconThemeLight = exprmcp.IconThemeLight

IconThemeLight marks an icon as designed for light backgrounds.

View Source
const ToolSearchExactMatchBoost = exprmcp.ToolSearchExactMatchBoost

ToolSearchExactMatchBoost ranks exact matches highly but keeps weaker matches eligible.

View Source
const ToolSearchExactMatchNarrow = exprmcp.ToolSearchExactMatchNarrow

ToolSearchExactMatchNarrow suppresses weaker matches when a query exactly matches a generated tool name or title.

View Source
const ToolSearchExactMatchOff = exprmcp.ToolSearchExactMatchOff

ToolSearchExactMatchOff disables exact-match special handling.

Variables

This section is empty.

Functions

func APIVersion

func APIVersion(version string)

APIVersion sets the registry API version. This is used as a path segment in registry API calls (e.g., "v1", "2024-11-05").

APIVersion must appear in a Registry expression.

If not specified, defaults to "v1".

Example:

Registry("corp", func() {
    URL("https://registry.corp.internal")
    APIVersion("v1")
})

func AfterSystem

func AfterSystem()

AfterSystem configures the cache policy to place a checkpoint after all system messages. Providers that support prompt caching interpret this as a cache boundary immediately following the system preamble.

AfterSystem must appear inside a Cache expression.

func AfterTools

func AfterTools()

AfterTools configures the cache policy to place a checkpoint after tool definitions. Providers that support tool-level cache checkpoints interpret this as a cache boundary immediately following the tool configuration section.

AfterTools must appear inside a Cache expression.

func Agent

func Agent(name, description string, dsl func()) *expragents.AgentExpr

Agent defines an LLM-based agent associated with the current service. A service may provide one or more agents. An agent consists of a system prompt, optional toolset dependencies, and a run policy. Agents can export toolsets for consumption by other agents or services.

Agent must appear in a Service expression.

Agent takes three arguments: - name: the name of the agent - description: a description of the agent - dsl: a function that defines the agent's system prompt, tools, and run policy

The dsl function can use the following helpers: - Use / Export: declare the toolsets the agent consumes or exposes. - RunPolicy: defines the run policy for the agent.

Example:

var DataIngestToolset = Toolset("data-ingest", func() {
	Tool("csv-uploader", func() {
		Input(func() { /* CSV file fields */ })
		Output(func() { /* Validation result */ })
	})
})

Agent("docs-agent", "Agent for managing documentation workflows", func() {
	Use("summarization-tools", func() {
		Tool("document-summarizer", "Summarize documents", func() {
			Args(func() { /* Document fields */ })
			Return(func() { /* Summary fields */ })
		})
	})
	Use(DataIngestToolset)
	Export("text-processing-suite", func() {
		Tool("doc-abstractor", "Create document abstracts", func() {
			Args(func() { /* Document fields */ })
			Return(func() { /* Summary fields */ })
		})
	})
	RunPolicy(func() {
		DefaultCaps(MaxToolCalls(5), MaxConsecutiveFailedToolCalls(2))
		TimeBudget("30s")
	})
})

func AgentToolset

func AgentToolset(service, agent, toolset string) *agentsexpr.ToolsetExpr

AgentToolset references a toolset exported by another agent identified by service and agent names. Use inside an Agent's Uses block to explicitly depend on an exported toolset when inference is not possible or ambiguous.

When to use AgentToolset vs Toolset:

  • Prefer Toolset(X) when you already have an expression handle (e.g., a top-level Toolset variable or an agent's exported Toolset). loom-mcp will infer a RemoteAgent provider automatically when exactly one agent in a different service Exports a toolset with the same name.
  • Use AgentToolset(service, agent, toolset) when you:
  • Do not have an expression handle to the exported toolset, or
  • Have ambiguity (multiple agents export a toolset with the same name), or
  • Want to be explicit in the design for clarity.

AgentToolset(service, agent, toolset)

  • service: Goa service name that owns the exporting agent
  • agent: Agent name in that service
  • toolset: Exported toolset name in that agent

The referenced toolset is resolved from the design, and a local reference is recorded with its Origin set to the defining toolset. Provider information is inferred during validation and will classify this as a RemoteAgent provider when the owner service differs from the consumer service.

func Args

func Args(val any, args ...any)

Args defines the input parameter schema for a tool. Use Args inside a Tool DSL to specify what arguments the tool accepts when invoked by an agent or LLM.

Args follows the same patterns as Goa's Payload function for methods. It accepts:

  • A function to define an inline object schema with Attribute() calls
  • A Goa user type (Type, ResultType, etc.) to reuse existing type definitions
  • A primitive type (String, Int, etc.) for simple single-value inputs

When using a function to define the schema inline, you can use:

  • Attribute(name, type, description) to define each parameter
  • Required(...) to mark parameters as required
  • All Goa attribute DSL functions (MinLength, Maximum, Pattern, etc.)

Example (inline schema):

Tool("search", "Search documents", func() {
    Args(func() {
        Attribute("query", String, "Search query text")
        Attribute("limit", Int, "Maximum number of results")
        Attribute("filters", MapOf(String, String), "Search filters")
        Required("query")
    })
    Return(func() { ... })
})

Example (reuse existing type):

var SearchParams = Type("SearchParams", func() {
    Attribute("query", String)
    Attribute("limit", Int)
    Required("query")
})

Tool("search", "Search documents", func() {
    Args(SearchParams)
    Return(func() { ... })
})

Example (primitive type for simple tools):

Tool("echo", "Echo a message", func() {
    Args(String)  // Single string parameter
    Return(String)
})

If Args is not called, the tool accepts no parameters (empty/null payload).

func Audience

func Audience(value ServerDataAudience)

Audience declares who this server-data payload is intended for.

Audience is used by downstream consumers (timeline projection, UI renderers, persistence sinks) to route server-data without relying on kind naming conventions.

Allowed values are:

  • "timeline": persisted and eligible for UI rendering and transcript export
  • "internal": tool-composition attachment; not persisted or rendered
  • "evidence": provenance references; persisted separately from timeline cards

func AudienceEvidence

func AudienceEvidence()

AudienceEvidence declares that the current server-data payload carries provenance references and should be persisted separately from timeline cards.

func AudienceInternal

func AudienceInternal()

AudienceInternal declares that the current server-data payload is intended only for downstream tool composition.

func AudienceTimeline

func AudienceTimeline()

AudienceTimeline declares that the current server-data payload is intended for persistence and UI rendering in the session timeline.

func BindTo

func BindTo(args ...string)

BindTo associates a tool with a Goa service method implementation. Use BindTo inside a Tool DSL to specify which service method executes the tool when invoked. This enables tools to reuse existing service logic and separates tool schema definitions from implementation.

BindTo accepts one or two arguments:

  • BindTo(methodName) - binds to a method in the agent's service
  • BindTo(serviceName, methodName) - binds to a method in a different service

The method name should match the Goa method name (case-insensitive). When using two arguments, the service name should match the Goa service name.

When a tool is bound to a method:

  • The tool's Args schema can differ from the method's Payload
  • The tool's Return schema can differ from the method's Result
  • Generated adapters will transform between tool and method types
  • Method payload/result validation still applies

Example (bind to method in same service):

Service("docs", func() {
	Method("search_documents", func() {
		Payload(func() { ... })
		Result(func() { ... })
	})
	Agent("assistant", "Helper", func() {
		Use("doc-tools", func() {
			Tool("search", "Search documents", func() {
				Args(func() { ... })  // Can differ from method payload
				Return(func() { ... }) // Can differ from method result
				BindTo("search_documents")
			})
		})
	})
})

Example (bind to method in different service):

Tool("notify", "Send notification", func() {
    Args(func() {
        Attribute("message", String)
    })
    BindTo("notifications", "send")  // notifications.send method
})

BindTo is optional. Tools without BindTo are external tools that must be implemented through custom executors or MCP callers.

func BoundedResult

func BoundedResult(fns ...func())

BoundedResult marks the current tool's result as a bounded view over a potentially larger data set. Bounded tools must return truncation metadata in planner.ToolResult.Bounds so runtimes can guide planners and users when results are partial. The semantic result shape remains fully domain-specific; BoundedResult does not add or validate top-level result fields. Instead it declares an explicit out-of-band bounds contract that codegen, runtimes, and method-backed executors can honor consistently.

BoundedResult may optionally include a DSL function to configure boundedness details. For example, cursor-based pagination fields can be declared via Cursor and NextCursor inside the optional DSL block:

Tool("search", "Search docs", func() {
    Args(SearchArgs)
    Return(SearchResult)
    BoundedResult(func() {
        Cursor("cursor")
        NextCursor("next_cursor")
    })
})

Cursor-based pagination contract:

  • Cursor values are opaque.
  • When paging, callers must keep all other parameters unchanged and only set the payload cursor field to the value returned in bounds as the next-page cursor.

BoundedResult must appear in a Tool expression.

func Branch added in v1.2.2

func Branch(name string, fromStep string, opts ...BranchOption)

Branch declares a deterministic branch selector.

func Budget

func Budget(duration string)

Budget sets the total wall-clock budget for an agent run. The runtime will cancel the run if execution exceeds this duration. Budget is equivalent to TimeBudget and can be used either inside Timing or directly inside RunPolicy.

Budget must appear inside a RunPolicy or Timing expression.

Budget takes a single argument which is a Go duration string. Valid formats include combinations of hours, minutes, seconds, and milliseconds:

  • "30s" — 30 seconds
  • "5m" — 5 minutes
  • "2h30m" — 2 hours 30 minutes
  • "1m30s" — 1 minute 30 seconds

Choose budgets that match your downstream SLAs. Consider network latency, model response times, and the complexity of tool operations.

Example:

RunPolicy(func() {
    Timing(func() {
        Budget("10m")
    })
})

func Cache

func Cache(fn func())

Cache defines the prompt caching policy for the current agent. It configures where the runtime should place cache checkpoints relative to system prompts and tool definitions for providers that support caching.

Cache must appear inside a RunPolicy expression.

Example:

RunPolicy(func() {
    Cache(func() {
        AfterSystem()
        AfterTools()
    })
})

func CacheTTL

func CacheTTL(duration string)

CacheTTL sets the local cache duration for registry data.

CacheTTL must appear in a Registry expression.

CacheTTL takes a duration string (e.g., "1h", "24h", "30m").

Example:

Registry("corp", func() {
    URL("https://registry.corp.internal")
    CacheTTL("1h")
})

func CallHintTemplate

func CallHintTemplate(s string)

CallHintTemplate configures a display template for tool invocations. The template is rendered with the tool's payload to produce a concise hint shown during execution. Templates are compiled with missingkey=error.

CallHintTemplate must appear in a Tool expression.

CallHintTemplate takes a single string argument which is the Go template text. Keep templates concise (≤ 140 characters recommended).

Example:

Tool("search", "Search documents", func() {
    Args(func() {
        Attribute("query", String)
        Attribute("limit", Int)
    })
    CallHintTemplate("Searching for: {{ .Query }} (limit: {{ .Limit }})")
})

func CompressAtMaxInputTokens added in v1.2.0

func CompressAtMaxInputTokens(n int)

CompressAtMaxInputTokens configures compression to run when the provider-visible transcript exceeds n exact input tokens.

CompressAtMaxInputTokens must appear inside a History expression.

func CompressAtTurns added in v1.2.0

func CompressAtTurns(n int)

CompressAtTurns configures compression to run once at least n logical turns have accumulated. It is optional when CompressAtMaxInputTokens is set.

CompressAtTurns must appear inside a History expression.

func Confirmation

func Confirmation(dsl func())

Confirmation declares that the current tool always requires explicit out-of-band operator confirmation before execution.

Confirmation must appear inside a Tool DSL in a Toolset.

The runtime enforces confirmation using the ask_question-style protocol: a confirmation tool is invoked out-of-band via AwaitExternalTools, and the tool is executed only after the user approves it.

func Cursor

func Cursor(field string)

Cursor declares which optional String field on the tool payload carries the cursor for cursor-based pagination. Cursor must be used inside BoundedResult.

func DefaultCaps

func DefaultCaps(opts ...CapsOption)

DefaultCaps configures resource limits for agent execution. Use DefaultCaps to control how many tools the agent can invoke and how many consecutive failures are tolerated before stopping execution.

DefaultCaps must appear in a RunPolicy expression.

DefaultCaps takes zero or more CapsOption arguments (created via MaxToolCalls and MaxConsecutiveFailedToolCalls).

Example:

RunPolicy(func() {
    DefaultCaps(
        MaxToolCalls(20),
        MaxConsecutiveFailedToolCalls(3),
    )
})

func DeniedResultTemplate

func DeniedResultTemplate(tmpl string)

DeniedResultTemplate sets the JSON template used to construct a schema-compliant tool result when the user denies confirmation. The template is executed with the tool payload value and must render valid JSON.

func DisableAgentDocs

func DisableAgentDocs()

DisableAgentDocs disables generation of the AGENTS_QUICKSTART.md quickstart guide.

Call DisableAgentDocs() inside your API design to opt-out of generating the contextual agent quickstart README at the module root. This affects only the documentation artifact; all other generated code is unaffected.

Example:

var _ = API("assistant", func() {
    // ...
    DisableAgentDocs()
})

func DynamicPrompt

func DynamicPrompt(name, description string, opts ...func(*exprmcp.DynamicPromptExpr))

DynamicPrompt marks the current method as a dynamic prompt generator. The method's payload defines parameters that customize the generated prompt, and the result contains the generated message sequence.

DynamicPrompt must appear in a Method expression within a service that has MCP enabled.

DynamicPrompt takes two arguments:

  • name: the prompt identifier
  • description: human-readable prompt description

Example:

Method("code_review", func() {
    Payload(func() {
        Attribute("language", String)
        Attribute("code", String)
    })
    Result(ArrayOf(Message))
    DynamicPrompt("code_review", "Generate code review prompt")
})

func DynamicPromptIcons added in v1.0.6

func DynamicPromptIcons(icons ...*exprmcp.IconExpr) func(*exprmcp.DynamicPromptExpr)

DynamicPromptIcons attaches icon metadata to a dynamic MCP prompt.

func Exclude

func Exclude(patterns ...string)

Exclude specifies glob patterns for namespaces to skip from a federated registry source. Exclude patterns are applied after Include patterns.

Exclude must appear in a Federation expression.

Exclude takes a variadic list of glob patterns.

Example:

Federation(func() {
    Include("*")
    Exclude("experimental/*", "deprecated/*")
})

func Export

func Export(value any, fn ...func()) *expragents.ToolsetExpr

Export declares that the current agent or service exports the specified toolset for other agents to consume. Providers typically declare reusable toolsets at the top level via Toolset or MCPToolset, then reference them from agents or services with Export.

func Expose added in v1.2.2

func Expose(surfaces ...ToolSurface) func(*mcpexpr.ToolExpr)

Expose declares the generated surfaces for the current toolset tool or returns a method-level MCP tool option.

func Federation

func Federation(fn func())

Federation configures external registry import settings. Use Federation inside a Registry declaration to specify which namespaces to import from a federated source.

Federation must appear in a Registry expression.

Inside the Federation DSL function, use:

  • Include: specifies glob patterns for namespaces to import
  • Exclude: specifies glob patterns for namespaces to skip

Example:

Registry("anthropic", func() {
    URL("https://registry.anthropic.com/v1")
    Federation(func() {
        Include("web-search", "code-execution")
        Exclude("experimental/*")
    })
})

func FinalMessage added in v1.2.2

func FinalMessage(message string)

FinalMessage sets the assistant message emitted after all workflow steps complete.

func FromArtifacts added in v1.2.2

func FromArtifacts(opts ...ArtifactProviderOption) *agentsexpr.ProviderExpr

FromArtifacts configures a toolset to expose persisted run artifacts as model-facing tools.

func FromMCP

func FromMCP(service, toolset string) *agentsexpr.ProviderExpr

FromMCP configures a toolset to be backed by an MCP server. Use FromMCP as a provider option when declaring a Toolset.

FromMCP takes:

  • service: Goa service name that owns the MCP server
  • toolset: MCP server name (also used as the toolset name if not specified)

Example:

var MCPTools = Toolset(FromMCP("assistant-service", "assistant-mcp"))

Or with an explicit name:

var MCPTools = Toolset("my-tools", FromMCP("assistant-service", "assistant-mcp"))

func FromMemory added in v1.2.2

func FromMemory(opts ...MemoryProviderOption) *agentsexpr.ProviderExpr

FromMemory configures a toolset to expose bounded memory lookup tools.

func FromMethodResultField

func FromMethodResultField(name string)

FromMethodResultField declares that the server-data payload is sourced from the bound method result field.

func FromRegistry

func FromRegistry(registry *agentsexpr.RegistryExpr, toolset string) *agentsexpr.ProviderExpr

FromRegistry configures a toolset to be sourced from a registry. Use FromRegistry as a provider option when declaring a Toolset.

FromRegistry takes:

  • registry: the RegistryExpr returned by Registry()
  • toolset: name of the toolset in the registry (also used as the toolset name if not specified)

Example:

var CorpRegistry = Registry("corp", func() {
    URL("https://registry.corp.internal")
})

var RegistryTools = Toolset(FromRegistry(CorpRegistry, "data-tools"))

Or with an explicit name:

var RegistryTools = Toolset("my-tools", FromRegistry(CorpRegistry, "data-tools"))

For version pinning, use the Version DSL inside the Toolset:

var PinnedTools = Toolset(FromRegistry(CorpRegistry, "data-tools"), func() {
    Version("1.2.3")
})

func FromSkills added in v1.2.2

func FromSkills(args ...any) *agentsexpr.ProviderExpr

FromSkills configures a toolset to expose local agent skills as model-facing tools. Each root must contain child skill directories with SKILL.md files.

Example:

var Skills = Toolset(FromSkills(".agents/skills"))

Or with an explicit name:

var AssistantSkills = Toolset("assistant.skills", FromSkills(".agents/skills", SkillPreload(SkillPreloadOnStart)))

func History

func History(fn func())

History defines how the agent runtime manages conversation history before each planner invocation. It can either:

  • KeepRecentTurns(N) to retain only the last N turns, or
  • CompressAt... plus KeepMax... to summarize older turns while preserving an exact recent tail.

CompressAtMaxInputTokens and CompressAtTurns decide when summarization runs, while KeepMaxInputTokens and KeepMaxTurns decide which newest complete turns stay exact after summarization.

At most one history policy may be configured per agent.

History must appear inside a RunPolicy expression.

Example:

RunPolicy(func() {
    History(func() {
        KeepRecentTurns(20)
    })
})

func Icon added in v1.0.6

func Icon(src string, opts ...IconOption) *exprmcp.IconExpr

Icon builds MCP icon metadata for implementations, tools, resources, and prompts.

func Idempotent

func Idempotent()

Idempotent marks a tool as idempotent within a run transcript.

When set, orchestration layers may treat repeated tool calls with identical arguments as redundant and avoid executing them once a successful result already exists in the transcript.

Use Idempotent only for tools whose result is a pure function of their arguments *for the lifetime of a run transcript*. If a tool answers questions about changing state (for example, "current mode") but does not accept a time or version parameter, it is not transcript-idempotent and should not be tagged.

Default: tools are not idempotent across a transcript unless explicitly tagged.

func Include

func Include(patterns ...string)

Include specifies glob patterns for namespaces to import from a federated registry source. If no Include patterns are specified, all namespaces are included by default.

Include must appear in a Federation expression.

Include takes a variadic list of glob patterns.

Example:

Federation(func() {
    Include("web-search", "code-execution", "data-*")
})

func Inject

func Inject(names ...string)

Inject marks specific payload fields as "injected" (server-side infrastructure). Injected fields are:

  1. Hidden from the LLM (excluded from the JSON schema).
  2. Exposed in the generated struct with a Setter method.
  3. Intended to be populated by runtime hooks (ToolInterceptor).

Example:

Tool("get_data", func() {
    BindTo("data_service", "get")
    // "session_id" is required by the service but hidden from the LLM
    Inject("session_id")
})

func Interceptors added in v1.2.2

func Interceptors(ids ...string)

Interceptors declares application-owned interceptor IDs for this agent.

Interceptors must appear in a RunPolicy expression.

func InterruptsAllowed

func InterruptsAllowed(allowed bool)

InterruptsAllowed configures whether user interruptions are permitted during agent execution. When enabled, users can interrupt running agents to provide guidance or stop execution.

InterruptsAllowed must appear in a RunPolicy expression.

InterruptsAllowed takes a single boolean argument.

Example:

RunPolicy(func() {
    InterruptsAllowed(true)
})

func Join added in v1.2.2

func Join(name string, deps ...string)

Join declares a dependency barrier in a workflow graph.

func KeepMaxInputTokens added in v1.2.0

func KeepMaxInputTokens(n int)

KeepMaxInputTokens keeps the newest whole logical turns whose exact transcript cost fits within n input tokens after compression.

KeepMaxInputTokens must appear inside a History expression with a compression trigger.

func KeepMaxTurns added in v1.2.0

func KeepMaxTurns(n int)

KeepMaxTurns caps the exact retention tail to at most n newest logical turns after compression.

KeepMaxTurns must appear inside a History expression with a compression trigger.

func KeepRecentTurns

func KeepRecentTurns(n int)

KeepRecentTurns configures a history policy that retains only the most recent N user/assistant turns while preserving system prompts and tool exchanges.

KeepRecentTurns must appear inside a History expression.

Example:

RunPolicy(func() {
    History(func() {
        KeepRecentTurns(20)
    })
})

func Loop added in v1.2.2

func Loop(name string, tool string, payloadJSON string, opts ...LoopOption)

Loop declares a bounded repeated tool node in a workflow graph.

func MCP

func MCP(name, version string, opts ...func(*exprmcp.MCPExpr))

MCP enables Model Context Protocol (MCP) support for the current service. It configures the service to expose tools, resources, and prompts via the MCP protocol. Once enabled, use Resource, Tool (in Method context), and related DSL functions within service methods to define MCP capabilities.

MCP must appear in a Service expression.

MCP takes two required arguments and an optional list of configuration functions:

  • name: the MCP server name (used in MCP handshake)
  • version: the server version string
  • opts: optional configuration functions (e.g., ProtocolVersion)

Example:

Service("calculator", func() {
    MCP("calc", "1.0.0", ProtocolVersion("2025-06-18"))
    Method("add", func() {
        Payload(func() {
            Attribute("a", Int)
            Attribute("b", Int)
        })
        Result(func() {
            Attribute("sum", Int)
        })
        Tool("add", "Add two numbers")
    })
})

func MCPPlacement added in v1.2.2

func MCPPlacement(service string, mcpServer string) func(*mcpexpr.ToolExpr)

MCPPlacement declares the generated MCP server that receives a projected method-backed toolset tool.

func MemoryMaxResults added in v1.2.2

func MemoryMaxResults(n int) memoryMaxResultsOption

MemoryMaxResults caps memory results for memory tools or preload.

func MemoryScopeCurrentRun added in v1.2.2

func MemoryScopeCurrentRun() memoryScopeOption

MemoryScopeCurrentRun selects current-run memory for preload.

func MemoryScopeIndexed added in v1.2.2

func MemoryScopeIndexed() memoryScopeOption

MemoryScopeIndexed selects indexed memory for preload.

func MemoryVisibilityShared added in v1.2.2

func MemoryVisibilityShared() memoryVisibilityOption

MemoryVisibilityShared scopes long-term memory to explicitly shared knowledge.

func MemoryVisibilityUser added in v1.2.2

func MemoryVisibilityUser() memoryVisibilityOption

MemoryVisibilityUser scopes long-term memory to the resolved user.

func NextCursor

func NextCursor(field string)

NextCursor declares the canonical field name for the next-page cursor in the bounded paging contract. Providers return the actual cursor through planner.ToolResult.Bounds.NextCursor; codegen and runtimes then project that value into the model-visible result JSON using this field name. NextCursor must be used inside BoundedResult.

func Notification

func Notification(name, description string)

Notification marks the current method as an MCP notification sender. The method's payload defines the notification message structure.

Notification must appear in a Method expression within a service that has MCP enabled.

Notification takes two arguments:

  • name: the notification identifier
  • description: human-readable notification description

Example:

Method("progress_update", func() {
    Payload(func() {
        Attribute("task_id", String)
        Attribute("progress", Int)
    })
    Notification("progress", "Task progress notification")
})

func OAuth added in v1.1.0

func OAuth(opts ...OAuthOption) func(*exprmcp.MCPExpr)

OAuth declares that the MCP server is an OAuth 2.0 protected resource. Pass AuthorizationServer, Scope, ResourceIdentifier, BearerMethodsSupported, and ResourceDocumentationURL options to populate the Protected Resource Metadata document (RFC 9728) and the WWW-Authenticate challenge.

Example:

MCP("server", "1.0.0",
    OAuth(
        AuthorizationServer("https://auth.example.com"),
        OAuthScope("read", "Read tool results"),
        ResourceIdentifier("https://api.example.com/mcp"),
    ),
)

func OnMissingFields

func OnMissingFields(action string)

OnMissingFields configures how the agent responds when tool invocation validation detects missing required fields. This allows you to control whether the agent should stop, wait for user input, or continue execution.

OnMissingFields must appear in a RunPolicy expression.

OnMissingFields takes a single string argument. Valid values:

  • "finalize": stop execution when required fields are missing
  • "await_clarification": pause and wait for user to provide missing information
  • "resume": continue execution despite missing fields
  • "" (empty): let the planner decide based on context

Example:

RunPolicy(func() {
    OnMissingFields("await_clarification")
})

func Parallel added in v1.2.2

func Parallel(fn func())

Parallel declares tool steps that are ready at the same graph frontier.

func Passthrough

func Passthrough(toolName string, target any, methodNameOpt ...string)

Passthrough defines deterministic forwarding for an exported tool to a Goa service method. It must appear within the DSL of a Tool nested under Export.

Passthrough accepts a tool name and a target, which can be:

  • A *goaexpr.MethodExpr (e.g., Passthrough("tool", MyService.MyMethod))
  • A service name and method name (e.g., Passthrough("tool", "MyService", "MyMethod"))

Example:

Export("logging-tools", func() {
    Tool("log_message", "Log a message", func() {
        Args(func() { /* ... */ })
        Return(func() { /* ... */ })
        Passthrough("log_message", "LoggingService", "LogMessage")
    })
})

func Plan

func Plan(duration string)

Plan sets the timeout for PlanStart and PlanResume planner activities. These activities invoke your planner implementation and typically involve LLM API calls. If the planner does not respond within this duration, the activity is retried according to the retry policy.

Plan must appear inside a RunPolicy or Timing expression.

Plan takes a single argument which is a Go duration string (e.g., "30s", "1m", "2m30s"). Choose a timeout that accommodates your model provider's typical response latency plus a safety margin for retries.

Example:

RunPolicy(func() {
    Timing(func() {
        Plan("45s")  // Allow 45 seconds for planner activities
    })
})

func PreloadLongTermMemory added in v1.2.2

func PreloadLongTermMemory(opts ...PreloadLongTermMemoryOption)

PreloadLongTermMemory enables bounded long-term memory entries in planner inputs.

PreloadLongTermMemory must appear in a RunPolicy expression.

func PreloadMemory added in v1.2.2

func PreloadMemory(opts ...PreloadMemoryOption)

PreloadMemory enables bounded memory snippets in planner inputs.

PreloadMemory must appear in a RunPolicy expression.

func PromptIcons added in v1.0.6

func PromptIcons(icons ...*exprmcp.IconExpr) func(*exprmcp.PromptExpr)

PromptIcons attaches icon metadata to a static MCP prompt.

func PromptTemplate

func PromptTemplate(tmpl string)

PromptTemplate sets the operator-facing prompt template rendered during confirmation. The template is executed with the tool payload value.

func ProtocolVersion

func ProtocolVersion(version string) func(*exprmcp.MCPExpr)

ProtocolVersion configures the MCP protocol version supported by the server. It returns a configuration function for use with MCP.

ProtocolVersion takes a single argument which is the protocol version string.

Example:

Service("calculator", func() {
    MCP("calc", "1.0.0", ProtocolVersion("2025-06-18"))
})

func PublishTo

func PublishTo(registry *agentsexpr.RegistryExpr)

PublishTo configures registry publication for an exported toolset. Use PublishTo inside an Export DSL to specify which registries the toolset should be published to.

PublishTo must appear in a Toolset expression that is being exported.

PublishTo takes a registry expression returned by Registry().

Example:

var CorpRegistry = Registry("corp", func() {
    URL("https://registry.corp.internal")
})

var LocalTools = Toolset("utils", func() {
    Tool("summarize", "Summarize text", func() {
        Args(func() { Attribute("text", String) })
        Return(func() { Attribute("summary", String) })
    })
})

Agent("data-agent", "Data processing agent", func() {
    Use(LocalTools)
    Export(LocalTools, func() {
        PublishTo(CorpRegistry)
        Tags("data", "etl")
    })
})

func Registry

func Registry(name string, fn ...func()) *agentsexpr.RegistryExpr

Registry declares a registry source for tool discovery. Registries are centralized catalogs of MCP servers, toolsets, and agents that can be discovered and consumed by loom-mcp agents.

Registry must appear at the top level of a design.

Registry takes a name and an optional DSL function to configure the registry:

  • name: unique identifier for this registry within the design
  • fn: optional configuration function

Inside the DSL function, use:

  • URL: sets the registry endpoint URL (required)
  • Description: sets a human-readable description
  • APIVersion: sets the registry API version (defaults to "v1")
  • Security: references Goa security schemes for authentication
  • Timeout: sets HTTP request timeout
  • Retry: configures retry policy for failed requests
  • SyncInterval: sets how often to refresh the catalog
  • CacheTTL: sets local cache duration
  • Federation: configures external registry import settings

Example:

var CorpRegistry = Registry("corp-registry", func() {
    Description("Corporate tool registry")
    URL("https://registry.corp.internal")
    APIVersion("v1")
    Security(CorpAPIKey)
    Timeout("30s")
    Retry(3, "1s")
    SyncInterval("5m")
    CacheTTL("1h")
})

Example with federation:

var AnthropicRegistry = Registry("anthropic", func() {
    Description("Anthropic MCP Registry")
    URL("https://registry.anthropic.com/v1")
    Security(AnthropicOAuth)
    Federation(func() {
        Include("web-search", "code-execution")
        Exclude("experimental/*")
    })
    SyncInterval("1h")
    CacheTTL("24h")
})

func RequestInput added in v1.2.2

func RequestInput(name string, title string, schemaJSON string)

RequestInput declares a schema-typed human input node in a workflow graph.

func Resource

func Resource(name, uri, mimeType string, opts ...func(*exprmcp.ResourceExpr))

Resource marks the current method as an MCP resource provider. The method's result becomes the resource content returned when clients read the resource.

Resource must appear in a Method expression within a service that has MCP enabled.

Resource takes three arguments:

  • name: the resource name (used in MCP resource list)
  • uri: the resource URI (e.g., "file:///docs/readme.md")
  • mimeType: the content MIME type (e.g., "text/plain", "application/json")

Example:

Method("readme", func() {
    Result(String)
    Resource("readme", "file:///docs/README.md", "text/markdown")
})

func ResourceIcons added in v1.0.6

func ResourceIcons(icons ...*exprmcp.IconExpr) func(*exprmcp.ResourceExpr)

ResourceIcons attaches icon metadata to an MCP resource.

func ResultHintTemplate

func ResultHintTemplate(s string)

ResultHintTemplate configures a display template for tool results. The template is rendered after execution to produce a concise preview.

Result templates receive an explicit runtime-owned wrapper:

  • `.Result` is the tool's typed semantic result value.
  • `.Bounds` is the runtime-owned bounded-result metadata when the tool returned `planner.ToolResult.Bounds`, otherwise nil.

Templates are compiled with missingkey=error.

ResultHintTemplate must appear in a Tool expression.

ResultHintTemplate takes a single string argument which is the Go template text.

Example:

Tool("search", "Search documents", func() {
    Return(func() {
        Attribute("count", Int)
        Attribute("results", ArrayOf(String))
    })
    ResultHintTemplate("Found {{ .Result.Count }} results")
})

func ResultReminder

func ResultReminder(s string)

ResultReminder configures a static system reminder that is injected into the conversation after the tool result is returned. Use this to provide backstage guidance to the model about how to interpret or present the result to the user.

The reminder text is automatically wrapped in <system-reminder> tags by the runtime. Do not include the tags in the text.

This DSL function is for static, design-time reminders that apply every time the tool is called. For dynamic reminders that depend on runtime state or tool result content, use PlannerContext.AddReminder() in your planner implementation instead. Dynamic reminders support rate limiting, per-run caps, and can be added or removed based on runtime conditions.

ResultReminder must appear in a Tool expression.

Example:

Tool("get_time_series", "Get Time Series", func() {
    Args(GetTimeSeriesToolArgs)
    Return(GetTimeSeriesToolReturn)
    ResultReminder("The user sees a rendered graph of this data.")
})

func Retry

func Retry(maxRetries int, backoff string)

Retry configures the retry policy for failed registry requests.

Retry must appear in a Registry expression.

Retry takes:

  • maxRetries: maximum number of retry attempts
  • backoff: initial backoff duration between retries (e.g., "1s", "500ms")

Example:

Registry("corp", func() {
    URL("https://registry.corp.internal")
    Retry(3, "1s")
})

func RetryAndReflect added in v1.2.2

func RetryAndReflect(opts ...RetryAndReflectOption)

RetryAndReflect enables tool-error reflection. When a tool executor returns an error, the runtime converts it into a planner retry hint so the model can repair the call arguments instead of immediately failing the run.

RetryAndReflect must appear in a RunPolicy expression.

func Return

func Return(val any, args ...any)

Return defines the output result schema for a tool. Use Return inside a Tool DSL to specify what data structure the tool produces when successfully executed.

Return follows the same patterns as Goa's Result function for methods. It accepts:

  • A function to define an inline object schema with Attribute() calls
  • A Goa user type (Type, ResultType, etc.) to reuse existing type definitions
  • A primitive type (String, Int, etc.) for simple single-value outputs

When using a function to define the schema inline, you can use:

  • Attribute(name, type, description) to define each result field
  • Required(...) to mark fields as always present
  • All Goa attribute DSL functions (Example, MinLength, etc.)

Example (inline schema):

Tool("analyze", "Analyze document", func() {
    Args(func() { ... })
    Return(func() {
        Attribute("summary", String, "Document summary")
        Attribute("keywords", ArrayOf(String), "Extracted keywords")
        Attribute("score", Float64, "Confidence score")
        Required("summary", "keywords", "score")
    })
})

Example (reuse existing type):

var AnalysisResult = ResultType("application/vnd.analysis", func() {
    Attribute("summary", String)
    Attribute("keywords", ArrayOf(String))
    Required("summary")
})

Tool("analyze", "Analyze document", func() {
    Args(func() { ... })
    Return(AnalysisResult)
})

Example (primitive type for simple tools):

Tool("count_words", "Count words in text", func() {
    Args(String)
    Return(Int)  // Returns single integer count
})

If Return is not called, the tool produces no output (empty/null result).

func RunPolicy

func RunPolicy(fn func())

RunPolicy defines execution constraints for the current agent. Use RunPolicy to configure resource limits, timeouts, history management, and runtime behaviors that govern how the agent executes. These policies are enforced by the runtime during agent execution.

RunPolicy must appear in an Agent expression.

RunPolicy takes a single argument which is the defining DSL function.

The DSL function may use:

  • DefaultCaps to set capability limits (tool calls, consecutive failures)
  • TimeBudget to set maximum execution duration
  • InterruptsAllowed to enable or disable user interruptions
  • OnMissingFields to configure validation behavior
  • History to configure how conversation history is truncated or compressed
  • Cache to configure prompt caching hints for supported providers

Example:

Agent("assistant", "Helper agent", func() {
    RunPolicy(func() {
        DefaultCaps(MaxToolCalls(10), MaxConsecutiveFailedToolCalls(3))
        TimeBudget("5m")
        InterruptsAllowed(true)
        OnMissingFields("await_clarification")
        History(func() {
            KeepRecentTurns(20)
        })
    })
})

func RuntimePrompt added in v1.2.2

func RuntimePrompt(agentID, role string, opts ...RuntimePromptOption) func(*exprmcp.PromptExpr)

RuntimePrompt declares that a static MCP prompt should also be registered as a runtime prompt spec. The static prompt must contain exactly one message so the generated prompt spec has one unambiguous template body.

func ServerData

func ServerData(kind string, schema any, args ...any)

ServerData declares typed server-only data emitted alongside a tool result. Server data is never sent to model providers; it exists for UIs, observability, and persistence layers.

Each ServerData entry has:

  • a Kind identifier used by consumers (UIs, sinks) to dispatch decoders, and
  • a schema type, which loom-mcp uses to generate a JSON codec so values remain workflow-safe (canonical JSON bytes) and can be decoded reliably by tools, runtimes, and downstream consumers.

ServerData does not define emission policy. Tool implementations may emit or omit server-data items depending on their own contracts. Consumers that need “model-controlled” server-data should express it explicitly in the tool schema.

Usage patterns:

Typed server-data (tool-implemented):

Tool("get_time_series", "Get Time Series", func() {
    Args(GetTimeSeriesToolArgs)
    Return(GetTimeSeriesToolReturn)
    ServerData("atlas.time_series", GetTimeSeriesSidecar)
})

Typed server-data sourced from a bound method result field:

Tool("get_time_series", "Get Time Series", func() {
    // ...
    BindTo("GetTimeSeries")
    ServerData("aura.evidence", Evidence, func() {
        Description("Evidence references emitted for persistence and downstream UIs.")
        FromMethodResultField("evidence")
    })
})

Typed server-data with a compact description:

Tool("get_time_series", "Get Time Series", func() {
    // ...
    ServerData("atlas.time_series", GetTimeSeriesSidecar, "Time-series chart rendered in the UI.")
})

func ServerIcons added in v1.0.6

func ServerIcons(icons ...*exprmcp.IconExpr) func(*exprmcp.MCPExpr)

ServerIcons attaches implementation icons to the MCP server metadata.

func SkillDirectory added in v1.2.2

func SkillDirectory(root string) func(*exprmcp.MCPExpr)

SkillDirectory exposes agent skill directories as MCP skill:// resources.

The root directory is scanned at runtime. Each child directory containing a SKILL.md file becomes a skill with resources for SKILL.md, _manifest, and any supporting files named by the manifest.

func StaticPrompt

func StaticPrompt(name, description string, args ...any)

StaticPrompt adds a static prompt template to the MCP server. Static prompts provide pre-defined message sequences that clients can use without parameters.

StaticPrompt must appear in a Service expression with MCP enabled.

StaticPrompt takes a name, description, and a list of role-content pairs:

  • name: the prompt identifier
  • description: human-readable prompt description
  • messages: alternating role and content strings (e.g., "user", "text", "assistant", "text")

Example:

Service("assistant", func() {
    MCP("assistant", "1.0")
    StaticPrompt("greeting", "Friendly greeting",
        "user", "Hello!",
        "assistant", "How can I help?")
})

func Step added in v1.2.2

func Step(name string, tool string, payloadJSON string)

Step appends one sequential tool call to the current Workflow.

func Subscription

func Subscription(resourceName string)

Subscription marks the current method as a subscription handler for a watchable resource. The method is invoked when clients subscribe to the resource identified by resourceName.

Subscription must appear in a Method expression within a service that has MCP enabled.

Subscription takes a single argument which is the resource name to subscribe to. The resource name must match a WatchableResource declaration.

Example:

Method("subscribe_status", func() {
    Payload(func() {
        Attribute("uri", String)
    })
    Result(String)
    Subscription("status")
})

func SubscriptionMonitor

func SubscriptionMonitor(name string)

SubscriptionMonitor marks the current method as a server-sent events (SSE) monitor for subscription updates. The method streams subscription change events to connected clients.

SubscriptionMonitor must appear in a Method expression within a service that has MCP enabled.

SubscriptionMonitor takes a single argument which is the monitor name.

Example:

Method("watch_subscriptions", func() {
    StreamingResult(func() {
        Attribute("resource", String)
        Attribute("event", String)
    })
    SubscriptionMonitor("subscriptions")
})

func SyncInterval

func SyncInterval(duration string)

SyncInterval sets how often to refresh the registry catalog.

SyncInterval must appear in a Registry expression.

SyncInterval takes a duration string (e.g., "5m", "1h", "30s").

Example:

Registry("corp", func() {
    URL("https://registry.corp.internal")
    SyncInterval("5m")
})

func Tags

func Tags(values ...string)

Tags attaches metadata labels to a tool for categorization and filtering. Tags can be used by agents, planners, or monitoring systems to organize and discover tools based on their capabilities or domains.

Tags accepts a variadic list of strings. Each tag should be a simple lowercase identifier or category name. Common patterns include:

  • Domain categories: "nlp", "database", "api", "filesystem"
  • Capability types: "read", "write", "search", "transform"
  • Risk levels: "safe", "destructive", "external"
  • Performance hints: "slow", "fast", "cached"

Example (domain and capability tags):

Tool("search_docs", "Search documentation", func() {
    Args(func() { ... })
    Return(func() { ... })
    Tags("search", "documentation", "nlp")
})

Example (risk and performance tags):

Tool("delete_file", "Delete a file", func() {
    Args(func() { ... })
    Tags("filesystem", "write", "destructive")
})

Tags are optional. Tools without tags are still fully functional but may be harder to organize in systems with many available tools.

func TerminalRun

func TerminalRun()

TerminalRun marks the current tool as terminal for the run: after the tool executes, the runtime should complete the run immediately without requesting a follow-up planner PlanResume/finalization turn.

TerminalRun must appear in a Tool expression.

func TimeBudget

func TimeBudget(duration string)

TimeBudget sets the maximum execution time for the agent. The agent will be stopped if it exceeds this duration.

TimeBudget must appear in a RunPolicy expression.

TimeBudget takes a single argument which is a duration string (e.g., "30s", "5m", "1h").

Example:

RunPolicy(func() {
    TimeBudget("5m")
})

func Timing

func Timing(fn func())

Timing groups timing configuration for an agent's run. Use Timing inside a RunPolicy to configure fine-grained timeouts for different phases of execution.

Timing provides a cleaner way to organize multiple duration settings compared to calling Budget, Plan, and Tools directly inside RunPolicy. Both approaches are valid and produce equivalent configurations.

Timing must appear inside a RunPolicy expression.

Available settings inside Timing:

  • Budget: total wall-clock time budget for the entire run
  • Plan: timeout for Plan and Resume planner activities
  • Tools: default timeout for tool execution activities

Example:

RunPolicy(func() {
    Timing(func() {
        Budget("10m")  // Total run time
        Plan("45s")    // Planner timeout
        Tools("2m")    // Tool timeout
    })
})

Without Timing grouping (equivalent):

RunPolicy(func() {
    TimeBudget("10m")  // Note: Budget and TimeBudget are equivalent
})

func Tool

func Tool(name string, args ...any)

Tool declares a tool for agents or MCP servers. It has two distinct use cases:

  1. Inside a Toolset (agent tools): Declares a tool with inline argument and return schemas. Use this for custom tools in agent toolsets or external MCP servers where you manually define the schemas.

  2. Inside a Method (MCP tools): Marks a Goa service method as an MCP tool. The method's payload becomes the tool input schema and the method result becomes the tool output schema. This automatically exposes the method via the service's MCP server.

Tool takes two required arguments and one optional DSL function:

  • name: the tool identifier
  • description: a concise summary presented to the LLM
  • dsl (optional): configuration block (only for toolset tools, ignored for method tools)

Inside toolsets, the DSL function can use:

  • Args: defines the input parameter schema
  • Return: defines the output result schema
  • Tags: attaches metadata labels
  • BindTo: binds to a service method for implementation (optional)
  • Inject: marks fields as infrastructure-only (hidden from LLM)

Example (toolset tool with inline schemas):

Toolset("utils", func() {
    Tool("summarize", "Summarize a document", func() {
        Args(func() {
            Attribute("text", String, "Document text")
            Required("text")
        })
        Return(func() {
            Attribute("summary", String, "Summary text")
        })
        Tags("nlp", "summarization")
    })
})

Example (external MCP tool with inline schemas):

var RemoteSearch = Toolset("remote", FromMCP("search-service", "search"), func() {
    Tool("web_search", "Search the web", func() {
        Args(func() { Attribute("query", String) })
        Return(func() { Attribute("results", ArrayOf(String)) })
    })
})

Agent("helper", "", func() {
    Use(RemoteSearch)
})

Example (service-backed tool with inheritance):

Toolset("docs", func() {
    Tool("search_docs", func() {
        BindTo("doc_service", "search")
        Inject("session_id")
    })
})

func ToolDiscoveryCallTemplateArg added in v1.2.2

func ToolDiscoveryCallTemplateArg(name string, value any) func(*exprmcp.ToolExpr)

ToolDiscoveryCallTemplateArg adds an exemplar argument to progressive discovery call_tool templates. The argument remains optional unless the payload schema itself marks it required.

func ToolDiscoveryCategory added in v1.2.2

func ToolDiscoveryCategory(category string) func(*exprmcp.ToolExpr)

ToolDiscoveryCategory sets the MCP tool progressive discovery category.

func ToolDiscoveryKeywords added in v1.2.2

func ToolDiscoveryKeywords(keywords ...string) func(*exprmcp.ToolExpr)

ToolDiscoveryKeywords sets the MCP tool progressive discovery keywords.

func ToolDiscoveryTags added in v1.2.2

func ToolDiscoveryTags(tags ...string) func(*exprmcp.ToolExpr)

ToolDiscoveryTags sets the MCP tool progressive discovery tags.

func ToolIcons added in v1.0.6

func ToolIcons(icons ...*exprmcp.IconExpr) func(*exprmcp.ToolExpr)

ToolIcons attaches icon metadata to an MCP tool.

func ToolSearch added in v1.2.2

func ToolSearch(opts ...ToolSearchOption) func(*exprmcp.MCPExpr)

ToolSearch configures generated progressive discovery ranking defaults for an MCP server. Runtime adapter options can still override operational fields.

func ToolTitle added in v1.2.2

func ToolTitle(title string) func(*exprmcp.ToolExpr)

ToolTitle sets the MCP tool display title.

func Tools

func Tools(duration string)

Tools sets the default timeout for ExecuteTool activities. This timeout applies to individual tool invocations when the tool executor runs the underlying implementation (service method call, MCP request, or nested agent execution).

Tools must appear inside a RunPolicy or Timing expression.

Tools takes a single argument which is a Go duration string (e.g., "30s", "2m", "5m"). The appropriate timeout depends on your tool implementations:

  • Fast lookups: 10-30 seconds
  • Database queries: 30 seconds to 2 minutes
  • External API calls: 1-5 minutes
  • Long-running operations: 5+ minutes (consider async patterns)

Example:

RunPolicy(func() {
    Timing(func() {
        Tools("2m")  // Allow 2 minutes per tool execution
    })
})

func Toolset

func Toolset(args ...any) *agentsexpr.ToolsetExpr

Toolset defines a provider-owned group of related tools. Declare toolsets at the top level using Toolset(...) and reference them from agents via Use / Export.

Tools declared inside a Toolset may be:

  • Bound to Goa service methods via BindTo, in which case codegen emits transforms and client helpers.
  • Backed by MCP tools declared with the MCP DSL (MCP + Tool) and exposed via Toolset with FromMCP provider option.
  • Implemented by custom executors or agent logic when left unbound.

Toolset accepts a single form:

  • Toolset("name", func()) declares a new toolset with the given name and tools.

Example (provider toolset definition):

var CommonTools = Toolset("common", func() {
    Tool("notify", "Send notification", func() {
        Args(func() {
            Attribute("message", String, "Message to send")
            Required("message")
        })
    })
})

Agents consume this toolset via Use:

Agent("assistant", "helper", func() {
    Use(CommonTools, func() {
        Tool("notify") // reference existing tool by name
    })
})

For MCP-backed toolsets, use FromMCP provider option:

var MCPTools = Toolset(FromMCP("assistant-service", "assistant-mcp"))

For registry-backed toolsets, use FromRegistry provider option:

var RegistryTools = Toolset(FromRegistry(CorpRegistry, "data-tools"))

Toolset accepts these forms:

  • Toolset("name", func()) - local toolset with inline schemas
  • Toolset(FromMCP(service, toolset)) - MCP-backed toolset (name derived from toolset)
  • Toolset(FromRegistry(registry, toolset)) - registry-backed toolset (name derived from toolset)
  • Toolset("name", FromMCP(...)) - MCP-backed with explicit name
  • Toolset("name", FromRegistry(...)) - registry-backed with explicit name
  • Toolset(FromMCP(...), func()) - MCP-backed with additional config

func Use

func Use(value any, fn ...func()) *expragents.ToolsetExpr

Use declares that the current agent consumes the specified toolset. The value may be either:

  • A *expragents.ToolsetExpr returned by Toolset or MCPToolset (provider-owned)
  • A string name for an inline, agent-local toolset definition

An optional DSL function can:

  • Subset tools from a referenced provider toolset by name (Tool("name"))
  • Define ad-hoc tools local to this agent

Example (referencing a provider toolset and subsetting):

var CommonTools = Toolset("common", func() {
    Tool("notify", "Send notification", func() { ... })
    Tool("log", "Log message", func() { ... })
})

Agent("assistant", "helper", func() {
    Use(CommonTools, func() {
        Tool("notify") // consume only a subset
    })
})

Example (inline agent-local toolset):

Agent("planner", "Session planner", func() {
    Use("adhoc", func() {
        Tool("foo", "Foo tool", func() { ... })
    })
})

func UseAgentToolset deprecated

func UseAgentToolset(service, agent, toolset string) *agentsexpr.ToolsetExpr

UseAgentToolset is an alias for AgentToolset. Prefer AgentToolset in new designs; this alias exists for readability in some codebases.

Deprecated: Use AgentToolset instead. This function will be removed in a future release.

func WatchableResource

func WatchableResource(name, uri, mimeType string, opts ...func(*exprmcp.ResourceExpr))

WatchableResource marks the current method as an MCP resource that supports subscriptions. Clients can subscribe to receive notifications when the resource content changes.

WatchableResource must appear in a Method expression within a service that has MCP enabled.

WatchableResource takes three arguments:

  • name: the resource name (used in MCP resource list)
  • uri: the resource URI (e.g., "file:///logs/app.log")
  • mimeType: the content MIME type (e.g., "text/plain")

Example:

Method("system_status", func() {
    Result(func() {
        Attribute("status", String)
        Attribute("uptime", Int)
    })
    WatchableResource("status", "status://system", "application/json")
})

func WebsiteURL added in v1.0.6

func WebsiteURL(rawURL string) func(*exprmcp.MCPExpr)

WebsiteURL exposes the server implementation website URL.

func Workflow added in v1.2.2

func Workflow(fn func())

Workflow configures a generated deterministic workflow planner for the current agent.

Types

type ArtifactProviderOption added in v1.2.2

type ArtifactProviderOption func(*agentsexpr.ProviderExpr)

ArtifactProviderOption configures FromArtifacts.

func MaxArtifactBytes added in v1.2.2

func MaxArtifactBytes(n int) ArtifactProviderOption

MaxArtifactBytes caps load_artifact response content bytes.

func MaxArtifacts added in v1.2.2

func MaxArtifacts(n int) ArtifactProviderOption

MaxArtifacts caps list_artifacts response count.

type BranchOption added in v1.2.2

type BranchOption func(*expragents.WorkflowBranchExpr)

BranchOption configures Branch nodes.

func BranchDefault added in v1.2.2

func BranchDefault(target string) BranchOption

BranchDefault sets the branch target used when no Case matches.

func Case added in v1.2.2

func Case(path, equals, target string) BranchOption

Case maps a JSONPath equality predicate to a branch target node.

type CapsOption

type CapsOption func(*expragents.CapsExpr)

CapsOption defines a functional option for configuring per-run resource limits on agent execution.

func MaxConsecutiveFailedToolCalls

func MaxConsecutiveFailedToolCalls(n int) CapsOption

MaxConsecutiveFailedToolCalls configures the maximum number of consecutive tool failures before the agent stops execution. Use this with DefaultCaps to prevent runaway failure loops.

MaxConsecutiveFailedToolCalls takes a single integer argument specifying the maximum consecutive failure count.

Example:

DefaultCaps(MaxConsecutiveFailedToolCalls(3))

func MaxToolCalls

func MaxToolCalls(n int) CapsOption

MaxToolCalls configures the maximum number of tool invocations allowed during agent execution. Use this with DefaultCaps to limit total tool usage.

MaxToolCalls takes a single integer argument specifying the maximum count.

Example:

DefaultCaps(MaxToolCalls(15))

type IconOption added in v1.0.6

type IconOption func(*exprmcp.IconExpr)

IconOption customizes one MCP icon metadata entry.

func IconMIMEType added in v1.0.6

func IconMIMEType(mimeType string) IconOption

IconMIMEType sets the icon MIME type.

func IconSizes added in v1.0.6

func IconSizes(sizes ...string) IconOption

IconSizes sets the supported icon sizes.

func IconTheme added in v1.0.6

func IconTheme(theme string) IconOption

IconTheme sets the icon theme preference.

type LoopOption added in v1.2.2

type LoopOption func(*expragents.WorkflowLoopExpr)

LoopOption configures Loop nodes.

func MaxIterations added in v1.2.2

func MaxIterations(n int) LoopOption

MaxIterations bounds Loop execution.

func UntilJSONPath added in v1.2.2

func UntilJSONPath(step, path, equals string) LoopOption

UntilJSONPath stops Loop when a prior step JSON value equals the expected string.

type MemoryProviderOption added in v1.2.2

type MemoryProviderOption interface {
	// contains filtered or unexported methods
}

MemoryProviderOption configures FromMemory.

func MemoryIndexedTranscript added in v1.2.2

func MemoryIndexedTranscript() MemoryProviderOption

MemoryIndexedTranscript exposes indexed transcript memory from FromMemory.

func MemoryLongTerm added in v1.2.2

func MemoryLongTerm() MemoryProviderOption

MemoryLongTerm exposes long-term entry memory from FromMemory.

func MemoryTranscript added in v1.2.2

func MemoryTranscript() MemoryProviderOption

MemoryTranscript exposes current-run transcript memory from FromMemory.

type OAuthOption added in v1.1.0

type OAuthOption func(*exprmcp.OAuthExpr)

OAuthOption configures one aspect of the MCP OAuth protected-resource configuration.

func AuthorizationServer added in v1.1.0

func AuthorizationServer(url string) OAuthOption

AuthorizationServer appends one OAuth 2.0 authorization server URL to the PRM document. Call multiple times to advertise more than one.

func BearerMethodsSupported added in v1.1.0

func BearerMethodsSupported(methods ...string) OAuthOption

BearerMethodsSupported enumerates the OAuth 2.0 bearer token methods (header, body, query) the server accepts. Defaults to ["header"] at generation time when empty.

func OAuthScope added in v1.1.0

func OAuthScope(name, description string) OAuthOption

OAuthScope documents one OAuth 2.0 scope exposed by the protected resource. The name is "OAuthScope" rather than "Scope" to avoid colliding with Loom's core DSL Scope when both DSLs are dot-imported in a design file.

func ResourceDocumentationURL added in v1.1.0

func ResourceDocumentationURL(url string) OAuthOption

ResourceDocumentationURL surfaces as resource_documentation in the PRM document.

func ResourceIdentifier added in v1.1.0

func ResourceIdentifier(url string) OAuthOption

ResourceIdentifier pins the canonical resource URI emitted as the "resource" field in the Protected Resource Metadata document. When omitted, the generated handler derives the value from the incoming request URL, honoring X-Forwarded-* and Forwarded headers. Declaring ResourceIdentifier is the recommended production posture.

func TrustProxyHeaders added in v1.1.1

func TrustProxyHeaders() OAuthOption

TrustProxyHeaders opts the generated server into honoring X-Forwarded-Proto, X-Forwarded-Host, and RFC 7239 Forwarded headers when deriving the canonical resource URL and the WWW-Authenticate challenge origin. Default (without this option) is not to trust forwarded headers at all.

Only enable this when every request reaches the server through a reverse proxy the operator fully controls and that strips these headers from direct-client requests. A server reachable directly by clients must NOT trust forwarded headers — an attacker would otherwise control the PRM `resource` field advertised to clients.

For most production deployments, pinning ResourceIdentifier(...) is preferred: a declared identifier bypasses forwarded-header derivation entirely and is the spec's recommended posture.

type PreloadLongTermMemoryOption added in v1.2.2

type PreloadLongTermMemoryOption interface {
	// contains filtered or unexported methods
}

PreloadLongTermMemoryOption configures bounded long-term memory preload.

type PreloadMemoryOption added in v1.2.2

type PreloadMemoryOption interface {
	// contains filtered or unexported methods
}

PreloadMemoryOption configures bounded memory preload.

type RetryAndReflectOption added in v1.2.2

type RetryAndReflectOption func(*expragents.RetryAndReflectExpr)

RetryAndReflectOption configures RetryAndReflect policy behavior.

func ErrorIfRetryExceeded added in v1.2.2

func ErrorIfRetryExceeded(enabled bool) RetryAndReflectOption

ErrorIfRetryExceeded configures whether the original tool error should be returned once the reflected retry budget has been consumed.

func MaxRetries added in v1.2.2

func MaxRetries(n int) RetryAndReflectOption

MaxRetries configures how many reflected retry hints are allowed for a run/tool pair. Zero uses the runtime default.

type RuntimePromptOption added in v1.2.2

type RuntimePromptOption func(*exprmcp.RuntimePromptExpr)

RuntimePromptOption customizes the runtime prompt spec generated for a static MCP prompt.

func RuntimePromptVersion added in v1.2.2

func RuntimePromptVersion(version string) RuntimePromptOption

RuntimePromptVersion sets the baseline version for a generated runtime prompt spec. When omitted, the runtime prompt registry derives a deterministic version from the template.

type ServerDataAudience

type ServerDataAudience string

ServerDataAudience declares who a server-data payload is intended for.

const (
	// AudienceTimeline indicates the payload is persisted and eligible for UI rendering.
	ServerDataAudienceTimeline ServerDataAudience = "timeline"
	// AudienceInternal indicates the payload is an internal tool-composition attachment.
	ServerDataAudienceInternal ServerDataAudience = "internal"
	// AudienceEvidence indicates the payload carries provenance references.
	ServerDataAudienceEvidence ServerDataAudience = "evidence"
)

type SkillProviderOption added in v1.2.2

type SkillProviderOption func(*agentsexpr.ProviderExpr)

SkillProviderOption configures FromSkills.

func SkillPreload added in v1.2.2

SkillPreload configures when model-facing skill instructions are preloaded.

func SkillReload added in v1.2.2

SkillReload configures when model-facing skill files are reloaded from disk.

type ToolSearchOption added in v1.2.2

type ToolSearchOption func(*exprmcp.ToolSearchExpr)

ToolSearchOption customizes generated progressive tool discovery search.

func ToolSearchBroadFallback added in v1.2.2

func ToolSearchBroadFallback(enabled bool) ToolSearchOption

ToolSearchBroadFallback toggles weaker metadata, description, parameter, and schema matching when no strong name/title match exists.

func ToolSearchExactMatch added in v1.2.2

func ToolSearchExactMatch(mode string) ToolSearchOption

ToolSearchExactMatch sets exact-name/title behavior. Use ToolSearchExactMatchNarrow, ToolSearchExactMatchBoost, or ToolSearchExactMatchOff.

func ToolSearchFuzzyNameMatching added in v1.2.2

func ToolSearchFuzzyNameMatching(enabled bool) ToolSearchOption

ToolSearchFuzzyNameMatching toggles fuzzy matching for tool names and titles.

func ToolSearchMaxResults added in v1.2.2

func ToolSearchMaxResults(n int) ToolSearchOption

ToolSearchMaxResults sets the generated default search result cap.

func ToolSearchMinScore added in v1.2.2

func ToolSearchMinScore(score int) ToolSearchOption

ToolSearchMinScore sets the generated minimum ranking score.

func ToolSearchWeights added in v1.2.2

func ToolSearchWeights(opts ...ToolSearchWeightOption) ToolSearchOption

ToolSearchWeights configures generated ranking weights.

type ToolSearchWeightOption added in v1.2.2

type ToolSearchWeightOption func(*exprmcp.ToolSearchWeightsExpr)

ToolSearchWeightOption customizes generated progressive discovery ranking weights.

func ToolSearchDescriptionWeight added in v1.2.2

func ToolSearchDescriptionWeight(weight int) ToolSearchWeightOption

ToolSearchDescriptionWeight sets the description ranking weight.

func ToolSearchFuzzyNameWeight added in v1.2.2

func ToolSearchFuzzyNameWeight(weight int) ToolSearchWeightOption

ToolSearchFuzzyNameWeight sets the fuzzy name/title ranking weight.

func ToolSearchMetadataWeight added in v1.2.2

func ToolSearchMetadataWeight(weight int) ToolSearchWeightOption

ToolSearchMetadataWeight sets the category/tag/keyword ranking weight.

func ToolSearchNameWeight added in v1.2.2

func ToolSearchNameWeight(weight int) ToolSearchWeightOption

ToolSearchNameWeight sets the tool-name ranking weight.

func ToolSearchParameterWeight added in v1.2.2

func ToolSearchParameterWeight(weight int) ToolSearchWeightOption

ToolSearchParameterWeight sets the parameter/schema ranking weight.

func ToolSearchTitleWeight added in v1.2.2

func ToolSearchTitleWeight(weight int) ToolSearchWeightOption

ToolSearchTitleWeight sets the tool-title ranking weight.

type ToolSurface added in v1.2.2

type ToolSurface = agentsexpr.ToolSurface

ToolSurface identifies a generated surface a toolset tool may be exposed on.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL