Skip to content

feat: add polished boot screen on CLI startup#118

Merged
ilblackdragon merged 2 commits intomainfrom
feat/boot-screen
Feb 17, 2026
Merged

feat: add polished boot screen on CLI startup#118
ilblackdragon merged 2 commits intomainfrom
feat/boot-screen

Conversation

@ilblackdragon
Copy link
Copy Markdown
Member

@ilblackdragon ilblackdragon commented Feb 17, 2026

Summary

  • Adds a new boot_screen module that displays a polished ANSI-styled status panel on CLI startup, summarizing runtime state: model, database, tool count, enabled features, active channels, and gateway URL
  • Suppresses the old one-liner REPL banner when the boot screen is shown
  • Collects channel names and gateway URL during initialization to populate the boot screen

Test plan

  • Run cargo test boot_screen to verify boot screen rendering tests pass
  • Launch in interactive CLI mode and verify the boot screen displays correctly with all configured features
  • Launch with --message flag and verify boot screen is skipped
  • Launch with --no-db and verify database shows as "none"
  • Verify the old one-liner banner no longer appears in interactive mode

🤖 Generated with Claude Code

Replace the minimal one-liner REPL banner with an ANSI-styled status
panel that summarizes the agent's runtime state after initialization:
model, database, tool count, enabled features, active channels, and
the gateway URL. The boot screen is shown only in interactive CLI mode
(skipped for single-message -m mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings February 17, 2026 03:00
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @ilblackdragon, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience for the CLI by introducing a comprehensive and visually appealing boot screen. Instead of a simple banner, users will now see a detailed summary of the agent's configuration and operational status right after startup. This change provides immediate insight into the running environment, making it easier to verify setup and understand the agent's capabilities at a glance.

Highlights

  • New Boot Screen Module: A new boot_screen module has been added, responsible for rendering a detailed, ANSI-styled status panel upon CLI startup. This screen summarizes the agent's runtime state, including model, database, tool count, enabled features, active channels, and gateway URL.
  • REPL Banner Suppression: The traditional one-liner REPL banner is now suppressed when the new boot screen is displayed, providing a cleaner and more informative startup experience.
  • Runtime State Collection: The application now actively collects and aggregates various pieces of runtime information, such as active channel names and the gateway URL, during initialization to populate the new boot screen.
Changelog
  • src/boot_screen.rs
    • Introduced BootInfo struct to encapsulate all data points required for the boot screen display.
    • Implemented print_boot_screen function to format and print the detailed status panel using ANSI escape codes.
    • Added unit tests to verify the rendering of the boot screen under various conditions (full, minimal, no features).
  • src/channels/repl.rs
    • Added a suppress_banner atomic boolean field to the ReplChannel struct.
    • Implemented a suppress_banner public method to set this flag.
    • Modified the run method to conditionally print the old one-liner startup banner based on the suppress_banner flag's state.
  • src/lib.rs
    • Declared the new boot_screen module as public, making its functionality accessible throughout the crate.
  • src/main.rs
    • Modified the ReplChannel instantiation logic to call suppress_banner() when the CLI channel is enabled and not in single-message mode.
    • Introduced channel_names vector and gateway_url option to collect runtime information about active channels and the gateway.
    • Populated channel_names with 'repl', 'wasm', 'http', and 'gateway' based on configuration.
    • Captured current tool count, LLM model, and cheap LLM model before moving these resources.
    • Constructed a boot_screen::BootInfo instance using the collected runtime data.
    • Invoked ironclaw::boot_screen::print_boot_screen to display the new boot screen if the CLI is in interactive mode.
Activity
  • No human activity has been recorded on this pull request yet.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new boot screen shown on interactive CLI startup to present a richer ANSI status panel (model/db/tools/features/channels/gateway), while suppressing the old REPL one-liner banner and collecting init-time data to populate the screen.

Changes:

  • Introduces boot_screen module with BootInfo + print_boot_screen and basic tests.
  • Suppresses the REPL startup banner when the boot screen will be shown.
  • Tracks channel names and gateway URL during startup to display in the boot screen.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
src/main.rs Collects boot screen data (channels, gateway URL, model/tool counts) and prints boot screen in interactive mode; suppresses REPL banner.
src/lib.rs Exposes the new boot_screen module from the library crate.
src/channels/repl.rs Adds a suppress_banner flag to disable the REPL one-liner banner.
src/boot_screen.rs Implements ANSI boot screen rendering and adds non-panicking tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/main.rs Outdated
gw_config.port,
gw.auth_token()
);
tracing::info!("Web UI: {}", gateway_url.as_deref().unwrap_or(""));
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

gateway_url embeds the gateway auth token and is logged via tracing::info!("Web UI: {}", ...). This leaks the bearer token into structured logs (which may be persisted/forwarded). Consider logging only the base URL (no query string) and printing the full tokenized URL only to the interactive boot screen / stdout (or gating it behind debug).

Suggested change
tracing::info!("Web UI: {}", gateway_url.as_deref().unwrap_or(""));
let public_gateway_url = format!("http://{}:{}/", gw_config.host, gw_config.port);
tracing::info!("Web UI: {}", public_gateway_url);

Copilot uses AI. Check for mistakes.
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.

Fixed in 036cd84. The tracing line now logs only http://host:port/ without the token. The full tokenized URL is still passed to the boot screen for interactive display only.

Comment thread src/boot_screen.rs Outdated
println!();
println!("{border}");
println!();
println!(" {bold}IronClaw{reset} v{}", info.version);
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The boot screen header is hard-coded as "IronClaw" and never uses info.agent_name. Since BootInfo includes agent_name and main.rs populates it from config.agent.name, the displayed name will be wrong if the agent is renamed/configured differently. Use info.agent_name in the header (or remove the field if it isn't meant to vary).

Suggested change
println!(" {bold}IronClaw{reset} v{}", info.version);
println!(" {bold}{}{reset} v{}", info.agent_name, info.version);

Copilot uses AI. Check for mistakes.
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.

Fixed in 036cd84. Now uses info.agent_name instead of hardcoded "IronClaw".

Comment thread src/boot_screen.rs
Comment on lines +17 to +20
pub gateway_url: Option<String>,
pub embeddings_enabled: bool,
pub embeddings_provider: Option<String>,
pub heartbeat_enabled: bool,
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

BootInfo::embeddings_provider is populated by main.rs but never displayed. If the intent is to summarize runtime state, consider incorporating the provider into the features line (e.g., "embeddings (openai)") or drop the field to avoid it drifting out of sync with what the boot screen actually shows.

Copilot uses AI. Check for mistakes.
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.

Fixed in 036cd84. The features line now shows embeddings (openai) when the provider is set.

Comment thread src/boot_screen.rs
Comment on lines +123 to +150
#[test]
fn test_print_boot_screen_full() {
let info = BootInfo {
version: "0.2.0".to_string(),
agent_name: "ironclaw".to_string(),
llm_backend: "nearai".to_string(),
llm_model: "claude-3-5-sonnet-20241022".to_string(),
cheap_model: Some("gpt-4o-mini".to_string()),
db_backend: "libsql".to_string(),
db_connected: true,
tool_count: 24,
gateway_url: Some("http://127.0.0.1:3001/?token=abc123".to_string()),
embeddings_enabled: true,
embeddings_provider: Some("openai".to_string()),
heartbeat_enabled: true,
heartbeat_interval_secs: 1800,
sandbox_enabled: true,
claude_code_enabled: false,
routines_enabled: true,
channels: vec![
"repl".to_string(),
"gateway".to_string(),
"telegram".to_string(),
],
};
// Should not panic
print_boot_screen(&info);
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The tests only verify that print_boot_screen doesn't panic; they don't validate any rendered content (e.g., that model/db/tool count/channels appear). Consider refactoring rendering into a function that returns a String (or writing to a generic Write) so tests can assert on the output and catch regressions in formatting/omitted fields.

Copilot uses AI. Check for mistakes.
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.

No change. The boot screen is simple visual output — no-panic tests are sufficient. Refactoring to impl Write would add complexity without meaningful regression coverage for what is essentially a formatted print. If the boot screen grows more complex we can revisit.

Copy link
Copy Markdown
Contributor

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

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 a polished boot screen on CLI startup, which is a great enhancement for user experience. The implementation is well-structured, with a new boot_screen module and clear logic for gathering the necessary information in main.rs. My review includes a few suggestions to improve the robustness and maintainability of the new feature. Specifically, I've pointed out a minor bug where the agent name is hardcoded, an unused field in the BootInfo struct, and opportunities to make the UI alignment more robust and the code in main.rs more concise by leveraging Rust's trait system. All original comments have been retained as they align with best practices and are not contradicted by any specific rules. Overall, this is a solid feature addition.

Comment thread src/boot_screen.rs Outdated
println!();
println!("{border}");
println!();
println!(" {bold}IronClaw{reset} v{}", info.version);
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.

medium

The agent name is hardcoded as "IronClaw". The BootInfo struct already contains the agent_name field, which should be used here to correctly display the configured agent name.

Suggested change
println!(" {bold}IronClaw{reset} v{}", info.version);
println!(" {bold}{}{reset} v{}", info.agent_name, info.version);

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.

Fixed in 036cd84. Now uses info.agent_name instead of hardcoded "IronClaw".

Comment thread src/boot_screen.rs
pub tool_count: usize,
pub gateway_url: Option<String>,
pub embeddings_enabled: bool,
pub embeddings_provider: Option<String>,
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.

medium

The embeddings_provider field is populated in main.rs but is not used anywhere in print_boot_screen. This field should either be used to display the provider information on the boot screen or be removed from the BootInfo struct and the data collection logic in main.rs to eliminate dead code.

If you intend to display it, you could add it to the "features" line, for example:

if info.embeddings_enabled {
    let mut feature_str = "embeddings".to_string();
    if let Some(provider) = &info.embeddings_provider {
        feature_str.push_str(&format!(" ({})", provider));
    }
    features.push(feature_str);
}

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.

Fixed in 036cd84. The features line now shows embeddings (openai) when the provider is set.

Comment thread src/boot_screen.rs
Comment on lines +51 to +71
println!(
" {dim}model{reset} {model_display} {dim}via {}{reset}",
info.llm_backend
);

// Database line
let db_status = if info.db_connected {
"connected"
} else {
"none"
};
println!(
" {dim}database{reset} {cyan}{}{reset} {dim}({db_status}){reset}",
info.db_backend
);

// Tools line
println!(
" {dim}tools{reset} {cyan}{}{reset} {dim}registered{reset}",
info.tool_count
);
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.

medium

The alignment of the key-value pairs in the boot screen is done using a fixed number of spaces (e.g., model , database ). This is fragile and can lead to misaligned output if a key is longer or shorter than expected, or if the font is not monospaced.

To make the layout more robust, you could calculate the padding dynamically based on the length of the longest key. This ensures consistent alignment regardless of the key names.

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.

No change. The labels are a fixed compile-time set (model, database, tools, features, channels, gateway) — there's no dynamic key that could change length. Fixed padding is deliberate and appropriate here; dynamic calculation would add complexity for no benefit.

Comment thread src/main.rs Outdated
Comment on lines +1242 to +1245
match config.database.backend {
ironclaw::config::DatabaseBackend::Postgres => "postgres".to_string(),
ironclaw::config::DatabaseBackend::LibSql => "libsql".to_string(),
}
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.

medium

This match statement manually converts DatabaseBackend enum variants to strings. This can be simplified and made more maintainable by implementing the Display trait for the DatabaseBackend enum in src/config.rs.

You could add the following implementation in src/config.rs:

// in src/config.rs
impl std::fmt::Display for DatabaseBackend {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Postgres => write!(f, "postgres"),
            Self::LibSql => write!(f, "libsql"),
        }
    }
}

Then, you can simplify the code here to:

db_backend: if cli.no_db {
    "none".to_string()
} else {
    config.database.backend.to_string()
},

This change would also be beneficial elsewhere, as the LlmBackend enum already has a Display implementation.

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.

Fixed in 036cd84. Added Display impl for DatabaseBackend in config.rs, simplified the match to config.database.backend.to_string().

- Stop logging gateway auth token in tracing::info! (security)
- Use info.agent_name instead of hardcoded "IronClaw" in header
- Display embeddings provider in features line: "embeddings (openai)"
- Add Display impl for DatabaseBackend, simplify main.rs match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ilblackdragon ilblackdragon merged commit 63302ab into main Feb 17, 2026
2 checks passed
@ilblackdragon ilblackdragon deleted the feat/boot-screen branch February 17, 2026 05:50
This was referenced Feb 17, 2026
jaswinder6991 pushed a commit to jaswinder6991/ironclaw that referenced this pull request Feb 26, 2026
* feat: add polished boot screen on CLI startup

Replace the minimal one-liner REPL banner with an ANSI-styled status
panel that summarizes the agent's runtime state after initialization:
model, database, tool count, enabled features, active channels, and
the gateway URL. The boot screen is shown only in interactive CLI mode
(skipped for single-message -m mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback on boot screen

- Stop logging gateway auth token in tracing::info! (security)
- Use info.agent_name instead of hardcoded "IronClaw" in header
- Display embeddings provider in features line: "embeddings (openai)"
- Add Display impl for DatabaseBackend, simplify main.rs match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
bkutasi pushed a commit to bkutasi/ironclaw that referenced this pull request Mar 28, 2026
* feat: add polished boot screen on CLI startup

Replace the minimal one-liner REPL banner with an ANSI-styled status
panel that summarizes the agent's runtime state after initialization:
model, database, tool count, enabled features, active channels, and
the gateway URL. The boot screen is shown only in interactive CLI mode
(skipped for single-message -m mode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review feedback on boot screen

- Stop logging gateway auth token in tracing::info! (security)
- Use info.agent_name instead of hardcoded "IronClaw" in header
- Display embeddings provider in features line: "embeddings (openai)"
- Add Display impl for DatabaseBackend, simplify main.rs match

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.

2 participants