You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(cli): add runtime completers for sandbox/cluster/provider names #41
Follow-up from #71. The dynamic completion framework (CompleteEnv) is now in place. This issue tracks adding runtime completers that fetch live data on tab-press using ArgValueCompleter.
Motivation
Currently, tab-completion covers subcommands and flags. With runtime completers, users could get:
navigator sandbox connect <tab> → list of sandbox names
navigator sandbox get <tab> → list of sandbox names
navigator sandbox delete <tab> → list of sandbox names
navigator cluster use <tab> → list of cluster names
navigator provider get <tab> → list of provider names
Implementation Notes
Use clap_complete::engine::ArgValueCompleter with the #[arg(add = ...)] derive attribute
Completer functions have signature fn(&OsStr) -> Vec<CompletionCandidate> and run synchronously before the tokio runtime is initialized
The completer will need to:
Resolve the active cluster from ~/.config/navigator/active_cluster
Load cluster metadata for the gateway endpoint
Set up TLS and make a blocking HTTP/gRPC call to list resources
Return names as CompletionCandidate values
Consider a shared helper (e.g., fn complete_resource(resource_type) -> Vec<CompletionCandidate>) to avoid duplication across sandbox/cluster/provider completers
Completers should fail silently (return empty vec) if the cluster is unreachable — completion failures should never block the CLI
Complexity
Medium — the completer logic is straightforward, but the blocking network call with TLS inside a synchronous context needs care (e.g., spinning up a one-shot tokio runtime or using a blocking HTTP client).
Originally by @pimlock on 2026-02-25T16:05:01.423-08:00
Issue type:feat Complexity: Medium Confidence: High — clear path, two critical blockers already identified with solutions
Summary
Add runtime tab-completion for sandbox, cluster, and provider names by creating completer functions that fetch live data from the Navigator gateway (or local filesystem for clusters). This requires a new completers.rs module with shared helpers, wiring ArgValueCompleter onto 10 existing positional arguments, and fixing two initialization-order issues in main.rs.
Scope
crates/navigator-cli/src/completers.rs (NEW, ~130 lines): Three public completer functions (complete_sandbox_names, complete_cluster_names, complete_provider_names) plus shared helpers (blocking_complete for thread-spawning async gRPC calls, completion_grpc_client with 2s timeout)
crates/navigator-cli/src/lib.rs (1 line): Add pub mod completers;
crates/navigator-cli/src/main.rs (~30 lines modified): Move crypto provider init before CompleteEnv::complete(), add #[arg(add = ArgValueCompleter::new(...))] to 10 target arguments, add import
Critical Blockers (Already Solved)
Crypto provider init order — rustls::crypto::aws_lc_rs::default_provider().install_default() currently runs AFTER CompleteEnv::complete(). Any TLS-based completer would fail. Fix: Move init before complete().
Nested tokio runtime — #[tokio::main] creates a runtime, and complete() runs synchronously inside block_on. Creating another runtime on the same thread panics. Fix: Spawn a dedicated OS thread via std::thread::spawn + tokio::runtime::Builder::new_current_thread() for async gRPC calls.
Target Arguments (10 total)
Command
Field
Completer
SandboxCommands::Get
name: String
complete_sandbox_names
SandboxCommands::Delete
names: Vec<String>
complete_sandbox_names
SandboxCommands::Connect
name: String
complete_sandbox_names
SandboxCommands::Sync
name: String
complete_sandbox_names
ForwardCommands::Start
name: String
complete_sandbox_names
ForwardCommands::Stop
name: String
complete_sandbox_names
ClusterCommands::Use
name: String
complete_cluster_names
ProviderCommands::Get
name: String
complete_provider_names
ProviderCommands::Update
name: String
complete_provider_names
ProviderCommands::Delete
names: Vec<String>
complete_provider_names
Implementation Steps
Move crypto provider init before CompleteEnv::complete() in main.rs — Zero-risk reorder. The init is idempotent and has no dependencies on the tokio runtime.
complete_cluster_names(prefix: &OsStr) -> Vec<CompletionCandidate> — Uses list_clusters() from navigator-bootstrap (local filesystem scan, no network call, fast)
blocking_complete(future) -> Vec<CompletionCandidate> — Shared helper that spawns an OS thread, creates a current_thread tokio runtime, runs the async future, returns results (or empty vec on any error)
completion_grpc_client(endpoint) -> NavigatorClient — Async helper that builds a gRPC client with 2s connect timeout and mTLS (reuses require_tls_materials + build_tonic_tls_config from tls.rs)
complete_sandbox_names(prefix: &OsStr) -> Vec<CompletionCandidate> — Resolves active cluster, calls blocking_complete with gRPC ListSandboxes
complete_provider_names(prefix: &OsStr) -> Vec<CompletionCandidate> — Resolves active cluster, calls blocking_complete with gRPC ListProviders
All completers return empty vec on any error (unreachable cluster, no active cluster, TLS failure) — never block the shell
Add pub mod completers; to lib.rs
Wire #[arg(add = ArgValueCompleter::new(...))] on all 10 target arguments in main.rs
Add tests:
Unit tests in completers.rs: verify complete_cluster_names returns results when metadata files exist, returns empty vec when config dir is missing
Graceful-failure test: verify sandbox/provider completers return empty vec when no active cluster is configured (no panic, no hang)
Run mise run pre-commit and verify all checks pass
Test Plan
Unit tests: In completers.rs — test cluster completer with mock filesystem, test sandbox/provider completers return empty vec gracefully when cluster is unavailable
Integration tests: N/A for initial PR — gRPC mock server testing deferred to avoid scope creep. The completer's error-resilience is validated by unit tests.
E2E tests: N/A — completions are interactive shell features; manual smoke testing with navigator sandbox get <tab> against a live cluster
Risks & Open Questions
Shell hang risk (Medium): Mitigated by 2s timeout on the gRPC client. If a cluster is unreachable, completion returns empty in ≤2s.
Large resource counts (Low): Completers don't paginate; capped at whatever the first response returns. Acceptable for completion UX (unlikely to have >200 sandboxes/providers).
--cluster flag unavailable to completers (Low): Clap hasn't parsed args when completers run, so completers use NAVIGATOR_CLUSTER env var or active_cluster file. This matches the common case.
Inference route completions: Deferred to a follow-up issue to keep this PR focused on the three core resource types mentioned in the issue.
Will this show some kind of indicator when the names are being retrieved? Also it should fail gracefully — if something is not working (cannot connect, etc.) it shouldn't show anything.
Loading indicator: No — there's no way to show a spinner or loading indicator during tab-completion. The shell blocks while waiting for the completer function to return, and the shell itself controls the UX. This is standard behavior for all CLI tools with dynamic completions (e.g., kubectl, docker, gh). The 2-second timeout ensures the shell doesn't hang long if the cluster is unreachable.
Graceful failure: Yes — this is already covered in the plan. All completers return an empty Vec<CompletionCandidate> on any error (unreachable cluster, no active cluster configured, TLS failure, timeout, etc.). The user just sees no completions appear, same as if there were no matching resources. No error messages, no panics, no shell disruption.
No changes to the plan needed — both behaviors are already accounted for.
Originally by @pimlock on 2026-02-26T19:47:03.563-08:00
Runtime tab-completion for sandbox, cluster, and provider name arguments across 10 CLI commands. Cluster completions use local metadata (no network), sandbox/provider completions query the gateway via gRPC with a 2s timeout. All completers fail silently.
Tests
Unit: 3 tests added (graceful failure for each completer type)
Integration: N/A
E2E: N/A
Docs updated
None needed (no architecture/cli.md exists; inline comments document the approach)
The issue will auto-close when the MR is merged.
Originally by @pimlock on 2026-02-26T20:04:57.428-08:00
Activity
pimlock commentedon Feb 27, 2026
Implementation Plan
Issue type:
featComplexity: Medium
Confidence: High — clear path, two critical blockers already identified with solutions
Summary
Add runtime tab-completion for sandbox, cluster, and provider names by creating completer functions that fetch live data from the Navigator gateway (or local filesystem for clusters). This requires a new
completers.rsmodule with shared helpers, wiringArgValueCompleteronto 10 existing positional arguments, and fixing two initialization-order issues inmain.rs.Scope
crates/navigator-cli/src/completers.rs(NEW, ~130 lines): Three public completer functions (complete_sandbox_names,complete_cluster_names,complete_provider_names) plus shared helpers (blocking_completefor thread-spawning async gRPC calls,completion_grpc_clientwith 2s timeout)crates/navigator-cli/src/lib.rs(1 line): Addpub mod completers;crates/navigator-cli/src/main.rs(~30 lines modified): Move crypto provider init beforeCompleteEnv::complete(), add#[arg(add = ArgValueCompleter::new(...))]to 10 target arguments, add importCritical Blockers (Already Solved)
Crypto provider init order —
rustls::crypto::aws_lc_rs::default_provider().install_default()currently runs AFTERCompleteEnv::complete(). Any TLS-based completer would fail. Fix: Move init beforecomplete().Nested tokio runtime —
#[tokio::main]creates a runtime, andcomplete()runs synchronously insideblock_on. Creating another runtime on the same thread panics. Fix: Spawn a dedicated OS thread viastd::thread::spawn+tokio::runtime::Builder::new_current_thread()for async gRPC calls.Target Arguments (10 total)
SandboxCommands::Getname: Stringcomplete_sandbox_namesSandboxCommands::Deletenames: Vec<String>complete_sandbox_namesSandboxCommands::Connectname: Stringcomplete_sandbox_namesSandboxCommands::Syncname: Stringcomplete_sandbox_namesForwardCommands::Startname: Stringcomplete_sandbox_namesForwardCommands::Stopname: Stringcomplete_sandbox_namesClusterCommands::Usename: Stringcomplete_cluster_namesProviderCommands::Getname: Stringcomplete_provider_namesProviderCommands::Updatename: Stringcomplete_provider_namesProviderCommands::Deletenames: Vec<String>complete_provider_namesImplementation Steps
Move crypto provider init before
CompleteEnv::complete()inmain.rs— Zero-risk reorder. The init is idempotent and has no dependencies on the tokio runtime.Create
crates/navigator-cli/src/completers.rswith:complete_cluster_names(prefix: &OsStr) -> Vec<CompletionCandidate>— Useslist_clusters()fromnavigator-bootstrap(local filesystem scan, no network call, fast)blocking_complete(future) -> Vec<CompletionCandidate>— Shared helper that spawns an OS thread, creates acurrent_threadtokio runtime, runs the async future, returns results (or empty vec on any error)completion_grpc_client(endpoint) -> NavigatorClient— Async helper that builds a gRPC client with 2s connect timeout and mTLS (reusesrequire_tls_materials+build_tonic_tls_configfromtls.rs)complete_sandbox_names(prefix: &OsStr) -> Vec<CompletionCandidate>— Resolves active cluster, callsblocking_completewith gRPCListSandboxescomplete_provider_names(prefix: &OsStr) -> Vec<CompletionCandidate>— Resolves active cluster, callsblocking_completewith gRPCListProvidersAdd
pub mod completers;tolib.rsWire
#[arg(add = ArgValueCompleter::new(...))]on all 10 target arguments inmain.rsAdd tests:
completers.rs: verifycomplete_cluster_namesreturns results when metadata files exist, returns empty vec when config dir is missingRun
mise run pre-commitand verify all checks passTest Plan
completers.rs— test cluster completer with mock filesystem, test sandbox/provider completers return empty vec gracefully when cluster is unavailablenavigator sandbox get <tab>against a live clusterRisks & Open Questions
--clusterflag unavailable to completers (Low): Clap hasn't parsed args when completers run, so completers useNAVIGATOR_CLUSTERenv var oractive_clusterfile. This matches the common case.Documentation Impact
architecture/cli.md: Update with runtime completion architecture (completer functions, blocking bridge pattern, TLS init order)Revision 1 — initial plan
Originally by @pimlock on 2026-02-26T19:39:43.699-08:00
pimlock commentedon Feb 27, 2026
Loading indicator: No — there's no way to show a spinner or loading indicator during tab-completion. The shell blocks while waiting for the completer function to return, and the shell itself controls the UX. This is standard behavior for all CLI tools with dynamic completions (e.g.,
kubectl,docker,gh). The 2-second timeout ensures the shell doesn't hang long if the cluster is unreachable.Graceful failure: Yes — this is already covered in the plan. All completers return an empty
Vec<CompletionCandidate>on any error (unreachable cluster, no active cluster configured, TLS failure, timeout, etc.). The user just sees no completions appear, same as if there were no matching resources. No error messages, no panics, no shell disruption.No changes to the plan needed — both behaviors are already accounted for.
Originally by @pimlock on 2026-02-26T19:47:03.563-08:00
pimlock commentedon Feb 27, 2026
Implementation Complete
MR: !63
What was built
Runtime tab-completion for sandbox, cluster, and provider name arguments across 10 CLI commands. Cluster completions use local metadata (no network), sandbox/provider completions query the gateway via gRPC with a 2s timeout. All completers fail silently.
Tests
Docs updated
architecture/cli.mdexists; inline comments document the approach)The issue will auto-close when the MR is merged.
Originally by @pimlock on 2026-02-26T20:04:57.428-08:00
chore: update readme (NVIDIA#41)
Merge pull request NVIDIA#41 from opendatahub-io/konflux/mintmaker/ma…