How-Tos
Build a tool
A tool package is an AWORG Capability, a folder of small Python files. Here's the whole contract.
What a tool package is
In AWORG, a Tool is one thing the Resident can call, and a Capability is a folder of related tools that the owner switches on and off as a unit. A tool package in the store is one Capability.
weather/
__init__.py the capability: its label and description
get_weather.py one tool
_helpers.py anything starting with _ is not a tool
The folder name is the capability's name, and the package's name.
__init__.py
LABEL = "Weather"
DESCRIPTION = (
"Looking up the weather anywhere by name: what it is doing there now, "
"and the days ahead."
)
VERSION = "1.0.0" # optional; the store reads it
LICENSE = "MIT" # optional
HOMEPAGE = "https://example.com/weather" # optional
The owner sees LABEL and DESCRIPTION in the Capabilities pane.
A tool file
Each .py beside __init__.py that doesn't start with _ is a tool. It declares three constants and one async function:
from __future__ import annotations
import httpx
from aworg.tools.base import ToolContext, ToolError, ToolResult
NAME = "get_weather"
DESCRIPTION = (
"Look up the current weather and the forecast for a place, by name. "
"Give a town, city, postcode or landmark."
)
INPUT_SCHEMA = {
"type": "object",
"properties": {
"place": {"type": "string", "description": "Where to look up."},
"days": {"type": "integer", "description": "Days of forecast, 0 to 7."},
},
"required": ["place"],
}
async def run(context: ToolContext, place: str, days: int = 3) -> ToolResult:
if not place.strip():
raise ToolError("get_weather needs a place to look up.")
async with httpx.AsyncClient(timeout=20) as client:
...
return ToolResult(
text="Kyoto: 18°C, light rain ...", # what the model reads
summary="18°C, light rain", # the one-line version shown in the interface
payload={"raw": "..."}, # the full data, for the owner
)
- NAME is what the model calls. Keep it unique;
service_verbworks well. - DESCRIPTION is what the model reads to decide whether to call it. Say what it does, what to give it and what comes back.
- INPUT_SCHEMA is JSON Schema for the arguments. They arrive as keyword arguments to
run. rungets aToolContextfirst and returns aToolResult.- Raise
ToolErrorwith a sentence the model can act on ("No place called 'Daytn' was found. Check the spelling.") rather than letting a traceback escape.
The store reads NAME, DESCRIPTION and LABEL without running your code, the same way AWORG does, so they must be plain string literals, not built from function calls or f-strings.
Cleaning up on reload
AWORG reloads a capability when its files change. Before dropping your modules, it calls unload() in any of them that defines one, sync or async. If your tool keeps something alive between calls, such as a browser, a connection or a subprocess, close it there, or it's orphaned when the new version loads:
async def unload() -> None:
await _client.aclose()
Files your capability creates in its own folder (a downloaded binary, a cache) are kept when aworg get installs a new version. Only what the store shipped is replaced.
The rules of an installed capability
- Import absolutely.
from aworg.tools.base import ..., notfrom ..base import .... Your folder lives in the owner's home, not inside the package. - It runs as the Aworg. Your code loads into AWORG's process, with its interpreter and its permissions. Nothing sandboxes it. That's what makes tools powerful, and it's why owners are told to read tools before installing them. Keep yours short enough to read.
- Use what AWORG has, or bring your own.
httpxis always there. Anything else, you have to vendor into your folder or install at run time. The Chromium capability, for example, downloads its browser with aninstall_enginetool rather than shipping it. - Don't try to hide.
INTERNALandREQUIREDare reserved for AWORG's own capabilities. The store refuses packages that declare them, and AWORG ignores them. - You can't replace a built-in.
filesystem,shell,http,application,delegation,journal,knowledgeandplanningare taken.
What the context gives you
context.paths.workspaceis the Living Workspace, the application's files.context.paths.homeis the Aworg's home,~/.aworg. Keep large downloads outside your capability folder so a reinstall doesn't throw them away.context.hosthas facts about the machine: OS, Python, CPU and so on.context.progress(fraction, detail)reports how far a slow tool has got.context.result_limitis the most text the model can take back. Trim to fit.
Images
A tool can show the model a picture by returning images=[{"media_type": "image/png", "data": "<base64>"}] in its ToolResult, alongside the text.
Try it locally
cp -r weather ~/.aworg/capabilities/
A running Aworg notices within seconds; no restart. Every time you save a change, the next message runs the new code. If yours doesn't appear in the Capabilities pane, AWORG shows the reason it refused it.
Publish it
Zip the folder and upload it. See Publish a package.