A command-line tool and Go SDK for the Agent Name Service (ANS) Registry Authority and Transparency Log.
ans-cli(cmd/ans-cli) — the fastest way to register, verify, and manage agents from a terminal. Most users start here.- Go SDK (
github.com/godaddy/ans-sdk-go/ans) — the library the CLI is built on. Embed it in Go services that need to register agents programmatically, verify agent badges, or query the Transparency Log.
Both the CLI and the SDK target the published REST API:
Top two options shown; see cmd/ans-cli/README.md#installation for all five (release archive, go install, build from source).
# macOS / Linux
brew install godaddy/ans/ans-cli# Windows (PowerShell)
scoop bucket add ans https://github.com/godaddy/scoop-ans
scoop install ans/ans-cliexport ANS_API_KEY="your-api-key"
export ANS_BASE_URL="https://api.ote-godaddy.com" # OTE — use https://api.godaddy.com for production# 1. Generate identity + server CSRs
ans-cli generate-csr \
--host myagent.example.com \
--org "Example Corp" \
--version 1.0.0 \
--out-dir ./certs
# 2. Register the agent — declare endpoint, transports, and functions with tags
ans-cli register \
--name "My Agent" \
--host myagent.example.com \
--version 1.0.0 \
--description "An AI agent that analyzes sentiment" \
--identity-csr ./certs/identity.csr \
--server-csr ./certs/server.csr \
--endpoint-url https://myagent.example.com/mcp \
--metadata-url https://myagent.example.com/.well-known/agent-card.json \
--endpoint-protocol MCP \
--endpoint-transports STREAMABLE-HTTP \
--function "analyze-sentiment:Sentiment Analysis:nlp,ml" \
--function "extract-entities:Entity Extraction:nlp,ner"
# Note the agentId from the response.
# 3. Place the DNS TXT record shown in the registration response.
# 4. Trigger ACME validation
ans-cli verify-acme <agentId>
# 5. Poll until certificates are ready
ans-cli status <agentId>
# 6. Retrieve your certificates
ans-cli get-identity-certs <agentId>
ans-cli get-server-certs <agentId>ans-cli search --name "My Agent"
ans-cli resolve myagent.example.com --version "^1.0.0"
ans-cli badge <agentId> --audit
ans-cli events --follow
ans-cli revoke <agentId> --reason SUPERSEDED --comments "Replaced by v2.0.0"For full per-command flag references and additional workflows, see cmd/ans-cli/README.md. For release-engineering / publishing the CLI, see RELEASE.md.
go get github.com/godaddy/ans-sdk-gopackage main
import (
"context"
"fmt"
"log"
"github.com/godaddy/ans-sdk-go/ans"
"github.com/godaddy/ans-sdk-go/models"
)
func main() {
// Create a new Registry Authority client
client, err := ans.NewClient(
ans.WithBaseURL("https://api.godaddy.com"),
ans.WithAPIKey("your-api-key", "your-api-secret"),
ans.WithVerbose(true),
)
if err != nil {
log.Fatal(err)
}
// Register a new agent
req := &models.AgentRegistrationRequest{
AgentDisplayName: "My AI Agent",
AgentHost: "my-agent.example.com",
AgentDescription: "An example AI agent",
Version: "1.0.0",
IdentityCSRPEM: string(identityCSR),
Endpoints: []models.AgentEndpoint{
{
AgentURL: "https://my-agent.example.com/mcp",
MetaDataURL: "https://my-agent.example.com/.well-known/agent-card.json",
Protocol: "MCP",
Transports: []string{"STREAMABLE-HTTP"},
Functions: []models.AgentFunction{
{
ID: "search",
Name: "Web Search",
Tags: []string{"search", "web", "retrieval"},
},
{
ID: "summarize",
Name: "Text Summarizer",
Tags: []string{"nlp", "summarization", "text"},
},
{
ID: "translate",
Name: "Language Translator",
Tags: []string{"nlp", "translation", "i18n"},
},
},
},
},
}
ctx := context.Background()
result, err := client.RegisterAgent(ctx, req)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Agent registered: %s (ID: %s)\n", result.ANSName, result.AgentID)
}package main
import (
"context"
"fmt"
"log"
"github.com/godaddy/ans-sdk-go/ans"
)
func main() {
// Create a new Transparency Log client
tlClient, err := ans.NewTransparencyClient(
ans.WithBaseURL("https://transparency.ans.godaddy.com"),
ans.WithVerbose(true),
)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Get transparency log entry
logEntry, err := tlClient.GetAgentTransparencyLog(ctx, "agent-uuid-here")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", logEntry.Status)
if logEntry.MerkleProof != nil {
fmt.Printf("Tree Size: %d\n", logEntry.MerkleProof.TreeSize)
}
}- ✅ Agent Registration
- ✅ Agent Details Retrieval
- ✅ Agent Search
- ✅ Agent Resolution (by host + version pattern)
- ✅ Agent Revocation
- ✅ Certificate Management
- ✅ Identity Certificate Retrieval
- ✅ Server Certificate Retrieval
- ✅ CSR Submission (Identity & Server)
- ✅ CSR Status Checking
- ✅ ACME Challenge Verification
- ✅ DNS Record Verification
- ✅ Event Stream (Pagination + Follow mode)
- ✅ Agent Transparency Log Retrieval
- ✅ Audit Trail Queries (Paginated)
- ✅ Log Checkpoint Retrieval
- ✅ Checkpoint History (Paginated)
- ✅ Log Schema Retrieval
- ✅ Badge-verified HTTP client
- ✅ GET/POST/PUT/DELETE with automatic verification
- ✅ JSON request/response helpers
- ✅ Configurable failure policies (fail-open/fail-closed)
- ✅ RSA key pair generation (2048+ bits)
- ✅ EC key pair generation (P-256, P-384, P-521)
- ✅ PEM encoding/decoding with optional encryption
- ✅ File I/O utilities
- ✅ JWT Bearer Token
- ✅ API Key (Public gateway endpoints)
- ✅ Custom HTTP Client support
The SDK uses the functional options pattern for flexible client configuration:
client, err := ans.NewClient(
ans.WithBaseURL("https://api.godaddy.com"),
ans.WithJWT("your-jwt-token"),
ans.WithTimeout(120 * time.Second),
ans.WithVerbose(true),
ans.WithHTTPClient(customHTTPClient),
)| Option | Description | Example |
|---|---|---|
WithBaseURL(url string) |
Set the API base URL | ans.WithBaseURL("https://api.godaddy.com") |
WithJWT(token string) |
Set JWT authentication | ans.WithJWT("eyJhbGciOi...") |
WithAPIKey(key, secret string) |
Set API key authentication (public gateway) | ans.WithAPIKey("key", "secret") |
WithTimeout(duration time.Duration) |
Set HTTP client timeout | ans.WithTimeout(60 * time.Second) |
WithVerbose(verbose bool) |
Enable verbose logging | ans.WithVerbose(true) |
WithHTTPClient(client *http.Client) |
Use custom HTTP client | ans.WithHTTPClient(myClient) |
| Environment | Registry Authority | Transparency Log |
|---|---|---|
| Production | https://api.godaddy.com |
https://transparency.ans.godaddy.com |
| OTE | https://api.ote-godaddy.com |
https://transparency.ans.ote-godaddy.com |
All methods accept context.Context as the first parameter for cancellation and timeouts.
RegisterAgent(ctx context.Context, req *models.AgentRegistrationRequest) (*models.RegistrationPending, error)Registers a new agent with the ANS Registry. Returns pending registration with challenges.
GetAgentDetails(ctx context.Context, agentID string) (*models.AgentDetails, error)Retrieves detailed information about a specific agent.
SearchAgents(ctx context.Context, opts ...ans.SearchOption) (*models.AgentSearchResponse, error)Searches for agents using flexible criteria with pagination support. Filter values are provided via functional options:
ans.WithSearchName(name)— agent display name (partial match)ans.WithSearchHost(host)— agent host domain (partial match)ans.WithSearchVersion(version)— agent version (flexible match)ans.WithSearchProtocol(models.AgentProtocolMCP)— endpoint protocolans.WithSearchStatus(models.AgentStatusPendingDNS, ...)— lifecycle status (multi-valued). Defaults toACTIVEserver-side when unset; passAgentStatusPendingDNSto find registrations still completing DNS validation, orAgentStatusAllto include every state.ans.WithSearchLimit(n)/ans.WithSearchOffset(n)— pagination
Example — list every pending registration:
result, err := client.SearchAgents(ctx,
ans.WithSearchStatus(models.AgentStatusPendingDNS),
)ResolveAgent(ctx context.Context, host, version string) (*models.AgentCapabilityResponse, error)Resolves an agent by host and version pattern. Supports semver patterns: *, ^1.0.0, ~1.2.3.
RevokeAgent(ctx context.Context, agentID string, reason models.RevocationReason, comments string) (*models.AgentRevocationResponse, error)Revokes an agent registration with a specified reason.
VerifyACME(ctx context.Context, agentID string) (*models.AgentStatus, error)Triggers ACME challenge validation for an agent.
VerifyDNS(ctx context.Context, agentID string) (*models.AgentStatus, error)Verifies DNS records are configured correctly for an agent.
GetChallengeDetails(ctx context.Context, agentID string) (*models.ChallengeDetails, error)Retrieves ACME challenge details for an agent.
GetIdentityCertificates(ctx context.Context, agentID string) ([]models.CertificateResponse, error)Retrieves all identity certificates for an agent.
GetServerCertificates(ctx context.Context, agentID string) ([]models.CertificateResponse, error)Retrieves all server certificates for an agent.
SubmitIdentityCSR(ctx context.Context, agentID, csrPEM string) (*models.CsrSubmissionResponse, error)Submits an identity certificate signing request.
SubmitServerCSR(ctx context.Context, agentID, csrPEM string) (*models.CsrSubmissionResponse, error)Submits a server certificate signing request.
GetCSRStatus(ctx context.Context, agentID, csrID string) (*models.CsrStatusResponse, error)Checks the status of a submitted CSR.
GetAgentEvents(ctx context.Context, limit int, providerID, lastLogID string) (*models.EventPageResponse, error)Retrieves paginated agent events for monitoring and synchronization.
GetAgentTransparencyLog(ctx context.Context, agentID string) (*models.TransparencyLog, error)Retrieves the current transparency log entry for an agent, including Merkle proof, payload, and status.
GetAgentTransparencyLogAudit(ctx context.Context, agentID string, params *models.AgentAuditParams) (*models.TransparencyLogAudit, error)Retrieves a paginated list of transparency log records for an agent.
GetCheckpoint(ctx context.Context) (*models.CheckpointResponse, error)Retrieves the current checkpoint (state) of the Transparency Log.
GetCheckpointHistory(ctx context.Context, params *models.CheckpointHistoryParams) (*models.CheckpointHistoryResponse, error)Retrieves a paginated list of historical checkpoints with optional filtering.
GetLogSchema(ctx context.Context, version string) (*models.JSONSchema, error)Retrieves the JSON schema for a specific Transparency Log event schema version.
The SDK provides a verified HTTP client for secure agent-to-agent communication:
import (
"context"
"time"
"github.com/godaddy/ans-sdk-go/ans"
)
// Create agent client with badge verification
agentClient := ans.NewAgentClient(
ans.WithAgentClientTimeout(30 * time.Second),
ans.WithAgentClientVerifyServer(true),
)
// Make verified requests
resp, err := agentClient.Get(ctx, "https://other-agent.example.com/api/data")
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
// JSON helpers
var result MyResponse
resp, err = agentClient.GetJSON(ctx, "https://other-agent.example.com/api/data", &result)| Option | Description |
|---|---|
WithAgentClientTimeout(d time.Duration) |
Set HTTP client timeout (default: 30s) |
WithAgentClientVerifyServer(bool) |
Enable/disable server certificate verification |
WithAgentClientFailurePolicy(policy) |
Set failure policy (verify.FailClosed, verify.FailOpenWithCache, or verify.FailOpen) |
WithAgentClientTLS(*tls.Config) |
Use custom TLS configuration |
WithAgentClientVerifierOptions(opts...) |
Pass custom verify.Option values (e.g., verify.WithCacheConfig(...)) |
Note: When using
verify.FailOpenWithCache, you must also provide a cache viaverify.WithCacheConfig(...)in the verifier options. Without a cache,FailOpenWithCachebehaves likeFailClosed.
The keygen package provides utilities for key generation:
import "github.com/godaddy/ans-sdk-go/keygen"
// Generate RSA key pair
keyPair, err := keygen.GenerateRSAKeyPairWithPEM(2048, nil)
if err != nil {
log.Fatal(err)
}
// Generate EC key pair (P-256)
ecKeyPair, err := keygen.GenerateECKeyPairWithPEM(keygen.CurveP256(), nil)
if err != nil {
log.Fatal(err)
}
// Save to files
err = keyPair.WriteKeyPairToFiles("private.key", "public.pem")API errors are returned as *models.ResponseError, which provides the HTTP status code, API error code, message, and optional details:
import (
"errors"
"net/http"
"github.com/godaddy/ans-sdk-go/models"
)
result, err := client.GetAgentDetails(ctx, agentID)
if err != nil {
var respErr *models.ResponseError
if errors.As(err, &respErr) {
switch respErr.StatusCode {
case http.StatusNotFound:
fmt.Println("Agent not found")
case http.StatusUnauthorized:
fmt.Println("Authentication failed")
case http.StatusBadRequest:
fmt.Printf("Invalid request: %s\n", respErr.Code)
default:
fmt.Printf("API error %d: %s\n", respErr.StatusCode, respErr.Message)
}
} else {
fmt.Printf("Error: %v\n", err)
}
}
## Package Structureans-sdk-go/ ├── go.mod # Module definition ├── README.md # This file ├── ans/ # Main SDK package │ ├── client.go # Registry Authority client │ ├── agent_client.go # Agent-to-agent HTTP client │ ├── transparency.go # Transparency Log client │ └── options.go # Functional options ├── keygen/ # Key generation utilities │ └── keygen.go # RSA/EC key generation ├── models/ # Data models (importable) │ ├── agent.go # Agent-related models │ ├── certificate.go # Certificate models │ ├── event.go # Event models │ ├── resolution.go # Agent resolution models │ ├── revocation.go # Agent revocation models │ ├── transparency.go # Transparency Log models │ └── error.go # Error types & sentinel errors ├── verify/ # Certificate verification │ └── ... # Verification utilities ├── examples/ # Usage examples │ └── byoc/ # BYOC registration example └── cmd/ └── ans-cli/ # CLI application ├── main.go ├── cmd/ # CLI commands └── internal/ # CLI-specific code
## Testing
Run tests with:
```bash
go test ./...
Run tests with coverage:
go test -cover -coverprofile=coverage.out ./...
go tool cover -html=coverage.outRun linting:
golangci-lint run ./...Always pass context.Context to client methods for proper cancellation and timeout handling:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
result, err := client.RegisterAgent(ctx, req)Use errors.As to extract structured error details from API responses:
agent, err := client.GetAgentDetails(ctx, agentID)
var respErr *models.ResponseError
if errors.As(err, &respErr) && respErr.StatusCode == http.StatusNotFound {
return nil, fmt.Errorf("agent %s does not exist", agentID)
}The SDK automatically handles URL encoding for query parameters and path segments. Don't encode values manually:
// ✅ Correct - SDK handles encoding
client.SearchAgents(ctx,
ans.WithSearchName("Name with spaces"),
ans.WithSearchHost("host.com"),
ans.WithSearchVersion("1.0.0"),
ans.WithSearchLimit(20),
)
// ❌ Wrong - don't pre-encode
client.SearchAgents(ctx, ans.WithSearchName(url.QueryEscape("Name with spaces")))We welcome contributions! Please see CONTRIBUTING.md for guidelines on how to get involved, including commit message conventions, code review process, and more.
This project is licensed under the MIT License - see the LICENSE file for details.