Skip to content
Bruce D'Ambrosio edited this page Jan 11, 2026 · 3 revisions

Tools & Primitives

Tools are resources the planner can invoke. They are very loosely modelled on the simpler forms of Anthropic Skills, but strict compatibility is neither intended not likely forthcoming.

  • They come in two flavors: primitives (core hardoced infospace operations) and external.
  • External tools can be any one of three types:
    • instruction tools are text that is added to the planner context - generally 'how to' hints
    • llm tools contain a text prompt and invoke the internal llm
    • Python tools run the tool method in a required tool.py file in the same directory as the Skill.md

Infospace: the planner’s data plane

Notes

A Note is a single persisted resource that contains either:

  • Text (free-form narrative, excerpts, logs, etc.), or
  • A structured object (dict/JSON) for machine-readable state/results.

Notes are the primary unit of memory and interchange between tools and planner.

Collections

A Collection is an ordered list of Notes. Common producers:

  • web / academic search tools
  • filters and transforms (filter-*, map, project, pluck, joins)
  • batching (group related Notes for later summarization or extraction)

Why this matters

Most “built-in” tools are CRUD + processing primitives over Notes and Collections:

  • CRUD: create notes, load notes, save notes, store results
  • Processing: map/filter/join/project/transform/summarize/extract## Tool Structure Each tool is defined by its Skill.md file:
  • Skill.md: Tool interface/contract
    • frontmatter: name, type, and short description (strict format)
    • inputs / outputs (contract)
    • behavior and “when to use” guidance (tool selection)
  • In addition, python tools require a tool.py: Implementation (for Python tools only)
  • While some minecraft world tools directly invoke other tools for efficiency, most tools should be written to return results to the planner.

Tool Locations:

  • Core tools: src/tools/<tool-name>/
  • World tools: src/world-tools/<world_name>/<tool-name>/

**The easiest way to understand tools is to look at one of the simpler existing tools of the type you are interested in.

Uniform Return Format

  • At the planner / reasoning level, tools create a Note or Collection, as described above (if a text or dict is returned, a Note will be created to wrap the return by the InfospaceExecutor.
  • At the engineering level, all python tools must return a uniform dictionary** via InfospaceExecutor._create_uniform_return():
{
    "status": "success" | "failed",
    "data": <raw_value>,  # Dict/list/etc. on success, or reason/value on failure
    "value": <formatted_string>,  # Display/logging string (may be truncated)
    "reason": <failure_reason>,  # Only present on failure
    "resource_id": <resource_id>  # Optional: ID of created/updated resource
}

Critical: When consuming tool outputs programmatically, use result["data"], not result["value"]. The value field is for display/logging and may be truncated.

Tool Catalog

The planner sees tools grouped by source:

  • World tools first (e.g., #MINECRAFT)
  • Core infospace tools (#INFOSPACE CORE)

Each tool entry includes:

  • description: Brief description for tool catalog
  • source: "core" or "<world_name>"
  • schema_hint: JSON schema for arguments (if available)
  • type: "method" for method tools, omitted for standard tools

Primitives

Built-in infospace operations executed directly by InfospaceExecutor:

Storage:

  • save, load, create-note, create-collection

Computation:

  • apply, map, coerce

Indexing & Search:

  • index, search-notes, search-collections, search-within-collection

Structured Operations:

  • project, pluck, filter-structured, sort, join

Communication:

  • say, think

Python Tools

Custom tools implemented in Python. Must follow conventions:

Function Signature:

def tool(input_value=None, **kwargs):
    executor: InfospaceExecutor = kwargs.get("executor")
    if not executor:
        return executor._create_uniform_return(
            status="failed",
            reason="executor not available",
            value=None
        )
    # ... tool logic ...
    return executor._create_uniform_return(
        status="success",
        data=<raw_result>,
        value=<formatted_string>
    )

Required:

  • Top-level tool() function
  • Retrieve executor from kwargs
  • Use executor._create_uniform_return() for all returns
  • Use executor.execute_action_with_log() for nested tool calls

Method Tools

Special tools that define protocols rather than direct actions. The planner executes these as bounded inner loops.

Characteristics:

  • Defined with type: method in Skill.md frontmatter
  • Protocol defined as numbered steps in Skill.md body
  • Planner interprets protocol and selects tools at each step
  • Cannot invoke other method tools (prevents recursion)

See Method-Tools for detailed documentation.

Tool Loading

Tools are loaded on executor initialization:

  1. Core tools from src/tools/ (always loaded)
  2. World tools from src/world-tools/<world_name>/ (if world_config.world_name is set)

Tools are discovered by scanning subdirectories for Skill.md files.

Tool Execution Flow

Planner selects tool
  └─> InfospaceExecutor.execute_action()
       ├─> If primitive → execute directly
       ├─> If Python tool → import and call tool()
       └─> If method tool → run_method_protocol() (inner loop)
            └─> Planner executes protocol steps iteratively

Best Practices

  1. Always use _create_uniform_return(): Ensures consistent format
  2. Return raw data in data: Don't truncate or format for data field
  3. Format value for display: Human-readable string for logging/UI
  4. Handle executor absence: Check for executor in kwargs
  5. Use execute_action_with_log(): For nested tool calls (ensures logging)
  6. Document clearly: Skill.md should be precise and minimal for LLM consumption

Clone this wiki locally