Skip to main content
Build and ship your first Autonomy application, step-by-step. This walkthrough will help you understand how the parts of a simple Autonomy app fit together.
  1. Follow the initial instructions to Get Started with Autonomy.
  2. Then continue on to the following steps:

Step 1: Create a new directory

Create a new directory for your app.
mkdir hello && cd hello
All subsequent commands should be run from inside this hello directory.

Step 2: Create autonomy.yaml

Create a file named autonomy.yaml in the hello directory with the following content:
autonomy.yaml
name: hello
pods:
  - name: main-pod
    public: true
    containers:
      - name: main
        image: main
This configuration file defines a Zone in Autonomy Computer. Think of a Zone as your app’s dedicated infrastructure. The Autonomy Computer will provision everything needed to run it.
  • name: hello - The zone’s name (must be ≤ 10 characters, using only a to z and 0 to 9).
  • pods - List of pods to create in this zone (a pod is a group of containers that run together).
  • public: true - Serve the http server on port 8000 of this pod on a public address over HTTPS.
  • containers - List of containers in the main-pod.
  • image: main - Create main container using the image defined in images/main.

Step 3: Create the image directory

Create the directory structure for your container images:
mkdir -p images/main
Your project structure now looks like:
hello/
├── autonomy.yaml
└── images/
    └── main/

Step 4: Create a Dockerfile for the main image:

Create images/main/Dockerfile with the following content:
images/main/Dockerfile
FROM ghcr.io/build-trust/autonomy-python
COPY . .
ENTRYPOINT ["python", "main.py"]
  • The base image is pre-installed with Python and the Autonomy Framework.
  • Copy all files from images/main/ into the container.
  • Run main.py when the container starts.

Step 5: Create the application code:

Create images/main/main.py with the following content:
images/main/main.py
from autonomy import Agent, Model, Node

async def main(node):
  await Agent.start(
    node=node,
    name="henry",
    instructions="You are Henry, an expert legal assistant",
    model=Model("claude-sonnet-4-v1")
  )

Node.start(main)
This Python module:
  1. Imports modules from the Autonomy Framework - Agent, Model, and Node
  2. Defines an async main function that:
    • Starts an agent named “henry”
    • Gives it instructions to act as a legal assistant
    • Configures it to use Claude Sonnet 4 model.
  3. Starts an Autonomy Node - This creates the actor runtime that hosts your agent. It also starts an http server on port 8000 with a set of built-in APIs to interact with your agent.
Built-in Tools: Your agent automatically has access to a set of built-in tools:
  • get_current_time_utc - get current time in utc.
  • get_current_time - get current time in any timezone.

Step 6: Create a web interface

Create images/main/index.html with the following content:
images/main/index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body { margin: 10% 15%; line-height: 1.8; overflow-y: scroll; overflow-x: hidden; font: 21px "Courier New", Courier, monospace; padding: 0; }
    main { max-width: 1080px; margin: 0 auto; padding: 3rem 1rem; }
    pre { padding-top: 30px; box-sizing: border-box; white-space: pre-wrap; overflow-wrap: break-word; }
    textarea { width: 100%; max-width: 1080px; box-sizing: border-box; border: 1px solid #e9e9e9; border-radius: 5px; box-shadow: 2px 2px 10px #f4f4f4; font-size: inherit; padding: 1rem; display: block; height: calc(3 * 1.8em + 14.8px); }
  </style>
  <title>Henry - Legal Assistant</title>
</head>
<body>
  <main>
    <textarea id="in" autofocus placeholder="How can I help you..."></textarea>
    <pre id="out"></pre>
  </main>

  <script>
  async function appendCharByChar(text, delay = 5) {
    for (const char of text) {
      out.textContent += char;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }

  async function processLine(line) {
    if (line.trim()) {
      const parsed = JSON.parse(line);
      for (const message of parsed.messages) {
        if (message && message.content && message.content.text) {
          await appendCharByChar(message.content.text);
        }
      }
    }
  }

  async function send(message) {
    const input = document.getElementById("in");
    input.disabled = true;

    const out = document.getElementById("out");
    out.textContent = "";

    const response = await fetch("/agents/henry?stream=true", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: message }),
    });

    const decoder = new TextDecoder();
    let buffer = "";

    for await (const chunk of response.body) {
      buffer += decoder.decode(chunk, { stream: true });
      const lines = buffer.split('\n');
      buffer = lines.pop();

      if (!out.textContent) input.value = "";
      for (const line of lines) await processLine(line);
    }
    await processLine(buffer);

    input.disabled = false;
    input.focus();
  }

  document.getElementById("in").addEventListener("keydown", async e => {
    if (e.key === "Enter" && !e.shiftKey && !e.target.disabled && e.target.value.trim()) {
      e.preventDefault();
      await send(e.target.value);
    }
  });
  </script>
</body>
</html>
This HTML file creates a simple chat interface that:
  1. Display an input text area where users type messages.
  2. Call the agent’s streaming API at /agents/henry?stream=true.
  3. Show responses using a typewriter effect character by character.
  4. Handle streaming JSON responses from the agent.
The Autonomy Node’s default http server automatically serves index.html at the root of the pods URL. The complete code structure now looks like:
hello/
├─ autonomy.yaml
└─ images/
    └─ main/
        ├─ Dockerfile
        ├─ main.py
        └─ index.html

Step 7: Enroll with your cluster

Connect your workstation to your cluster in Autonomy Computer:
autonomy cluster enroll --no-input
This command will:
  1. Display a code.
  2. Open your browser for authentication.
  3. Complete enrollment once you sign in.
You only need to do this once per workstation.

Step 8: Deploy your app

Deploy your zone to the Autonomy Computer:
autonomy zone deploy
This command will:
  1. Build the container image.
  2. Push the image to your cluster.
  3. Deploy the zone with its pods and containers.
The deployment takes a couple of minute to fully start.

Step 9: Your zone’s URL

Your zone’s URL follows this pattern:
https://${CLUSTER}-${ZONE}.cluster.autonomy.computer
To find your cluster and zone names, run:
autonomy cluster show
autonomy zone list
For example, if your cluster is a25bff50 and zone is hello, your URL is:
https://a25bff50-hello.cluster.autonomy.computer

Step 10: Test the Agent API

Test that your agent is responding to API calls: Non-streaming request:
curl --request POST \
  --header "Content-Type: application/json" \
  --data '{"message":"What is a contract?"}' \
  "https://${CLUSTER}-${ZONE}.cluster.autonomy.computer/agents/henry"
Streaming request:
curl --request POST \
  --header "Content-Type: application/json" \
  --data '{"message":"What is a contract?"}' \
  "https://${CLUSTER}-${ZONE}.cluster.autonomy.computer/agents/henry?stream=true"
Replace ${CLUSTER} and ${ZONE} with your actual cluster and zone names.

Step 11: Open your app in a browser

Open your web interface:
https://${CLUSTER}-${ZONE}.cluster.autonomy.computer
You should see the chat interface. Try asking Henry questions like:
  • “What are the key elements of a contract?”
  • “What is consideration in contract law?”
  • “Explain breach of contract”

Step 12: View logs (optional)

To view logs from your deployed zone, create a private encrypted portal to the logs server in your zone.
autonomy zone inlet --to logs
This will create a private link to the logs server on localhost and display the address http://127.0.0.1:32101. Open it in the browser to see streaming logs for all container in the zone.

Common Issues and Solutions

Zone names must be 10 characters or less, using only a to z and 0 to 9. Edit autonomy.yaml and change the name field to something shorter.
Start Docker Desktop or your Docker daemon. Verify with docker ps.
Run source "$HOME/.autonomy/env" to add the command to your PATH.
Wait a couple of minutes after deployment.
Check the logs using the portal method shown in Step 12. Look for errors in the pod startup or agent initialization.
Verify that index.html is in images/main/ and was included in the container build. Redeploy with autonomy zone deploy.

Update Your App

To make changes to your app:
  1. Edit your files (e.g., change the agent instructions in main.py).
  2. Redeploy with autonomy zone deploy.
  3. Wait a couple of minutes for the new version to be ready.
  4. Test your changes.
Each deployment deploys a new version of your zone and replaces the old version.

Delete the zone

When you’re done experimenting, delete your zone to free up resources:
autonomy zone delete