---
title: "Integrate the Go SDK"
url: "https://docs.caracal.run/guides/sdk-go/"
markdown_url: "https://docs.caracal.run/markdown/guides/sdk-go.md"
description: "Install the Go SDK, load a runtime profile, spawn agents with context.Context, delegate authority, and inject Caracal headers."
page_type: "page"
concepts: []
requires: []
---

# Integrate the Go SDK

Canonical URL: https://docs.caracal.run/guides/sdk-go/
Markdown URL: https://docs.caracal.run/markdown/guides/sdk-go.md
Description: Install the Go SDK, load a runtime profile, spawn agents with context.Context, delegate authority, and inject Caracal headers.
Page type: page
Concepts: none
Requires: none

---

Use the Go SDK in services and agents that need Caracal context propagation, agent sessions, delegation, and Gateway-aware HTTP clients.

## Install

```bash
go get github.com/garudex-labs/caracal/packages/sdk/go
```

## Connect

```go
package main

import (
	"context"
	"log"

	caracal "github.com/garudex-labs/caracal/packages/sdk/go"
)

func main() {
	client, err := caracal.New()
	if err != nil {
		log.Fatal(err)
	}

	if err := client.Spawn(context.Background(), func(ctx context.Context) error {
		headers, err := client.Headers(ctx)
		if err != nil {
			return err
		}
		_ = headers
		return nil
	}); err != nil {
		log.Fatal(err)
	}
}
```

`New()` loads `CARACAL_CONFIG`, a `caracal.toml` in the default config path, or environment variables.

## Use an HTTP client

```go
httpClient := client.Transport(nil)

err := client.Spawn(context.Background(), func(ctx context.Context) error {
	req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.example.com/tickets", nil)
	if err != nil {
		return err
	}
	_, err = httpClient.Do(req)
	return err
})
```

The transport injects Caracal envelope headers from `context.Context`. For explicit Gateway routing, use `GatewayRequest()`.

## Long-lived service agents

Daemons and workers that outlive a single request use `Service` instead of `Spawn`. It returns a handle you own: keep the session alive by calling `Heartbeat` on a timer and retire it with `Close`. A service session is reaped by the coordinator if it stops heartbeating before its lease expires.

```go
svc, err := client.SpawnService(context.Background(), caracal.ServiceOptions{
	Labels: []string{"billing-worker"},
})
if err != nil {
	return err
}
defer svc.Close(context.Background())

for running {
	if err := svc.Heartbeat(context.Background()); err != nil {
		return err
	}
	doWork(svc.Context)
	time.Sleep(30 * time.Second)
}
```

## Spawn a narrowed child

```go
err := client.Spawn(context.Background(), func(ctx context.Context) error {
	return client.Spawn(ctx, func(child context.Context) error {
		_, _ = client.Current(child)
		return nil
	}, caracal.SpawnOptions{
		Grant: caracal.Grant{
			Mode:        caracal.GrantModeNarrow,
			Scopes:      []string{"tickets:read"},
			Constraints: &caracal.DelegationConstraints{MaxHops: 1, Budget: 5},
			TTLSeconds:  600,
		},
	})
})
```

A plain `client.Spawn` runs the child under the application's authority. Set `SpawnOptions.Grant` to `caracal.GrantNarrow(...)` only when the child should hold a least-privilege subset, or `caracal.GrantNone()` for a child with no inherited authority. Use `Current(ctx)` to inspect the bound Caracal context and `Headers(ctx)` to project it to outbound HTTP headers.

## Troubleshooting

| Symptom | Check |
| --- | --- |
| Missing config error | Confirm the runtime profile or required environment variables. |
| `Headers` without context fails | Call inside `Spawn`, `Delegate`, or pass `RootOptions{AllowRoot: true}` intentionally. |
| Delegation fails | Ensure delegation runs from a context with an active agent session. |
| Gateway URL error | Confirm the runtime profile includes `gateway_url`. |

Related pages: [Protect a Go net/http Service](/guides/protect-nethttp/) and [Agent Delegation](/concepts/delegation/).
