By default downloadRossoctl installs the latest release; pin a version with
ROSSOCTL_CLI_VERSION:
curl -fsSL https://raw.githubusercontent.com/kagenti/rossoctl-cli/main/downloadRossoctl \
| ROSSOCTL_CLI_VERSION=v0.1.0 shThe script prints how to add $HOME/.config/rossoctl to your PATH. Each release
ships prebuilt binaries built by .github/workflows/release.yml; the asset
names are rossoctl-<version>-<uname>-<uname -m>.tar.gz (arm64 is labeled
arm64 on both Linux and Darwin).
This project follows the standard Go CLI layout:
.
├── main.go # Thin entry point; calls cmd.Execute()
├── cmd/ # Cobra command tree (grouped by command)
│ ├── root.go # Root command + Execute() + persistent flags
│ ├── version.go # `rossoctl version`
│ ├── unimplemented.go # newGroup/newLeaf helpers + UNIMPLEMENTED stub
│ ├── install.go # `rossoctl install` (prints setup instructions)
│ ├── status.go # `rossoctl status` (session + platform status)
│ ├── login.go # `rossoctl login` (--token or OAuth device flow)
│ ├── agents.go # `rossoctl agents ...` (`list` fetches GET /agents)
│ ├── authconfig.go # `rossoctl auth-config` (shows server auth config)
│ ├── config.go # `rossoctl config ...` (context management)
│ ├── namespaces.go # `rossoctl namespaces ...` (`list` fetches GET /namespaces)
│ ├── tools.go # `rossoctl tools ...` (list/get/delete/import, mirrors agents)
│ └── ui.go # `rossoctl ui open` (opens the context server's site root)
├── internal/ # Private application logic (not importable externally)
│ ├── apiclient/ # HTTP client for the Rossoctl backend API
│ ├── buildinfo/ # Version metadata formatting
│ ├── config/ # ~/.config/rossoctl/config.yaml context persistence
│ └── deviceflow/ # OAuth 2.0 device authorization grant (Keycloak)
├── Makefile
└── go.mod
Design principles:
main.gostays trivial — it only callscmd.Execute().cmd/handles the CLI surface — flag parsing, help text, and wiring. Each command lives in its own file and registers itself withrootCmdininit().internal/holds the real logic — packages there are free of Cobra and of I/O, so they can be unit-tested directly.internal/also prevents other modules from importing this code.
make build # -> ./bin/rossoctl (version info injected via -ldflags)
make install # install into $GOBIN
make test # go test ./...Contexts are persisted in ~/.config/rossoctl/config.yaml (directory 0700, file
0600). Each context has a name, a server URI, an optional namespace, and an
optional bearer token.
The file is created lazily — the first command that needs it seeds a context
from the default server (http://kagenti-ui.localtest.me:8080/api/v1/) and
makes it current. Creating a context makes it current.
The server a command talks to is resolved as: an explicit --server flag wins
(and no bearer token is sent); otherwise the current context supplies both the
server URI and its bearer token. The global --server and --verbose/-v
flags must appear before the subcommand; -v logs each REST request (method,
URL, status, timing) to stderr.
rossoctl login --token <token> stores a token on a context. With --server,
the token is stored on the context named after that server's hostname (created
if none exists), which becomes current; without --server, it is stored on the
current context. rossoctl login (no --token) runs the OAuth 2.0 device
authorization grant (RFC 8628): it reads keycloak_url, realm, and
client_id from GET <server>/auth/config, requests a device code from
Keycloak, prints a verification URL and one-time code (and best-effort opens a
browser), polls until you authorize, and saves the resulting bearer token on
the target context.
The command tree mirrors the subcommands referenced in the Rossoctl docs
(agents, config, namespaces, tools, ui,
plus auth-config and the top-level install, login, status). The
config context commands, login, auth-config, install, status,
agents list, agents get, agents delete, agents import from-image,
tools list, tools get, tools delete, tools import from-image,
namespaces list, and ui open are implemented; other leaf commands currently
print UNIMPLEMENTED as a placeholder.