Skip to main content
Store, list, and load resources and templates, including media in and out. The runtime stores content behind a storage provider and loads it through the resource manager — by storage id, by URL, or from a raw file, as text or as media. A template is one kind of stored resource: content the runtime renders with kwargs. This guide covers managing that content from the CLI.

Wire a storage provider

Storage is dead by default — the skeleton ships no provider. Name a provider module in the manifest to turn the storage surface on:
examples/storage/storage_provider_manifest.yaml
The concrete provider (a local filesystem or an object store) ships as a separate plugin package. With none wired, tai storage info reports the empty state and every CRUD door answers a 501.

The raw resource surface

tai storage is the raw provider-resource surface — upload, list, stat, download, and delete resources by id:
Upload takes exactly one of --text (stored verbatim) or --base64 (decoded to bytes); an existing id is overwritten. A resource id must be a relative path with no .. segment. The full subcommand set:
examples/storage/storage_help.sh

Upload and list templates

Upload a local file as a template under a key, then list what is stored.
Read one back with its input schema:

Render a template

Render a stored template by id, or inline content, passing render kwargs with the repeatable --kw key=value or a JSON --kwargs object.
Clear the render cache after changing a template out of band:

Load content in and out

The resource manager loads content by storage id or URL and returns it as text or media. To load a stored resource or a URL from within a tool run, enable the file-loader built-in tool, which returns a file’s content as text or media:
manifest.yml
The resource-management capabilities — upload_template, get_resource_by_id, and list_resources — are operations. Each is always a route and a CLI command, and projects as an MCP tool when api_tools allows it, so a tool run or an MCP client reaches the same surface the CLI does:
get_resource_by_id takes a resource_id and optional render kwargs; with no kwargs it returns the loaded content as-is, and with kwargs (any object, including {}) it renders text as a Jinja template, refusing media with a 400. list_resources answers {"resources": [...]} — the sorted resource ids from the active provider — and upload_template takes a path and returns {"path", "uploaded": true}.
The storage provider is a plugin, so where content lives is swappable. The text and media surfaces are the same regardless of backend — a text-only backend satisfies the binary surface through built-in bridging. To build a backend, see Author a storage provider.

See also