Quick Start
Quick Start
This walkthrough takes you from zero to a governed tool call in three steps:
install the SDK, initialise the runtime, and wrap your tools so every call is
checked against the AI Agent Assembly gateway. The whole thing is a single
main you can copy, paste, and run.
go get today — following
this quick-start will not make your agent appear in the dashboard. The steps
below wrap and govern tool calls, but the register handshake runs only under
the opt-in native cgo binding (-tags aa_ffi_go, CGO_ENABLED=1), and that
native library (libaa_ffi_go) is not published anywhere yet: building with
-tags aa_ffi_go fails with ld: library 'aa_ffi_go' not found outside a full
monorepo checkout. The default pure-Go build has no native transport, so it does
not register even when WithSidecarAddress
is set (see that option’s godoc). Publishing the native library — or dropping the
cgo requirement — is a separate product decision; track status in
AAASM-4547 and
AAASM-4469.Prerequisites
Go ≥ 1.26 (the floor declared in
go.mod).For local development: nothing else —
Initauto-discovers a gateway onhttp://localhost:7391, and starts one for you if none is running (theaasmCLI must be on yourPATH).Local-mode transports —
:7391REST +:50051gRPC.Initshells out to the following command to auto-start the gateway:aasm start --mode local --foregroundThe
:7391auto-discovery above only resolves the REST gateway URL. Agent registration is a separate concern that talks to the gateway’s gRPC endpoint (default127.0.0.1:50051) —Initdoes not auto-derive this address the way the Python and Node SDKs do. Reaching it requires an explicitWithSidecarAddress(orWithSidecarBinary) option; without one,InitreturnsErrSidecarUnavailable. And per the warning at the top of this page, the registration handshake itself only runs under the opt-in native cgo binding today.To confirm both surfaces are actually up rather than guessing from
Init’s behavior, check them directly:curl http://localhost:7391/healthz # REST — real JSON: mode, storage, version, uptime_secs nc -z localhost 50051 && echo "gRPC port open" # gRPC has no health endpoint yet; this only confirms the port accepts connectionsFor production: a gateway URL and, if your gateway requires auth, an API key. Both can come from options, environment variables, or a config file — see Configuration.
(Optional) a C compiler, only if you opt into the native FFI transport with
-tags aa_ffi_go. The default transport is pure-Go and needs none.
Step 1 — Install
go get github.com/ai-agent-assembly/go-sdkStep 2 — Initialise the runtime
Init returns an *assembly.Assembly — your runtime handle. Always Close it
when you’re done so the connection (and any managed sidecar) is released.
package main
import (
"context"
"log"
"github.com/ai-agent-assembly/go-sdk/assembly"
)
func main() {
// Stamp this agent's identity onto the context. The SDK forwards it to
// the gateway on every check and record.
ctx := assembly.WithAgentID(context.Background(), "my-agent")
a, err := assembly.Init(ctx,
assembly.WithGatewayURL("https://gateway.example.com"),
assembly.WithAPIKey("..."), // optional — omit for local, unauthenticated dev
)
if err != nil {
log.Fatalf("init assembly runtime: %v", err)
}
defer func() {
if err := a.Close(); err != nil {
log.Printf("close assembly runtime: %v", err)
}
}()
log.Println("assembly runtime ready")
}For local development you can drop both options entirely — assembly.Init(ctx)
resolves the gateway from the environment, then ~/.aasm/config.yaml, then the
local default. See Configuration
for the full resolution order.
Step 3 — Wrap your tools
Your tools just need to satisfy the SDK’s small Tool interface:
type Tool interface {
Name() string
Description() string
Call(ctx context.Context, input string) (string, error)
}WrapTools takes your []Tool and a governance client, and returns a new
[]Tool where every Call is governed:
governed := assembly.WrapTools(myTools, nil)The second argument is the GovernanceClient that talks to the gateway.
Passing nil gives you a passthrough wrapper — the tools run, but no
Check/RecordResult calls are made. That’s the simplest starting point and
what the package’s own runnable example uses; wire in a real client when you’re
ready to enforce policy (see
Handle allow/deny decisions and errors).
Hand governed to your agent in place of the originals. From here on, each call
against a governed tool is checked against the gateway policy before execution
and recorded after.
Govern your first agent
Pick your framework — each tab shows the governance slice copied verbatim from a
runnable example in the
examples repo
(a CI drift check keeps them in lockstep). Go’s per-framework
surface is thin today, so the tabs are LangChainGo (the framework path) and
Plain (the framework-agnostic path). Two more validated Go examples already
exist — Tool Policy and CLI Runtime (sidecar) — but those are patterns
(an allow/deny policy demo and sidecar wiring), not “first agent” frameworks, so
they’re intentionally left out of this quick-start; see
metadata/quickstart/README.md for the tab-selection rationale. A new tab
appears automatically once a new Go framework example lands.
Governance slice from the runnable go/langchaingo/main.go example.
// Wrap the LangChainGo tools with Agent Assembly governance. The wrapped
// values still satisfy langchaingo's tools.Tool, so they can be handed
// straight to a LangChainGo agent/executor.
governed := assembly.WrapTools(
[]assembly.Tool{&searchTool{}, &sendEmailTool{}},
&policyClient{},
)Putting it together
package main
import (
"context"
"log"
"github.com/ai-agent-assembly/go-sdk/assembly"
)
// echoTool is a minimal Tool implementation.
type echoTool struct{}
func (echoTool) Name() string { return "echo" }
func (echoTool) Description() string { return "returns its input unchanged" }
func (echoTool) Call(_ context.Context, input string) (string, error) {
return input, nil
}
func main() {
ctx := assembly.WithAgentID(context.Background(), "my-agent")
a, err := assembly.Init(ctx,
assembly.WithGatewayURL("https://gateway.example.com"),
assembly.WithAPIKey("..."),
)
if err != nil {
log.Fatalf("init: %v", err)
}
defer a.Close()
tools := []assembly.Tool{echoTool{}}
governed := assembly.WrapTools(tools, nil)
out, err := governed[0].Call(ctx, "hello, governance")
if err != nil {
log.Fatalf("tool call: %v", err)
}
log.Println("result:", out) // result: hello, governance
}What to expect
Initsucceeds once a gateway is reachable (resolved or auto-started). If no gateway can be found and noaasmbinary is onPATH, you’ll get a typed*assembly.ConfigurationError— see Troubleshooting.- Tool calls run and return the inner tool’s result. With a real governance
client wired in, a
denydecision surfaces as a*assembly.PolicyViolationErrorand the inner tool never runs.
Where to next
- Core Concepts — what’s actually happening inside the SDK.
- Examples — wire the SDK into the framework you actually use.
- Guides — wrap a real agent, integrate a framework, handle decisions.
- Configuration — every
Initoption, defaults, and enforcement modes. - Troubleshooting — what to do when
Initor a check fails.