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: a breaking
change raises the major number (1.0.0 → 2.0.0), a new feature the minor,
and a fix the patch. Before 1.0, a breaking change raised the minor number
instead. 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, and commands marked beta, are not.
Cutting a release adds a ## <version> - <date> heading below
## Unreleased, which stays in place so the next change has somewhere to go.
tests/changelog.rs fails while Cargo.toml names a version with no such
heading.
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.
- The telemetry event of a command that uses no token, such as
--version, now reports the token kind and account an API command would use. Output and exit codes are unchanged. mapbox usage --dimensions browsers,countries,hostsasks the Statistics API for the per-browser, per-country and per-host breakdown, which it now sends only on request. Without the flag the request is unchanged, and each product'sdimensionsin-o jsonis{}.static get-image,static get-tileandtilesets get-tileno longer need their trailing optional positionals:<highRes>,<format>and<quality>can be left off instead of passed as"". Writing""still works, so existing scripts are unaffected.--schemanow reports these arguments as not required.- A flag for a true/false API parameter now takes
=false:--attribution=falsesendsattribution=false. Alone it still sendstrue, as before. Where the API defaults totrue(--attribution,--logo,--autocomplete,--dedupe,--continue-straighton driving profiles), this is the only way to turn the setting off. A workflow step'sfalsestill leaves the flag out, as before. directions --snapping-include-closuresand--snapping-include-static-closurestake a value:trueorfalseper coordinate, semicolon-separated (true;false). They were switches that sent a singletrue, which the API rejects with a 422 for any route, so no working command changes. In--schemathey change from a boolean flag to a string option; this is a fix rather than a breaking change for the same reason.--helpshows each parameter's whole description rather than its first sentence, so the allowed values and what else a parameter needs ("Requiresoverview=full") are no longer cut off.- An API command's
--helpshows the opening of its description as plain text, followed by aDocs:link, instead of the whole Markdown page with its headings, tables and curl examples (geocoder batchwas 113 lines).--schemastill carries the full description. --idon a command that is not an API command (history show,auth profiles,config listand the like) is now a usage error, exit code 2. It used to be ignored:history show --id xprinted the newest run as if it werex.--schema:envanddefaultare filled for every argument, including the ones read by hand (--timeout,--output,--no-color,--profile,workflow install --repo/--ref), which only mentioned them in their description. A new top-levelgroupslist carries what a command group's own help says, such asmapbox history, whichcommands(leaves only) never included.feedbackmoved from the Search help group to Maps and data.
- The update check now runs in published builds. 0.3.0 through 1.1.0 were
built with it off, so they never said a newer version existed. At a
terminal, at most once a day,
mapboxnow prints a notice on stderr when one does;MAPBOX_NO_UPDATE_CHECK=1ormapbox config set update-check offturns it off. Nothing reaches stdout, and piped or CI runs never check. install.sh/install.ps1: the MCP question no longer waits several seconds before it appears. The installer asks whenever it found a coding agent or VS Code, and only after a yes does it look for Claude Code, Codex, VS Code and Cursor and check what each already has. A reinstall therefore asks again even when every server is registered; a yes then reports each one as already there.
mapbox workflow(beta): install and run workflows, which are named, multi-step recipes ofmapboxcommands and scripts defined in aworkflow.yaml.installcopies one from a local directory or from a GitHub repository'sworkflow/<name>/(by defaultmapbox/mapbox-cli;GH_TOKEN/GITHUB_TOKENfor a private one) into~/.mapbox/workflows/, recording the commit a GitHub ref resolved to, andlist,show,runanduninstallwork on what is installed.runtakes each of the workflow's inputs as a flag, as inmapbox workflow run copy-style --style-id <id> --from-profile source --to-profile target.run --dry-runruns only the steps a workflow marksdry_run, which write nothing, so the plan can show real data. At a terminal each step shows a spinner, the details its script reports on stderr (a::progressline updates the spinner's text, a::warnline is a warning, listed again at the end), and✓or✗with the time it took; off a terminal, each step is a plain[n/total]line followed by its details.--quietdrops the details but keeps warnings. A workflow's optionalresulttemplate is what text mode prints;-o jsonprints its outputs. A command step'ssave: <file>keeps its stdout, such as a style's ZIP, as a file for later steps, in an owner-only working directory removed when the run ends, Ctrl-C included (the run then fails withcancelled); a command step may be markeddry_runonly when its command is known to change nothing: an APIGET, or a local read such asconfig list. The generated agent skill leavesworkflowout. A script step needs its interpreter onPATH: on Windows,.pyneeds apython3, which the python.org installer does not add. A workflow may name its ownversion, independent of the CLI's, and the oldest CLI itrequires;installrefuses one that needs a newer CLI.installlists the scripts a workflow runs, and from a repository other thanmapbox/mapbox-cli, or a--refnot on itsmain, asks first, refusing withconfirmation_requiredwhere there is no terminal and no typed--yes(MAPBOX_YESdoes not answer it). A failed command step's own error is undercausein the run'sworkflow_failed, and on Unix a SIGTERM to the run is passed on to the running step. The first one published iscopy-style, which copies a style between accounts with its custom fonts and icons, and on a partial failure lists what it created and the commands that remove it. The command, theschema: 1format and the published workflows may change or be removed in any release, and everyworkflowsubcommand says so on stderr. Nothing changes for a script that does not use them.
-
New
mapbox report "<message>"sends feedback about the CLI itself to the Mapbox CLI team, with the CLI's version and OS appended. It is filed under Mapbox's account, not yours. It is sent with the CLI's own token, so it needs no login and nouser-feedback:writescope; your token stands in while the CLI's can't be used (including when it is rate-limited), or when you pass--tokenor--use-login, and the request then carries your token.--categoryis optional and defaults togeneral. Two new error codes say why the CLI's token couldn't be used when you have no token either:cli_token_unavailableandcli_token_forbidden(see Errors). -
The CLI's own token, used for telemetry, is now fetched from
https://cli.mapbox.com/config/token.jsonand kept in~/.mapbox/cli-token.jsoninstead of being built into the binary, so it can be rotated without a release. What changes for an existing setup:MAPBOX_CLI_BUNDLED_TOKENis no longer read at build time. A build from source fetches the token like a release does.- Keeping the token creates
~/.mapboxif it is missing, even on a run whose only network use is telemetry. - When an API refuses the token, the Tokens API is asked why and the endpoint asked for a new token at once. A revoked, invalid, expired or malformed token is replaced; a different token served is used from the next run on.
- Three failures in a row, each a fetch that finds no usable token or a
refusal with no different token served, stop telemetry sending and
fetching for an hour. The count is telemetry's own: it never holds
mapbox reportorMAPBOX_CLI_TOKEN, and the waits an earlier dev build kept incli-token.jsonare ignored. A new token ends it, even onemapbox reportfetched.
-
tilesets queryrenders as a numbered list under-o textagain, as documented. It had printed pretty JSON since 0.2.0, when the command moved fromtilequery getand the renderer kept matching the old name.-o jsonis unchanged. -
New
mapbox commands search "<task>"finds the commands that match a task, best first, andmapbox commands listlists every command with its summary. Both are local keyword lookups: no request, no token.jsongives[{command, summary, score}], wherescore(0 to 1) is how much of the query the command's own text covers. The query is sent in telemetry as its length only. Top-level help now points tocommands search(agents see it in their hint), and an unknown command with no near spelling suggests it in the error'sfix. No existing command or output changes. -
mapbox usagereads as a chart: one row per product with no blank lines between, every sparkline as wide as the period, bars scaled from zero so their height is proportional to the value, and the tallest stopping short of the row above. Each row is to its own scale and ends with the peak its tallest bar stands for (peak 407/day). A day with any usage never draws as a day without. At a terminal the title and bars are in the accent over a muted baseline, and the tips look like every other command's. The footer is one line (31 active days · generated 2026-09-08 09:49 UTC), and theTOTALcolumn lines up under its header. Text output only. -
An API parameter's help line no longer stops at the first dot inside an id, a number or "e.g.":
tilesets get-tiledescribed<tilesets>as "Tileset ID(s) in the formatusername" and now shows the whole first sentence. Help text only;--schema` always had the full description. -
Color reads on light and dark terminal themes alike. Tables, tips, the banner and help use a small fixed palette (teal, gray, red) instead of the terminal's own bright blue and dim, which fell below 2:1 on some light themes; every colored run of text is bold. Help asks the terminal for its background and uses a palette made for a dark or a light one; everything else, and help where the terminal doesn't answer, uses one that reads on both. A terminal not known to show 24-bit color gets bold and plain text instead. New
--no-colorflag turns color off, asNO_COLORdoes, andFORCE_COLOR=1now keeps color in a pipe; either way off wins. -
Top-level
mapbox --helplists commands in groups (Maps and data, Search, Navigation, Account, Coding agents, CLI), each with a line saying what it does rather than which API it wraps, and the global options under Authentication, Output and Behavior, wrapped to the terminal. At a terminal, help — top-level or a command's — opens with themapbox · v<version>banner, as a command run does. Subcommand help uses clap's compact layout for--helpas well as-h, with the command's full description at the top, and points tomapbox --helpfor the global options instead of repeating them; they still work on every command. Headings are teal; names to type and values to fill in are bold in the terminal's own foreground; notes are gray. clap's yellow and green in usage errors are bold now too. Help text only: no command, flag, exit code or result output changes. -
Top-level
mapbox --help/mapbox helpchanges. It ends with a "Learn more" section linking the CLI docs, the agent-setup prompt, Mapbox Agent Skills, the Mapbox MCP server and the API docs. When a coding agent runs it (detected the same way as for theUser-Agent), it opens with a two-line hint pointing atmapbox --schema. Help also wraps to the terminal width (100 columns when piped), and env-backed options read[env: NAME]without the variable's value. Help text only: no flag, exit code or result output changes. -
Breaking:
--eta-type,--navigation-profileand--originremoved frommapbox search category. The category endpoint does not currently return an ETA, so the flags were accepted but had no effect. A script that passes them now fails with an unknown-argument error; drop the flags.mapbox search forwardkeeps them. (#76) -
mapbox places <mapbox-id>..., full place detail — hours, phone, website, photos, address, coordinates, activity data — for one or moremapbox_ids a Search Box API result already returned, up to 100 in one call. Always uses the batch endpoint, even for a single id, so there is one command rather than a choice between one id and a hand-typed JSON array. Hand-authored intocustom-openapi/since no upstream spec exists yet. Places is Public Preview, with a 1000-records-per-account monthly quota. -
mapbox matrix, travel time and/or distance between every pair in a set of up to 25 coordinates in one call, for driving (with or without live traffic), walking, or cycling. No subcommand: likemapbox directionsbelow, this API has one operation, so there's nothing a second word (the oldcompute) would disambiguate; seespec::FLATTENED_SERVICES. Hand-authored intocustom-openapi/for the same reason the other Navigation commands were: no upstream spec exists yet. Reuses theprofile-vs---profilecollision fix (ARG_NAME_OVERRIDESgets a fourth row) and the free-form (notenum) routing profile, for the same OEM-account reason.--sources/--destinationstake semicolon-separated indices, not comma; verified against production after the API answered a comma-separated list with a 422. -
mapbox map-match, snapping a noisy GPS trace to the road network and returning the route it most likely followed, for driving (with or without live traffic), walking, or cycling. No subcommand: likemapbox directionsbelow, this API has one operation, so there's nothing a second word (the oldmatch) would disambiguate; seespec::FLATTENED_SERVICES. Hand-authored intocustom-openapi/for the same reasonmapbox directionsandmapbox isochronewere: no upstream spec exists yet. Reuses theprofile-vs---profilecollision fix (ARG_NAME_OVERRIDESgets a third row) and the free-form (notenum) routing profile, for the same OEM-account reason. Excludes POST, for the same reasondirectionsdoes: the API's own POST is for a trace too long for a URL, a real gap rather than a design choice. -
mapbox isochrone, how far you can get from a point in a given time or distance, for driving (with or without live traffic), walking, or cycling, returned as GeoJSON polygons or linestrings. No subcommand: likemapbox directionsbelow, this API has one operation, so there's nothing a second word would disambiguate; seespec::FLATTENED_SERVICES. Hand-authored intocustom-openapi/for the same reasonmapbox directionswas: no upstream spec exists yet. Reusesdirections's fix for a spec parameter namedprofilecolliding with the global--profileflag (ARG_NAME_OVERRIDESalready covered the mechanism, this is just a second row, not a second fix) and its free-form (notenum) routing profile, for the same OEM-account reason. -
mapbox directions, routes between 2-25 waypoints for driving (with or without live traffic), walking, or cycling. No subcommand: this API has one operation, so, likemapbox usage, there's nothing a second word would disambiguate; seespec::FLATTENED_SERVICES. Hand-authored intocustom-openapi/rather than waiting on an upstream spec. The whole Navigation API category had no CLI coverage before this; excludes the ~30 electric-vehicle-routing parameters (engine=electricand everything under it), which describe one vehicle's charge/discharge curve down to the watt and are a poor fit for a hand-typed CLI flag. Left for a follow-up.The routing profile (
mapbox/drivingetc.) is a free-form value, not a fixed set of four: an early version rejected anything else client-side, which would have broken this command for exactly the accounts that most need it, since some (OEM agreements, mainly) have additional profiles of their own never published to docs.mapbox.com. Reported in review before this shipped anywhere. Two path-parameter bugs surfaced while wiring the original four up and are fixed for every command, not just this one: a spec parameter literally namedprofile(the routing profile) silently collided with the global--profilecredentials flag, since clap has one namespace of ids per command and a positional of the same name replaced it outright; and a path parameter whose every legitimate value contains a literal/(mapbox/driving) was being percent-encoded to%2Fby the same escaping that stops a free-text value from smuggling in extra path segments. That's safe to skip for a parameter named in a small table (UNESCAPED_PATH_PARAMS) whose values are trusted to carry that character on purpose. -
Breaking:
--exclude-fieldsremoved frommapbox search forwardandmapbox search category. Thephotosandreviewsfields it omitted are only returned for accounts with a specific data provider arrangement, so for everyone else it never had an effect. A script that passes it now fails with an unknown-argument error; drop the flag. (#77) -
mapbox mcp list/mapbox mcp install: registers a Mapbox MCP server (direct tool-calling access to Mapbox's APIs, not just guidance about them) with a coding agent's own CLI or config. Claude Code, Codex, VS Code and Cursor are supported today, against the hosted Mapbox MCP endpoints. An existing server with the same name is left alone rather than replaced. VS Code and Cursor currently register for every project regardless of--global, since neither has a working way to scope it to one project; Codex may report a serverinstalled, login incompletewhen its own OAuth step fails against Mapbox's hosted MCP server, a known incompatibility between the two rather than something this command controls. -
mapbox feedback createsubmits a feedback item, filed under the account that owns the token. The required fields are flags (--feedback,--lat,--lon,--category); the rest go through--data.--lat/--londefault to 0 for feedback with no place.mapbox auth loginnow also asks for theuser-feedback:writescope it needs, so log in again to use it. -
install.sh/install.ps1: when the install finds a coding agent on the machine, it now asks, once, whether to write this CLI's own skill and install the Mapbox Agent Skills library for it, naming the agent and what will be written before doing either. Answered no, or asked somewhere with no terminal to answer on (a CI job, a container), it does neither and prints the two commands to run by hand instead. On a reinstall, it never overwrites a skill file you edited: it checks first, and only replaces what is unchanged from what was published, reporting local edits rather than discarding them.MAPBOX_CLI_NO_AGENT_SETUP=1skips the question entirely, same spelling convention asMAPBOX_CLI_NO_TELEMETRY. -
mapbox feedback list/get, reading the feedback end users submit from apps built with Mapbox — filterable, sortable, paginated. Each filter takes one value for now. Hand-authored intocustom-openapi/, likesearch, because no upstream spec exists yet. -
mapbox generate-skills/agent-skills install/agent-skills update, when no coding agent is detected and none was named with--agent,--globalor--dir: the failure now carries a stableno_agent_detectederror code (previously an unstructured message with the genericerrorcode, indistinguishable from an unrelated internal failure). Same message, same non-zero exit — only thecodea caller can match on is new. Documented in docs/commands.md's "Where they go" section. -
install.shnow adds its install directory toPATHby appending one line to your shell profile (~/.zshrc,~/.bash_profileor~/.bashrc, fish'sconfig.fish, otherwise~/.profile), the wayinstall.ps1already edits the userPATHon Windows. It never writes the line twice. SetMAPBOX_NO_MODIFY_PATH=1to keep the old behavior of only printing the line. Both installers' output is also shorter and ends with what to run next. -
install.sh/install.ps1: after the skill question, the install now asks whether to add the Mapbox MCP servers to the coding agents it finds, the same asmapbox mcp install --global. It is asked only at a terminal and only when something is not registered yet; the default is no.MAPBOX_CLI_NO_AGENT_SETUP=1skips it along with the skill question. -
install.shnow writes a log of each run to~/.local/state/mapbox-cli/install.log($XDG_STATE_HOMEwhen set): every step, and the full output of eachmapboxand Tilesets command it ran after installing the binary. The previous run's is kept asinstall.log.1. -
New command:
mapbox styles download <style-id> > style.zipsaves a style as a ZIP with its sprite icons and custom fonts.mapbox auth loginnow also asks for thestyles:downloadscope it needs, so log in again to use it. The account also needs access to this API, which Mapbox grants on request; without it the command fails with a 403 saying so. -
A command that returns a file (
styles download,static get-image, a tile or glyph range) now confirms it on stderr at a terminal:Wrote application/zip (988165 bytes).stdout is unchanged, and--quiet/-qhides it. -
A 403 that names a missing scope now says which token lacks it: a login is told to run
mapbox auth loginagain (also innext_actions), and a token from--tokenorMAPBOX_ACCESS_TOKENto add the scope to that token. A 403 for an API the account has not been given access to says to contact Mapbox. Other 403s are unchanged. -
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,searchandtilesets query, 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 config set telemetry offturns telemetry off for good, in every shell, the wayMAPBOX_CLI_NO_TELEMETRY=1does for one: the run's event, theUser-Agentmarkers and the update notice. The run that turns it off records nothing either.mapbox config listnow also reportstelemetry, andmapbox doctorreports it astelemetry_persisted; itstelemetry_allowedstill means the environment variable alone. Version 0.3.0 doesn't know this key, and itsmapbox config setdrops it from the file, so with two installs, set it again after using the older one. -
Each run sends one
cli.commandtelemetry event to Mapbox, from a background process the command doesn't wait for. It is only ever sent with the CLI's own public token, never yours (--token,MAPBOX_ACCESS_TOKENor your login), since Mapbox Events keeps the token an event was sent with. When the CLI's token can't be used, or the send fails, the event is dropped; it is never sent twice. It never touches stdout, the exit code or how long a command takes, so a script sees no difference; a machine that already has~/.mapboxfinds a.telemetrydirectory in it.MAPBOX_CLI_NO_TELEMETRY=1turns it off. -
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, including in a VM on Apple Silicon, ran the x64 build under emulation before this, 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. -
rustls-webpkimoved to 0.103.16 andwebpki-rootsto 1.0.10, fixing RUSTSEC-2026-0382 and RUSTSEC-2026-0381 (CVE-2026-111943): certificate verification could accept a path through distrusted emSign intermediates, whose private keys are now public. Both are reached throughreqwest, so every HTTPS request this CLI makes used the affected versions; nothing in the crate itself had to change. Fixed in mapbox/mapbox-cli#106.
-
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.