The command line is the primary interface for engineers to interact with Fuchsia and its tools, drivers, and devices. Providing clear, consistent, and coherent tooling is critical to ensuring better productivity and satisfaction for all the engineers and teams developing Fuchsia. This document provides guidance for developing and evolving CLI tools for Fuchsia.
The guidelines are divided into three main sections:
Fuchsia, and the devices running Fuchsia, make up a broad developer surface with varying needs and requirements for users at all levels of the stack. When developing Fuchsia tools and subtools, it’s important to ensure consistency, architectural predictability, reliability, and ongoing support and maintenance for end users.
Depending on the distribution scope, different tools will have different expectations. The following guidelines and rubric will help tool developers understand the UX considerations, technical requirements, and documentation expectations for Fuchsia CLI tools.
Note: These guidelines focus on host-side CLI tools for Fuchsia development. Shell scripts, test tools, target-side tools, and generic 1P or 3P tools, such as C or Rust compilers, are out of scope.
Fuchsia CLI tools are built, maintained, and used by many different people and teams. A one-size-fits-all approach will not serve users who are working in separate contexts, for example in-tree versus out-of-tree or SDK users. Additionally, some users may have unique workflows for specific areas of development, such as drivers, kernel, or product configuration.
When developing or updating Fuchsia tools, understanding the target audience, their context, and their specific use cases is critical to building a better developer experience.
Ensuring that CLI tools are discoverable and well-documented will make it easier for developers to find existing tools, understand workflows, and identify gaps. In some cases, it may be more helpful to extend an existing tool to add new features rather than creating a new subtool. For example, if you want to flash a device over TCP, prefer adding a TCP option to ffx target flash
rather than creating a separate tool.
Tip: Refer to the Tools overview to see what Fuchsia CLI tools are currently available in the SDK and in the source code. You can also run ffx --help
in the command line to explore available ffx subtools, commands, and options.
Deciding which tool, script, or library to use will depend on your use case. ffx is the CLI tool for interacting with target devices or developing products that run Fuchsia, such as smart displays. In-tree tools like fx are generally scripts that know about things outside of Fuchsia, for example, build systems, repositories, and integrations.
Examples
- Use ffx to interact with Fuchsia devices (e.g.,
ffx target flash
to flash a Fuchsia image on a device, orffx component run
to interact with components on a device)- Use fx to develop Fuchsia in tree (e.g.,
fx set
to configure a build, orfx test
to run tests on a host machine)
--help
content in order to support developersIn addition to ffx, there are libraries for interacting with and scripting interactions with Fuchsia targets from development hosts.
ffx is the top-level tool that provides core developer functionality for interacting with devices running Fuchsia. ffx has an extensible interface that enables other tools which are useful for Fuchsia developers to be registered as subtools, making it easier to discover them.
The goal of ffx is to create a cohesive tooling platform that provides a stable command line argument surface and a standardized JSON output for commands. Ideally, ffx subtools will be able to use common services such as configuration, logging, error handling, and testing frameworks. This will provide a robust collection of tools that are loosely coupled and can be adapted to specific project needs.
Before developing, updating, or deprecating an ffx subtool, there are several considerations to take into account. Who is the tool for? Will it be available in the SDK or in-tree only? Does a similar tool already exist?
Note: Internal Googlers see Subtool lifecycle playbook for detailed information on policy and process for developing or changing Fuchsia tools, or making updates to the tooling platform.
When building a new tool, use the following prompts as a guide. You can also consult the CLI tool development rubric to determine whether your tool meets Fuchsia requirements.
Who are the intended users of the tool and how will they use it?
- Where does the tool fit in the existing command structure?
Can human users and scripts/other tools use the tool equally well?
- Is it clearly defined which parts of the tool are intended for machine and automated workflows?
- Is the machine interface well documented?
Is the command interface in line with Fuchsia guidelines and best practices?
- Does the tool follow UX guidelines?
- Does the tool provide solid documentation and help for the user following the CLI Help requirements?
- Does the tool provide clear and useful error messages?
- Have you considered accessibility?
Have other users tested the tool?
- Ask someone outside of your team to run through the commands and outputs to see if they are usable.
Is the tool compiled and independent of the runtime environment?
- Does the tool minimize runtime link dependencies?
- Is the tool built from the fuchsia.git source tree?
Does the tool support machine interfaces?
- Is there comprehensive documentation for machine interfaces?
- Does the tool include manifest or JSON files for machine input?
What are the tool’s compatibility guarantees?
Does the tool collect metrics?
- Is it compliant with privacy requirements for collecting metrics?
How will you distribute the tool?
- Will it only be available in-tree or included in the SDK?
Who will own the maintenance of the tool?
- Is there a plan in place to update, evolve, or deprecate the tool?
Where can users go to find answers to common questions or ask new questions?
How are you tracking user-reported issues?
- Does the help output and error output include a bug link?
What events have been instrumented? Where can one find metrics for this tool?
Tip: Score each criterion on a scale of 1-5 (low to high) based on how well your tool meets it. Identify areas for improvement, then prioritize enhancements based on user needs and project goals.
Key
- Needs significant improvement
- Needs improvement
- Meets minimum requirements
- Exceeds expectations
- Excellent
Providing clear, consistent, and coherent tooling is critical to ensuring better productivity and satisfaction for all the engineers and teams developing Fuchsia. These UX guidelines are designed to help people building and integrating CLI tools create a consistent developer experience for users. These guidelines use Fuchsia’s main developer tool, ffx, to illustrate best practices.
Key Point: ffx is a unified tooling platform and command line interface (CLI) for Fuchsia development. The ffx tool is the top-level interface for connecting to, flashing, and communicating with a device running Fuchsia. ffx tools are used by humans and in scripts, and should be designed for readability and ease of use.
Always aim to make the ffx interface as simple as possible.
ffx commands are structured as a tree under the root ffx command. This supports a hierarchical organization which streamlines UX: instead of having to iterate through a list of tools, users can traverse the tree of commands, eliminating paths unrelated to their desired functionality.
Paths on the ffx command tree should follow a noun noun… verb structure. Command paths consist of internal nodes that are nouns with increasing specificity that culminate in a leaf node that is a verb, which is the actual command.
For example, in ffx component run <URL>
there is a root command noun (ffx), a subtool noun (component), a subcommand verb (run), and an argument (URL), which is the value passed to the command when it is executed.
ffx component run /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
When developing a new CLI tool, it’s important to consider the developer experience across the platform. Keep the number of commands under a tool organized and reasonable. Avoid repetition, or adding unrelated commands to a tool. Provide sensible organization of the commands in the help and documentation.
In general, for tools that cover common workflows (such as host-to-target interaction, system integration, and publishing), prefer extending an existing tool rather than creating a new standalone tool. Add flags, options, or subcommands to take advantage of shared code and functionality.
However, if the overall workflow enabled does not exist, consider a new command or a higher level subgrouping. Review the existing command surface reference documentation to understand where the new command or tool may fit.
Tools may be used for different development tasks. On a large team, these roles may be separate people. Consider which users may use a tool and cater the tool to the audience.
Examples
- Component development
- Driver development
- Fuchsia development (SDK)
- Build integration (GN, etc.)
- System integrators (e.g., on-device network tools)
- Publishing (from dev host to server)
- Deployment (from server to customers)
Tools may have different integration expectations. For example, a developer doing component development may expect tools to integrate with their Integrated Development Environment (IDE), while a build integration tool may be called from a script.
Related commands for Fuchsia workflows should be grouped under a common tool. For example, ffx is organized into subtools and command groups that map to high-level Fuchsia subsystems. This helps encourage the team toward a shared workflow and provides a single point of discovery.
Command line tools can vary in scope depending on user needs and goals. Create tools that are ergonomic for their purpose. Sometimes, a simple, single-purpose tool may be useful to automate a time-consuming process. Larger, more featureful tools should encompass an entire task at the user (developer) level.
Examples
- Avoid making a tool that accomplishes one small step of a task; instead design a tool that will perform a complete task.
- For example, when developing a C++ application: run the preprocessor, run the compiler, run the linker, start the built executable.
- Prefer tools that will accomplish all the steps needed by default, but allow for an advanced user to do a partial step.
- For example, passing an argument to ask the C++ compiler to only run the preprocessor.
ffx subtools (previously called plugins) are organized into command groups that map to high-level Fuchsia subsystems. In ffx target
, ffx is the root command and target is the subtool (subcommand). ffx subtools may have their own arguments and options (e.g., ffx target list --format [format] [nodename]
).
The ffx CLI should follow a standard structure and vocabulary so that users experience ffx as an integrated whole rather than a patchwork of separate tools. A user familiar with one ffx tool should be able to predict and understand the command names in another tool.
When designing ffx subtools, there will be tradeoffs between complexity and brevity. In general, ffx subtools should map to documented Fuchsia concepts or subsystems (e.g., target, package, bluetooth
). When possible, subtool command groups should be limited to a primary feature or capability, with additional options added as flags. Adding a secondary command group is discouraged, but sometimes is unavoidable. Clarity is more important than brevity.
Use well-known US English nouns for ffx commands, which are also known as ffx subtools. Subcommands should be imperative verbs.
ffx bluetooth
, not ffx bt
)--log-level
).Follow the noun-noun-verb structure. Nest related commands as subcommands under a parent tool.
Don't create tools with hyphenated names, like add-foo
and remove-foo
. Instead create a foo
command that accepts add
and remove
subcommands.
Use clear, concise verbs that accurately reflect the command’s action.
Prefer subcommands to multiple tools that are hyphenated (e.g., avoid foo-start, foo-stop, foo-reset
; instead have foo
that accepts commands start|stop|reset
)
Align with established Fuchsia terminology and patterns to minimize cognitive load. Use common verb pairings (e.g., start/stop, add/remove, import/export
) and follow existing ffx command patterns.
Aim for the shortest command and option names without sacrificing clarity or discoverability. Command names should be at least 3 characters long.
Avoid acronyms or abbreviations with ambiguous definitions (e.g., bt
could mean bluetooth, Bigtable, or British Telecom on different Google products).
An argument is a value that is passed to a command when it is executed. Arguments in ffx can be exact text, ordered (also known as positional arguments), or unordered options (also called flags).
Options (also called flags) are unordered, and can appear anywhere after the group or command in which they're defined, including at the very end. See the top-level ffx options.
--log-level
)Caution: Options should not overlap with top-level ffx commands (e.g., ffx target
)
Do not use uppercase letters for options. Do not use numeric options. If a numeric value is needed, make a keyed option, like --repeat <number>
.
The presence of a switch means the feature it represents is ‘on’ while its absence means that it is ‘off.’ Switches default to ‘off.’
-v
is a common switch meaning verbose; it doesn't take a value.Use switches to evolve the functionality of a tool. Switches are more easily controlled than feature flags.
Running switches together is not allowed, e.g., -xzf
or -vv
, each must be separate: -x -z -f
or -v -v
.
In general, UX recommends avoiding short flags. However, we recognize that it can be helpful for experts to use short aliases for some frequently used options. Overuse of short aliases can introduce confusion and ambiguity (e.g., does -b
mean --bootloader
or --product-bundle
or --build-dir
?). Short aliases should be used sparingly.
Short aliases should be used in a consistent manner throughout the ffx CLI (e.g., -c
should not be shorthand for --config
in the main ffx tool, --command
in one subtool, and --font-color
in another).
Positional or ordered arguments must appear after the command name and are identified by the order in which they appear. Only use ordered arguments for parameters where the sequence is crucial for understanding (e.g., copy <source> <destination>
). In general, avoid positional arguments and prefer exact text arguments with specific options.
Caution: Avoid using more than one positional argument in the same command. Positional arguments should relate to the same type of elements (e.g., filenames) that are processed together. Do not use positional arguments that refer to different elements.
The CLI help text, accessible via --help
, is a vital communication tool for users. It should be clear, concise, and provide essential information at a glance as well as a path to more in-depth documentation where needed. See CLI tool help requirements for more detail and examples.
The terminal is a minimalistic text environment. Providing too much information can make it difficult for users to get the help they need in the moment. Help output should be standardized to provide users with actionable guidance and a clear path to find more information when needed.
Required elements
Recommended elements
Caution: Avoid recursive help explanations. That is, do not repurpose a command's name to explain what it does.
The help text should adhere to a clear structure and style for optimal readability, including consistent indentation and line wrapping at 80 characters. The text should be written in clear, grammatically correct US English and follow Fuchsia’s documentation standards.
Errors provide critical information to developers when things are not working as expected. Error messages and Warnings are an opportunity to educate developers with an accurate mental model of how a system or tool works, and its intended use. Fuchsia error messages should help a reasonably technical user understand and resolve an issue quickly and easily.
These guidelines apply to errors created as part of the Fuchsia platform. Errors created by a particular runtime or language outside of Fuchsia may not follow these guidelines.
Users should know exactly what went wrong, where, and why. The error message should offer a solution, next steps, or explain how the specific error can be corrected.
Use a shortlink to redirect users to correct documentation and assist with troubleshooting by further explaining the problem. Follow these guidelines to create shortlinks.
Indicate if specific constraints or pre-conditions were not met. Users should understand if an error occurred because of input validation (e.g., file not found), processing (e.g., syntax errors in the file), or other unexpected reasons (e.g., file corrupt, cannot read from disk).
If the error involves values that the user can modify (text, settings, command- line parameters, etc.), then the error message should indicate the offending values. This makes it easier to debug the issue. However, very long values should only be disclosed progressively or truncated.
Logs data can help users learn more about how and why the error occurred. Use canonical names, categories, and values, and include clear descriptions in documentation so an error can be easily referenced.
Including a unique identifier or standardized error code in addition to the message can help users identify the error easily and find more information in an error index or error catalog. For example, error codes in FIDL are always rendered with the prefix fi- followed by a four digit code, like fi-0123.
To deliver a consistent developer experience across Fuchsia, CLI tools should use standard libraries, consistent configuration, common logging and error handling, and continuous support for users.
Tip: See Fuchsia's CLI tool development rubric for a quick checklist of considerations and guidelines.
Fuchsia CLI tools may be written in C++, Rust, and Go. Tools must be compiled and be independent of the runtime environment. Programming languages like Bash, Python, Perl, and JavaScript are not supported.
To make compiled tools easier to distribute and maintain, minimize runtime link dependencies. Prefer to statically link dependencies instead. On Linux, it is acceptable to runtime link against the glibc suite of libraries (libm, etc.); other runtime link dependencies are not allowed.
Fuchsia tools should be built from the fuchsia.git source tree. Use the same build and dependency structure as the code in the platform source tree. Do not make a separate system to build tools.
Metrics are important to drive quality and business decisions. The type and content of the metrics collected must be carefully chosen.
Questions to answer with metrics
- Which OS are our users using? - to prioritize work for various platforms
- Which tools are they using? - to prioritize investments, and to learn which workflows are currently being used so we can prioritize investments or identify weak spots
- How often do they use a tool? - so we know how to prioritize investments, and to learn which workflows are currently being used so we can prioritize investments or identify weak spots
- Do our tools crash in the wild? How often? - so we know how to prioritize maintenance of tools
- How do they use a tool? - assuming that a tool can do one or more things, we'd like to learn how to prioritize investments in particular workflows of a tool
Note: For internal Googlers, every tool must file a Privacy Design Document (PDD) in order to collect usage metrics. All tools must go through the Google-standard PDD review process to ensure they are compliant with Google's practices and policies. Tools must get approval on which metrics are collected before collection.
Tools often need to know something about the environment and context in which they are running. This section provides guidelines on how that information should be gathered and/or stored.
Tools should not attempt to gather or read settings or state files directly from the environment in which they are running. Information such as an attached target's IP address, the out directory for build products, or a directory for writing temporary files should be gathered from a platform-independent source. Separating out the code that performs platform-specific work will allow tools to remain portable between disparate platforms.
Where practical, configuration information should be stored in a way familiar to the user of the host machine (e.g., on Windows, use the registry). Tools should gather information from SDK files or platform-specific tools that encapsulate the work of reading from the Windows registry or Linux environment.
Tools should be unbiased towards any build system or environment. Accessing a common file such as a build input dependency file is allowed.
Tools should not modify configuration or environment settings, except when the tool is clearly designed for the purpose of modifying an expected portion of the environment.
If modifying the environment outside of the tool's normal scope may help the user, the tool may do so with the express permission of the user.
Tools that are distributed in the SDK or included in the build system must include tests that guarantee correct behavior. Include both unit tests and integration tests with each tool. Tests will run in Fuchsia continuous integration.
Note: Tests for fx tools are preferred, but not required.
All Fuchsia tools require documentation on how to use the tool and a troubleshooting guide. Standard --help
output must include:
More verbose usage examples and explanations should be documented in markdown on fuchsia.dev.
A tool may be run interactively by a human user or programmatically via a script (or other tool).
While each tool will default to interactive or non-interactive mode if it can determine what is preferred, it must also accept explicit instruction to run in a given mode (e.g., allow the user to execute the programmatic interface even if the tool is running in an interactive shell).
For tools that are not normally interactive, avoid requesting user input (e.g., readline or linenoise). Don't add an unexpected prompt to ask the user a question.
For interactive tools (e.g., zxdb) prompting the user for input is expected.
When sending output to the user on stdout, use proper spelling and grammar. Avoid unusual abbreviations. If an unusual abbreviation or term is used, be sure it has an entry in the glossary.
Use stderr for reporting invalid operation (diagnostic output) i.e. when the tool is misbehaving. If the tool's purpose is to report issues (like a linter, where the tool is not failing) output those results to stdout instead of stderr.
Exit code 0 is always treated as “no error” and exit code 1 is always a “general error.” Don’t rely on specific non-zero values. Use machine output to return a specific error code and message. See FIDL error catalog for an example.
Logging is distinct from normal output and is usually configured to be redirected to a file, or should be written to stderr. The audience for logging is typically the tool developer or a user trying to debug an issue.
detail, info, warning, error, fatal
Include a programmatic interface where reasonable to allow for automation. If there is an existing protocol for that domain, try to follow suit (or have a good reason not to). MachineWriter (--machine
) can be used to support structured output in JSON.
To promote a consistent developer experience across Fuchsia, CLI tools should follow existing style guidelines for programming languages and Fuchsia documentation. For example, if the tool is included with Zircon and written in C++, use the style guide for C++ in Zircon. Avoid creating separate style guides for CLI tools.
All CLI tools, output, and documentation should follow the guidelines set forth in Fuchsia’s Respectful Code policy. Read more about documentation standards on Fuchsia.
Don't rely on case sensitivity in file paths. Different platforms handle uppercase and lowercase differently. Windows is case insensitive and Linux is case sensitive. Be explicit about specific filenames. Don’t expect that src/BUILD
and src/build
are different files.
You may use ANSI color in the command line interface to make text easier to read or to highlight important information. When using color, be sure to use colors that are distinct for readers who may not be able to see a full range of color (e.g., color-blindness)
Never rely solely on color to convey information. Only use color as an enhancement. Seeing the color must not be required to correctly interpret output. Read more about accessibility on Fuchsia.
All Fuchsia tools should use standard output formatting with a consistent look and feel. Don’t use ASCII art to format tables or otherwise enhance the output. ASCII art can make your interface difficult to read and is not compatible with screen readers for accessibility.