cli

package
v1.801.108 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: Apache-2.0 Imports: 31 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func ControlCommands() map[string]string

ControlCommands returns the verb→description map for `hanzo help`.

func DeleteCredentials

func DeleteCredentials() error

DeleteCredentials removes the credential store (used by logout).

func Execute

func Execute(args []string) error

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

func IsControlVerb(sub string) bool

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>/<app>/<env>, e.g. hanzoai/iam/main
	Org         string          `json:"org"` // image namespace, e.g. hanzoai
	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"`
	Health      string          `json:"health"`
	Phase       string          `json:"phase"`
	Cluster     string          `json:"cluster"`
	Namespace   string          `json:"namespace"`
	Endpoints   []string        `json:"endpoints"`
	Drift       json.RawMessage `json:"drift"`
}

AppView mirrors clients/paas.AppView (the LIVE board DTO). Tags/health are plain strings ("" == unknown, rendered "-"); 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/paas/apps envelope: ordered rows + a drift summary.

type AppsQuery

type AppsQuery struct {
	Env    string
	Health string
	Drift  bool
}

AppsQuery are the optional /v1/paas/apps filters (server-honored). Env/Health/ Drift narrow the board; there is deliberately no org filter — the board is confined to the caller's org by the validated identity, never a client value.

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"`
	DoClusterID   string     `json:"doClusterId"`
	Name          string     `json:"name"`
	Region        string     `json:"region"`
	Status        string     `json:"status"`
	NodePools     []NodePool `json:"nodePools"`
	NodeSize      string     `json:"nodeSize"`
	NodeCount     int        `json:"nodeCount"`
	CreatedAt     string     `json:"createdAt"`
	Kind          string     `json:"kind"`
	NvidiaGPU     int        `json:"nvidiaGpu"`
	AmdGPU        int        `json:"amdGpu"`
}

Cluster mirrors clients/visor.clusterView — the LIVE cluster DTO. `kind` is "managed" (Visor-provisioned) or "byo" (attached kubeconfig).

func (Cluster) ID added in v1.801.89

func (c Cluster) ID() string

ID is the stable cluster identifier for display/lookup: the DOKS id when managed, else the name (a BYO cluster keys on its attached name).

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

func LoadConfig() (*Config, error)

LoadConfig reads ~/.hanzo/config (or HANZO_CONFIG).

func (*Config) Save

func (c *Config) Save() error

Save persists the config (mode 0644 — non-secret).

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 DeployResult added in v1.801.89

type DeployResult struct {
	OK          bool   `json:"ok"`
	App         string `json:"app"`
	Namespace   string `json:"namespace"`
	Env         string `json:"env"`
	RestartedAt string `json:"restartedAt"`
}

DeployResult is the /deploy acceptance (202): the restarted app + its namespace.

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 NodePool added in v1.801.89

type NodePool struct {
	PoolID    string `json:"poolId"`
	Name      string `json:"name"`
	Size      string `json:"size"`
	Count     int    `json:"count"`
	MinNodes  int    `json:"minNodes"`
	MaxNodes  int    `json:"maxNodes"`
	AutoScale bool   `json:"autoScale"`
}

NodePool mirrors clients/visor.nodePoolView.

type Platform

type Platform struct {
	// contains filtered or unexported fields
}

Platform is a thin client over the LIVE Hanzo Cloud control plane (platform.hanzo.ai / api.hanzo.ai → svc `cloud`, the Go binary). Every route it calls is served by that one binary and authorized off ONE IAM identity: after `hanzo login` the CLI sends the IAM access token as the bearer, and the cloud's identity middleware (SanitizeIdentity) validates the JWT and org-scopes the caller — no separate platform/service token. A purpose-minted machine token still works (flag > env > credential store > IAM login) for automation.

func (*Platform) App

func (p *Platform) App(ctx context.Context, app string) (*AppView, error)

App gets one app row by its <app> CR name (production by default; the server scans the caller's authorized namespaces main→test→dev).

func (*Platform) Apps

func (p *Platform) Apps(ctx context.Context, q AppsQuery) (*AppsList, error)

func (*Platform) Clusters

func (p *Platform) Clusters(ctx context.Context) ([]Cluster, error)

func (*Platform) EnqueueBuild

func (p *Platform) EnqueueBuild(ctx context.Context, req BuildReq, buildToken string) (*BuildJob, error)

EnqueueBuild enqueues a native build. buildToken is resolved by the caller (IAM login is the final fallback; a dedicated build token wins when present).

func (*Platform) Redeploy

func (p *Platform) Redeploy(ctx context.Context, app, env string) (*DeployResult, error)

Redeploy triggers a rolling restart of the named app. env is optional (main|test|dev); empty targets production (the first match, main→test→dev).

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 {
	AllowedOrgs     []string `json:"allowedOrgs,omitempty"`     // org owners allowed to run here (empty = any)
	AllowedProjects []string `json:"allowedProjects,omitempty"` // project ids allowed (empty = any)
	AllowedJobTypes []string `json:"allowedJobTypes,omitempty"` // e.g. ["studio.render"] (empty = any this worker handles)
	AllowedModels   []string `json:"allowedModels,omitempty"`   // model ids allowed (empty = any)
	MaxConcurrent   int      `json:"maxConcurrent,omitempty"`   // 0 = unbounded (the worker is serial today)
}

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).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL