Quickstart: build your first agent
In this quickstart, you'll build a small agent in Rust, by hand or with a coding agent, and run it in Cosmonic Desktop. You'll watch it stream a reply, change how it behaves, give it a tool, and then look at exactly what it could reach and what it called.
Requirements
- Access to a model that supports tool calling. Either Ollama on your machine with a model pulled, or an API key for Anthropic, OpenAI, or an OpenAI-compatible service.
- Cosmonic Desktop 0.5.32 or later. You'll use the Agents page under AI & agents in the sidebar.
wash2.7.0 or later, the command-line tool that builds and pushes components.- Rust 1.94 or later, plus the
wasm32-wasip2compile target. - Optional: a coding agent, such as Claude Code or Codex, if you'd rather it run the build for you.
Desktop can install wash and Rust for you. Accept its Install build toolchain offer on first run, or install them later from Settings → Toolchain. Desktop doesn't change your shell's PATH, so run the commands below, or your coding agent, in Desktop's built-in terminal, or on macOS and Linux add the tools to your own shell first:
export PATH="$HOME/.cargo/bin:$HOME/.local/bin:$PATH"To install them yourself instead, follow the wasmCloud installation guide, install Rust with rustup, and add the target with rustup target add wasm32-wasip2.
1. Build the harness
You'll start from minimal-agent, a small reference agent harness in the public agent-sdk repository. An agent harness is the loop at the center of an agent: it sends the conversation to a model, runs the tools the model asks for, and repeats until it has an answer.
Build it yourself, or hand the build to a coding agent such as Claude Code or Codex.
- By hand
- With a coding agent
Get the harness
Clone the release this quickstart was written against, and move into the example:
git clone --depth 1 --branch minimal-agent-v0.3.1 \
https://github.com/cosmonic-labs/agent-sdk.git
cd agent-sdk/components/minimal-agentThe harness is about 2,000 lines of Rust in src/. You'll change one line of it in step 4.
Build it
The harness is built against the cosmonic:agent interfaces, which are published to ghcr.io the way a library is published to crates.io. Tell wash where to find them, then build:
export WKG_CONFIG_FILE=$PWD/../../wit/wkg-registries.toml
wash buildKeep the export in place for the rest of the quickstart, because every wash build needs it. The last line of output names what you built:
Successfully built component at: .../target/wasm32-wasip2/release/minimal_agent.wasmThat file is a component: a compiled WebAssembly program, about 330 KB, that can only call the interfaces it imports. It plays the part a container image plays for a container.
Inspect what it can reach
Before you run it, look at everything it is able to call:
wash inspect target/wasm32-wasip2/release/minimal_agent.wasmHere are the interesting lines:
import cosmonic:agent/models@0.4.2;
import cosmonic:agent/chat@0.4.2;
import cosmonic:agent/session@0.4.2;
import cosmonic:agent/tools@0.4.2;
...
export cosmonic:agent/run@0.4.2;It can open a model by name, chat with it, keep its conversation in a session and call tools, all through the host. The rest of the list is type definitions plus the clock, random numbers and console output that Rust's standard library brings in. There is no wasi:http/client, no wasi:sockets and no wasi:filesystem, so it has no way to make a request or open a file.
The one export, run, is how the host hands it a message.
Push it to Desktop's registry
Desktop runs agents from images in an OCI registry, the same kind of registry as Docker Hub. Desktop has one built in at oci.localhost:8200. Push your build there:
wash oci push --insecure oci.localhost:8200/examples/minimal-agent:0.1.0 \
target/wasm32-wasip2/release/minimal_agent.wasm--insecure is there because the built-in registry speaks plain HTTP on your own machine.
Use oci.localhost.cosmonic.sh:8200 in place of oci.localhost:8200, here and in step 2. It is the same registry under a public name that points to your own machine.
Paste this prompt into your coding agent, in an empty folder:
Build the minimal-agent reference agent harness from the Cosmonic Agent SDK and
push it to Cosmonic Desktop's local registry. Clone
https://github.com/cosmonic-labs/agent-sdk at the tag minimal-agent-v0.3.1 and
work in components/minimal-agent. Don't change the code. Build it with
WKG_CONFIG_FILE=$PWD/../../wit/wkg-registries.toml wash build, run wash inspect
on the component it builds and show me its imports and exports, then push it as
oci.localhost:8200/examples/minimal-agent:0.1.0 with wash oci push --insecure.
If oci.localhost does not resolve, use oci.localhost.cosmonic.sh:8200 instead.
Don't add any network or filesystem imports.The agent clones the harness, builds a component of about 330 KB, and pushes it to the registry built into Desktop. A component is a compiled WebAssembly program that can only call the interfaces it imports. It plays the part a container image plays for a container.
Check the imports it shows you. You should see cosmonic:agent/models, chat, session and tools, plus the clock, random numbers and console output that Rust's standard library brings in. There should be no wasi:http/client, no wasi:sockets and no wasi:filesystem, so the harness has no way to make a request or open a file. Its one export, run, is how the host hands it a message.
A coding agent like Claude Code or Codex runs on your machine with your permissions. What it builds runs in the sandbox, with only the access the host grants it.
2. Add the harness to Desktop
- In Desktop, select Agents under AI & agents in the sidebar. If you already have sessions, select New at the top of the session list.
- Select the agent chip next to the message box. It shows the current agent's name, such as Goose.
- Choose Add a new agent…. The Add a new agent dialog opens.
- Fill in:
- Name:
Navigator - Image:
oci.localhost:8200/examples/minimal-agent:0.1.0
- Name:
- Select Check and save.
Desktop reads the image's imports, the list you saw in step 1, and refuses an agent that imports the network or the filesystem. Yours passes, and Navigator is now the selected agent.
Desktop saves the image pinned to the digest it just checked, so the agent always runs exactly those bytes.
3. Start a session and watch it stream
-
Select the model chip next to the message box. It reads Choose a model until you pick one. Choose a source in the first dropdown (such as Ollama on this machine, or Add a source… to enter an API key), choose a model in the second, then select Done.
-
In the message box, type:
Hello! What can you do? -
Select the send arrow in the message box.
Desktop starts a session: a new workload that runs your agent, with a conversation the host keeps for it. The reply streams in as the model writes it. It may mention things from your tool catalog, because the agent can search the catalog by default. The session doesn't have those tools unless you add them.
The model call did not come from your agent. It asked the host for the model named default, and Desktop made the call to the source you chose, with a key your agent never saw.
4. Change how your agent behaves
- By hand
- With a coding agent
The harness's instructions to the model are a constant near the top of src/conversation.rs:
const SYSTEM_PROMPT: &str = "You are a small agent running as a sandboxed WebAssembly \
component. You have no network access of your own: you reach the outside world only \
through the tools you are given, and you may have none. Use a tool when it helps, and \
never claim a result a tool did not return. Answer concisely.";Give it a personality you will recognize. Replace the last line with:
never claim a result a tool did not return. Answer concisely, as a ship's navigator, \
and end every reply with a nautical sign-off.";Rebuild, and push under a new tag:
wash build
wash oci push --insecure oci.localhost:8200/examples/minimal-agent:0.1.1 \
target/wasm32-wasip2/release/minimal_agent.wasmThe harness's instructions to the model are a constant, SYSTEM_PROMPT, near the top of src/conversation.rs. Ask your coding agent to change it and push a new build under a new tag:
In components/minimal-agent, change SYSTEM_PROMPT in src/conversation.rs so the
agent answers concisely as a ship's navigator and ends every reply with a
nautical sign-off. Change nothing else. Rebuild with the same wash build
command, and push it as oci.localhost:8200/examples/minimal-agent:0.1.1 with
wash oci push --insecure.Then point Desktop at the new build:
- Select Settings in the sidebar, then Sandboxed agents under Agent workspace.
- In the Your agents card, select Edit next to Navigator.
- Change Image to
oci.localhost:8200/examples/minimal-agent:0.1.1and select Check and save.
Go back to Agents, select New, check that Navigator is selected, and start a session with any message. The reply now ends with a nautical sign-off. Sessions you started before keep the image they started with, and Desktop lists them as Unrecognized agent.
5. Give your agent a tool
Your agent can call tools, but so far no session has given it any. Start one that has a tool:
-
Select New. Under the message box, select Tool settings….
-
Select Add tools yourself…. The Add tools yourself dialog opens.
-
In Search tools, type
ISS, then select Add next to ISS tracker. Its card says what it reaches:api.wheretheiss.at. -
Select Done.
-
Type this message and select the send arrow:
Where is the International Space Station right now?
The agent calls the tool, and the reply should give the station's latitude and longitude, with a sign-off.
The tool is its own sandboxed component in the session. It can reach api.wheretheiss.at and nothing else. Your agent still has no network: it asked the host to call the tool, and the host made the call.
Let the agent find tools is on by default in Tool settings…. Ask a session for something none of its tools can do, and the agent can search your tool catalog and ask to add a tool. Desktop shows you what that tool would reach, and nothing is added unless you select Allow.
6. See what your agent could reach and what it called
- If the session details panel is not open, select Show session details in the session header.
- Find This session can…. It lists what the session's tools let it do, one line per kind of reach. You'll see Reach
api.wheretheiss.at, with ISS tracker under it. - Select ISS tracker to open it. It shows the names the agent calls it by (The agent calls it as
iss_positionand the others), its version and image digest, and every call it made.
The top of the panel shows the agent, the model and what the session has spent, and says The agent itself has no network access. That panel is the whole story of the session: the agent reached a model through the host, and one tool reached one host.
What you built
- An agent harness with no reach of its own. Its imports allow a model by name, a session and tools, and nothing else. Desktop checked that before saving it.
- A behavior you changed in code. The instructions live in your Rust, and each build is pinned by digest, so you always know which code a session runs.
- A tool with its own boundary. The tool reached one host; the agent reached none.
Note: The sandbox limits what the agent and its tools can reach. It does not make the model's answers correct, and it does not stop a model from being misled by text it reads.
Next steps
- Anatomy of an agent explains what happened during each run.
- Give an agent a tool covers folder tools and host approvals.
- Write a typed tool builds a tool of your own in Rust.
- Run an agent on Cosmonic Control runs the same agent on Kubernetes.
- Agent sandboxes covers ready-made agents built on the same interfaces, on Desktop and on Control.