microsoft/artifacts
> Fetch data assets into the kernel, transfer Python objects between servers, and publish output files to the user. Activate when working with data files, cross-server data movement, or when the user asks for downloads or exports.
npx skills add https://github.com/microsoft/agora-workbench --skill artifacts
Servers with a data catalog expose tools for finding available datasets:
search_data(query="temperature observations", domain="earthscience", top=5)
list_domains() # See all available data domains
get_artifact(artifact_id="...") # Get full metadata for a specific artifact
query_catalog(sql="SELECT name, domain, description FROM artifacts WHERE domain = 'powergrid'")
Not all servers have a data catalog. These tools (search_data,
list_domains, get_artifact, query_catalog) are registered only when the
server is configured with one — and unlike most tools they are not prefixed
with the server name. If they are not in the server's tool list, the server has
no catalog: skip them and use the data references the user provides directly.
Configuring a catalog is a server-author/deployment task, not something you can
do from the client side.
When present, results include the artifact's storage_uri, domain,
source_type (local or blob), description, and content_type. Use these
tools to find the correct asset reference before using it in code.
Asset references use a type-tagged format where the tag indicates the storage
backend and the inner value is the artifact identifier to resolve:
| Tag format | Storage location | Example |
|------------|------------------|---------|
| <blob>{artifact_id}</blob> | Azure Blob Storage (resolved server-side from the artifact ID) | <blob>abc123</blob> |
| <local>/data/grid/lines.geojson</local> | Server local filesystem | <local>/data/grid/lines.geojson</local> |
For blob assets, use the artifact id returned by search_data / get_artifact inside the <blob>…</blob> tag (not a blob path).
Embed these tagged references as string literals in your code — the server
automatically detects them, downloads the file to a local cache, and replaces
the literal with a Path variable:
# The tag tells the server which asset to resolve; it is replaced with a local Path at runtime
df = pd.read_csv("<blob>abc123</blob>")
network = load_network("<local>/data/grid/texas_grid.nc</local>")
You do not need to handle authentication or downloads — the server's managed
identity fetches the data on your behalf.
Move Python objects between servers without serializing through agent context:
{server}_send(data_ref="molecule_data", to="gis", name="input_data")
Use the logical server name (e.g., "gis", "chemistry") as the to
parameter. The server resolves this to the correct internal address based on
its deployment configuration.
If the transfer fails with a connection or trust error, the error message will
indicate the expanded URL and what went wrong. Surface this error to the user —
it is an operator configuration issue (the environment variables
OBJECT_TRANSFER_TRUSTED_HTTP_HOSTS or OBJECT_TRANSFER_ALLOWED_HOSTS may
need to be adjusted by the deployment operator).
Do not attempt to guess deployment URLs, ports, or hostnames — the logical name
is the correct default in all environments.
| Parameter | Usage |
|-----------|-------|
| data_ref | Kernel variable name or filename in AGORA_OUTPUT_DIR to transfer |
| to | Logical destination name (e.g., "gis", "blob", "user", "local") |
| name | Variable name at destination (defaults to data_ref if empty) |
| path | Full destination path for blob/local publishers (e.g., "outputs/report.csv") |
| session_id | Target session ID (if empty, uses the caller's first active session on target) |
To produce downloadable files for the user:
execute_{server}_code.The kernel pre-injects a helper and a variable for this — never resolve the
path to an absolute string yourself:
# ✓ Preferred — agora_output() builds the path for you, no f-string needed
df.to_csv(agora_output("results.csv"), index=False)
# ✓ Also correct — use the pre-injected variable name directly
df.to_csv(f"{AGORA_OUTPUT_DIR}/results.csv", index=False)
# ✓ Also correct — read AGORA_OUTPUT_DIR from the environment
import os
df.to_csv(f"{os.environ['AGORA_OUTPUT_DIR']}/results.csv", index=False)
# ✗ WRONG — do not hardcode the resolved path (triggers path guardrails)
df.to_csv("/tmp/agora_output_abc123/results.csv", index=False)
Both agora_output("name") and the bare AGORA_OUTPUT_DIR symbol are
injected automatically — no import is required to use them.
{server}_send(data_ref="results.csv", to="user")
| Destination | Publisher | Use case |
|-------------|-----------|----------|
| "user" | GuiPublisher | Browser download for the user |
| "blob" | BlobPublisher | Azure Blob Storage |
| "local" | LocalFilePublisher | Local filesystem |
Not all destinations are available on every server. Available destinations
depend on the server's configured publishers. If you use an unsupported
destination, the tool returns an error listing the available options. When
unsure, try "user" first — the GuiPublisher is always available.
AGORA_OUTPUT_DIR — files elsewhere stay inside the container.agora_output("name") or the AGORA_OUTPUT_DIR variable — never hardcode the resolved absolute path.data_ref must match a file already written to AGORA_OUTPUT_DIR (for file-based sends).Take microsoft/artifacts from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.