cli

package
v1.801.477 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: Apache-2.0 Imports: 35 Imported by: 0

Documentation

Overview

Package cli is the Hanzo cloud-control CLI — the client half of the `hanzo` binary: one command tree over the Hanzo Cloud.

Every verb registered in newRootCmd MANAGES the Hanzo Cloud from here; every other verb cmd/hanzo hands to the Rust fabric CLI (IsControlVerb draws that line off this tree). What runs here:

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 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 link --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. cmd/hanzo RESOLVES it once (resolveVersion: the -ldflags stamp, else the build metadata the toolchain embeds) and assigns it here — this package holds the answer and never re-derives it. Reported by `hanzo version` and sent as the User-Agent.

Functions

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 names a command this binary serves, and so must run here rather than being handed to the fabric CLI. It asks the command tree itself — cobra's own name and alias resolution over newRootCmd — so the router and the command set are one fact and cannot drift apart.

A hand-kept verb list was the previous answer, and it drifted both ways: it still claimed `code` and `k8s` after those commands were deleted, so cobra answered `unknown command` for verbs the fabric CLI implements, and it never listed `completion`, so a command registered right here was handed away.

func Passthrough added in v1.801.157

func Passthrough(args []string) bool

Passthrough delegates a verb this binary does not own — node, dev, wallet, network, … — to the Rust fabric/dev CLI (resolved by fabricCLI, installed as `hanzo-node`), so the single `hanzo` name is a SUPERSET: Go verbs served natively, everything else handed through unchanged. `hanzo node up` (the fabric `link` itself composes) works for users too. It runs the delegate to completion with inherited stdio and exits with its code; it returns false only when no fabric CLI is resolvable, so the caller can report unknown-subcommand.

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/platform.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/platform/fleet envelope: ordered rows + a drift summary.

type AppsQuery

type AppsQuery struct {
	Env    string
	Health string
	Drift  bool
}

AppsQuery are the optional /v1/platform/fleet 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 BuildBinary added in v1.801.293

type BuildBinary struct {
	Name      string   `json:"name" yaml:"name"`
	Main      string   `json:"main,omitempty" yaml:"main"`
	Run       string   `json:"run,omitempty" yaml:"run"`
	Out       string   `json:"out,omitempty" yaml:"out"`
	Ldflags   string   `json:"ldflags,omitempty" yaml:"ldflags"`
	Platforms []string `json:"platforms,omitempty" yaml:"platforms"`
	Image     string   `json:"image,omitempty" yaml:"image"`
}

BuildBinary is ONE hanzo.yml `binaries:` entry, sent verbatim. The recipe a repo declares IS the request body — there is no CLI-side recipe format.

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"`
	Index      string `json:"index,omitempty"`
}

BuildJob is the enqueue acceptance (HTTP 202). Image is the image lane's output; Index is the artifact lane's binaries.json — a build has one or other.

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"`

	// The artifact lane: `binaries:` + `bucket:` from the repo's hanzo.yml.
	Binaries []BuildBinary `json:"binaries,omitempty"`
	Bucket   string        `json:"bucket,omitempty"`
	Tag      string        `json:"tag,omitempty"`
}

BuildReq is the direct-enqueue body. Repo/SHA are required, plus EITHER Image (build a container image) or Binaries (build the artifacts hanzo.yml declares).

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"` // sk-… key, shared with the rest of the toolchain
}

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