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

# Go SDK

> Install the Go SDK, classify user input and tool output, and handle typed block errors.

## Prerequisites

Use Go 1.22 or later.

Set `SILMARIL_API_KEY` and `SILMARIL_API_URL` from your [deployment access](/docs/start/quickstart#get-access).

## Install

```sh theme={"theme":"github-light-default"}
go get github.com/Silmaril-Security/sdk-go/firewall@v0.6.1
```

<a id="initialize" />

<a id="classify" />

## Classify your first request

Create one client per protected system and reuse it. Label each call with the boundary it checks, and check each call's error before making the next one.

```go theme={"theme":"github-light-default"}
package main

import (
	"context"
	"errors"
	"log"
	"os"

	"github.com/Silmaril-Security/sdk-go/firewall"
)

func main() {
	fw, err := firewall.New(firewall.Options{
		APIKey: os.Getenv("SILMARIL_API_KEY"),
		APIURL: os.Getenv("SILMARIL_API_URL"),
	})
	if err != nil {
		log.Fatal(err)
	}

	ctx := context.Background()

	result, err := fw.Classify(ctx, "Summarize this release note.",
		firewall.WithHook(firewall.HookUserInput),
	)
	if err != nil {
		var blocked *firewall.FirewallBlockedError
		if errors.As(err, &blocked) {
			log.Printf("block score=%.4f threshold=%.4f", blocked.Score, blocked.Threshold)
			return
		}
		log.Fatalf("classify failed: %v", err)
	}

	log.Printf("prediction=%s score=%.4f", result.Prediction, result.Score)
}
```

In a service, pass the request context instead of `context.Background()`. For tool output, pass the tool name as well, and handle its error the same way.

```go theme={"theme":"github-light-default"}
result, err = fw.Classify(ctx, toolOutput,
	firewall.WithHook(firewall.HookToolResponse),
	firewall.WithToolName("read_file"),
)
```

### Expected result

A benign request logs `prediction=BENIGN` and its score. When the effective mode is block, a malicious request returns `*firewall.FirewallBlockedError`. Its `Result` field holds the full verdict. In shadow or warn mode the call returns the result instead, so route on `result.Prediction`. Your deployment sets the mode unless the client or call sets `Mode`. Outcome meanings and recommended actions are in the [outcome taxonomy](/docs/sdk/outcomes#outcome-taxonomy).

Any other error means the call did not produce a verdict. That includes `*firewall.APIError` for a non-2xx API response, and a network, timeout, or context error. Decide whether that boundary fails open or closed.

## Concurrent requests

Reuse one client across goroutines. Each `Classify` or `ClassifyBatch` call takes a context, so canceling one call also stops its retry wait. Caller-owned metadata, callbacks, and custom transports must be safe for concurrent access.

## Shadow mode

Shadow mode returns results instead of blocking errors, so you can measure would-block decisions while traffic continues. Per-call options can enforce one boundary before you change the client default.

```go theme={"theme":"github-light-default"}
fw, err := firewall.New(firewall.Options{
	APIKey:     os.Getenv("SILMARIL_API_KEY"),
	APIURL:     os.Getenv("SILMARIL_API_URL"),
	ShadowMode: true,
	OnClassify: func(event firewall.ClassifyEvent) {
		if event.Blocked && event.ShadowMode {
			log.Printf("would block %s score=%.4f", event.Hook, event.Result.Score)
		}
	},
})
if err != nil {
	log.Fatal(err)
}

_, err = fw.Classify(ctx, text,
	firewall.WithHook(firewall.HookToolResponse),
	firewall.WithShadowMode(false),
)
```

The classify call passes `WithShadowMode(false)`, so that call enforces. `OnClassify` can run on overlapping calls. Synchronize any shared state it touches.

## Errors

Enforced blocks return `*firewall.FirewallBlockedError`, which carries `Score`, `Threshold`, and `Result`.

```go theme={"theme":"github-light-default"}
var blocked *firewall.FirewallBlockedError
if errors.As(err, &blocked) {
	log.Printf("blocked score=%.4f threshold=%.4f", blocked.Score, blocked.Threshold)
	return
}
```

Read `blocked.Result` for the verdict, or use shadow mode when you need the result without a blocking error. Outcome meanings and recommended actions are in the [outcome taxonomy](/docs/sdk/outcomes#outcome-taxonomy).
