What changed, and what it means for scripts that already use this tool. Newest first, written by hand — the commit subject rarely explains why a change matters.
Versions follow semantic versioning. Pre-1.0 rule:
while the version starts with 0., a breaking change raises the minor
number (0.1.0 → 0.2.0); everything else raises the patch. What counts as
breaking is written down in CONTRIBUTING.md — briefly,
command names, flags, the two output modes and the exit codes are promises;
the Mapbox APIs' own response bodies are not.
Cutting a release adds a ## <version> - <date> heading below
## Unreleased, which stays in place so the next change has somewhere to go.
Dev-channel builds (v0.1.3-dev.<sha>) are published straight from a branch
that may never merge. They are not releases and are not listed here.
-
A run at a terminal now opens with a
mapbox · v<version>banner on stderr. stdout is unchanged, and nothing is printed when stderr is not a terminal or formapbox completion.--quiet/-qorMAPBOX_QUIET=1hides it. Table headers, the labels of key/value lists (auth whoami,doctor,config list, a single object's fields), the result lists ofgeocoder,searchandtilequery, and tips are styled at a terminal too, and a result written to a file or pipe never is;NO_COLORturns color off everywhere. -
mapbox config listin text mode now aligns its keys with spaces, like every other key/value list, instead of separating them with a tab. A script reading it should use-o json, which is unchanged. -
Diagnostic logs, off by default:
mapbox config set log on(orMAPBOX_LOG=1) keeps, for each run in history, the command line, each request and the error message, tokens redacted, on your machine only.mapbox history showincludes the log, or says it was not captured or is no longer available (diagnostics.status:captured,not_captured,unavailable). Kept up to 30 days and 100 MB; needs history on.mapbox config listnow reports a third key,log. -
Command history, on by default: each run appends one line to
~/.mapbox/history/<date>.jsonl, kept 30 days and at most 10 MB, with its command path, exit code, error code, duration and request ids — never an argument value. It stays on your machine.mapbox history listandmapbox history showread it back. Turn it off withmapbox config set history offorMAPBOX_HISTORY=0. A script sees no change on stdout, stderr or the exit code; it does find a~/.mapbox/historydirectory it didn't before, andmapbox config listnow reports a second key,history. -
MAPBOX_CLI_EXTRA_QUERYappends raw query parameters to every request, in the samek1=v1&k2=v2shape as a URL's own query string — for an API parameter this CLI's specs don't declare a flag for. -
mapbox auth profiles— lists every credential profile stored on disk, not just the one--profilewould select. Read-only, likewhoami, and answers a different question than it does:whoamireports which token the next command will use, this reports what's stored at all, for someone who has forgotten which named profiles they've logged into. -
mapbox doctor— a read-only snapshot of what the next command would see: which token wins and its state, which proxy variables are in effect, and where the update-check and telemetry switches currently stand.--verifyadditionally checks thatapi.mapbox.comis reachable, the only part of this that makes a request — the same precedentauth whoami --verifysets. -
A native
aarch64-pc-windows-msvcbuild. Windows on Arm ran the x64 build under emulation before this — including inside a VM on Apple Silicon, the larger of the two populations this serves — whichinstall.ps1already said out loud and now no longer has reason to.install.ps1already asked the manifest for this target before falling back to the x64 one, and.cargo/config.tomlalready named it, so publishing the artifact was the whole client-side change. -
install.sh/install.ps1now document a convention forMAPBOX_CLI_INSTALL_SOURCEwhen a coding agent invokes the installer on someone's behalf:agent-<name>(agent-claude-code,agent-cursor), so an access-log query can tell those installs apart from a human or CI one. A dash rather than the slash an earlier proposal used —/is stripped by the installers' own sanitizer, which would have collapsedagent/claude-codeintoagentclaude-codeand lost the separator. Comment-only: neither installer's behavior changed.
-
mapbox config—get/setfor settings that persist across shells and sessions, written to~/.mapbox/config.json(or$MAPBOX_CONFIG_DIR) rather than an environment variable that only lasts for the session it was set in. One setting today:update-check, whichmapbox config set update-check offturns off for good, mirroringMAPBOX_NO_UPDATE_CHECK. -
mapbox config list/unset, alongsideget/set.listreports every setting in one call rather than one key at a time;unsetclears a setting back to "never set" rather than writing its current default value explicitly — the difference that lets a later default change reach a cleared key but not one a caller pinned to the old default on purpose. -
The README now documents installing without the install script: the archives are plain HTTP downloads,
manifest.jsonlists every target with its checksum, and the commands to verify and extract one are written out. Nothing new is published — this is the same channel the install script reads, for anyone whose employer does not allow piping a script into a shell.
-
The skill
mapbox generate-skillswrites now tells an agent which of the three ways to authenticate it can actually use. It listed all three without comment, so an agent with no token would read "credentials stored bymapbox auth login" as an option and try it — a command that opens a browser and waits for a person, which in a coding-agent session can only fail. It now says to haveMAPBOX_ACCESS_TOKENset, and to ask for one rather than reaching forauth login. Reported from a real session that hit exactly this. -
mapbox generate-skillsnow prints the command that removes what it wrote, in both output modes, and the JSON carries it asremove_with. The write isgenerate-skillsand the undo isagent-skills uninstall, a differently named command belonging to a different feature, so there was no way to get from one to the other — a reader ofgenerate-skills --helpsaw no way back. Reported after an agent reached forrm -rfinstead, had it refused by its sandbox, and left untracked directories in a git working tree. A dry run does not print it, since nothing was written.--help, the generated reference page and the README say it too. -
Advice that is a command to paste now names every shell instead of guessing one. The repair for a file blocking the credential directory offered
mvandexport NAME="$(cat …)", which a Windows reader cannot run; it now givesmv/Move-Item/moveand all four ofexport, fish'sset -gx, PowerShell's$env: … Get-Contentandcmd.exe'sset /p, each labeled with the shell it belongs to. The tip printed after a successful login no longer offersexport MAPBOX_USERNAME=…either; it says what to set rather than how.Keying this on the operating system would have been wrong in both directions, which is why it does not: PowerShell runs on macOS and Linux and Git Bash runs on Windows. Each row also uses the name its shell owns rather than one that may be aliased —
Move-ItemandGet-Contentrather thanmvandcat, which resolve differently depending on what is installed. -
The refusal from
mapbox auth loginwith no terminal now names both ways out. It said "Set MAPBOX_ACCESS_TOKEN for a script or a CI job", which describes automation and assumes that is who is asking; a person working through a coding agent hits this too, and hits it again when they try the command themselves in that agent's shell, which has no terminal either. The fix now leads with running it in a terminal window and keeps the token as the answer for a script, a CI job or an agent. -
A file sitting where the credential directory belongs now says so when it looks like an access token, which the one older Mapbox tools left at
~/.mapboxdoes. The advice was to move it aside, with nothing to tell the reader whether they were moving junk or a working credential; it now says the token still works and gives theMAPBOX_ACCESS_TOKENline that keeps using it. The token itself is never printed, and a test holds that. -
Code & Command Clean up.
-
The README described the published builds as signed. They are not code-signed with a Developer ID or an Authenticode certificate; what the install script checks is a SHA-256 checksum. The claim is gone, and the new section says what a macOS user hits because of it: Gatekeeper refuses an unsigned binary carrying a quarantine flag, which a browser download sets and
curldoes not. -
The URL printed by
--debug, and by a text-mode--dry-run, is now a URL. Query values were concatenated raw, so any value containing a space rendered with literal spaces andcurlrefused it outright — which is the one thing that line is printed for. Found withmapbox search forward --q "Dog friendly coffee shops near me", an ordinary call now that the Search Box API takes free text. The request itself was never affected: reqwest encodes what it sends, and a JSON dry run keepsurlandqueryas separate fields, so only this rendering was wrong. Values are percent-encoded with%20rather than form-urlencoding's+, and,:/@are kept literal, so a coordinate or a style URI still reads as one.It also stops a value from misrepresenting the request. A value holding
&used to split into anothername=valuepair, so the line claimed a parameter the request never carried, and anyone pasting it sent something different from what was being debugged. -
MAPBOX_CLI_VERSIONnow accepts a version with or without the leadingv. The channel's directories are namedv0.2.1, but every place a person reads a version from shows it without one —mapbox --version, this file,Cargo.toml— so the spelling somebody would copy was the one that failed, and it failed as a bare403from S3 on a path that does not exist. That reads as "you are not allowed" rather than "no such version".latestand any other non-numeric channel name are untouched. Both installers, both covered by their suites. -
MAPBOX_CLI_VERSIONandMAPBOX_INSTALL_DIRare documented in the README, which never mentioned either of them.
-
mapbox usageis no longer described as a private preview: the Statistics API it calls is generally available, somapbox auth loginnow requestsstatistics:readunconditionally instead of through a feature flag. Nothing about who can run the command or what it prints changed — the flag it used to go through was already on for everyone. -
The 403 a missing
statistics:readscope gets back now leads with "runmapbox auth loginagain", the fix that actually applies, before falling back to "contact Mapbox support" for the rarer case of an account with no access at all. It used to jump straight to support, which was written for the old private-preview gate and never distinguished the two — the API answers both with 403, not the 401/403 split the docs previously assumed.
- A path parameter can no longer change the shape of the request URL. Values
are substituted into a path template, so one carrying URL syntax altered
where the request went rather than naming a segment in it:
?appended query parameters the caller never asked for,..(and its backslash spelling) moved the path, and#truncated it — each with the caller's token and the command's method attached. The host was never reachable, so nothing could be directed at another server./,?,#and\are now percent-encoded, and a value of.or..is refused asinvalid_path_parameter. Punctuation these values legitimately carry — a static-images overlay,@2x,.png, a comma-separated coordinate — is untouched. See #15.
-
Paginated listings now say when there is more to fetch. A response the API paged answers with one page, and the CLI prints the flags that fetch the next one — "More results: add
--limit 2 --start …for the next page" — on stderr in both output modes. Before this the extra pages were unreachable: the API signals them in aLinkheader, which nothing read, so-o textand-o jsonboth looked complete.--idon a paged listing now also distinguishes "not on this page" from "does not exist", and says how to look further. Following the pages is still the caller's job; there is no--allyet. -
Failures now carry the response's request id, which is what Mapbox support needs to find one request in their logs. In practice that is CloudFront's
x-amz-cf-id, which every Mapbox response carries; a service sending its ownx-request-idis preferred when one does. Present on every failure under-o jsonasrequest_id; printed under-o textfor a 5xx only, where the server is at fault and there is nothing the caller can do about it.mapbox agent-skillsis exempt — it fetches from GitHub, whose request id Mapbox support cannot look up. -
--datacan now read the request body instead of carrying it:@<path>reads a file and@-reads stdin, the spelling curl uses. Before this the only way to send a style from a file was--data "$(cat style.json)", which has nocmd.exeequivalent on a platform this CLI ships installers for, put the body in the process table wherepsshows it, and broke at a size that failed in the shell beforemapboxran — so no error message could explain it. Five operations take--data. A body read this way also gets the 900-second transfer budget rather than the 60-second one, since nothing bounds a file the way a command line bounds what can be typed.
-
Breaking: nine more commands renamed, continuing #116's cleanup, and two dropped outright:
Was Is now mapbox geocoder forward-geocodemapbox geocoder forwardmapbox geocoder reverse-geocodemapbox geocoder reversemapbox geocoder batch-geocodemapbox geocoder batchmapbox tilesets get-rastertilemapbox tilesets get-tilemapbox tilesets get-vectortilemapbox tilesets get-mvtmapbox rasterarrays get-mrt-tilemapbox tilesets get-mrtmapbox tilequery getmapbox tilesets querymapbox static-images get-static-imagemapbox static get-imagemapbox static-tiles get-static-tilemapbox static get-tilemapbox rasterarrays,mapbox tilequery,mapbox static-imagesandmapbox static-tilesno longer exist: each held exactly one operation, and that operation now answers undertilesetsorstaticinstead — the same reasoning 0.1.8 gave forspritesandtilesetsappearing there.mapbox staticis new for it.static-images get-static-image-autoandget-static-image-bboxare gone, not renamed — the decision record's reason for withholding both is that they will merge intoget-image's own parameters, but that merge hasn't happened yet, so today there is simply no way to ask for an auto-fit or bounding-box static image from this CLI.Nothing answers to any of the old spellings, the same as 0.1.8's rename: no hidden alias, and the two dropped commands are not offered under any spelling.
-
The advice under a transport failure now names
ALL_PROXYalongsideHTTPS_PROXYandNO_PROXY, and says that a SOCKS proxy is not supported.ALL_PROXY=socks5://…fails the request rather than being ignored, andunsupported scheme socks5in the message is the part that distinguishes it from the network being down. -
randmoved from 0.8 to 0.10. No behavior changes: the two places it is used — the PKCE verifier and the OAuthstateinmapbox auth login— draw fromThreadRngbefore and after, whichranddeclares a CSPRNG, andthread_rng().gen()becomingrandom()is a rename. Recorded because it is the crate that generates those two values, so a login problem around this release should be able to find it. Both are now covered by tests against RFC 7636, which they were not before. -
Both installers now honor
MAPBOX_CLI_NO_TELEMETRY, the name the binary reads. They were left on the oldDISABLE_TELEMETRYwhen the binary was renamed, so neither name silenced both halves: the documented variable stopped the CLI's markers but not the installer's, and the old one did the reverse.DISABLE_TELEMETRYkeeps working in the installers only — the binary's break was announced, and a script fetched and run in one line has no release notes in front of the reader, so breaking an opt-out there would have happened silently. When both are set the new name wins. -
A usage error under
-o jsonnow carries clap's own suggestion asfix:mapbox styles lstanswers"fix": "A similar subcommand exists: 'list'". Clap renders that tip in a paragraph of its own, andmessageis built from the first one, sojsonconsumers — scripts and agents — were the only ones not told what was probably meant. It matters most for the renames above: a script pinned to a command that no longer exists now gets a pointer to the one that replaced it.-o textis unchanged, where clap already printed it. Misspelled flags are covered too.
rustlsmoved to 0.23.45, fixing RUSTSEC-2026-0285 — "TLS 1.3 handshake messages incorrectly accepted across encryption level boundaries", medium severity, published 2026-09-14.rustlsis reached throughreqwest, so every HTTPS request this CLI makes used the affected version; nothing in the crate itself had to change. Fixed in mapbox/mapbox-cli#2.
Initial beta release. The next release is 0.2.0.
- Commands generated from the Mapbox OpenAPI specs, covering
accounts,fonts,geocoder,maps,rasterarrays,search,static-images,static-tiles,styles,tilequeryandvectortiles. mapbox auth login,whoami,logoutandrefresh: a browser OAuth flow, credentials stored per--profile, andwhoamianswering which token the next command would actually use.mapbox tilesets-cli …, forwarding its arguments verbatim to the Python Tilesets CLI with the resolved token injected through the child's environment rather than its argv.mapbox usage, showing account or per-token usage by Mapbox product and day.mapbox agent-skills list,install,updateanduninstall, installing the Mapbox Agent Skills for coding agents.mapbox generate-skillswrites a skill describing this CLI's own commands, for fifteen agents with auto-detection.mapbox completion bash|zsh|fish|powershell, printing a shell completion script for commands, subcommands and flag names.mapbox uninstall, removing the running binary and nothing else.--schema: what a command takes and what request it would make, as JSON, for one command, one service or the whole surface — no token required.--dry-runon every mutating command.-o jsonand-o text(alsoMAPBOX_OUTPUT), with stdout carrying the result and nothing else, and progress, warnings and errors on stderr.- A confirmation before a destructive request, asked only at a terminal,
and
--yesto answer it in advance. --timeout <SECONDS>andMAPBOX_TIMEOUT, and a distinctrequest_timed_outerror naming the flag when a request runs out of it.install.shandinstall.ps1for macOS, Linux and Windows.- A background check for a newer release, at most once a day, at a
terminal.
MAPBOX_NO_UPDATE_CHECK=1orMAPBOX_CLI_NO_TELEMETRY=1turns it off. - Deprecation notices for a retired command or an endpoint its own OpenAPI spec marks deprecated.
- Every request identifies itself with
User-Agent: mapbox-cli/<version>, extended with a few non-identifying markers (OS, architecture, CI presence, detected coding-agent, TTY state, command group) thatMAPBOX_CLI_NO_TELEMETRY=1drops entirely. See README.md's Privacy section.