Skip to content

Go SDK

The jennah-sdk-go module provides Go bindings for the Jennah gRPC API.

go get github.com/alphauslabs/jennah-sdk-go

Quickstart

Authenticate using jnh login (see CLI overview) or by setting the JENNAH_API_KEY environment variable. The following example initializes a client, creates an agent, stores a vector chunk, and performs semantic search:

package main

import (
    "context"
    "crypto/rand"
    "fmt"
    "log"
    "strings"

    jennah "github.com/alphauslabs/jennah-sdk-go"
)

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

    // Uses stored credentials from `jnh login` or $JENNAH_API_KEY.
    jc, err := jennah.NewClient(jennah.Config{})
    if err != nil {
        log.Fatal(err)
    }
    defer jc.Close()

    id := "quickstart-" + strings.ToLower(rand.Text()[:8])
    agent, err := jc.Spawn(ctx, jennah.SpawnInput{AgentInstanceID: id})
    if err != nil {
        log.Fatal(err)
    }
    defer agent.Destroy(ctx)

    // Store a vector chunk. RawContent is embedded automatically.
    if _, err := agent.Vectors.Upsert(ctx, &jennah.VectorChunk{
        ChunkId: "pref-1",
        RawContent: "The customer prefers invoices in Japanese yen, " +
            "sent on the 5th.",
    }); err != nil {
        log.Fatal(err)
    }

    // Semantic search query.
    res, err := agent.Vectors.Search(ctx, &jennah.SemanticQuery{
        QueryText: "what currency does the customer want to be " +
            "billed in?",
        Limit: 3,
    })
    if err != nil {
        log.Fatal(err)
    }
    for _, m := range res.GetMatches() {
        fmt.Printf("%.3f  %s\n", m.GetDistance(), m.GetRawContent())
    }
}
0.235  The customer prefers invoices in Japanese yen, sent on the 5th.

jc.Ping(ctx) checks endpoint connectivity using the unauthenticated health check service. It does not validate credentials.

Services and stubs

Client.Agent(id) provides access to agent memory operations: Memory.Commit and Memory.Query for the unified memory API, and Logs, Vectors, and Graph for single-section operations. Additional platform services are available directly on the client (Auth, Datasets, Approvals, Billing, and Platform).

To invoke gRPC services directly without wrapper methods, instantiate generated stubs using Client.Conn(). The underlying connection manages authentication and token renewal for all stubs:

import agentpb "github.com/alphauslabs/jennah-sdk-go/jennah/agent/v1"

scopes := agentpb.NewScopeServiceClient(jc.Conn())

Authentication and credentials

The SDK resolves credentials in the following order of precedence, using the first available source:

  1. Config.Credentials: A custom credentials provider.
  2. Config.APIKey: An explicit API key string.
  3. JENNAH_API_KEY: An environment variable.
  4. Stored CLI session: Credentials created by jnh login.

When running locally in an environment already authenticated via jnh login, no explicit configuration is required:

jc, err := jennah.NewClient(jennah.Config{})

If no credentials can be resolved from any source, NewClient returns an error during initialization.

Stored sessions reside in ~/.config/jennah/credentials (respecting XDG_CONFIG_HOME) with owner-only file permissions (0600). Because the SDK shares this credential store with the jnh CLI, running jnh login authenticates SDK processes on the same machine.

Endpoint resolution

Stored CLI sessions record the HTTP gateway endpoint used by the CLI. The Go SDK connects to Config.Endpoint, defaulting to jennah-grpc.alphaus.cloud:443 when unspecified.

Client.Credential() returns credential type and source information without exposing sensitive values:

log.Printf("authenticated with %s", jc.Credential())

Token renewal

Session credentials automatically refresh upon access token expiration:

  • When an RPC fails due to an expired access token, the SDK refreshes the token and retries the RPC once.
  • Token refresh rotates the refresh token. The renewed session is written atomically to ~/.config/jennah/credentials, keeping concurrent SDK clients and the CLI synchronized.
  • Concurrent RPCs coordinate so that only a single renewal request is executed.

API keys are static and do not undergo renewal. If an API key is rejected by the server, the SDK returns credentials.ErrKeyRefused, which satisfies jennah.IsUnauthenticated(err).