# Contributing to zilliz
This guide covers everything you need to build, test, and modify the project.
## Prerequisites
- Rust toolchain (edition 2021) -- install via [rustup](https://rustup.rs/)
API model definitions (`control-plane.json` and `data-plane.json`) are embedded at compile time via `include_str!()`, so no external dependencies are needed.
## Development Setup
### Install binaries
```bash
cd vdc/zilliz-tui
# Install both `zilliz` and `zz` to ~/.cargo/bin/ (release build)
cargo install --path .
# Verify
zilliz version
```
After code changes, re-run `cargo install --path .` to update.
### Quick iteration
Use `cargo run` for faster debug builds during development:
```bash
# Launch TUI
cargo run
# Run CLI commands
cargo run -- cluster list
cargo run -- collection list -o json
```
### Type checking
```bash
cargo check
```
### Run tests
```bash
cargo test
```
### Debug logging
Logs are written to stderr (stdout is reserved for CLI/TUI output):
```bash
RUST_LOG=zilliz=debug cargo run -- cluster list
```
## Project Structure
```
src/
api/ HTTP client (ApiClient) and error types
bin/ Binary entry points (zilliz primary, zz alias)
cli/ CLI commands and dispatch
args.rs Clap argument parser definitions
auth.rs OAuth and API key login logic
auth_cmd.rs Auth subcommand handlers (status, switch)
configure.rs Interactive credential setup
context.rs Cluster context management
dispatch.rs Dynamic resource operation dispatch
formatter.rs Output formatting (table, JSON, YAML, CSV, text)
alert.rs Alert rule management
billing.rs Billing queries (usage, invoices)
cluster.rs Cluster-specific operations (create)
metrics.rs Metrics query and display
job_waiter.rs Async job polling with backoff
completion.rs Shell completion install/uninstall
help.rs Custom help text generation
error_hints.rs User-friendly error messages
version.rs Version display
config/ Config management (~/.zilliz/)
manager.rs ConfigManager -- reads/writes INI config files
credentials.rs API key extraction from login responses
context.rs Cluster context state
model/ JSON model loader and type definitions
loader.rs ModelLoader -- parses embedded JSON models
types.rs CliModel, Resource, Operation, Param types
builtin_models/ Embedded API definitions
control-plane.json Cloud management APIs
data-plane.json Milvus operation APIs
service/ Shared operation executor
executor.rs OperationExecutor -- builds and invokes API calls
tui/ Terminal UI (ratatui + crossterm)
app.rs Application state and screen enum
event.rs Event system (KeyEvent, Tick, Resize)
handler.rs Keyboard input routing
render.rs Frame rendering dispatch
views/ Screen renderers (welcome, etc.)
widgets/ Custom ratatui widgets
lib.rs Library entry point (main_impl, async_main)
main.rs CLI entry point
build.rs Triggers recompile when model JSON files change
```
## Architecture
### Model-driven design
CLI commands are not hardcoded. They are generated dynamically from two JSON model files:
- `src/model/builtin_models/control-plane.json` -- cloud management APIs (cluster, project, backup, etc.)
- `src/model/builtin_models/data-plane.json` -- Milvus APIs (collection, vector, index, etc.)
These are embedded at compile time via `include_str!()` in `src/model/loader.rs`. The `build.rs` script watches these files and triggers recompilation when they change.
Each model defines resources with operations. Each operation specifies the HTTP method, URL path, parameters (with types, defaults, choices), and pagination settings. To add a new resource command, add it to the appropriate JSON file -- no Rust code changes needed for standard CRUD operations.
### Dispatch flow
1. `lib.rs` parses CLI args via clap, loads models and config
2. Built-in commands (login, context, alert, etc.) are handled directly
3. Dynamic resource commands go through `cli/dispatch.rs`:
- Finds the resource and operation in the loaded models
- Prompts for required parameters if missing
- Confirms dangerous operations (delete, drop, suspend)
- Calls `service/executor.rs` to build and execute the HTTP request
4. `cli/formatter.rs` formats the response (table, JSON, YAML, CSV, text)
### Shared executor
`service/executor.rs` is used by both CLI and TUI. It handles path parameter interpolation, body/query parameter classification, and pagination (fetching all pages with `--all`).
### TUI architecture
The TUI uses [ratatui](https://github.com/ratatui/ratatui) with [crossterm](https://github.com/crossterm-rs/crossterm) as the terminal backend:
- `tui/mod.rs` -- entry point: sets up raw mode, alternate screen, and mouse capture; runs the event loop (render -> handle input -> check quit); cleans up terminal on exit
- `tui/app.rs` -- application state (`App` struct) with current screen and quit flag
- `tui/event.rs` -- event system producing `KeyEvent`, `Tick`, and `Resize` variants
- `tui/handler.rs` -- routes keyboard events to the appropriate handler
- `tui/views/` -- screen renderers, each responsible for drawing a single view
- `tui/render.rs` -- dispatches rendering to the active view
To add a new TUI screen: add a variant to the `Screen` enum in `app.rs`, create a view in `views/`, add rendering in `render.rs`, and add key handling in `handler.rs`.
## Configuration Internals
Config files live in `~/.zilliz/` (overridable via `ZILLIZ_CONFIG_DIR`). Both files use INI format parsed by the `rust-ini` crate.
| `credentials` | `[default]` | `api_key`, `user`, `org`, `plan` |
| `config` | `[default]` | `cluster_id`, `endpoint`, `database` |
On Unix, the `credentials` file is created with mode `0o600` (owner read/write only) to protect API keys.
`ConfigManager` in `config/manager.rs` handles all reads and writes. It creates the config directory and files on first use.
## Debugging Against UAT (Internal)
Zilliz contributors can point the CLI at the internal UAT control plane
(`https://api.cloud-uat3.zilliz.com`) via the hidden `--dev` flag on `login`.
The flag does not appear in `zilliz login --help` output and is not documented
in the user-facing README; it is contributor-only and may change at any time.
```bash
# Pass the API key directly
zilliz login --dev --api-key sk-uat-xxxxxxxx
# Or paste it interactively
zilliz login --dev
# All subsequent control-plane calls now hit UAT until you log out
zilliz cluster list
# Switch back to production:
zilliz logout # clears the persisted UAT endpoint
zilliz login --api-key sk-xxx # plain login also clears it on success
```
Notes:
- `--dev` is API-key only. The CLI does not call Auth0 or open a browser under
this flag. Get a UAT API key from the UAT3 console (`cloud-uat3.zilliz.com`).
- `--dev` is mutually exclusive with `--cn`.
- The persisted endpoint lives in `~/.zilliz/config [default].endpoint`. As long
as it is set to the UAT URL, every command targets UAT — including data-plane
and control-plane operations. `zilliz auth status` shows the active endpoint
as `Cloud: Dev (UAT)`.
- Do not advertise this flag to customers; if you want a customer-visible
"use the dev cloud" affordance, open a discussion first.
## Release Notes
Release notes live in `CHANGELOG.md` and are the single source of truth for what appears on each GitHub Release page.
### When you open a PR
If your PR adds a user-facing change (new command, new flag, bug fix, behavior change), add a bullet to `CHANGELOG.md` under `## [Unreleased]`, in the appropriate subsection:
- `### Added` -- new features, commands, flags, options
- `### Changed` -- behavior changes to existing features
- `### Deprecated` -- features marked for removal in a future version
- `### Removed` -- features removed in this release
- `### Fixed` -- bug fixes
- `### Security` -- security fixes
Create the subsection heading only if it does not already exist. Keep bullets short and user-facing; link to issues or PRs when it helps.
Internal refactors, test-only changes, CI tweaks, and dependency bumps do not need a changelog entry.
### When you cut a release
In the same commit that bumps `version` in `Cargo.toml`:
1. Rename `## [Unreleased]` to `## [X.Y.Z] - YYYY-MM-DD` (use today's date).
2. Add a fresh empty `## [Unreleased]` section above the versioned one.
3. Commit both changes together with a message like `chore(zilliz-tui): release v1.2.3`.
The CI release workflow (`.github/workflows/zilliz-tui.ci.yml`, triggered via `workflow_dispatch` with `release: true`) runs `scripts/extract-changelog.sh <version>` to pull the section for the version being released into the GitHub Release body. **If that section is missing, the release fails fast** -- it will not publish an empty or placeholder release.
### Testing the extractor locally
```bash
# From the repo root
vdc/zilliz-tui/scripts/extract-changelog.sh 1.0.2
```
Prints the body of the `## [1.0.2]` section to stdout. Pass a version that does not exist to see the failure path.