| name | artifacthub-client |
| description | Use when working with the Artifact Hub API client, adding new API endpoints, fixing HTTP requests, or debugging values/schema lookups for Helm charts. |
| allowed-tools | Read, Write, Edit, Bash, Grep |
Artifact Hub Client Pattern
The Artifact Hub client in internal/artifacthub/ is an HTTP client for the public API at https://artifacthub.io/api/v1.
For the full design (two-tier lookup strategy, enforced workflow, caching, config flags), see IMPLEMENTATION.md section "Artifact Hub Integration — Deterministic Helm Config".
API Endpoints We Use
All endpoints are unauthenticated GET requests. Base URL is configurable.
GET /packages/search?ts_query_web={q}&kind=0&limit={n} → search Helm charts
GET /packages/helm/{repo}/{pkg} → package metadata (latest)
GET /packages/helm/{repo}/{pkg}/{version} → package metadata (specific version)
GET /packages/helm/{repo}/{pkg}/{version}/values → default values.yaml (YAML string)
GET /packages/helm/{repo}/{pkg}/{version}/values-schema → values.schema.json (JSON Schema)
GET /packages/helm/{repo}/{pkg}/{version}/templates → chart template files
GET /packages/helm/{repo}/{pkg}/{version}/changelog.md → changelog in markdown
Source: Artifact Hub OpenAPI spec
Client Structure
type Client struct {
BaseURL string
HTTPClient *http.Client
Cache *ValuesCache
}
func New(cfg Config) *Client {
return &Client{
BaseURL: cfg.BaseURL,
HTTPClient: &http.Client{
Timeout: cfg.Timeout,
},
Cache: NewValuesCache(cfg.CacheTTL),
}
}
Request Pattern
func (c *Client) GetValues(ctx context.Context, repo, pkg, version string) (string, error) {
key := fmt.Sprintf("%s/%s@%s", repo, pkg, version)
if cached, ok := c.Cache.Get(key); ok {
return cached, nil
}
u := fmt.Sprintf("%s/packages/helm/%s/%s/%s/values",
c.BaseURL,
url.PathEscape(repo),
url.PathEscape(pkg),
url.PathEscape(version),
)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
return "", fmt.Errorf("artifacthub get values: %w", err)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return "", fmt.Errorf("artifacthub get values: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusTooManyRequests {
return "", fmt.Errorf("artifacthub get values: rate limited (429)")
}
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("artifacthub get values: HTTP %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("artifacthub get values: read body: %w", err)
}
result := string(body)
c.Cache.Set(key, result)
return result, nil
}
Rules
- Always use
http.NewRequestWithContext — never lose the caller's context
- Respect 429: return an error, don't retry automatically (let the LLM decide)
- URL-encode path segments with
url.PathEscape
- Cache by
repo/pkg@version key — values don't change for a given version
- The values endpoint returns raw YAML as a string, not JSON
- The schema endpoint returns JSON Schema (may be empty object if chart has no schema)
- Feature-gated: check
cfg.Enabled before making any requests