From 41a4f8e24cd03773d365ec34ac130ff4526f58d0 Mon Sep 17 00:00:00 2001 From: BootIntel Agent Date: Sun, 27 Sep 2026 09:17:50 +0000 Subject: [PATCH 1/2] Stop telling people to visit a URL that 404s Every "get an API key" message pointed at https://bootintel.com/settings/api-keys. That page does not exist and never has: there is no /settings route on the site at all. Keys live at /dashboard/developer. Six places said otherwise: doctor, whoami twice, scan --api twice, and analyze --api. It surfaced because someone ran `bootintel doctor` on a Mac and pasted the output. That line had presumably been wrong for as long as it existed, and no test could have caught it: it is a string, and the route it names is in a different repo. The advice was also stale in a way I introduced. API-key auth is gated at Pro, so for anyone below that tier the instruction was not merely a broken link but the wrong action entirely. These messages now recommend `bootintel login` first, which is the path for a person at a terminal, and mention keys as the CI and scripting option they are. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 12 ++++++++++++ crates/cli/src/api/client.rs | 2 +- crates/cli/src/cmd/analyze.rs | 2 +- crates/cli/src/cmd/doctor.rs | 2 +- crates/cli/src/cmd/scan/api.rs | 7 +++++-- crates/cli/src/cmd/whoami.rs | 4 ++-- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ad86d7..99c9fc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,18 @@ All notable changes to bootintel-cli are documented here. Format follows [Keep a ## [Unreleased] +### Fixed +- **Every "get an API key" message pointed at a URL that 404s.** + `https://bootintel.com/settings/api-keys` does not exist and never has; + there is no `/settings` route at all. Keys live at `/dashboard/developer`. + Six places said otherwise: `doctor`, `whoami` twice, `scan --api` twice, and + `analyze --api`. Surfaced by running `bootintel doctor` on a Mac, which is + the first time anyone read that line back. +- The same messages are now correct about what to do, not just where to go. + `bootintel login` is the path for a person at a terminal and the only one + that works below Pro, since API-key auth is Pro-gated. They recommend it + first and mention keys as the CI and scripting option. + ## [0.6.0] — 2026-09-27 — applicability without sending the log New flag, no breaking change, so MINOR per the policy above. diff --git a/crates/cli/src/api/client.rs b/crates/cli/src/api/client.rs index 987eefd..de001ea 100644 --- a/crates/cli/src/api/client.rs +++ b/crates/cli/src/api/client.rs @@ -291,7 +291,7 @@ impl ScanError { "quota exhausted — see https://bootintel.com/pricing, or fall back to client-side `bootintel scan` (no --api)", ), ScanError::Unauthorized { .. } => Some( - "check $BOOTINTEL_API_KEY, or regenerate at https://bootintel.com/settings/api-keys", + "run `bootintel login` again, or regenerate a key at https://bootintel.com/dashboard/developer", ), ScanError::BadRequest { .. } => Some( "common causes: log > 256KB (server limit), or the file isn't a boot log", diff --git a/crates/cli/src/cmd/analyze.rs b/crates/cli/src/cmd/analyze.rs index 110f5e1..80ae71a 100644 --- a/crates/cli/src/cmd/analyze.rs +++ b/crates/cli/src/cmd/analyze.rs @@ -267,7 +267,7 @@ fn build_api_config(args: &Args) -> Result> { let api_key = crate::config::resolve_api_key(); if !args.preview && api_key.is_none() { bail!( - "--api requires ${API_KEY_ENV} to be set (or use --api --preview for the free anonymous quota — 3/day per IP).\n Get a key at https://bootintel.com/settings/api-keys" + "--api needs credentials. Run `bootintel login` to sign in from this terminal,\n or `--api --preview` for the free anonymous quota (3/day per IP).\n For CI and scripting, an API key (Pro and above) comes from https://bootintel.com/dashboard/developer" ); } // Same plaintext-transport policy as `scan` — shared helper in diff --git a/crates/cli/src/cmd/doctor.rs b/crates/cli/src/cmd/doctor.rs index e178dc6..91562ad 100644 --- a/crates/cli/src/cmd/doctor.rs +++ b/crates/cli/src/cmd/doctor.rs @@ -233,7 +233,7 @@ fn check_api_key() -> Check { _ => Check { name: "$BOOTINTEL_API_KEY", status: Status::Warn, - detail: "unset — --api will need --preview (anonymous, 3/day per IP).\nGet a key at https://bootintel.com/settings/api-keys".into(), + detail: "unset. Run `bootintel login` to sign in from this terminal.\nOr `--api --preview` for the anonymous quota, no account needed.\nAn API key (Pro and above, for CI and scripting) comes from https://bootintel.com/dashboard/developer".into(), }, } } diff --git a/crates/cli/src/cmd/scan/api.rs b/crates/cli/src/cmd/scan/api.rs index 8705c22..9bd7823 100644 --- a/crates/cli/src/cmd/scan/api.rs +++ b/crates/cli/src/cmd/scan/api.rs @@ -25,7 +25,7 @@ pub(super) fn run_api(args: &Args, raw: &str) -> Result<()> { if !args.preview && api_key.is_none() { bail!( - "--api requires ${API_KEY_ENV} to be set (or use --api --preview for the free anonymous quota — 3/day per IP).\n Get a key at https://bootintel.com/settings/api-keys" + "--api needs credentials. Run `bootintel login` to sign in from this terminal,\n or `--api --preview` for the free anonymous quota (3/day per IP).\n For CI and scripting, an API key (Pro and above) comes from https://bootintel.com/dashboard/developer" ); } if args.preview && api_key.is_some() { @@ -177,7 +177,10 @@ pub(super) fn render_api_error(err: ScanError, preview: bool) -> Result<()> { } writeln!(e)?; writeln!(e, " Check that {API_KEY_ENV} is set to a valid key.")?; - writeln!(e, " Manage keys: https://bootintel.com/settings/api-keys")?; + writeln!( + e, + " Manage keys: https://bootintel.com/dashboard/developer" + )?; } ScanError::BadRequest { detail } => { writeln!(e, "bootintel: server rejected the request.")?; diff --git a/crates/cli/src/cmd/whoami.rs b/crates/cli/src/cmd/whoami.rs index 98afa2f..b5fa123 100644 --- a/crates/cli/src/cmd/whoami.rs +++ b/crates/cli/src/cmd/whoami.rs @@ -95,7 +95,7 @@ pub fn run(args: Args) -> Result<()> { Some(k) => k, None => { eprintln!( - "no API key found — set $BOOTINTEL_API_KEY, or `bootintel config set api_key bik_...`\n Get a key at https://bootintel.com/settings/api-keys" + "not signed in. Run `bootintel login` to sign in from this terminal.\n For CI and scripting, an API key (Pro and above) comes from https://bootintel.com/dashboard/developer" ); std::process::exit(EX_NOPERM); } @@ -114,7 +114,7 @@ pub fn run(args: Args) -> Result<()> { Err(ProbeError::Unauthorized) => { eprintln!("unauthorized — API key rejected by {base}"); eprintln!( - " regenerate at https://bootintel.com/settings/api-keys or check $BOOTINTEL_API_KEY" + " run `bootintel login` again, or regenerate a key at https://bootintel.com/dashboard/developer" ); std::process::exit(EX_NOPERM); } From bfc664433768fba5809632a480d6ea39285d56c5 Mon Sep 17 00:00:00 2001 From: BootIntel Agent Date: Sun, 27 Sep 2026 09:19:05 +0000 Subject: [PATCH 2/2] Keep naming the env var, so the constant stays used Rewriting the --api message dropped the ${API_KEY_ENV} interpolation, which made the constant dead code and broke clippy under -D warnings. Naming the variable is useful to the reader anyway, so it goes back in the message rather than the constant coming out. Co-Authored-By: Claude Opus 5 (1M context) --- crates/cli/src/cmd/analyze.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/cmd/analyze.rs b/crates/cli/src/cmd/analyze.rs index 80ae71a..cfd0533 100644 --- a/crates/cli/src/cmd/analyze.rs +++ b/crates/cli/src/cmd/analyze.rs @@ -267,7 +267,7 @@ fn build_api_config(args: &Args) -> Result> { let api_key = crate::config::resolve_api_key(); if !args.preview && api_key.is_none() { bail!( - "--api needs credentials. Run `bootintel login` to sign in from this terminal,\n or `--api --preview` for the free anonymous quota (3/day per IP).\n For CI and scripting, an API key (Pro and above) comes from https://bootintel.com/dashboard/developer" + "--api needs credentials. Run `bootintel login` to sign in from this terminal,\n or `--api --preview` for the free anonymous quota (3/day per IP).\n For CI and scripting, set ${API_KEY_ENV} to a key from https://bootintel.com/dashboard/developer (Pro and above)" ); } // Same plaintext-transport policy as `scan` — shared helper in