Skip to content

feat(cli): seictl gov subcommands for in-cluster governance operations #164

@bdchatham

Description

@bdchatham

Problem

Operators today run seienv vote / seienv propose-upgrade (in slanders/seienv) to perform fleet-wide governance operations against EC2 validators via SSH. With validators migrating to Kubernetes via sei-k8s-controller, the canonical operator tool going forward is seictl. seictl does not yet expose governance commands — it needs gov subcommands that resolve a SeiNode's sidecar URL from the K8s API and submit the sign-tx tasks introduced in the sister issue.

Impact

  • User-visible replacement for seienv vote / seienv propose-upgrade.
  • Closes the loop on the K8s-native validator-governance workflow.
  • Without it, the sidecar task surface exists but there's no ergonomic way for human operators to call it.

Relevant experts

  • platform-engineer — K8s client integration, kubeconfig handling, sidecar discovery
  • product-engineer — CLI ergonomics, fan-out across deployments

Proposed approach

  1. New top-level cobra command seictl gov in cmd/gov/ with subcommands:
    • seictl gov vote <proposal-id> <yes|no|abstain|no_with_veto> --validator <seinode-name> [--namespace <ns>] [--fees <fees>] [--memo <memo>]
    • seictl gov submit-proposal software-upgrade <name> --validator <seinode-name> --height <h> [--info <url>] [--deposit <amt>] [--fees <fees>]
    • seictl gov deposit <proposal-id> <amount> --validator <seinode-name> [--fees <fees>]
  2. Fan-out flags for fleet-wide ops (mirrors seienv's implicit fan-out):
    • --deployment <seinodedeployment-name> — resolves all SeiNodes owned by the deployment and submits in parallel
    • --threads N — parallelism cap (default 10)
  3. Sidecar discovery: K8s client (controller-runtime or client-go) fetches the SeiNode, resolves its headless Service DNS or Pod IP, constructs the sidecar URL (http://<seinode>-0.<seinode>.<ns>.svc.cluster.local:7777). Existing NewSidecarClientFromPodDNS helper covers this shape.
  4. Kubeconfig: uses standard clientcmd resolution (KUBECONFIG env, ~/.kube/config, in-cluster service-account if running in a pod).
  5. Output: task UUID printed immediately; if --wait is passed (default true), polls task status until terminal and prints {txHash, height, rawLog}.
  6. Idempotency: caller-supplied UUID via --task-id flag; CLI auto-generates and prints if not provided. Enables operator retry without double-voting.
  7. Error handling: surface sidecar task errors verbatim; on partial-failure across a fleet fan-out, print a per-validator status table and exit non-zero.

Acceptance criteria

  • Three subcommands implemented (vote, submit-proposal software-upgrade, deposit)
  • Single-validator and --deployment fleet fan-out modes work
  • Idempotent retry via --task-id works as documented
  • Per-validator status table for fan-out mode
  • Help text + examples included on every subcommand
  • Integration test against a kind cluster with two SeiNodes + a local seid devnet
  • User-facing docs in docs/gov.md mirroring slanders/seienv/cheatsheet.md governance section

Out of scope

  • Non-gov tx commands (staking, distribution, IBC) — same pattern, separate issues
  • Proposal types beyond software-upgrade in the initial cut (param-change, community-pool, text proposals) — additive later
  • Web UI / dashboard
  • Authn handshake — wires in when "Sidecar authn + authz middleware" lands; until then, CLI calls the unauthenticated endpoint

References

  • Coral session 2026-05-11
  • Predecessor: slanders/seienv cmd/vote.go, cmd/propose.go, propose.sh, cheatsheet.md
  • Sister issue: sidecar sign-tx task family (this repo)
  • Sidecar discovery pattern: sidecar/client/client.go (NewSidecarClientFromPodDNS)
  • Cobra command structure: main.go:43-52

Sequencing

Phase 1, step 4 of 5 in the governance-flow migration. Depends on step 3 (sign-tx task family). Step 5 (authn) is the final hardening pass and lands after this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions