pkg/agents/skills.Store supports complete-bundle Put, Get, paginated List, and idempotent Delete. Built-in stores use files or S3; implement the interface for a database or service. See Skills to attach the library to an agent.
Connect storage and the UI
Importpkg/agents/skills, pkg/agents/prompts, pkg/agui, and pkg/agui/web. With model configured:
web.Handler in your authentication middleware and set agui.WithNamespaceResolver. Share the same store with the agent client and HTTP handler.
Bundle format and limits
A bundle contains one rootSKILL.md with a name and description, plus relative resource paths. Limits are 100 files and 10 MiB of decoded content. HTTP requests are limited to 20 MiB including encoding overhead. Parent-folder uploads containing several skills and ZIP extraction are unsupported.
File storage uses one JSON file per bundle and atomic replacement. Its format is separate from the ordinary skill directories read by NewDirSource. S3 uses one JSON object per bundle. Concurrent replacements use last-writer-wins semantics.
Use S3
Supply an application-owned AWS SDK v2 S3 client:Management routes
Withweb.Handler, these routes live under /api/agui:
POST accepts multipart files with relative filenames or JSON such as
{"files":{"SKILL.md":"<base64>"}}. PUT accepts JSON. Page sizes are 1–200. Invalid content returns 400, namespace denial 403, missing content 404, reserved global names 409, oversized uploads 413, and storage failures 500.
For a standalone API, use skills.NewHandler(store, skills.WithNamespaceResolver(resolve)). Without a resolver, the standalone handler denies requests. skills.WithReservedNames can supply protected global names. Management namespaces come from authenticated requests, not payload fields.
Cache listings
Both built-in stores cache listing pages with a private memory cache and a one-minute TTL by default. Content reads still use storage. Importpkg/cache for the shared byte-oriented cache implementations:
cache.NewRedisCache(redisClient, prefix) returns a cache and error. Share the same cache and backing storage across replicas for shared invalidation. Uploads and deletes invalidate the namespace’s listing pages. Direct filesystem or S3 writes become visible after TTL expiry. Use WithCache(nil) or WithCacheTTL(0) to bypass caching.
The custom skills.KeyValueStore contract is Get(ctx, key) ([]byte, bool, error), Set(ctx, key, value, ttl) error, and Delete(ctx, key) error. Cache failures are returned; a failed invalidation can be reported after the underlying write succeeded.