Skip to content

feat: implement progressive CLI help disclosure and dynamic deploy help#10772

Open
joehan wants to merge 11 commits into
mainfrom
improve-cli-help
Open

feat: implement progressive CLI help disclosure and dynamic deploy help#10772
joehan wants to merge 11 commits into
mainfrom
improve-cli-help

Conversation

@joehan

@joehan joehan commented Jul 7, 2026

Copy link
Copy Markdown
Member

Description

Revamping the --help and firebase help command to use progressive disclosure. Instead of dumping a massive list of commands all at once, you can navigate this layer by layer so that there is not a ton of irrelevant info flooding the terminal (or context).

I also cleaned up some of our Winston logging transport initialization logic - it was spread our over a few places (and was happening late enough to miss some errors early in the flow). Now, it lives at the main entry point for the cli binary.

I also ran our eval suite before and after this change - in cases where the --help command was run, we saw significant performance improvements:

Averages Across Help-Executing Cases

Metric BEFORE Run AFTER Run Change / Diff (%)
Average Turns 45.1 turns 30.2 turns -33.0%
Average Duration 72.2s 60.5s -16.2%
Average Tokens 128.2k 97.6k -23.9%

Testing

Before this change, firebase --help would print every single command, and firebase <command> help would print the help text for just that command. There was no support for firebase <namespace> --help - doing so would just give you a 'command not found error'

Some examples of the new behavior - at the top level, --help just returns all of the top level namespaces:

$ firebase --help
Usage: firebase [options] [command]
Options:
  -V, --version                        output the version number
  -P, --project <alias_or_project_id>  the Firebase project to use for this command
  --account <email>                    the Google account to use for authorization
  -j, --json                           output JSON instead of text, also triggers non-interactive mode
  --token <token>                      DEPRECATED - will be removed in a future major version
  --non-interactive                    error out of the command instead of waiting for prompts
  -i, --interactive                    force prompts to be displayed
  --debug                              print verbose debug output and keep a debug log file
  -c, --config <path>                  path to the firebase.json file to use for configuration
  -h, --help                           display help for command
Commands:
  deploy [options]                     deploy code and assets to your Firebase project
  ext                                  display information on how to use ext commands
  help [command]                       display help information
  init [feature]                       interactively configure the current directory as a Firebase project
  login [options]                      log the CLI into Firebase
  logout [email]                       log the CLI out of Firebase
  mcp|experimental:mcp                 Run the multi-modal conversational platform (MCP) server.
  open [link]                          quickly open a browser to relevant project resources
  serve [options]                      start a local server for your static assets
  target [type]                        display configured deploy targets for the current project
  use [options] [alias_or_project_id]  set an active Firebase project for your working directory
  appdistribution                      manage App Distribution resources
  apptesting                           manage apptesting resources
  apps                                 manage Firebase apps
  auth                                 manage Firebase Auth
  crashlytics                          manage Crashlytics symbols and mappings
  database                             manage Realtime Database
  emulators                            start and manage local Firebase emulators
  experiments                          enable and disable CLI experiments
  firestore                            manage Cloud Firestore resources
  functions                            manage Cloud Functions
  hosting                              manage Firebase Hosting sites and channels
  apphosting                           manage App Hosting resources
  projects                             manage Firebase projects
  remoteconfig                         manage Remote Config
  setup                                manage setup resources
  dataconnect                          manage Data Connect resources
  studio                               manage studio resources
To see more about a specific namespace or command, run:
  firebase <namespace|command> --help

To dig deeper you request help on the hosting namespace. It prints only the hosting subcommands and sub-namespaces (like channel and sites), filtering out all other unrelated CLI commands:

$ firebase hosting --help
Usage: firebase hosting [options] [command]
manage Firebase Hosting sites and channels
Options:
  -h, --help                              display help for command
Commands:
  hosting:clone <source> <targetChannel>  clone a version from one site to another
  hosting:disable [options]               stop serving web traffic to your Firebase Hosting site
  hosting:channel                         manage hosting:channel resources
  hosting:sites                           manage hosting:sites resources
To see more about a specific command, run:
  firebase hosting:<command> --help

This applies for all namespace levels - for example, running help on hosting:channel lists all leaf commands scoped strictly under that namespace:

$ firebase hosting:channel --help
Usage: firebase hosting:channel [options] [command]
manage hosting:channel resources
Options:
  -h, --help                                    display help for command
Commands:
  hosting:channel:create [options] [channelId]  create a Firebase Hosting channel
  hosting:channel:delete [options] <channelId>  delete a Firebase Hosting channel
  hosting:channel:deploy [options] [channelId]  deploy to a specific Firebase Hosting channel
  hosting:channel:list [options]                list all Firebase Hosting channels for your project
  hosting:channel:open [options] [channelId]    opens the URL for a Firebase Hosting channel
To see more about a specific command, run:
  firebase hosting:channel:<command> --help

I also improved the flow for deploy - that is one of our most complicated comands, and it previously offered no meaningful help:
Now, it offers details about all the targets:

$ firebase deploy--help
Usage: firebase deploy [options]
deploy code and assets to your Firebase project
Options:
-f, --force              delete Cloud Functions missing from the current
                         working directory and bypass interactive prompts
-p, --public <path>      override the Hosting public directory specified in
                         firebase.json
-m, --message <message>  an optional message describing this deploy
--only <targets>         only deploy to specified, comma-separated targets
                         ...
-h, --help               display help for command
Deploy targets include:
hosting        Deploys assets, redirects, rewrites, and headers configuration from your project's firebase.json.
database       Deploys security rules defined in your project's firebase.json.
firestore      Deploys security rules and indexes defined in your project's firebase.json.
functions      Deploys functions from the functions directory. Supports filtering function deploys:
    --only functions:func1,functions:func2 (scoped function deploy)
    --only functions:group.subgroup (scoped by export group)
    --only functions:codebase:func (scoped by codebase and function)
storage        Deploys security rules for Cloud Storage buckets defined in your project's firebase.json.
remoteconfig   Deploys templates defined in your project's firebase.json.
extensions     Deploys configuration changes to your installed Extension instances.
dataconnect    Deploys Data Connect services, schemas, and connectors. Supports filtering:
    --only dataconnect:serviceId
    --only dataconnect:serviceId:connectorId
    --only dataconnect:serviceId:schema
apphosting     Deploys Next.js / Angular / Astro app backends. Supports configuration in apphosting.yaml.
auth           Deploys configuration settings for Firebase Authentication providers.
To deploy specific targets, use `--only` followed by a comma-separated list of targets.
For example, firebase deploy --only hosting,firestore.
To see detailed setup and configuration details for a specific target, run:
firebase help deploy:<target>

And, you can view specific details about how to use a target:

$ firebase deploy:hosting--help
Detailed deploy information for hosting:
Firebase Hosting deploys web assets, redirects, rewrites, and header configurations.
Single site configuration in firebase.json:
{
"hosting": {
  "public": "public",
  "ignore": [
    "firebase.json",
    "**/.*",
    "**/node_modules/**"
  ],
  "rewrites": [
    { "source": "**", "destination": "/index.html" }
  ]
}
}
Multiple sites configuration (by site ID or deploy target):
{
"hosting": [
  {
    "site": "my-site-id",
    "public": "dist"
  },
  {
    "target": "my-site-target",
    "public": "build"
  }
]
}

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces progressive help for CLI commands, dynamically registering intermediate namespaces and filtering subcommands. It also refactors deploy targets to centralize their metadata, enabling dynamic help generation and detailed target-specific help via firebase help deploy:<target>. The review feedback highlights several opportunities to align with the repository style guide, such as replacing console.log with the central logger, avoiding any type escapes with proper interfaces, correcting an inaccurate reference to database indexes, and improving type safety in dynamic imports to prevent potential prototype pollution.

Comment thread src/bin/progressiveHelp.ts
Comment thread src/bin/progressiveHelp.ts Outdated
Comment thread src/bin/progressiveHelp.ts
Comment thread src/bin/progressiveHelp.ts
Comment thread src/deploy/database/index.ts Outdated
Comment thread src/commands/help.ts Outdated
Comment thread src/commands/deploy.ts
@joehan joehan requested a review from chkuang-g July 8, 2026 22:21
@chkuang-g

Copy link
Copy Markdown
Contributor

Could you provide some example about how CLI help looks like now? It is a bit hard to comprehend by reading your code.

Please provide some CLI example and their output.

Thank you

@joehan

joehan commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

Could you provide some example about how CLI help looks like now? It is a bit hard to comprehend by reading your code.

Please provide some CLI example and their output.

Thank you

Done - added a bunch of example output to the description.

@joehan joehan removed the request for review from chkuang-g July 14, 2026 19:44
Comment thread src/bin/cli.ts Outdated
Comment thread src/bin/cli.ts Outdated
Comment thread src/bin/progressiveHelp.spec.ts Outdated
Comment thread src/bin/progressiveHelp.spec.ts Outdated
Comment thread src/bin/progressiveHelp.spec.ts Outdated
Comment thread src/deploy/extensions/index.ts Outdated
"Configuration format in firebase.json:\n" +
"{\n" +
' "extensions": {\n' +
' "storage-resize-images": "extensions/storage-resize-images.env"\n' +

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. The expected format is "my-extension-instance-id": "firebase/storage-resize-images@^0.1.0"

Comment thread src/deploy/firestore/index.ts
Comment thread src/deploy/hosting/index.ts Outdated
Comment thread src/deploy/remoteconfig/index.ts Outdated
Comment thread src/logger.ts Outdated
Comment thread src/commands/deploy.ts Outdated
"\nTo deploy specific targets, use `--only` followed by a comma-separated list of targets.\n";
targetHelp += `For example, ${boldFn("firebase deploy --only hosting,firestore")}.\n`;
targetHelp += `\nTo see detailed setup and configuration details for a specific target, run:\n`;
targetHelp += ` ${boldFn("firebase help deploy:<target>")}`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the preferred way to get help, firebase help <cmd> or firebase <cmd> --help? This suggests the former but src/bin/progressiveHelp.ts suggests the latter. It's okay to support both but we should only suggest one consistently to avoid confusion

Comment thread src/commands/deploy.ts
.before(requireConfig)
.before((options: Options) => {
options.filteredTargets = filterTargets(options, VALID_DEPLOY_TARGETS);
options.filteredTargets = filterTargets(options, [...VALID_DEPLOY_TARGETS]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this change?

Comment thread src/commands/help.ts Outdated
const client = this.client; // eslint-disable-line @typescript-eslint/no-invalid-this
if (commandName && commandName.startsWith("deploy:")) {
const targetName = commandName.split(":")[1];
const { TARGETS, VALID_DEPLOY_TARGETS } = require("../deploy") as typeof import("../deploy");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this use src/dynamicImport.js? I'm not sure either

Comment thread src/commands/deploy.ts Outdated
targetHelp +=
"\nTo deploy specific targets, use `--only` followed by a comma-separated list of targets.\n";
targetHelp += `For example, ${boldFn("firebase deploy --only hosting,firestore")}.\n`;
targetHelp += `\nTo see detailed setup and configuration details for a specific target, run:\n`;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: repetitive use of the word "details"

Comment thread src/commands/help.ts Outdated
const target = isValidTarget ? TARGETS[targetName as keyof typeof TARGETS] : undefined;
if (target && target.detailedHelp) {
logger.info();
logger.info(clc.bold(`Detailed deploy information for ${targetName}:`));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I find the phrase "deploy information" a bit confusing. It almost sounds like information of my deployment in production. Do we need this header? Or can this be phrased differently e.g. "detailed setup and configuration" to be consistent with firebase deploy --help?

Comment thread src/commands/help.ts Outdated
return;
} else {
logger.warn();
utils.logWarning(`No detailed deploy information found for target: ${targetName}`);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this line confusing too TBH. And have we considered just delegating to firebase deploy --help text? Saying "just run another command" doesn't seem that useful to me. Humans will need to do additional copy and paste, agents waste context window and may prompt the human to approve yet another command. This gets especially frustrating after following the advice from firebase deploy --help only to be pointed back to where they came from.

What if we just say:

See Firebase documentation on deploying <targetName>.
For example, you can find a full reference of `firebase.json` on https://firebase.google.com/docs/cli#the_firebasejson_file"

Here's some general information about the `firebase deploy` command just in case:
<delegated output here>

Comment thread src/deploy/firestore/index.ts Outdated

export { prepare, deploy, release };

export const help = "Deploys security rules and indexes defined in your project's firebase.json.";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const help = "Deploys security rules and indexes defined in your project's firebase.json.";
export const help = "Deploys security rules and indexes referenced by your project's firebase.json.";

Comment thread src/deploy/database/index.ts Outdated
export { deploy } from "./deploy";
export { release } from "./release";

export const help = "Deploys security rules defined in your project's firebase.json.";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const help = "Deploys security rules defined in your project's firebase.json.";
export const help = "Deploys security rules referenced by your project's firebase.json.";

Comment thread src/deploy/database/index.ts Outdated
"{\n" +
' "database": [\n' +
' { "target": "my-db-target", "rules": "rules.rules" },\n' +
' { "database": "my-database-id", "rules": "rules.rules" }\n' +

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
' { "database": "my-database-id", "rules": "rules.rules" }\n' +
' { "database": "my-database-id", "rules": "rules2.rules" }\n' +

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants