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 ¶
- Variables
- func DeleteCredentials() error
- func Execute(args []string) error
- func IsControlVerb(sub string) bool
- func Passthrough(args []string) bool
- func RestoreStdout()
- func SaveActive(c *Credentials) error
- type AgentRunReq
- type AgentRunResult
- type AppView
- type AppsList
- type AppsQuery
- type BotRunReq
- type BotRunResult
- type BuildBinary
- type BuildJob
- type BuildReq
- type Cluster
- type Config
- type Credentials
- type DeployResult
- type Env
- type IdentityStore
- type NodePool
- type Platform
- func (p *Platform) App(ctx context.Context, app string) (*AppView, error)
- func (p *Platform) Apps(ctx context.Context, q AppsQuery) (*AppsList, error)
- func (p *Platform) Clusters(ctx context.Context) ([]Cluster, error)
- func (p *Platform) EnqueueBuild(ctx context.Context, req BuildReq, buildToken string) (*BuildJob, error)
- func (p *Platform) Redeploy(ctx context.Context, app, env string) (*DeployResult, error)
- type RunResult
- type RunSpec
- type SharePolicy
Constants ¶
This section is empty.
Variables ¶
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 ¶
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 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
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 ¶
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).
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 ¶
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 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 ¶
App gets one app row by its <app> CR name (production by default; the server scans the caller's authorized namespaces 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 {
}
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).