Documentation
¶
Overview ¶
Package cli is the Hanzo cloud-control CLI — the gcloud/doctl-class client half of the `hanzo` binary.
`hanzo <subsystem>` SERVES a subsystem (server mode, cmd/hanzo dispatch); `hanzo <verb>` CONTROLS the live estate (client mode, this package):
hanzo login | auth identity against hanzo.id (IAM) hanzo apps list|get the platform apps board (declared/running/drift) hanzo deploy drive a platform redeploy (rolling, zero-downtime) hanzo clusters … provision/list/select dedicated DOKS clusters hanzo build enqueue a platform-native build (runner fabric) hanzo k8s … current deploy target helpers hanzo config … ~/.hanzo/config preferences
It is a THIN client over surfaces that already exist — Hanzo IAM (hanzo.id /v1/iam/oauth/*), the platform REST control plane (platform.hanzo.ai /v1/*), and the cloud /v1 API. It invents no parallel API and holds no business logic; every command is one HTTP call shaped by resolved configuration. Secrets live only in ~/.hanzo (0600) or the environment — never in source, never logged.
device.go — RFC 8628 Device Authorization Grant for `hanzo login`: the ONE way any machine signs in. The CLI asks IAM for a device+user code, shows the verification link as text AND a terminal QR (scan with a phone), and polls the token endpoint until the user approves in any browser session. No password ever touches this terminal; works headless (GPU boxes, ssh, CI).
studio.go — local Hanzo Studio render-backend supervision for `hanzo gpu connect --studio-dir <checkout>`. The gpu-jobs claim loop renders on the LOCAL studio server (127.0.0.1:8188); this keeps that server alive so the box needs no separate watchdog script or hand-rolled systemd unit — the hanzo CLI is the one way a BYO box joins the fleet, render backend included.
Semantics (ported from the GB10 watchdog it replaces): health-probe /system_stats; on failure, one grace re-check, then free the port (a stale main.py holding :8188 makes the new one crash on EADDRINUSE) and relaunch from the checkout's venv. Emits a line only on restart events.
Index ¶
- Variables
- func ControlCommands() map[string]string
- func DeleteCredentials() error
- func Execute(args []string) error
- func IsControlVerb(sub string) bool
- func RestoreStdout()
- func SaveActive(c *Credentials) error
- type AgentRunReq
- type AgentRunResult
- type AppView
- type AppsList
- type AppsQuery
- type BotRunReq
- type BotRunResult
- type BuildJob
- type BuildReq
- type Cluster
- type Config
- type Credentials
- type Env
- type IdentityStore
- type Platform
- func (p *Platform) App(ctx context.Context, id, org string) (*AppView, error)
- func (p *Platform) Apps(ctx context.Context, q AppsQuery) (*AppsList, error)
- func (p *Platform) Clusters(ctx context.Context, org string) ([]Cluster, error)
- func (p *Platform) EnqueueBuild(ctx context.Context, req BuildReq, buildToken string) (*BuildJob, error)
- func (p *Platform) InstallBaseline(ctx context.Context, org, clusterID string) error
- func (p *Platform) ProvisionCluster(ctx context.Context, org string, req ProvisionReq) (*Cluster, error)
- func (p *Platform) Redeploy(ctx context.Context, org, project, env, container string) error
- func (p *Platform) SelectTarget(ctx context.Context, org string, clusterID *string) (*Target, error)
- func (p *Platform) SyncApps(ctx context.Context) error
- func (p *Platform) Target(ctx context.Context, org string) (*Target, error)
- type ProvisionReq
- type RunResult
- type RunSpec
- type SharePolicy
- type Target
Constants ¶
This section is empty.
Variables ¶
var Version = "dev"
Version is the binary version, set by cmd/hanzo from its -ldflags value so the CLI and the server report one string. Used in the User-Agent.
Functions ¶
func ControlCommands ¶
ControlCommands returns the verb→description map for `hanzo help`.
func DeleteCredentials ¶
func DeleteCredentials() error
DeleteCredentials removes the credential store (used by logout).
func Execute ¶
Execute runs the control CLI with args (already stripped of "hanzo"). It is the single entrypoint cmd/hanzo calls for client-mode verbs.
func IsControlVerb ¶
IsControlVerb reports whether sub is a client-mode command (and therefore must be routed to this package, not the server dispatcher).
func RestoreStdout ¶
func RestoreStdout()
RestoreStdout restores the real process stdout. cmd/hanzo calls this as its first statement so every command writes to the genuine stdout.
func SaveActive ¶ added in v1.801.59
func SaveActive(c *Credentials) error
SaveActive writes c back as the active identity (store + mirror), keeping the two consistent after an in-place token refresh. With no store yet it falls back to the single-file write.
Types ¶
type AgentRunReq ¶ added in v1.786.165
type AgentRunReq struct {
Task string `json:"task"`
GPU bool `json:"gpu,omitempty"`
Timeout string `json:"timeout,omitempty"`
Repo string `json:"repo,omitempty"`
}
AgentRunReq is the POST /v1/agents/:ref/run body — a task for a managed agent.
type AgentRunResult ¶ added in v1.786.165
type AgentRunResult struct {
RunID string `json:"runId"`
Status string `json:"status"`
URL string `json:"url"`
}
AgentRunResult is the agent-run acceptance.
type AppView ¶
type AppView struct {
ID string `json:"id"`
Org string `json:"org"`
App string `json:"app"`
Env string `json:"env"`
Repo string `json:"repo"`
Registry string `json:"registry"`
DeclaredTag *string `json:"declaredTag"`
RunningTag *string `json:"runningTag"`
LatestTag *string `json:"latestTag"`
ReleaseURL *string `json:"releaseUrl"`
ReleaseAssets int `json:"releaseAssets"`
Health *string `json:"health"`
Cluster *string `json:"cluster"`
Namespace *string `json:"namespace"`
LastObserved *string `json:"lastObserved"`
UpdatedAt string `json:"updatedAt"`
Drift json.RawMessage `json:"drift"`
}
AppView mirrors the platform apps-lifecycle DTO. Nullable columns are *string so JSON null round-trips; Drift is kept raw so --json is byte-faithful and the drift schema can evolve without a client bump.
type AppsList ¶
type AppsList struct {
Apps []AppView `json:"apps"`
Summary struct {
Total int `json:"total"`
ByDrift map[string]int `json:"byDrift"`
} `json:"summary"`
}
AppsList is the /v1/apps envelope: ordered rows + a drift summary.
type BotRunReq ¶ added in v1.786.165
type BotRunReq struct {
Task string `json:"task"`
Surface string `json:"surface"` // desktop | terminal
GPU bool `json:"gpu,omitempty"`
Timeout string `json:"timeout,omitempty"`
}
BotRunReq is the boot-a-computer-using-agent body. Surface selects the sandbox the operative runtime drives: "desktop" (noVNC GUI) or "terminal" (shell only).
type BotRunResult ¶ added in v1.786.165
type BotRunResult struct {
RunID string `json:"runId"`
Status string `json:"status"`
SessionURL string `json:"sessionUrl"`
}
BotRunResult carries the live session: a URL to watch/attach (noVNC / terminal) plus the run id.
type BuildJob ¶
type BuildJob struct {
BuildJobID string `json:"buildJobId"`
Status string `json:"status"`
RunnerPool string `json:"runnerPool"`
Image string `json:"image"`
Target string `json:"target"`
}
BuildJob is the enqueue acceptance (HTTP 202).
type BuildReq ¶
type BuildReq struct {
Repo string `json:"repo"`
SHA string `json:"sha"`
Image string `json:"image"`
Branch string `json:"branch,omitempty"`
Ref string `json:"ref,omitempty"`
Dockerfile string `json:"dockerfile,omitempty"`
Context string `json:"context,omitempty"`
DockerTarget string `json:"dockerTarget,omitempty"`
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
OrganizationID string `json:"organizationId,omitempty"`
}
BuildReq is the direct-enqueue body. Repo/SHA/Image are required.
type Cluster ¶
type Cluster struct {
DoksClusterID string `json:"doksClusterId"`
Name string `json:"name"`
DoClusterID *string `json:"doClusterId"`
Region string `json:"region"`
Status string `json:"status"`
Endpoint *string `json:"endpoint"`
K8sVersion *string `json:"k8sVersion"`
HA bool `json:"ha"`
Phase string `json:"phase"`
OperatorInstalled bool `json:"operatorInstalled"`
BaselineInstalled bool `json:"baselineInstalled"`
Active bool `json:"active"`
BaselineError *string `json:"baselineError"`
OrganizationID string `json:"organizationId"`
CreatedAt string `json:"createdAt"`
Tags []string `json:"tags"`
MaintenancePolicy json.RawMessage `json:"maintenancePolicy,omitempty"`
}
Cluster mirrors a doks_cluster record. `status` is DigitalOcean state; `phase` is the platform provisioning lifecycle — orthogonal (a DO-running cluster is not a usable target until phase=ready).
type Config ¶
type Config struct {
Org string `json:"org,omitempty"`
Output string `json:"output,omitempty"` // "table" (default) | "json"
IAMIssuer string `json:"iam_issuer,omitempty"`
PlatformURL string `json:"platform_url,omitempty"`
CloudURL string `json:"cloud_url,omitempty"`
ClientID string `json:"client_id,omitempty"`
APIKey string `json:"apiKey,omitempty"` // hk-… key; what `hanzo code` hands the agents
CodeTool string `json:"code_tool,omitempty"` // default agent for bare `hanzo` / `hanzo code`: dev|claude|codex
CodeModel string `json:"code_model,omitempty"` // default model for `hanzo code` (else defaultCodeModel)
}
Config holds non-secret CLI preferences. Every field is optional; empty fields fall back to the built-in defaults at resolution time.
func LoadConfig ¶
LoadConfig reads ~/.hanzo/config (or HANZO_CONFIG).
type Credentials ¶
type Credentials struct {
AccessToken string `json:"access_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
TokenType string `json:"token_type,omitempty"`
Expiry int64 `json:"expiry,omitempty"` // unix seconds
Subject string `json:"subject,omitempty"`
Owner string `json:"owner,omitempty"` // org slug from the token
PlatformToken string `json:"platform_token,omitempty"`
BuildToken string `json:"build_token,omitempty"`
}
Credentials holds secret material, ~/.hanzo/credentials.json, mode 0600. AccessToken/RefreshToken are the IAM user identity (from `hanzo login`); PlatformToken/BuildToken are the machine-to-machine tokens the platform REST control plane requires (it cannot validate IAM user tokens).
func LoadCredentials ¶
func LoadCredentials() (*Credentials, error)
LoadCredentials reads ~/.hanzo/credentials.json.
func (*Credentials) Save ¶
func (c *Credentials) Save() error
Save persists credentials with mode 0600 (owner read/write only).
type Env ¶
type Env struct {
Org string
Output string
IAMIssuer string
PlatformURL string
CloudURL string
ClientID string
// contains filtered or unexported fields
}
Env is the fully-resolved runtime context for a command: config + creds merged with environment and the global flags. Built once in the root's PersistentPreRunE and read by every subcommand.
type IdentityStore ¶ added in v1.801.59
type IdentityStore struct {
Active string `json:"active,omitempty"`
Identities map[string]*Credentials `json:"identities,omitempty"`
}
IdentityStore is the on-disk shape of ~/.hanzo/identities.json.
func LoadIdentities ¶ added in v1.801.59
func LoadIdentities() (*IdentityStore, error)
LoadIdentities reads the store. A pre-existing single-file credentials.json with no store yet is migrated in (read-only) as the sole, active identity, so upgrades are seamless — the first write persists it into the store.
func (*IdentityStore) Put ¶ added in v1.801.59
func (s *IdentityStore) Put(c *Credentials) string
Put stores c under its key and makes it active, returning the key.
func (*IdentityStore) Remove ¶ added in v1.801.59
func (s *IdentityStore) Remove(key string)
Remove deletes an identity; Save re-points Active if it was the one removed.
func (*IdentityStore) Save ¶ added in v1.801.59
func (s *IdentityStore) Save() error
Save persists the store (0600) and mirrors the active identity into credentials.json for legacy single-file readers. When the store is empty it removes both files. Active is normalized to a real key first.
type Platform ¶
type Platform struct {
// contains filtered or unexported fields
}
Platform is a thin client over the platform.hanzo.ai /v1 control plane. That surface is machine-to-machine (service-token, "No OIDC" — it cannot validate IAM user tokens), so the token here is the platform service token, resolved from flag/env/credential store by the caller; the build endpoint takes its own token per call.
func (*Platform) EnqueueBuild ¶
func (p *Platform) EnqueueBuild(ctx context.Context, req BuildReq, buildToken string) (*BuildJob, error)
EnqueueBuild enqueues a native build. It authenticates with the dedicated build-callback token, not the service token.
func (*Platform) InstallBaseline ¶
func (*Platform) ProvisionCluster ¶
func (*Platform) Redeploy ¶
Redeploy triggers a rolling restart of the container's k8s Deployment. The coordinates are exact (the platform validates org+project+env+container scope).
type ProvisionReq ¶
type ProvisionReq struct {
Region string `json:"region,omitempty"`
HA bool `json:"ha,omitempty"`
NodeSize string `json:"nodeSize,omitempty"`
NodeCount int `json:"nodeCount,omitempty"`
}
ProvisionReq is the dedicated-cluster provisioning body (org forced by path).
type RunResult ¶ added in v1.786.165
type RunResult struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Status string `json:"status"`
Shape string `json:"shape"`
}
RunResult is the enqueue/creation acceptance.
type RunSpec ¶ added in v1.786.165
type RunSpec struct {
Name string `json:"name,omitempty"`
Image string `json:"image,omitempty"` // container artifact (run)
Source string `json:"source,omitempty"` // source ref/path (fn)
Runtime string `json:"runtime,omitempty"`
Port int `json:"port,omitempty"`
Shape string `json:"shape"` // service | function | task
Min int `json:"minScale"`
Max int `json:"maxScale"`
GPU bool `json:"gpu,omitempty"`
Env map[string]string `json:"env,omitempty"`
}
RunSpec is the POST /v1/run (container) / /v1/fn (source) body. Shape selects the execution model: "service" (autoscaled, long-lived), "function" (per-request, scale-to-zero), or "task" (run-to-completion).
type SharePolicy ¶ added in v1.786.131
type SharePolicy struct {
}
SharePolicy is the per-machine sharing policy: which jobs this GPU accepts and for whom. ONE object on the machine record (advertised in the fleet registration) and enforced ONCE, at claim. A nil/zero policy is fully permissive — an unconfigured box behaves exactly as before. A linked GPU can thus be shared to specific orgs / projects / job types / models with per-scope limits, edited on the machine record (desktop UI / visor) and loaded here via HANZO_GPU_POLICY (inline JSON) or HANZO_GPU_POLICY_FILE (path).