7.8 KiB
Tools Architecture and Authoring
A tool is declared by a .meta file. It may also have an accompanying executable, but neither form is required in every case:
- Metadata plus binary/script: place
<name>.metabeside an executable named<name>. - Metadata only: set
cmdin<name>.metato a shell command. The registry executes that command directly.
Both approaches are valid. The .meta file is always the source of discovery, model-facing documentation, and the JSON argument schema.
The registry reads the metadata, presents the tool to the model, and executes the resolved command when called. No integration with the Ollie source tree is required. Put the .meta file in $OLLIE_TOOLS_PATH; the tool is available on the next discovery or session start.
Quick start
Metadata plus an executable
~/.config/ollie/tools/
├── my_tool # executable in any language
└── my_tool.meta # JSON metadata
Metadata-only tool
{
"description": "Extract a value from JSON.",
"prompt": "## json_value\n\nRead `.path` from JSON input.",
"cmd": "input=$(cat); echo \"$input\" | jq -r '.path'",
"args": {
"type": "object",
"required": ["path"],
"properties": {"path": {"type": "string"}}
}
}
A metadata-only tool needs no script or binary. Its cmd is run through the shell with the tool-call JSON on standard input.
The .meta sidecar
The .meta file is the sole source of discovery and schema. The registry never inspects an accompanying executable to infer its interface.
{
"description": "One-liner shown in tool listings.",
"prompt": "## my_tool\n\nFull documentation shown when loaded.",
"args": {
"type": "object",
"required": ["path"],
"properties": {
"path": {"type": "string", "description": "File path"}
}
},
"tier": "hot",
"cmd": "my_tool"
}
| Field | Type | Purpose |
|---|---|---|
description |
string | One-liner shown in the tool listing. |
prompt |
string | Documentation injected when the tool is loaded. |
keywords |
array of strings | Additional user-language phrases used only for semantic discovery. Include synonyms, task verbs, file types, domains, and representative requests. |
args |
JSON Schema | Input schema exposed to the model. |
tier |
hot, warm, or cold |
Context retention tier. |
cmd |
string | Shell command or executable path/name. |
variants |
array | Conditional definitions for heterogeneous hosts. |
scope |
string | Tool scope metadata. |
outputFormat |
string | Output format metadata. |
resetsCounter |
bool | Marks tools that reset the relevant counter. |
Tool and skill discovery
Tool discovery remains metadata-driven: toolsrv scans .meta files and manages
which tools are loaded for an agent. Ollie adds a separate semantic ranking
layer before prompt assembly. The ranking text combines description, prompt,
and optional keywords. Keywords are discovery-only vocabulary: they should
contain the words users use to request the operation, including synonyms,
workflow phrases, file types, and domain terms. They are not shown as a second
model-facing schema and do not change execution. See architecture-embedding.md
for the embedding model, index lifecycle, matching thresholds, and failure
behavior.
Command resolution
When the registry resolves a tool named name, it checks:
$OLLIE_TOOLS_PATH/name— a co-located executable or script.- The resolved
.metacmdfield — an absolute path, bare executable name, or shell command. namethrough$PATH.
A co-located executable takes precedence over cmd. Metadata-only tools use the cmd value directly through the shell. This supports scripts, compiled binaries, wrappers, system commands, and pipelines.
Variants
The first variant whose conditions all match determines the tool’s schema, documentation, and command. If no variant matches, the tool is hidden.
| Key | Semantics | Example |
|---|---|---|
binary |
Binary exists in $PATH or at an absolute path. |
journalctl |
file |
File or directory exists. | /var/log/syslog |
os |
Matches runtime.GOOS. |
linux |
arch |
Matches runtime.GOARCH. |
amd64 |
env |
Environment variable is non-empty. | DISPLAY |
nenv |
Environment variable is empty or unset. | SSH_CONNECTION |
All keys in one match object use AND logic. An array value uses OR logic. Variant fields override top-level fields; unset fields inherit. If a remote toolsrv receives the metadata, it evaluates variants against the remote host.
{
"description": "Read system logs.",
"variants": [
{"match": {"binary": "journalctl"}, "cmd": "system_logs_journald"},
{"match": {"file": "/var/log/syslog"}, "cmd": "system_logs_syslog"}
]
}
Input and output contract
Both tool forms use the same contract:
- Input is one JSON object on standard input.
- Successful output is written to standard output and exits with status 0.
- Errors may be written to standard output or standard error and exit non-zero.
- Structured output may be returned as
{"content": [...]}JSON.
The dispatcher does not require flags, argv conventions, or language-specific integration.
Executable example
#!/usr/bin/env python3
import json
import sys
args = json.load(sys.stdin)
print(f"result: {args['path']}")
Metadata-only example
{
"description": "Search with ripgrep.",
"cmd": "input=$(cat); p=$(echo \"$input\" | jq -r '.pattern'); rg \"$p\"",
"args": {
"type": "object",
"required": ["pattern"],
"properties": {"pattern": {"type": "string"}}
}
}
For subcommand-style tools, parse the JSON with jq and construct the command explicitly. Avoid unsafe eval when arguments can be passed as arrays or quoted shell parameters.
Sandboxing and bypass
Toolsrv owns sandbox enforcement and the bypass approval path. See architecture-toolsrv.md. Tool metadata declares the command interface; it does not define the complete security policy.
Environment
Tools may receive:
| Variable | Purpose |
|---|---|
OLLIE_TOOLS_PATH |
Tool metadata and executable directory. |
OLLIE_BYPASS_SOCKET |
Bypass broker socket. |
PWD |
Session working directory. |
Installation and testing
Copy a .meta file and, when using the binary approach, its executable to the tools directory:
cp my_tool.meta ~/.config/ollie/tools/
cp my_tool ~/.config/ollie/tools/
chmod +x ~/.config/ollie/tools/my_tool
A metadata-only tool needs only the first command. Test its command contract with JSON on standard input:
echo '{"pattern":"TODO"}' | bash -c 'YOUR_CMD'
Agent profiles load tools at startup with autoLoad. Each profile specifies
the tools it needs — there is no lazy loading or automatic tool discovery at
call time:
{
"autoLoad": ["shell", "file_read", "file_edit", "file_grep", "file_glob"]
}
To add a tool to a running agent, use the ctl file:
client_9p(op="rdwr", path="session/$OLLIE_SESSION_ID/agent/$OLLIE_UNAME/ctl", data="tool_load <name>")
After loading, the agent refreshes its model-facing schemas when the toolsrv
registry revision changes. See architecture-toolsrv.md
for discovery, loading, registry, and execution architecture.
Repository examples
The repository includes executable and metadata-backed tools under data/tools/, including filesystem, GUI, LSP, and memory tools. Compiled tools are valid alongside scripts and metadata-only definitions.
See architecture.md for the design rationale, including why Ollie does not implement native MCP, embedded tool frameworks, workflow engines, parallel frontend control planes, or competing memory stores.