The palette is the --hz-* tokens from @hanzo/design and the hanzo.ai app shell: a black page, #171717 surfaces, #2e2e2e hairlines, white ink and a #a3a3a3 secondary, inverted under the light theme and stamped on <html> so tooltips, menus and suggestion lists follow it. The kit's blue accent ramp points at them, so no blue is left in the chrome; state keeps its hue (green, amber, red, at 60% on edges and the ratio bar), the neutral states take three grey rungs, and native checkboxes and radios take the ink. - Sidebar: one small mark and "Hanzo CD", the version only when the build was stamped, line icons from the app shell's set, rows that tint for the current page, and the list filters and their text fields restyled to match. - Sentence case everywhere: no uppercase transforms, and the all-caps titles, labels and table headers are written in sentence case. - Buttons: the first toolbar action is the white pill; the rest, tile actions, banner actions and filter clears are ghosts. The search box, view switch, health bar toggle, sort and Log out are quiet controls, and icon-only buttons carry their names. - Font Awesome 7 ignored the global $fa-font-path and asked for /webfonts/*, so every fa icon drew an empty box; main.scss configures its module with the assets/fonts path the build copies them to. - The empty list is a small outline icon, one line and a ghost action. - On a phone the sidebar is a 56px rail that opens over the page (Escape or the scrim closes it), and the toolbar wraps and scrolls with the page. - The operator banner, the clusters notice, tooltips, resource icons and the pod stats bar use the same tokens, and sit beside the rail when the sidebar is collapsed. - Keyboard focus draws one ring from the tokens, and the login card keeps its own colours when a session ends inside the light theme. The smoke gate also fails on any font that does not load, and checks the sidebar's mark, name and version, the empty state, the phone rail, a filter suggestion over the sidebar, the collapsed toolbar, the network view and the login page after a session ends. Co-authored-by: Hanzo Dev <[email protected]>
Hanzo CD — declarative continuous delivery for Kubernetes
Git holds the desired state; the controller applies it and reports drift.
Hanzo CD is a hard fork of Argo CD (Apache-2.0 — see NOTICE). The engine is theirs. The packaging, API group and platform integration are ours. Their community, docs, support channels and roadmap are not ours, so this file does not borrow them — the previous version of this README was upstream's with the names replaced, which had the effect of putting our name on other people's conference talks and blog posts.
What differs from upstream
| API group | apps.hanzo.ai — Application, ApplicationSet, AppProject |
| annotations | cd.hanzo.ai/* |
| binaries | cd, cd-server, cd-repo-server, cd-application-controller, cd-applicationset-controller, cd-commit-server, cd-cmp-server, cd-dex, cd-git-ask-pass, cd-k8s-auth |
| module | github.com/hanzoai/cd |
| image | ghcr.io/hanzoai/cd |
| SSO | Hanzo IAM (hanzo.id) over OIDC — dex builds but is not deployed |
| notifications | removed; we use hanzoai/notify |
Where it runs
cd.hanzo.ai, namespace hanzo-cd on hanzo-k8s.
It moves git → CR for the fleet; the Hanzo operator keeps CR → workload. The two never write the same field: Hanzo CD owns CR spec from git, the operator owns CR status and the child workload. Disjoint by construction, which is what lets both run without fighting over field ownership.
Deployment layout, the AppProject fences, and the one-observer/three-enforcer
split live in
hanzoai/universe → infra/k8s/hanzo-cd/.
Build
CGO_ENABLED=0 go build ./... # the gate hanzo.yml runs on every PR
Images build on platform.hanzo.ai from the root
Dockerfile; hanzo.yml declares the target.
Releases are tagged. A branch build publishes sha-<short> and will never
advance a service already pinned to a release, so shipping means cutting a
vX.Y.Z tag — not merging to main.