Skip to content

Getting started

This tutorial walks you through your first AI chat, end to end: activate a provider, resolve a credential, send a Chat message, and then ask for a structured Ask response unmarshalled straight into a Go struct.

You will do everything in one self-contained Go program so you can watch each moving part. We use Anthropic Claude here; the same shape works for every provider — you would swap only the blank import, the provider constant, and the credential env var.

Prerequisites

  • Go 1.26 or newer.
  • An Anthropic API key exported as ANTHROPIC_API_KEY.
  • A new module to experiment in:
mkdir chat-tutorial && cd chat-tutorial
go mod init example.test/chat-tutorial
go get gitlab.com/phpboyscout/go/chat
go get gitlab.com/phpboyscout/go/chat-anthropic

Step 1 — Activate a provider

Providers live in separate modules and are switched on by a blank import — the same pattern as database drivers or image/* decoders. Importing chat-anthropic for its init() side effect registers the claude provider with the core:

import (
    "gitlab.com/phpboyscout/go/chat"
    _ "gitlab.com/phpboyscout/go/chat-anthropic" // registers ProviderClaude
)

Without this import, chat.New with ProviderClaude returns unsupported provider: claude. The SDK-free claude-local provider is the only one that needs no import — it ships in the core.

Step 2 — Construct a client

chat.New takes package-owned Settings: a Config describing provider behaviour, and an optional *slog.Logger. Leave Token empty and the client falls back to the well-known ANTHROPIC_API_KEY environment variable.

client, err := chat.New(ctx, chat.Settings{
    Config: chat.Config{
        Provider:     chat.ProviderClaude,
        SystemPrompt: "You are a concise assistant.",
    },
})

If no Model is set, Claude defaults to claude-opus-4-8.

Step 3 — Send a message

Chat sends a prompt and returns the text reply. Message history is retained on the client, so follow-up calls continue the same conversation.

reply, err := client.Chat(ctx, "Name three uses for a CLI tool, one line each.")
if err != nil {
    log.Fatal(err)
}
fmt.Println(reply)

Step 4 — Ask for structured output

Ask unmarshals the model's answer directly into a Go value. Set a ResponseSchema on the Config and the provider is forced to return JSON matching your struct.

type Summary struct {
    Title  string   `json:"title"`
    Points []string `json:"points"`
}

structured, err := chat.New(ctx, chat.Settings{
    Config: chat.Config{
        Provider:       chat.ProviderClaude,
        ResponseSchema: Summary{},
        SchemaName:     "summary",
    },
})
if err != nil {
    log.Fatal(err)
}

var out Summary
if err := structured.Ask(ctx, "Summarise the Go language in a title and three points.", &out); err != nil {
    log.Fatal(err)
}
fmt.Printf("%s\n%v\n", out.Title, out.Points)

The complete program

package main

import (
    "context"
    "fmt"
    "log"

    "gitlab.com/phpboyscout/go/chat"
    _ "gitlab.com/phpboyscout/go/chat-anthropic"
)

type Summary struct {
    Title  string   `json:"title"`
    Points []string `json:"points"`
}

func main() {
    ctx := context.Background()

    client, err := chat.New(ctx, chat.Settings{
        Config: chat.Config{
            Provider:     chat.ProviderClaude,
            SystemPrompt: "You are a concise assistant.",
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    reply, err := client.Chat(ctx, "Name three uses for a CLI tool, one line each.")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(reply)

    structured, err := chat.New(ctx, chat.Settings{
        Config: chat.Config{
            Provider:       chat.ProviderClaude,
            ResponseSchema: Summary{},
            SchemaName:     "summary",
        },
    })
    if err != nil {
        log.Fatal(err)
    }

    var out Summary
    if err := structured.Ask(ctx, "Summarise the Go language in a title and three points.", &out); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n%v\n", out.Title, out.Points)
}

Run it:

export ANTHROPIC_API_KEY=sk-ant-...
go run .

Success criterion

The program prints a one-line-per-use answer, then a title and three bullet points parsed into the Summary struct. If you see unsupported provider: claude, the blank import in step 1 is missing; if you see a credential error, ANTHROPIC_API_KEY is not exported.

Next steps