Skip to main content

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.
  • wash 2.7.0 or later, the command-line tool that builds and pushes components.
  • Rust 1.94 or later, plus the wasm32-wasip2 compile target.
  • Optional: a coding agent, such as Claude Code or Codex, if you'd rather it run the build for you.
tip

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.

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-agent

The 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 build

Keep 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.wasm

That 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.wasm

Here 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.

If oci.localhost does not resolve

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.

2. Add the harness to Desktop​

  1. In Desktop, select Agents under AI & agents in the sidebar. If you already have sessions, select New at the top of the session list.
  2. Select the agent chip next to the message box. It shows the current agent's name, such as Goose.
  3. Choose Add a new agent…. The Add a new agent dialog opens.
  4. Fill in:
    • Name: Navigator
    • Image: oci.localhost:8200/examples/minimal-agent:0.1.0
  5. 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​

  1. 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.

  2. In the message box, type:

    Hello! What can you do?
  3. 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​

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.wasm

Then point Desktop at the new build:

  1. Select Settings in the sidebar, then Sandboxed agents under Agent workspace.
  2. In the Your agents card, select Edit next to Navigator.
  3. Change Image to oci.localhost:8200/examples/minimal-agent:0.1.1 and 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:

  1. Select New. Under the message box, select Tool settings….

  2. Select Add tools yourself…. The Add tools yourself dialog opens.

  3. In Search tools, type ISS, then select Add next to ISS tracker. Its card says what it reaches: api.wheretheiss.at.

  4. Select Done.

  5. 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.

The agent can find tools too

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​

  1. If the session details panel is not open, select Show session details in the session header.
  2. 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.
  3. Select ISS tracker to open it. It shows the names the agent calls it by (The agent calls it as iss_position and 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​