Skip to content

perf(cli): ~10x faster startup — lazy heavy imports + onedir standalone build - #920

Open
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1785193451-cli-startup-perf
Open

perf(cli): ~10x faster startup — lazy heavy imports + onedir standalone build#920
devin-ai-integration[bot] wants to merge 4 commits into
mainfrom
devin/1785193451-cli-startup-perf

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

strix --help (and view/auth/arg errors) took ~3.2s from pipx/source and ~8s+ from the standalone binary. Two fixes:

1. Standalone binary: onefile → onedir (no per-run self-extraction)

The PyInstaller onefile binary unpacked the full ~87MB bundle to a temp dir on every invocation (~4s on fast Linux; 8s+ on macOS with Gatekeeper). Switched to onedir (EXE(exclude_binaries=True) + COLLECT), so nothing is extracted at runtime:

  • release archives now contain an app directory strix-{version}-{target}/ (strix + _internal/); build.sh / build-release.yml updated accordingly
  • install.sh extracts the bundle contents into ~/.strix/bin/ (so strix stays on PATH at the same location, and re-running the installer cleanly replaces an old single-file install)
  • self-update no longer reimplements download/checksum/swap: strix --update now just pipes the hosted install script into bash with VERSION=<latest> (same approach as opencode's Installation.upgrade), deleting ~130 lines from update_check.py

Note: binaries already installed from ≤1.4.1 run the old self-update code, which won't understand the new archive layout — their strix --update fails with the standard "reinstall via curl" hint, and the reinstall lands them on the new layout.

2. Defer the two heaviest imports off the --help path

  • run_cli/run_tui (→ strix.core.runner → litellm ~1.3s + textual) now import inside main() right where the scan starts
  • configure_dependency_logging no longer does import litellm just to silence it — it only patches litellm if it's already in sys.modules (setup_scan_logging re-runs it on the scan path after litellm is loaded)

Measured on Linux x86_64: source/pipx --help 3.2s → 1.2s; standalone binary ~8s → ~1.2s (extraction gone + lazy imports).

Import-time was flat from v1.1.0→v1.4.1, and the onefile format dates to ~v0.5, so this wasn't a code regression.

All tests pass (installer/update tests adjusted to the new layout); ruff/mypy/pyright/bandit at parity with main.

Link to Devin session: https://app.devin.ai/sessions/bbaf548ef3ab442c833c4fca488c1ecc
Requested by: @0xallam

@0xallam 0xallam self-assigned this Jul 27, 2026
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR accelerates CLI startup and replaces standalone onefile releases with onedir bundles.

  • Defers scan-engine, reporting, Docker, model, CLI, and TUI imports until their paths execute.
  • Moves the lightweight maximum-turn constant into a standalone module and avoids eagerly importing LiteLLM for logging setup.
  • Changes PyInstaller and release packaging to produce onedir archives.
  • Updates installation and self-update flows to deploy or replace the executable together with _internal.

Confidence Score: 3/5

The PR should not merge until failed installs and self-updates reliably preserve the previous executable and _internal bundle.

Both replacement paths can leave the installed CLI unusable: self-update rollback can retain a new runtime beside the old executable, while the shell installer deletes the working bundle before a fallible recursive copy.

Files Needing Attention: strix/interface/update_check.py, scripts/install.sh

Important Files Changed

Filename Overview
strix/interface/update_check.py Adds onedir self-update support, but failure after activating the new runtime directory can leave a mismatched executable/runtime installation.
scripts/install.sh Adds onedir installation support through a destructive non-atomic upgrade that can erase a working installation on copy failure.
strix/interface/main.py Defers heavy imports to their actual scan, resume, reporting, and Docker paths while preserving the existing control flow.
strix/interface/init.py Lazily exposes the package-level main callable without affecting the direct module entrypoint.
strix.spec Converts the PyInstaller build from onefile to onedir using EXE plus COLLECT.
.github/workflows/build-release.yml Packages and validates the new platform-specific onedir release archives.
strix/telemetry/logging.py Avoids importing LiteLLM solely for log suppression and reapplies suppression after scan dependencies load.

Comments Outside Diff (1)

  1. strix/interface/update_check.py, line 1978-1979 (link)

    P1 Rollback Leaves Mismatched Bundle

    When executable replacement fails after the new _internal directory is activated, this condition skips restoring the old directory because internal still exists, leaving the previous executable paired with incompatible runtime files and causing subsequent strix startup or import failures.

    Knowledge Base Used: Update Notifications and Self-Update

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: strix/interface/update_check.py
    Line: 1978-1979
    
    Comment:
    **Rollback Leaves Mismatched Bundle**
    
    When executable replacement fails after the new `_internal` directory is activated, this condition skips restoring the old directory because `internal` still exists, leaving the previous executable paired with incompatible runtime files and causing subsequent `strix` startup or import failures.
    
    **Knowledge Base Used:** [Update Notifications and Self-Update](https://app.greptile.com/strix-org-3/-/custom-context/knowledge-base/usestrix/strix/-/docs/update-check-and-self-update.md)
    
    ---
    
    For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.
Prompt To Fix All With AI
### Issue 1
strix/interface/update_check.py:1978-1979
**Rollback Leaves Mismatched Bundle**

When executable replacement fails after the new `_internal` directory is activated, this condition skips restoring the old directory because `internal` still exists, leaving the previous executable paired with incompatible runtime files and causing subsequent `strix` startup or import failures.

### Issue 2
scripts/install.sh:176-178
**Upgrade Deletes Working Bundle**

When an upgrade copy is interrupted or fails because of insufficient disk space, permissions, or an I/O error, this branch has already deleted the working executable and `_internal` directory; `set -e` then exits with a partial installation, causing `strix` to stop launching.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "perf(cli): fast startup — lazy heavy imp..." | Re-trigger Greptile

Comment thread scripts/install.sh Outdated
Comment on lines +176 to +178
# Onedir app bundle (strix + _internal/).
rm -rf "$INSTALL_DIR/_internal" "$INSTALL_DIR/strix"
cp -R "$extracted/." "$INSTALL_DIR/"

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.

P1 Upgrade Deletes Working Bundle

When an upgrade copy is interrupted or fails because of insufficient disk space, permissions, or an I/O error, this branch has already deleted the working executable and _internal directory; set -e then exits with a partial installation, causing strix to stop launching.

Knowledge Base Used: Update Notifications and Self-Update

Prompt To Fix With AI
This is a comment left during a code review.
Path: scripts/install.sh
Line: 176-178

Comment:
**Upgrade Deletes Working Bundle**

When an upgrade copy is interrupted or fails because of insufficient disk space, permissions, or an I/O error, this branch has already deleted the working executable and `_internal` directory; `set -e` then exits with a partial installation, causing `strix` to stop launching.

**Knowledge Base Used:** [Update Notifications and Self-Update](https://app.greptile.com/strix-org-3/-/custom-context/knowledge-base/usestrix/strix/-/docs/update-check-and-self-update.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

✅ Full runtime test — CLI startup perf (onedir + lazy imports + install-script self-update)

Tested end-to-end on Linux x86_64. All 6 areas pass; no breakage.

Startup timing (3 runs, STRIX_NO_UPDATE_CHECK=1):

Command onedir (this PR) released onefile v1.4.1
--help 1.26 / 1.20 / 1.22s 4.55 / 4.58 / 4.40s
--version 1.24 / 1.21 / 1.24s 4.25 / 3.70 / 3.71s
view --help ~1.4s
auth --help ~1.42s

~3x faster — per-run self-extraction eliminated.

Scan TUI fully boots (deferred imports OK)

litellm loads lazily, agent spawns a Reconnaissance Agent, LLM connects, and the strix-sandbox:1.1.0 docker container runs — no ImportError from deferred run_tui/run_cli/litellm.

Scan TUI booted

Build / install / self-update / regression
  • Build: dist/strix/ = strix + _internal/; tarball top-level is the bundle dir. ✅
  • install.sh: fresh install → ~/.strix/bin/strix --version works + PATH export; upgrade over a legacy single-file strix → replaced with working bundle. ✅
  • Self-update: _run_installer pipes install.sh to bash -s with VERSION=... → exit 0, working bundle. ✅
  • Regression: uv run pytest586 passed. ✅
Test recording

e2e test recording

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