This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
go build -o zd # Build binary
go test ./... # Run all tests
go test ./internal/api/ -run TestName # Run a single test
go vet ./... # Lint
gofmt -w . # Format codeNo external test dependencies — tests use net/http/httptest with JSON fixtures in testdata/.
Conventional Commits required (enforced by lefthook commit-msg hook):
<type>[optional scope][!]: <description>
Types: feat | fix | docs | style | refactor | perf | test | build | ci | chore | revert
The lefthook pre-commit hook runs go build, gofmt check, go vet, and go test in parallel. Ensure gofmt -w . is run before committing.
Go CLI (zd) for Zendesk's ticketing REST API. Module: github.com/johanviberg/zd. Uses Cobra + Viper + XDG.
Commands in cmd/ are thin wiring: they read flags, call a service method, and format output. The core flow is:
rootCmd.PersistentPreRunEloads config and creates aFormatter, both stored incontext.Contextvia typed keys- Command handlers retrieve these via
configFromCtx()/formatterFromCtx() newTicketService(cmd)/newSearchService(cmd)resolve credentials, build an API client, and return a service- Service methods call
client.doJSON()which handles HTTP + JSON decoding - Formatter outputs results to stdout; errors go to stderr
api.NewClient builds a layered http.RoundTripper:
RetryTransport (exponential backoff + jitter for 429/5xx, max 3 retries)
→ AuthTransport (adds Basic or Bearer header from ProfileCredentials)
→ http.Transport (TLS 1.2+)
types.AppError carries a Code, Message, and ExitCode (0-5). API status codes map to specific AppError types: 401/403→AuthError, 404→NotFoundError, 429→RetryableError. output.ExitWithError renders errors (structured JSON when --output json) and exits with the appropriate code.
auth.ResolveCredentials: env vars (ZENDESK_OAUTH_TOKEN or ZENDESK_EMAIL+ZENDESK_API_TOKEN) → stored credentials file ($XDG_CONFIG_HOME/zd/credentials.json) by profile.
config.ConfigDir() reads XDG_CONFIG_HOME env directly (not the adrg/xdg cached value) for test compatibility. Config is per-profile under profiles.<name> in config.yaml.
cmd/mcp.go + cmd/mcp_tools.go implement a built-in MCP server (zd mcp serve) using modelcontextprotocol/go-sdk. Tool input types use jsonschema struct tags for automatic schema generation. Tools reuse newTicketService/newSearchService from the command layer.
internal/tui/ is a Bubble Tea (charmbracelet/bubbletea) app with split-panel layout (list + detail), search, comment, status/priority pickers, auto-refresh, and a bar chart view. The App struct holds service interfaces (zendesk.TicketService, zendesk.SearchService) and delegates to the same service layer as CLI commands.
internal/nlq/ translates natural language like "urgent tickets assigned to jane" into Zendesk search syntax (priority:urgent assignee:jane) purely locally — no LLM or API key. Queries already in Zendesk syntax pass through unchanged. Used by tickets search and TUI search.
internal/demo/ provides a Store with 100+ seeded synthetic tickets and implements the service interfaces (TicketService, SearchService, UserService). Activated via --demo flag; checked in newTicketService/newSearchService before credential resolution.
cmd/— Cobra commands. Each subcommand file registers itself viainit().tickets.gohas sharednewTicketService/newSearchService/newUserServicefactory functions.mcp_tools.goregisters MCP tool handlers.internal/api/—Client(HTTP),TicketService,SearchService,ArticleService,UserService,RetryTransport, cursor-based pagination.internal/auth/—AuthTransportRoundTripper, credential CRUD (credentials.json),OAuthFlow(browser-based).internal/output/—Formatterinterface with JSON/NDJSON/Text implementations, field projection viaprojectFields.internal/types/— Domain types (Ticket,Article,User,TicketPage,SearchPage),AppError, pagination options.internal/tui/— Bubble Tea interactive terminal UI.internal/nlq/— Local natural language → Zendesk query syntax translator.internal/demo/— Synthetic data store for--demomode.pkg/zendesk/— Public interfaces (TicketService,SearchService,UserService,ArticleService) used by commands and MCP tools.
buildUserMap + enrichTicket in cmd/tickets.go handle --include users sideloading: user IDs from tickets are resolved to names/emails via a map built from the sideloaded users array, then injected as requester_name, requester_email, assignee_name, assignee_email. The MCP tools do this automatically.
Tests create an httptest.Server with inline handlers or fixture data, then construct a Client pointing at server.URL (bypassing real auth/transport). See testClient() helper in internal/api/client_test.go.
zd commands -o json— full CLI surface with flags/types/defaultszd schema --command "tickets create"— JSON Schema for tool calling
--output json|ndjson|text(default:text)--fields id,status,subject— field projection- Errors always to stderr; structured JSON errors when
--output json
0=success, 1=general, 2=arg error, 3=auth, 4=retryable/rate-limited, 5=not found