Skip to content

feat(cli): new launch banner with repo + build metadata#26

Open
thad0ctor wants to merge 3 commits into
mainfrom
worktree-axolotl-banner
Open

feat(cli): new launch banner with repo + build metadata#26
thad0ctor wants to merge 3 commits into
mainfrom
worktree-axolotl-banner

Conversation

@thad0ctor

@thad0ctor thad0ctor commented May 24, 2026

Copy link
Copy Markdown
Owner

Description

Updates banner and enables it to be invoked (only) once via python -m axolotl.cli.train and accelerate launch / torchrun -m , also adds version and build to assist with log debugging

Motivation and Context

Boredom mostly

How has this been tested?

  1. Banner on subcommand help: "$VENV_PY" -m axolotl.cli.main train --help | head -15
  2. Banner via module entry: "$VENV_PY" -m axolotl.cli.train /tmp/missing.yaml 2>&1 | head -15
  3. Torchrun 2 ranks prints banner once: CUDA_VISIBLE_DEVICES="" "$TORCHRUN" --nproc_per_node=2 --master_port=29777 -m axolotl.cli.train /tmp/missing.yaml 2>&1 | grep -c "┌─┐┌─┐" (expect 1)
  4. Env-var silences subprocess: AXOLOTL_BANNER_PRINTED=1 "$VENV_PY" -m axolotl.cli.train /tmp/missing.yaml 2>&1 | grep -c "┌─┐┌─┐" (expect 0)
  5. End-to-end accelerate launcher: echo '{}' > /tmp/banner-empty.yaml && CUDA_VISIBLE_DEVICES="" "$VENV_PY" -m axolotl.cli.main train --launcher accelerate /tmp/banner-empty.yaml 2>&1 | grep -c "┌─┐┌─┐" (expect 1)
  6. Wheel install fallback (no git, URL + version only): "$VENV_PY" -c "import axolotl; axolotl.__file__='/tmp/fake/axolotl/__init__.py'; from axolotl.cli.art import print_axolotl_text_art; print_axolotl_text_art()"

AI Usage Disclaimer

Claude Opus tested and did env check

Screenshots (if appropriate)

Renders as:

 ┌─┐┌─┐    ┌─┐┌─┐
 │ ││ │    │ ││ │   █████   ██   ██   █████   ██        █████   ███████  ██
 │ └┘ └────┘ └┘ │  ██   ██   ██ ██   ██   ██  ██       ██   ██    ███    ██
 │              │  ███████    ███    ██   ██  ██       ██   ██    ███    ██
 │  ◉        ◉  │  ██   ██   ██ ██   ██   ██  ██       ██   ██    ███    ██
 └──────────────┘  ██   ██  ██   ██   █████   ███████   █████     ███    ███████
 ▄▄▄▄▄▄▄▄▄▄  ▄▄▄
 ▄▄▄  ▄▄▄▄▄▄▄▄▄▄            https://github.com/axolotl-ai-cloud/axolotl
                               v0.16.0.dev0 · dc8f7c718 · 2026-05-20

Types of changes

Solely Cosmetic

Replaces the @-symbol AXOLOTL logo with the new axolotl-head + AXOLOTL
letters art. Renders the GitHub URL and `vVERSION · <sha> · <date>`
centered under the letters; sha/date are best-effort from `git`, falling
back to just the version on non-git installs.

Also wires `print_axolotl_text_art()` into `axolotl.cli.train:do_cli` so
the banner shows when invoked via `python -m axolotl.cli.train` (e.g.
under torchrun in custom launch scripts), and adds an
`AXOLOTL_BANNER_PRINTED` env-var guard so the Click parent + spawned
subprocess (`accelerate launch` / `torchrun -m`) print it only once.
@coderabbitai

coderabbitai Bot commented May 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 341c8d0e-f19a-4838-bacb-cd8d2bafa42b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR replaces the static Axolotl ASCII banner with a dynamically constructed logo that embeds the package version and optional git metadata (short SHA and commit date). It adds helper functions to retrieve git information and center text, updates the print function to prevent duplicate banner output using module-level and environment variable flags, and integrates the banner printing into the CLI startup flow.

Changes

Dynamic Banner with Git Metadata

Layer / File(s) Summary
Banner constants and imports
src/axolotl/cli/art.py
Introduces GITHUB_URL constant and updates imports while preserving the HAS_PRINTED_LOGO guard variable and removing the static AXOLOTL_LOGO.
Git metadata and text centering helpers
src/axolotl/cli/art.py
Adds _get_git_info() to fetch git short SHA and commit date via subprocess with fallback on errors, and _centered_under_letters() to compute padding for centering text.
Dynamic logo builder
src/axolotl/cli/art.py
Implements _build_logo() to assemble the final banner by combining version, optional git metadata, and injecting them into the ASCII template with centered GitHub URL and build info.
Banner printing with deduplication
src/axolotl/cli/art.py
Updates print_axolotl_text_art() to check deduplication guards (module flag and AXOLOTL_BANNER_PRINTED env var), set the env var when printing, and output the dynamically built logo.
CLI entrypoint integration
src/axolotl/cli/train.py
Imports and invokes print_axolotl_text_art() at the start of do_cli() before config loading to display the banner.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(cli): new launch banner with repo + build metadata' directly and accurately summarizes the main change: adding a new CLI banner that displays repository and build metadata.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch worktree-axolotl-banner

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/axolotl/cli/art.py`:
- Around line 39-51: The _get_git_info() function calls subprocess.check_output
twice without timeouts and doesn't handle subprocess.TimeoutExpired; add a short
timeout (e.g., timeout=1 or 2 seconds) to both check_output calls and include
subprocess.TimeoutExpired in the except tuple alongside
subprocess.CalledProcessError, FileNotFoundError, and OSError so that a git hang
is treated as a fallback and the function returns (None, None) like other
failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aba1fa50-357c-417e-bb25-336aa76da4ab

📥 Commits

Reviewing files that changed from the base of the PR and between dc8f7c7 and 9f5ca7c.

📒 Files selected for processing (2)
  • src/axolotl/cli/art.py
  • src/axolotl/cli/train.py

Comment thread src/axolotl/cli/art.py
Comment on lines +39 to +51
try:
sha = subprocess.check_output( # nosec B603 B607
["git", "-C", str(repo_root), "rev-parse", "--short", "HEAD"],
stderr=subprocess.DEVNULL,
text=True,
).strip()
date = subprocess.check_output( # nosec B603 B607
["git", "-C", str(repo_root), "log", "-1", "--format=%cs"],
stderr=subprocess.DEVNULL,
text=True,
).strip()
return sha or None, date or None
except (subprocess.CalledProcessError, FileNotFoundError, OSError):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a timeout (and handle TimeoutExpired) to _get_git_info() best-effort git probes

subprocess.check_output() calls in src/axolotl/cli/art.py (lines 40 and 45) have no timeout and _get_git_info() doesn’t catch subprocess.TimeoutExpired, so startup can block if git hangs. Add a short timeout to both calls and treat TimeoutExpired like the other fallbacks.

Suggested fix
     try:
         sha = subprocess.check_output(  # nosec B603 B607
             ["git", "-C", str(repo_root), "rev-parse", "--short", "HEAD"],
             stderr=subprocess.DEVNULL,
             text=True,
+            timeout=1,
         ).strip()
         date = subprocess.check_output(  # nosec B603 B607
             ["git", "-C", str(repo_root), "log", "-1", "--format=%cs"],
             stderr=subprocess.DEVNULL,
             text=True,
+            timeout=1,
         ).strip()
         return sha or None, date or None
-    except (subprocess.CalledProcessError, FileNotFoundError, OSError):
+    except (
+        subprocess.CalledProcessError,
+        subprocess.TimeoutExpired,
+        FileNotFoundError,
+        OSError,
+    ):
         return None, None
🧰 Tools
🪛 Ruff (0.15.13)

[error] 40-40: subprocess call: check for execution of untrusted input

(S603)


[error] 41-41: Starting a process with a partial executable path

(S607)


[error] 45-45: subprocess call: check for execution of untrusted input

(S603)


[error] 46-46: Starting a process with a partial executable path

(S607)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/axolotl/cli/art.py` around lines 39 - 51, The _get_git_info() function
calls subprocess.check_output twice without timeouts and doesn't handle
subprocess.TimeoutExpired; add a short timeout (e.g., timeout=1 or 2 seconds) to
both check_output calls and include subprocess.TimeoutExpired in the except
tuple alongside subprocess.CalledProcessError, FileNotFoundError, and OSError so
that a git hang is treated as a fallback and the function returns (None, None)
like other failures.

@github-actions

Copy link
Copy Markdown

📖 Documentation Preview:

Deployed on Netlify from commit c7c8af4

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