Go CLI for fetching LangSmith traces and threads with deterministic output, strong tests, and SDK-backed auth/transport behavior.
Originally built as a personal project to learn Go while shipping a production-style CLI.
- Focused CLI commands:
trace,traces,thread,threads,config - Shared auth and HTTP transport via
langsmith-sdk/go - Supports LangSmith cloud and self-hosted endpoints
- Output modes:
pretty,json,raw - File and directory export modes with filename templating
- Concurrent bulk fetching with bounded workers and stable ordering
- Integration + unit coverage for request shape, parsing, retries, and error mapping
- Project Status
- Requirements
- Repository Layout
- Quick Start
- Setup Notes
- Authentication And Configuration
- Command Reference
- Output And File Modes
- Self-Hosted LangSmith
- Error Handling And Retries
- Parity Tracking
- Development
- CI Pipeline
- Troubleshooting
langsmith-fetch-go is an actively developed Go migration of the Python langsmith-fetch tool.
Current capabilities:
- End-to-end CLI flows for
trace,traces,thread,threads, andconfig show - Config file read/write (
~/.langsmith-cli/config.yaml) - Project UUID resolution by project name
- Metadata + feedback enrichment for traces
- Retry-aware transport and typed status-error mapping
- Go
1.22+ - A LangSmith API key
- Access to a compatible
langsmith-sdk/gocheckout (see Quick Start)
cmd/langsmith-fetch/ # CLI entrypoint
internal/cmd/ # command parsing + wiring
internal/core/ # single + bulk orchestration
internal/langsmith/ # domain accessors (runs/threads/feedback/projects)
internal/config/ # env + file config loading/saving
internal/output/ # pretty/json/raw rendering
internal/files/ # safe filename + file IO helpers
docs/parity/ # Python parity matrix
This repo currently uses a local Go module replace:
replace langsmith-sdk/go => ../langsmith-sdk/goSo keep both repos as siblings:
cd /path/to/workspace
git clone https://github.com/vishnu-ssuresh/langsmith-fetch-go.git
git clone https://github.com/vishnu-ssuresh/langsmith-sdk.gitcd langsmith-fetch-go
go build -o ./bin/langsmith-fetch ./cmd/langsmith-fetchUsing environment variables:
export LANGSMITH_API_KEY="lsv2_..."Or using config:
./bin/langsmith-fetch config set api-key "lsv2_..."./bin/langsmith-fetch trace <trace-id> --format prettyThis repo depends on langsmith-sdk/go via a local replace.
Default in go.mod:
replace langsmith-sdk/go => ../langsmith-sdk/goIf your SDK checkout is elsewhere (or you are testing a custom SDK branch), update the replace target:
go mod edit -replace=langsmith-sdk/go=/absolute/path/to/langsmith-sdk/go
go mod tidyVerify the module resolution path:
go list -m -f '{{.Path}} => {{.Dir}}' langsmith-sdk/golangsmith-fetch-go reads:
LANGSMITH_ENDPOINT(orLANGCHAIN_ENDPOINT)
Some repos use LANGSMITH_HOST_API_URL instead. If your env file uses that key, map it explicitly:
export LANGSMITH_ENDPOINT="${LANGSMITH_HOST_API_URL}"If you want to force default cloud behavior, unset endpoint overrides:
unset LANGSMITH_ENDPOINT LANGCHAIN_ENDPOINTExample flow when loading env vars from a sibling repo:
set -a
source ../ai-sdr/.env
set +a
# required when project is not in the env file
export LANGSMITH_PROJECT="gtm-agent"
# optional: use endpoint from host-url style env var
# export LANGSMITH_ENDPOINT="${LANGSMITH_HOST_API_URL}"
go run ./cmd/langsmith-fetch traces --limit 3 --format pretty --no-progress- Command flags (for fields that have flags, such as
--project-uuidor--format) - Environment variables
- Config file (
~/.langsmith-cli/config.yaml)
For API key specifically, runtime resolution is environment first, then config file.
Primary:
LANGSMITH_API_KEYLANGSMITH_ENDPOINTLANGSMITH_WORKSPACE_IDLANGSMITH_PROJECTLANGSMITH_PROJECT_UUID
Compat aliases:
LANGCHAIN_API_KEYLANGCHAIN_ENDPOINTLANGCHAIN_WORKSPACE_IDLANGCHAIN_PROJECTLANGCHAIN_PROJECT_UUID
langsmith-fetch config show
langsmith-fetch config set api-key <value>
langsmith-fetch config set workspace-id <value>
langsmith-fetch config set endpoint <value>
langsmith-fetch config set project-uuid <value>
langsmith-fetch config set project-name <value>
langsmith-fetch config set default-format <pretty|json|raw>Config file path:
~/.langsmith-cli/config.yaml
All commands:
tracefetch one trace by IDtraceslist tracesthreadfetch one thread by IDthreadslist threadsconfigshow or set configuration
langsmith-fetch trace <trace-id> [flags]
langsmith-fetch trace --trace-id <trace-id> [flags]Flags:
--format pretty|json|raw--file <path>--include-metadata--include-feedback
Examples:
langsmith-fetch trace 3b0b15fe-... --format json
langsmith-fetch trace 3b0b15fe-... --include-metadata --include-feedback
langsmith-fetch trace 3b0b15fe-... --file ./out/trace.jsonlangsmith-fetch traces [flags]Flags:
--project-id <uuid>(alias:--project-uuid)--limit <n>(alias:-n)--last-n-minutes <n>--since <RFC3339>--max-concurrent <n>--no-progress--include-metadata--include-feedback--format pretty|json|raw--file <path>--dir <path>--filename-pattern <pattern>(default:{trace_id}.json)
Rules:
--last-n-minutesand--sinceare mutually exclusive--fileand--dirare mutually exclusive
Examples:
langsmith-fetch traces --project-uuid <uuid> --limit 20 --format pretty
langsmith-fetch traces --project-uuid <uuid> --since 2025-12-09T10:00:00Z --format json
langsmith-fetch traces --project-uuid <uuid> --dir ./out/traces --filename-pattern "{index}_{trace_id}"langsmith-fetch thread <thread-id> [flags]
langsmith-fetch thread --thread-id <thread-id> [flags]Flags:
--project-id <uuid>(alias:--project-uuid)--format pretty|json|raw--file <path>
Examples:
langsmith-fetch thread test-thread --project-uuid <uuid>
langsmith-fetch thread test-thread --project-uuid <uuid> --format jsonlangsmith-fetch threads [flags]Flags:
--project-id <uuid>(alias:--project-uuid)--limit <n>(alias:-n)--last-n-minutes <n>--since <RFC3339>--max-concurrent <n>--no-progress--format pretty|json|raw--file <path>--dir <path>--filename-pattern <pattern>(default:{thread_id}.json)
Rules:
--last-n-minutesand--sinceare mutually exclusive--fileand--dirare mutually exclusive
Examples:
langsmith-fetch threads --project-uuid <uuid> --limit 10 --format pretty
langsmith-fetch threads --project-uuid <uuid> --dir ./out/threads --filename-pattern "thread_{index}"Output formats:
pretty: human-readable, line-orientedjson: indented JSONraw: compact JSON
File writing:
--file: write one aggregate output file--dir: write one file per item (bulk commands)--filename-patternplaceholders:{id}{trace_id}{thread_id}{index}
Set endpoint via env or config:
export LANGSMITH_ENDPOINT="https://smith.example.com"
langsmith-fetch trace <trace-id>or
langsmith-fetch config set endpoint "https://smith.example.com"- Transport retries retryable statuses (
429,5xx) and transient network failures per SDK policy. - Domain accessors map status codes to typed SDK errors:
ErrUnauthorized(401)ErrForbidden(403)ErrNotFound(404)ErrRateLimited(429)ErrTransient(5xx)
Python migration parity is tracked in:
Run tests:
go test ./...
go test -race ./...Run vet:
go vet ./...Build:
go build -trimpath ./cmd/langsmith-fetchGitHub Actions workflow:
Gates:
go test ./...go test -race ./...go vet ./...go build -trimpath ./cmd/langsmith-fetch- Cross-platform binary builds:
- linux (
amd64,arm64) - darwin (
amd64,arm64) - windows (
amd64,arm64)
- linux (
Set an API key via env or config:
export LANGSMITH_API_KEY="lsv2_..."
# or
langsmith-fetch config set api-key "lsv2_..."For thread-based commands, provide one of:
--project-uuid <uuid>LANGSMITH_PROJECT_UUIDLANGSMITH_PROJECT(name lookup path)
Use either --since or --last-n-minutes, not both.
If build fails resolving langsmith-sdk/go, ensure the sibling checkout exists:
../langsmith-sdk/go
Or repoint the replace target to your custom SDK checkout:
go mod edit -replace=langsmith-sdk/go=/absolute/path/to/langsmith-sdk/go
go mod tidy