> ## Documentation Index
> Fetch the complete documentation index at: https://docs.komodor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Go SDK

> Build an agent worker in Go — one blocking call manages registration, claiming, and telemetry, with no Python in the container.

The Go SDK builds agent workers in Go: register a worker, receive work, and stream runs, spans, and
results to the control plane with no Python in the container. This page covers the worker loop,
configuration, what the agent advertises about itself, and the telemetry surface available inside a
handler.

## Install

```bash theme={null}
go get github.com/komodorio/agentops-go
```

Requires Go 1.26 or newer.

## A minimal worker

```go theme={null}
package main

import (
	"context"
	"errors"
	"log"
	"os/signal"
	"syscall"

	"github.com/komodorio/agentops-go"
)

func main() {
	w, err := agentops.New(agentops.Config{
		Agent: agentops.Agent{Name: "my-worker", Version: "0.1.0"},
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
	defer stop()

	err = w.Run(ctx, func(ctx context.Context, run *agentops.Run) (map[string]any, error) {
		span := run.Span("investigate", agentops.KindAgent)
		defer span.End()

		run.Message("assistant", "looking into it…")

		return map[string]any{"text": "done"}, nil
	})
	if err != nil && !errors.Is(err, context.Canceled) {
		log.Fatal(err)
	}
}
```

`Run` blocks and manages the whole lifecycle — register, heartbeat, hold the reverse channel, claim
work, dispatch it — until the context is cancelled. Returning the output map completes the run;
returning an error fails it, and a panic is recovered into a run failure.

<Note>
  **Output convention, same as every other surface:** a `text` key in the returned map is the run's
  descriptive output — what a person sees as the answer — and every other key is structured detail.
</Note>

## Configuration

`Config` fields fall back to environment variables when unset:

| Field      | Environment variable    | Required | Notes                                                                            |
| ---------- | ----------------------- | -------- | -------------------------------------------------------------------------------- |
| `BaseURL`  | `AGENTOPS_BASE_URL`     | Yes      | The control-plane URL                                                            |
| `AgentID`  | `AGENTOPS_AGENT_ID`     | Yes      | The agent's friendly name, sent as its identifier                                |
| `Token`    | `AGENTOPS_WORKER_TOKEN` | Yes      | The worker token it authenticates with                                           |
| `WorkerID` | `AGENTOPS_WORKER_ID`    | No       | Defaults to the agent name plus the hostname; give replicas distinct, stable ids |

Two more are worth knowing:

* **`MaxConcurrent`** (`AGENTOPS_MAX_CONCURRENT`, default 1) — how many runs the worker handles at
  once. One at a time is the default; raise it for I/O-bound agents whose runs can overlap, and each
  run still gets its own `Run` and its own goroutine.
* **`DrainTimeout`** (default 30s) — how long an in-flight run may continue after shutdown begins
  before its context is cancelled.

Cluster placement is reported automatically from `AGENTOPS_CLUSTER_NAME`, `AGENTOPS_NAMESPACE`, and
`AGENTOPS_POD_NAME` when they are set.

## What the agent advertises

`Config.Agent` is the worker's self-description, sent once at registration and surfaced in the
fleet:

| Field                            | Purpose                                                                                                                                                                                   |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Name`, `Description`, `Version` | Identity in the fleet. `Version` defaults to `dev`.                                                                                                                                       |
| `Labels`                         | Fleet labels, which [label-scoped grants](/security-and-governance/identity-and-access/roles-permissions) match against                                                                   |
| `Model`                          | The primary model the agent uses                                                                                                                                                          |
| `DefaultInput`, `InputSchema`    | Seeds the invoke form, and declares the input accepted                                                                                                                                    |
| `Skills`                         | Instruction documents — markdown, not invocable                                                                                                                                           |
| `UseCases`                       | Invocable use cases, each with its own input and output schema; the platform turns each into a tool on the agent's own tool surface. See [Use cases](/manage-your-agents/build/use-cases) |
| `Triggers`                       | How the platform should invoke the agent automatically, synced at registration                                                                                                            |

<Note>
  `Skills` and `UseCases` are easy to confuse and are not the same thing. A skill is know-how the
  agent reads; a use case is an entry point something else can call, and a handler branches on
  `run.UseCase()` to tell which one it was invoked for.
</Note>

## Inside a handler

| Call                                                                | What it does                                                                                                  |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `run.Input`                                                         | The invocation payload                                                                                        |
| `run.Secrets`                                                       | Run-scoped credentials, delivered for this run                                                                |
| `run.Span(name, kind)`                                              | Open a trace span; `End()` or `Fail(err)` it                                                                  |
| `run.Message(role, content)`                                        | Stream a message to the run timeline                                                                          |
| `run.Log(level, message)`                                           | Stream a log line                                                                                             |
| `run.ToolCall(id, name, args)` / `run.ToolResult(id, name, result)` | Record a tool invocation and its result, matched by id, rendered as tool cards in the transcript              |
| `run.RecordUsage(usage)`                                            | Report token and cost usage per model call; calls accumulate and the total is attached when the run completes |
| `run.UpdateOutput(map)`                                             | Stream a partial output snapshot before the run finishes                                                      |
| `run.SaveArtifact(ctx, name, content, mimeType)`                    | Persist a text artifact on the run and get its id back                                                        |
| `run.Snapshot` / `run.SetSnapshot(map)`                             | Read and write the session-state envelope used to resume a later run                                          |

<Warning>
  The session snapshot is sent as-is and is **not** secret-masked — masking it would corrupt the state
  it exists to preserve. Keep credentials out of it.
</Warning>

## Next steps

<CardGroup cols={2}>
  <Card title="Python SDK" href="/developer-tools/python-sdk">
    The same contract in Python, with framework adapters.
  </Card>

  <Card title="Agent identity" href="/security-and-governance/identity-and-access/agent-identity">
    Where the worker token comes from.
  </Card>

  <Card title="Triggers & schedules" href="/manage-your-agents/build/triggers-schedules">
    What a declared trigger becomes on the platform side.
  </Card>

  <Card title="Runs & evidence" href="/manage-your-agents/run/runs-evidence">
    Where the spans and messages you stream end up.
  </Card>
</CardGroup>


## Related topics

- [Python SDK](/developer-tools/python-sdk.md)
- [Build from scratch](/manage-your-agents/build/build-from-scratch.md)
- [Interfaces](/get-started/interfaces.md)
- [Overview](/developer-tools/overview.md)
- [Data handling & redaction](/security-and-governance/architecture-considerations/data-handling-redaction.md)
