Skip to content

Write command names as plain text in CLI output - #2294

Merged
schnie merged 6 commits into
v2from
render-backticks
Oct 14, 2026
Merged

schnie merged 6 commits into
v2from
render-backticks

Conversation

@schnie

@schnie schnie commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

What

The CLI's own messages named commands, flags and paths the way the docs do, in backticks: "astro dev start was removed in Astro CLI v2. Use astro local start instead." A terminal printed the backticks literally, and so did the --output json error object. This PR writes them as plain text at the source:

astro dev start was removed in Astro CLI v2. Use astro local start instead.

There is no runtime transform. The PR's first commit (a renderer that bolded or stripped backticks at output time) is reverted in the second. Review found it unsafe in four ways:

  • a % inside a span went through aurora's Sprintf;
  • it stripped real backticks from uv, HTTP and Airflow text that passes through;
  • it rewrote copy-paste commands;
  • it missed notes inside json payloads.

Plain text at the source has none of those problems.

What changed

  • 217 string literals in 84 non-test Go files now carry no backticks. They cover errors, warnings, notes (astro init conversion notes, check notes, Deployment clone notes, the astro dev stub's payload error and notes), help Short/Long/flag usage, next steps (astro package), prompts, and removed-command and removed-flag messages. This spans cmd/, internal/, airflow/, and the pkg/* sub-modules awsauth, checks, container, emfetch, googleauth, imagebuild, instancelocate, instances, localrt and scaffold, plus pkg/httputil and pkg/util. Astro Desktop sees the plain text too, since it imports the sub-modules.
  • Wording is otherwise unchanged. Where a bare command read ambiguously mid-sentence, the sentence was minimally rephrased instead of quoted:
    • "set creates …" became "The set command creates …" in four places (env, deployment and link removal guidance);
    • "ls lists" became "The ls command lists" (local api), and "list shows" became "The list command shows" (variables);
    • "use astro local start --docker then" became "then use astro local start --docker" (dev stub note);
    • "Drop the local" became "Drop local from the command";
    • "run uv run pytest yourself" became "run your tests yourself with uv run pytest";
    • "mark a link default = true" became "set default = true on a link";
    • "add a line .env" became "add a .env line";
    • "link narrows … use get" became "linking narrows … use the get command";
    • "Check workspace and domain in pyproject.toml" became "Check the workspace and domain keys in pyproject.toml", with the same change for "sets no workspace" and "organization and workspace under [tool.astro]";
    • the MWAA region hint became "check this link's environment and the region under …";
    • "with dockerfile under [tool.astro]" became "with the dockerfile key under [tool.astro]";
    • the if r.Format == FormatJSON panic text became "branch on r.Format == FormatJSON";
    • the astro init note that lists several astro link add … commands now joins them with "; " rather than ", ", so one command is not read as running into the next.
  • The Otto upgrade prompt (pkg/scaffold/airflowupgradeprompt.go, and the CLI's own cliUpgradePrompt.BringUp clause in it) stays markdown. It is written for a model and is never printed.
  • Not touched: Go raw-string delimiters, comments, docs (docs/*.md are markdown), and text passed through from uv, Airflow or an API.

Guard tests

  • TestMessagesWriteCommandsAsPlainText (internal/archlint/backticks_test.go) parses every non-test .go file that git tracks (git ls-files), sub-modules included, so worktrees under .claude/, .git and untracked scratch files are never read. It fails on any string literal that holds a backtick, and the failure message states the convention. It skips e2e/, *.gen.go, testdata/ and the test-helper packages cliouttest/ and instancestest/. Its allowlist, backtickAllowed, is keyed by file, by file and declared const/var name, or by file and literal. It has four entries:

    • pkg/scaffold/templates.go: agentsContent: the AGENTS.md that astro init writes into a project, which is markdown;
    • pkg/scaffold/airflowupgradeprompt.go: the prompt handed to Otto, which is markdown for a model and is never printed;
    • cmd/local/upgrade.go: cliUpgradePrompt: the CLI's own words in that prompt;
    • pkg/scaffold/files1x.go, the literal "$*?\"`: the shell metacharacters that make an argument unsafe to repeat unquoted.

    An entry that no longer matches anything also fails the test.

  • TestHelpHasNoBackticks (cmd/help_backticks_test.go) renders every help page in every tree from rootsUnderTest, hidden commands included. It fails on any line with a backtick, which also catches strings assembled at run time. It also reads every flag's usage as written, because pflag takes a backticked word as the flag's value name and drops the backticks from the page.

  • docs/architecture.md: a new "Commands in messages" section under Output states the convention and the two guards, and the help style guide gains a bullet for it.

  • Tests that pinned backticked text were updated in 52 test files, including e2e/devstub_test.go and e2e/convert_test.go.

  • make update-schemas changed no goldens; they pin shapes, not values.

Merge with v2

v2 has since gained #2285, #2291, #2295, #2297, #2300 to #2310. Merging it (a merge commit, no force-push) conflicted in 15 files. Each was resolved to v2's code, with the backticks dropped from the messages v2 added or reworded:

  • cmd/astro/deployment_removed.go and cmd/astro/env_removed.go: the stubs' heads ("astro deployment %s was removed in Astro CLI v2.", "astro env %s %s was removed in Astro CLI v2.") and Shorts ("Removed in v2 — use astro env …", "… use the set command, which creates or updates").
  • cmd/astro/env_var_link.go: the create stub's Short and guidance.
  • cmd/local/dev.go: the stub's Short, the "Use %s instead" and "Use %s to make a new project here, or %s to convert …" lines, and "Local Airflow now lives under astro local:".
  • cmd/local/run_removed.go: the Short ("Removed in v2 — use " + replaceRunDag).
  • cmd/removed_flags.go: "To log in on another device, use astro login --login-link".
  • internal/deploy/deploy.go: the deploy-target refusal ("astro deploy or --deployment ", "default = true only preselects the prompt, and astro use and %s are for the query commands").

The other conflicts (airflow/docker.go, cmd/apc/deploy.go, cmd/astro/deploy.go, internal/platform/astro/deploy/deploy.go, internal/project/project.go) took v2's side unchanged: v2 had removed or rewritten that code, and its new text already had no backticks.

These are the only backticked literals v2 added: TestMessagesWriteCommandsAsPlainText found 16 after the merge, in the 7 files above, and none in v2's other new code. That includes the 1.x/APC messages, the shipcheck and deploy messages, and the local proxy pages, whose HTML templates use <code> and carry no backticks.

Tests that pinned the backticked text now read the plain form:

  • cmd/config_test.go
  • cmd/local/dev_test.go
  • cmd/local/initcmd_test.go
  • cmd/removed_flags_test.go (the t.Skip text)
  • cmd/removed_commands_test.go: namesReplacement looked for "`astro "; it now looks for " astro ".

Review follow-up

These changes are in a22032a:

  • pkg/instances: the reserved-name refusal now opens with "the name local is reserved for this machine and is not a deployment".
  • astro deployment update --development-mode: the help quotes 'enable' the way it already quotes 'disable'.
  • astro af messages that named a command by a bare fragment now print it in full through the target's suggest, as health does:
    • runs trigger-wait's help ("as astro af runs trigger does");
    • dags explore's help;
    • the error when a run has more task instances than one command reads.
  • astro env variable export's help now names astro env variable list -o json in full.
  • runs trigger-wait's two failure errors give the cause first and then "Check on it with …", so the command no longer runs into the wrapped error.
  • cmd/removed_commands_test.go: namesReplacement passes only when the words after "astro " reach a runnable command in the tree, not the root and not a removed or version-gated stub. Text that says there is no replacement also passes.
  • cmd/local/initcmd_test.go: the APC dev-stub text must hold no "Use " and no "Convert with " line.

These were re-run after the merge and the review follow-up:

  • go build ./... and GOOS=windows go build ./... pass.
  • GOOS=windows go vet ./cmd/... ./internal/... passes.
  • make test passes.
  • make test-submodules passes except pkg/airflowrt's TestHasProxyConfigured, which fails on the host where it ran. That host has a macOS system proxy (a PAC URL), and the test asserts there is none. This PR does not touch pkg/airflowrt.
  • make test-e2e (tier 0) passes.
  • make lint, make lint-submodules, make lint-e2e, make lint-goos and make deadcode pass.
  • make update-schemas produced no diff.

Breaking changes

The text of messages changes. A script that greps stderr, or an error object's error, for a backticked command (`astro local start`) now sees astro local start. The JSON shapes are unchanged.

Messages, help and errors name a command the way the docs do, in
backticks, and terminals printed the backticks literally. The source keeps
them; the output layer now renders them: bold on a terminal with color on,
plain text anywhere else (a pipe, a file, NO_COLOR), and plain text in the
--output json error object and warning records.

The rule is narrow (pkg/ansi/backticks.go): a pair of backticks on one line
around up to 200 characters that do not start or end with a space, with no
letter or digit outside either backtick. A lone backtick, an empty pair, a
run of three, and one inside a word or a quoted value are left as they are.

Co-Authored-By: Claude <noreply@anthropic.com>
@schnie
schnie requested review from a team as code owners October 9, 2026 18:27
@coveralls-official

coveralls-official Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 38598044054

Coverage increased (+0.003%) to 57.901%

Details

  • Coverage increased (+0.003%) from the base build.
  • Patch coverage: 11 uncovered changes across 6 files (115 of 126 lines covered, 91.27%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
cmd/local/runs_wait.go 11 8 72.73%
internal/instancelocate/instancelocate.go 4 1 25.0%
cmd/otto.go 2 0 0.0%
cmd/link_pickers.go 2 1 50.0%
cmd/local/local.go 4 3 75.0%
internal/platform/astro/deploy/deploy.go 2 1 50.0%
Total (53 files) 126 115 91.27%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 69398
Covered Lines: 40182
Line Coverage: 57.9%
Coverage Strength: 276.26 hits per line

💛 - Coveralls

schnie and others added 3 commits October 9, 2026 16:09
This reverts commit f3acec6. Review found the runtime transform unsafe: a % inside a span went through aurora's Sprintf, real backticks in passed-through uv, HTTP and Airflow text were stripped, and copy-paste commands were rewritten. Command names are written as plain text at the source instead, in the commits that follow.

Co-Authored-By: Claude <noreply@anthropic.com>
Messages, help and notes named commands, flags and paths the way the docs
do, in backticks, and a terminal printed the backticks as they were, as did
an error object's json. They are plain text now, at the source: "astro dev
start was removed in Astro CLI v2. Use astro local start instead." Where a
bare command read ambiguously mid-sentence, the sentence is rephrased
rather than quoted.

TestMessagesWriteCommandsAsPlainText (internal/archlint) fails on a string
literal holding a backtick anywhere in the repo's non-test Go code, except
what its backtickAllowed list names: the markdown astro init writes, the
upgrade prompt handed to Otto, and one shell-metacharacter set.
TestHelpHasNoBackticks renders every help page in every tree and fails on a
backtick.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@schnie schnie changed the title Render backticked command names in terminal output Write command names as plain text in CLI output Oct 9, 2026
schnie and others added 2 commits October 14, 2026 12:02
Conflicts resolved to v2's code, with the backticks dropped from the
messages v2 added or reworded: the removed-command stubs' heads and
Shorts (deployment, env, env variable link, dev, run), the dev stub's
replacement lines, the --login-link guidance and the deploy target
refusal. Tests that pinned the backticked text, and namesReplacement in
removed_commands_test.go, now read the plain form.

Co-Authored-By: Claude <noreply@anthropic.com>
- Name the reserved local deployment name as "the name local is reserved
  for this machine", quote 'enable' like 'disable' in --development-mode,
  and spell the af commands that help and errors point to in full, through
  the target's suggest, instead of as bare fragments.
- runs trigger-wait's errors put the cause before the command to run,
  instead of running the command into it.
- The Otto prompt's bring-up clause gets its backticks back: it is
  markdown for a model and never printed. backtickAllowed exempts it,
  and AGENTS.md, by declaration name instead of by file.
- The source guard reads only the files git tracks. The help guard also
  reads each flag's usage as written, since pflag hides a backticked word
  from the rendered page.
- The removed-command test asks for a runnable command in the guidance,
  and the APC dev-stub test for no Use or Convert with line at all.

Co-Authored-By: Claude <noreply@anthropic.com>
@schnie
schnie merged commit 08cc506 into v2 Oct 14, 2026
7 checks passed
@schnie
schnie deleted the render-backticks branch October 14, 2026 16:38
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.

1 participant