fx-cli-shape
Skill3.7k starsChanged yesterdayApache-2.0View on GitHub
Choose the mechanism and the names for any user-facing control in fx, and check changes against the agreed shape. Covers subcommands, arguments, flags and options, settings keys in settings.json and .fx.json, environment variables (FX_ env vars), slash commands, JSON output, and exit codes. Use when adding, renaming, deprecating, removing, or reviewing one, for example "add a flag", "add an option", "new env var", "make this configurable", "let users turn on X", "add a slash command", "deprecate this flag", "should this be a flag or a setting", or a diff that touches src/builtins/commands.zig, src/core/cli/, src/core/config/, or adds an FX_ env read. Not for parser internals or writing documentation prose.
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 5 are distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Ask in order and stop at the first yes:
- Distinctive: line 22
Should it persist? Use a setting, plus a flag with the same name for one-off overrides.
- Distinctive: line 62
Check it against the matching section of rules.md.
- Distinctive: line 68
When reviewing a diff, report shape findings alongside bug findings.
- Distinctive: line 72
Ask a maintainer before:
- Very specific: line 78
Ask before inventing a rule for something these rules don't cover: keyboard shortcuts, prompt shortcuts (@, $, !), verbosity levels …
- Very specific: line 82
Every command and slash command reads its flags through cli_flags.Parser in src/core/cli/cli_flags.zig, from the same OptionDoc list its …
- Very specific: line 89
Run ./zig-out/bin/fx <command> --help and the command itself after changing a flag.
- Very specific: line 97
Every test hook starts with FX_TEST_.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
fx CLI shape
fx follows git and Unix conventions for how people and scripts control it. Each concept gets one mechanism and one name, so anyone who knows git can guess the command, flag, or setting. Use this skill to pick the mechanism for a new control, name it on every surface, and check a change before it lands. The maintainers agreed on these rules; follow them unless a maintainer says otherwise in the conversation.
Current versus target
One piece the rules rely on isn't built yet: the Experimental section of /settings. Design new work toward them, but never tell a user to run something that doesn't exist yet. Check ./zig-out/bin/fx help and ./zig-out/bin/fx <command> --help when unsure. When a target piece is missing, use the nearest current pattern and say what's missing.
Decision order
Ask in order and stop at the first yes:
- Is it an action? Use a subcommand, named as a verb or a noun plus a verb. Inside a session, a slash command with the same name.
- Is it what the action works on? Use an argument.
- Is it a secret? Use the credential store, with an env var only for CI. Never a flag, which shows up in
psand shell history, and never.fx.json. - Does it matter for this run only? Use a flag.
- Should it persist? Use a setting, plus a flag with the same name for one-off overrides.
- Is it safe for an untrusted repo to set, and useful for a team to share? It may also be project-safe in
.fx.json, with a maintainer's approval. - Is it set by CI, a wrapper, a terminal, debugging, or tests? Use an env var in the right namespace.
- Is it unfinished? Use an
experimental.<name>setting.
Core rules
These are the rules agents most often get wrong. references/rules.md has the full set, with what's built today.
Extend before adding. Before adding a command, flag, setting, or env var, check whether extending an existing command or control covers the need, for example a scope flag on fx usage instead of a new fx stats. Every new control is a promise that costs a deprecation to take back. When a new one is still the right call, say why the existing one can't be extended.
Names. One concept, one name, cased per surface: snake_case for settings and JSON (permission_mode), kebab-case for flags (--permission-mode), FX_ plus upper snake case for env vars (FX_PERMISSION_MODE). Values use the same words everywhere. Before naming anything, check references/decided-names.md and reuse what's there. A second spelling for an existing concept is the drift this skill exists to stop.
Run flags never save; setter commands do. A flag that shapes a run, on fx, fx ask, fx pr, or fx acp, affects only that run. git works the same way: git pull --rebase doesn't save pull.rebase. A setter command, whose whole job is to change something, saves what it changes, and its flags say what to save: fx upgrade --channel dev keeps the dev channel for later upgrades, like rustup default stable. Other setters are fx provider codex, fx login, and fx teams. A setter should print one line naming the value and the file it went to. If asked for a run flag that saves, lead with the conflict and the compliant path: a setter command, or /model in a session, which saves the default model to the profile.
Flag syntax. --x value and --x=value both work. Booleans pair --x with --no-x. When a flag repeats or conflicts, the last one wins, so wrappers and aliases can override earlier flags. An enum is one flag that takes the value. No value goes inside a flag name.
Flag placement. Agent-run flags (--model, --provider, --effort, --fast, --ultrafast, --provider-order, --provider-strict, --permission-mode) go after the subcommand, and every command that runs the agent accepts the whole set, parsed by src/core/cli/agent_run_flags.zig. fx acp leaves out the two provider-order flags, because ACP sessions don't apply gateway provider routing. Plain fx takes them directly. Only launch-wide flags such as --add-dir go before a subcommand, as in git -C dir log.
Env vars are for context, not preferences. A setting gets a named env override only when CI or wrapper scripts need it for a whole process tree, and the override uses the setting's name: collapse_tool_calls becomes FX_COLLAPSE_TOOL_CALLS, never a shorter invented name. Other settings take fx ask --config key=value for one run. Diagnostics use FX_TRACE* and FX_RECORD*, tests use FX_TEST_*, and FX_HOME moves fx's home. Respect NO_COLOR and TERM=dumb.
Experiments are settings. An unfinished feature is experimental.<name>, off by default and profile-only. It never gets its own flag or env var, so finishing or dropping it removes nothing people type.
Project files are untrusted. Anyone who can commit to a repo controls its .fx.json, so it accepts only project-safe keys. Permission settings, credentials, and experiments are never project-safe.
Slash commands use the setting's name. A slash command that changes a setting uses that setting's name and values (/fast on writes fast_mode), like vim's :set number. A slash action uses the CLI command's name (/workspace add matches fx workspace add).
Output. Results go to stdout and diagnostics to stderr. Every command that prints data accepts --json, and its fields are only added; a shape that must change goes behind --json=v2. Don't add a schema_version field: commands such as fx status --json name their shape with kind. Usage errors exit with 2 and real failures with 1. Errors name the bad input and suggest the closest match.
Precedence. Highest first: managed by an administrator (reserved, not built), flag, env var, the profile's entry for this folder, the profile, the project's .fx.json, the default.
Scopes. Commands that choose where a setting lives use --global and --workspace, plus --project only when they write a committed file.
Change over time. Every control is stable, experimental, deprecated, or internal. Renaming or removing a stable control keeps the old name working with a warning for at least two releases and 30 days. The warning names the release that drops it, old_spelling_removal (0.0.17 for the current set), and CI fails once fx reaches it. Help and completion show only the new name.
Workflow
- List every control the change adds, renames, or removes. For a diff, run scripts/surface_diff.sh from the repo root; it prints lines such as
+ flag --fast-diff src/builtins/commands.zig. Matches come from string literals, so skip test fixtures. - Walk each control through the decision order.
- Name it on every surface where it appears, starting from an existing name for the same concept. Search the settings list in
src/core/config/settings_keys.zig, the specs insrc/builtins/commands.zig, and decided-names.md. A one-run flag or env override for an existing setting takes that setting's name: for thesession_titlessetting it would be--session-titlesand--no-session-titles, plusFX_SESSION_TITLESif an env var is warranted, never--no-titles. - Check it against the matching section of rules.md.
- List what else must change: the spec and help text in
src/builtins/commands.zig, which completion also reads; parsing insrc/core/cli/; for a setting, itssettings_keys.zigentry, parsing insrc/core/config/config_runtime.zig, and thefx configlists insrc/core/cli/cli_config.zig;tests/e2e/cli.test.ts; and the fx.sh page for that surface. - Report, in this order: any conflict or approval the request needs; then the control, its mechanism, its name on each surface, and the rule behind each choice; then what else changes and what isn't built yet.
When a request conflicts with a rule or needs a maintainer's approval, lead with the conflict: name the rule, say why it exists, and give the compliant version first. Describe the requested version only as a conditional, to build only if a maintainer approves the exception. Don't quietly build the non-compliant version, and don't quietly refuse.
When reviewing a diff, report shape findings alongside bug findings. A change can be broken and misnamed at once, and fixing the bug doesn't fix the name.
Stop and ask
Ask a maintainer before:
- adding a new top-level command, a new stable env var, or a new project-safe setting;
- renaming or removing a stable control:
fx ask --jsonfields, ACP behavior, or env vars documented on fx.sh; - making any exception to a rule above.
Ask before inventing a rule for something these rules don't cover: keyboard shortcuts, prompt shortcuts (@, $, !), verbosity levels (--quiet, --verbose), --dry-run, Ctrl+C and signals, and file-write safety.
Gotchas
- Every command and slash command reads its flags through
cli_flags.Parserinsrc/core/cli/cli_flags.zig, from the sameOptionDoclist its help renders. The global flags before a command readlaunch_optionsin prefix mode, which stops at the first argument it doesn't own. - To add a flag, add an
OptionDocto the command's list and a field to that command's flag enum in its parser.cli_flags.idTablefails the build when the list and the enum disagree in either direction, so a flag can't be parsed and missing from help. When subcommands take different flags, give each list its own enum or map names to one enum at compile time, assrc/core/mcp_host/verbs.zigdoes. A new global flag also needs atop_level_flagsrow, and a launch-wide one goes inlaunch_wide_options; a test incommands.zigchecks both directions, and the usage line after a launch-flag mistake is built fromlaunch_options. - Words typed in a session are plain slices, but the parser reads arguments as the CLI receives them. Copy them with
dupeSentinelinto an arena first, asparseinsrc/core/mcp_host/verbs.zigdoes forfx mcpand/mcp, rather than comparing flags by hand. - A subcommand offers only the flags in its own
options, plus--help, in completion. When it takes its parent's flags, declare them on it, asconfig listandgetandlogin verceldo; otherwise Tab stops offering them. Setsettable_keyon a<key>word that takes only the keysfx config setchanges. - A flag that takes a number in a range writes the range in its placeholder, as
--limit <1-100>, so a bad value gets--limit takes a whole number from 1 to 100, not abc.flagProblemincli_surface.zigwrites the same text for plain and--jsonerrors; don't add a separate message for one of them. fx config getwithout a scope reports the value a run uses, throughresolveSettingsinsrc/core/app/app_lifecycle.zig. A new plain setting goes inresolved_keysincli_config.zig, or infiles_only_keyswith a reason; a unit test fails until it does.- Don't compare an argument with a flag literal by hand. CI's
python3 -m scripts.check_cli_shapefails on it anywhere insrc/, in either argument order or through a named constant, unlessscripts/cli_shape_registry.jsonlists the flag inhand_parsed_flags, as it does for help and version detection and the fixed resume grammar, or the file inhand_parsed_files, as it does for code that reads another program's flags, such as the shell-command checks. - Run
./zig-out/bin/fx <command> --helpand the command itself after changing a flag. .fx.jsonfiltering is structural: onlyparseProjectSafeFieldsreads project files. Every key also goes in the settings list,src/core/config/settings_keys.zig, marked.profileor.project_safe. That list drives the "ignored in project" warning andfx doctor's unknown-key report, and the CI shape check fails if a parser reads a key it lacks.- Every
FX_*name insrc/must be registered, with a job and a stability, inscripts/cli_shape_registry.json, or CI fails. Known violations are listed there as exceptions, each with the change that removes it. A new exception needs a maintainer's approval; never add one to make a new control pass. -calready means continue, so git's-c key=valuecan't be copied. The one-run override isfx ask --config key=value.- Full access is saved and printed as
full-access, andyolois read until fx 0.0.17, withfx doctorpointing it out. Only ACP's mode_metaand the fx-managedyolo_acknowledgedkey keep the old word. - Build a deprecation warning from
command_specs.deprecated_until, as/setupdoes with"/setup " ++ command_specs.deprecated_until ++ "; use /login ...". Tests pin the full text, and writing the release by hand breaks when it moves. fx login vercel --api-keypastes an AI Gateway API key.fx setupand/setupstill work until fx 0.0.17 but warn:fx setuppoints tofx login vercel --api-key, and/setup, an alias of/provider, points to/loginand/provider. Neither appears in help. Don't give "setup" a new meaning.- Resume already has seven kept spellings. Use
--resume lastor--resume <id>; never add another form such as--resume-latest. - Every test hook starts with
FX_TEST_; CI rejects a test hook with any other prefix.
References
- references/rules.md: every rule by mechanism, marked as built or planned. Read it when choosing names or reviewing a change in detail.
- references/decided-names.md: names already settled. Read it before naming anything near resume, permissions, scopes, sound, the status line, experiments, aliases, setup, or login.
- scripts/surface_diff.sh: lists the env vars, flags, commands, slash commands, and settings keys a diff adds or removes. Run
scripts/surface_diff.sh --helpfor options.
Trending
More talk lately.about the whole repository
Who's talking about vercel-labs/fx
- A Hacker News story“Fx: Unix Like Coding Agent”Hacker News · Aug 18, 2026 · 5 points
- A Hacker News story“fx: Unix Like Coding Agent from Vercel Labs”Hacker News · Oct 22, 2026 · 2 points
- @mint-echosphere.bsky.social“fx、7.8MiBのZig製コーディングエージェントと聞くと、つい「軽いなら気軽に全部任せられる?」って思っちゃいます。でもREADMEを読むと、軽いのはまずハーネスとCLIの話でした🌿…”Bluesky · Aug 21, 2026 · 2 likes
- @aibiznes.bsky.social“Vercel выпустила агента для программирования fx Vercel представила агента для кодинга под названием fx. Он …”Bluesky · Aug 22, 2026 · 1 likes
- @sigmanor.net“https://github.com/vercel-labs/fx”Bluesky · Aug 21, 2026 · 1 likes
The biggest 5 of 35 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 35
Talked about on GitHub, Bluesky and Hacker News (35 times).
On GitHub · 30
- Aug 19, 2026fx: init at 0.0.3 — numtide/llm-agents.nix1 reaction
- Aug 19, 2026Add fx agent — agentclientprotocol/registry1 reaction
- Oct 30, 2026chore(docker): bump opencode, acp, amp, fx (2026-10-30) — desplega-ai/agent-swarm0 reactions · 5 comments
- Oct 29, 2026fx-agent 0.0.16 — Homebrew/homebrew-core0 reactions · 1 comment
- Oct 29, 2026Support Hermes Agent, FX/libfx, and Oh My Pi (OMP) as engines — savannahfeder/agentbox0 reactions
25 more on GitHub
- Oct 28, 2026feat(cli): errors name a next step and per-command help uses one heading style — anyrouter-dev/cli0 reactions · 1 comment
- Oct 28, 2026docs(readme): follow fx layout with features, quick start and a commands table — anyrouter-dev/cli0 reactions · 1 comment
- Oct 24, 2026Bump libfx from 0.0.10 to 0.0.14 — razaanstha/ulka0 reactions
- Oct 23, 2026RFC: optional native Tern surface over FX ACP — kvnloo/fx0 reactions · 1 comment
- Oct 23, 2026Add optional Tern semantic surface on FX ACP — kvnloo/fx0 reactions · 1 comment
- Oct 22, 2026[onboarding] vercel-labs/fx — DefuzeX-AI/AgentBehaviorBench0 reactions · 4 comments
- Oct 16, 2026Record libfx queue namespace when creating World runs — kvnloo/fx0 reactions
- Oct 16, 2026Keep multiline host-tool JSON within one native JSON-RPC frame — kvnloo/fx0 reactions · 7 comments
- Oct 15, 2026Serialize native libfx host tool JSON before framing — kvnloo/fx0 reactions · 1 comment
- Oct 13, 2026Add support for fx CLI (Vercel) — cristicretu/diri0 reactions · 1 comment
- Oct 12, 2026feat(parser): add fx session support — kenn-io/agentsview0 reactions · 10 comments
- Oct 12, 2026Add support for `fx` — kenn-io/agentsview0 reactions · 1 comment
- Oct 12, 2026fx.sh now states a 6.74 MiB binary, description says a 6 MB CLI — benjamincanac/whichcodingtools0 reactions · 1 comment
- Oct 10, 2026Bump libfx from 0.0.10 to 0.0.13 — razaanstha/ulka0 reactions · 1 comment
- Oct 4, 2026shouryamaanjain/session-history does not support fx 0.0.13 — shouryamaanjain/openmods0 reactions
- Sep 29, 2026Integrate with Vercel fx — codeaholicguy/ai-devkit0 reactions
- Sep 17, 2026Retain subagent statusline upon completion — scotttrinh/fx0 reactions
- Sep 14, 2026fx-agent 0.0.10 — Homebrew/homebrew-core0 reactions · 1 comment
- Sep 10, 2026Add fx (Vercel Labs) v0.0.8 — agentclientprotocol/registry0 reactions · 1 comment
- Aug 28, 2026[RESEARCH] fx Core Library API Surface for Mobile — 10xdev4u-alt/fx-mobile0 reactions · 1 comment
- Aug 28, 2026[RESEARCH] Subagent Architecture for Mobile — 10xdev4u-alt/fx-mobile0 reactions · 1 comment
- Aug 28, 2026[RESEARCH] MCP Server Support on Android — 10xdev4u-alt/fx-mobile0 reactions · 1 comment
- Aug 28, 2026[RESEARCH] Inference Engine: Xybrid (local) + Kilo (cloud) — 10xdev4u-alt/fx-mobile0 reactions · 3 comments
- Aug 23, 2026[HARNESS]: fx adapter must target ~/.fx (mcp.json root key 'mcp', array-form command) — current ~/.config/fx/fx.json is fictional — mastepanoski/ce-ai0 reactions · 1 comment
- Aug 18, 2026[Tool Submission] fx.sh — QAInsights/awesome-ai-tools0 reactions
On Bluesky · 3
- Aug 21, 2026fx、7.8MiBのZig製コーディングエージェントと聞くと、つい「軽いなら気軽に全部任せられる?」って思っちゃいます。でもREADMEを読むと、軽いのはまずハーネスとCLIの話でした🌿… — @mint-echosphere.bsky.social2 likes and reposts · 1 reply
- Aug 22, 2026Vercel выпустила агента для программирования fx Vercel представила агента для кодинга под названием fx. Он идёт против текущего тренда —… — @aibiznes.bsky.social1 likes and repost
- Aug 21, 2026https://github.com/vercel-labs/fx — @sigmanor.net1 likes and repost
On Hacker News · 2
- Aug 18, 2026Fx: Unix Like Coding Agent5 points · 1 comment
- Oct 22, 2026fx: Unix Like Coding Agent from Vercel Labs2 points
In this repository4 other files it gives its agents.
- AGENTS.mdAGENTS.md
- sdk/AGENTS.mdAGENTS.md
- tests/AGENTS.mdAGENTS.md
- technical-writerSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

