Popular starting points. Use Tab or arrow keys to browse results.

Skip to content
Aten SecurityThoth docs

Go SDK

Full reference for the Thoth Go SDK — Config, NewClient(), WrapTool(), WrapToolFunc(), InstrumentAnthropic(), InstrumentOpenAI(), StartSession(), Session, PolicyViolationError, StepUpRequiredError.

Reference examples

Start with Your first governed agent for a complete runnable example and tested package version. Examples here focus on individual APIs and may depend on callbacks or clients defined by your application. Replace illustrative tenant and endpoint values with the supplied connection details; agree on server policy before using real tools.

Installation

go get github.com/atensecurity/thoth-go

Go 1.25+ required. The SDK has no required external dependencies beyond the Go standard library.

Config

Config holds configuration for the Thoth client. APIURL is required (directly or via THOTH_API_URL). Other string fields support environment-variable fallbacks.

type Config struct {
    // APIKey is the Thoth API key for hosted authentication.
    // Env fallback: THOTH_API_KEY.
    APIKey string
 
    // TenantID is your organization's Thoth tenant identifier.
    // Env fallback: THOTH_TENANT_ID.
    TenantID string
 
    // AgentID is the unique name for this agent instance.
    // Env fallback: THOTH_AGENT_ID.
    AgentID string
 
    // APIURL overrides the Thoth API base URL.
    // Required (or set THOTH_API_URL).
    // Used for both /v1/enforce and /v1/events/batch.
    // Env fallback: THOTH_API_URL.
    APIURL string
 
    // Environment scopes policy lookup (for example, dev vs prod).
    // Default: "prod".
    // Env fallback: THOTH_ENV, then THOTH_ENVIRONMENT.
    Environment string
 
    // UserID identifies the user on whose behalf the agent is acting.
    // Env fallback: THOTH_USER_ID.
    UserID string
 
    // ApprovedScope lists intended tool names; server policy still applies.
    // Env fallback: THOTH_APPROVED_SCOPE (comma-delimited).
    ApprovedScope []string
 
    // SessionIntent declares workflow purpose for HIPAA minimum-necessary checks.
    // Env fallback: THOTH_SESSION_INTENT.
    SessionIntent string
 
    // EnforcementTraceID sets an explicit cross-service correlation ID.
    // Env fallback: THOTH_ENFORCEMENT_TRACE_ID.
    EnforcementTraceID string
 
    // Timeout is the HTTP timeout for enforcer calls. Default: 5s.
    Timeout time.Duration
 
    // FailOpen permits execution on retryable enforcer failures when enabled.
    // Default: false. Keep disabled while verifying governance.
    FailOpen bool
 
    // Enforcement controls how policy violations are handled.
    // Values: "observe" | "progressive" | "step_up" | "block"
    // Default: "block".
    Enforcement string
}

Enforcement values

ValueBehavior
"observe"Log only; never block or step-up
"progressive"Escalating enforcement
"step_up"Request approval according to server policy
"block"Immediately reject with PolicyViolationError

NewClient()

Initialize a Thoth client. Returns an error only if required configuration is missing after env var fallbacks are applied.

client, err := thoth.NewClient(thoth.Config{
    APIKey:      os.Getenv("THOTH_API_KEY"),
    APIURL:      os.Getenv("THOTH_API_URL"),
    TenantID:    "acme-corp",
    AgentID:     "invoice-processor-v2",
    Enforcement: "block",
})
if err != nil {
    log.Fatal(err)
}
defer client.Close()

Close()

Close() flushes buffered behavioral events and releases HTTP resources. Always defer it.

defer client.Close()

WrapTool()

Wrap a string-in / string-out tool function with Thoth governance. This is the most common variant for LLM tool calling, where both input and output are plain strings.

func (c *Client) WrapTool(
    name string,
    fn func(ctx context.Context, input string) (string, error),
) func(ctx context.Context, input string) (string, error)

Enforcement semantics

  • ALLOW — the tool executes normally; a behavioral event is emitted.
  • BLOCK — execution is prevented; *PolicyViolationError is returned.
  • STEP_UP — execution pauses; the enforcer waits for human approval. On timeout or denial, *PolicyViolationError is returned.
  • MODIFY — execution proceeds with policy-modified tool arguments.
  • DEFER — execution is deferred and returns *PolicyViolationError with defer metadata.
  • Enforcer unreachable — execution is blocked (fail-closed) and a policy violation error is returned.

Example

searchDocs := client.WrapTool("search_docs", func(ctx context.Context, query string) (string, error) {
    // your business logic
    return mySearch(ctx, query)
})
 
result, err := searchDocs(ctx, "quarterly earnings")
if err != nil {
    var pve *thoth.PolicyViolationError
    if errors.As(err, &pve) {
        log.Printf("blocked: %s (id=%s)", pve.Reason, pve.ViolationID)
        return
    }
    log.Fatal(err)
}
fmt.Println(result)

WrapToolFunc()

Wrap a map-based tool function with Thoth governance. Use this variant when your LLM framework passes tool arguments as map[string]any (e.g. OpenAI function calling, Anthropic tool use).

type ToolFunc func(ctx context.Context, args map[string]any) (any, error)
 
func (c *Client) WrapToolFunc(name string, fn ToolFunc) ToolFunc

Example

readFile := client.WrapToolFunc("read_file", func(ctx context.Context, args map[string]any) (any, error) {
    path, _ := args["path"].(string)
    content, err := os.ReadFile(path)
    if err != nil {
        return nil, err
    }
    return string(content), nil
})
 
result, err := readFile(ctx, map[string]any{"path": "/tmp/invoice.pdf"})
if err != nil {
    var pve *thoth.PolicyViolationError
    if errors.As(err, &pve) {
        log.Printf("blocked: %s", pve.Reason)
    }
}

InstrumentAnthropic()

Wrap a map of Anthropic-style tool functions with Thoth governance.

func (c *Client) InstrumentAnthropic(toolFns map[string]ToolFunc) map[string]ToolFunc

Each function is wrapped with the same enforcement/event pipeline as WrapToolFunc().

Example

wrapped := client.InstrumentAnthropic(map[string]thoth.ToolFunc{
    "search_docs": func(ctx context.Context, args map[string]any) (any, error) {
        return "docs for: " + args["query"].(string), nil
    },
})
 
out, err := wrapped["search_docs"](ctx, map[string]any{"query": "access policy"})

InstrumentOpenAI()

Wrap a map of OpenAI-style tool functions with Thoth governance.

func (c *Client) InstrumentOpenAI(toolFns map[string]ToolFunc) map[string]ToolFunc

Legacy aliases

These aliases remain supported for backward compatibility:

func (c *Client) WrapAnthropicTools(toolFns map[string]ToolFunc) map[string]ToolFunc
func (c *Client) WrapOpenAITools(toolFns map[string]ToolFunc) map[string]ToolFunc

StartSession()

Create a new agent session with its own isolated tool-call history and tracer. Recommended for per-request isolation in servers.

func (c *Client) StartSession(ctx context.Context, agentID, sessionID string) (*Session, error)
ParameterDescription
agentIDOverride the agent ID for this session. Pass "" to use the client's agent ID.
sessionIDCustom session ID. Pass "" to auto-generate a UUID.

Example

sess, err := client.StartSession(ctx, "", requestID)
if err != nil {
    return err
}
defer sess.Close()
 
govSearch := sess.WrapTool("search_docs", searchFn)
govPayment := sess.WrapToolFunc("submit_payment", paymentFn)

Session

Session represents an active agent session.

type Session struct {
    ID string  // UUID — the session identifier included in all behavioral events
    // unexported fields
}

Session.WrapTool()

Identical to Client.WrapTool() but scoped to this session's tool-call history.

func (s *Session) WrapTool(
    name string,
    fn func(ctx context.Context, input string) (string, error),
) func(ctx context.Context, input string) (string, error)

Session.WrapToolFunc()

Identical to Client.WrapToolFunc() but scoped to this session.

func (s *Session) WrapToolFunc(name string, fn ToolFunc) ToolFunc

Session.Close()

Emits a session_end behavioral event and marks the session as closed. Idempotent.

func (s *Session) Close()

PolicyViolationError

Returned when the enforcer blocks a tool call.

type PolicyViolationError struct {
    ToolName              string
    Reason                string
    ViolationID           string
    DecisionReasonCode    string
    ActionClassification  string
    AuthorizationDecision string
    DeferTimeoutSeconds   int
    StepUpTimeoutSeconds  int
    RiskScore             float64
    LatencyMs             float64
    PackID                string
    PackVersion           string
    RuleVersion           int
    RegulatoryRegimes     []string
    MatchedRuleIDs        []string
    MatchedControlIDs     []string
    PolicyReferences      []string
    ModelSignals          []string
    Receipt               map[string]any
}
 
func (e *PolicyViolationError) Error() string

These fields map directly from the enforcer decision envelope and can be logged to SIEM/audit pipelines without custom metadata parsing.

Handling

result, err := govTool(ctx, input)
if err != nil {
    var pve *thoth.PolicyViolationError
    if errors.As(err, &pve) {
        // Log to your observability system
        slog.Warn("thoth policy violation",
            "tool", pve.ToolName,
            "reason", pve.Reason,
            "violation_id", pve.ViolationID,
        )
        // Return safe default or surface to caller
        return ErrActionRequiresApproval
    }
    return fmt.Errorf("tool error: %w", err)
}

StepUpRequiredError

Exported for step-up approval workflows where callers choose to handle approval out-of-band. Current WrapTool / WrapToolFunc behavior waits inline and surfaces timeout/deny as PolicyViolationError, so StepUpRequiredError is not emitted by those wrappers today.

type StepUpRequiredError struct {
    ToolName  string  // the name of the tool pending approval
    HoldToken string  // opaque token for the Thoth step-up API
    Reason    string  // why step-up was triggered
}
 
func (e *StepUpRequiredError) Error() string

Complete example

package main
 
import (
    "context"
    "errors"
    "fmt"
    "log/slog"
    "net/http"
    "os"
    "time"
 
    "github.com/atensecurity/thoth-go"
)
 
func main() {
    client, err := thoth.NewClient(thoth.Config{
        // APIKey, TenantID, AgentID read from env vars if omitted
        APIURL:      os.Getenv("THOTH_API_URL"),
        Enforcement: "block",
        Timeout:     10 * time.Second,
    })
    if err != nil {
        slog.Error("failed to init thoth", "err", err)
        os.Exit(1)
    }
    defer client.Close()
 
    // Serve an HTTP endpoint that processes each request in its own session
    http.HandleFunc("/process", func(w http.ResponseWriter, r *http.Request) {
        sess, err := client.StartSession(r.Context(), "", r.Header.Get("X-Request-ID"))
        if err != nil {
            http.Error(w, "internal error", 500)
            return
        }
        defer sess.Close()
 
        govSearch := sess.WrapTool("search_docs", func(ctx context.Context, query string) (string, error) {
            return "search results for: " + query, nil
        })
        govSubmit := sess.WrapToolFunc("submit_payment", func(ctx context.Context, args map[string]any) (any, error) {
            return "payment submitted", nil
        })
 
        // Use tools in your agent logic
        result, err := govSearch(r.Context(), r.URL.Query().Get("q"))
        if err != nil {
            var pve *thoth.PolicyViolationError
            if errors.As(err, &pve) {
                http.Error(w, "action blocked by policy: "+pve.Reason, http.StatusForbidden)
                return
            }
            http.Error(w, err.Error(), 500)
            return
        }
 
        _ = govSubmit // use similarly
        fmt.Fprintln(w, result)
    })
 
    slog.Info("listening on :8080")
    if err := http.ListenAndServe(":8080", nil); err != nil {
        slog.Error("server error", "err", err)
        os.Exit(1)
    }
}

Environment Variables

VariableDescription
THOTH_API_KEYAPI key for hosted Thoth authentication
THOTH_TENANT_IDDefault tenant ID
THOTH_AGENT_IDDefault agent ID
THOTH_API_URLRequired tenant API base URL used for both enforcement and event ingestion
THOTH_ENVPolicy environment scope (default: prod)
THOTH_ENVIRONMENTAlternate environment scope key (used when THOTH_ENV is unset)
THOTH_ENFORCEMENT_MODEDefault enforcement mode override (block by default)
THOTH_ENFORCEMENTLegacy alias for enforcement mode override
THOTH_USER_IDDefault user ID for policy evaluation
THOTH_APPROVED_SCOPEComma-delimited default approved tool list
THOTH_SESSION_INTENTSession intent for HIPAA minimum-necessary checks
THOTH_ENFORCEMENT_TRACE_IDExplicit correlation ID for enforcement requests
THOTH_LOG_LEVELOptional SDK decision-log level override (DEBUG, INFO, WARN, ERROR); falls back to LOG_LEVEL

When decision logging is enabled at debug level, SDK logs include hold_token for STEP_UP flows.