Skip to content

perf(cli): fast-path project start in production - #96

Merged
Upd4ting merged 5 commits into
mainfrom
perf/production-launcher
Aug 20, 2026
Merged

perf(cli): fast-path project start in production#96
Upd4ting merged 5 commits into
mainfrom
perf/production-launcher

Conversation

@Upd4ting

@Upd4ting Upd4ting commented Aug 18, 2026

Copy link
Copy Markdown
Member

🔗 Linked issue

None.

❓ Type of change

  • 📖 Documentation
  • 🐞 Bug fix
  • 👌 Enhancement
  • ✨ New feature
  • ⚠️ Breaking change

📚 Description

Make the existing public command ajs project start [options] the lightweight
production launcher. There is still exactly one package binary, ajs:

  • ajs project run / ajs project dev keep using the complete developer CLI;
  • ajs project build keeps producing .antelope/build/build.json;
  • ajs project start now dispatches directly to launchFromBuild.

The ajs entry point is a small argument dispatcher. Only the canonical
project start invocation loads the native node:util.parseArgs start path;
every other command dynamically loads the unchanged Commander CLI, command
trees, scaffolding and npm update check. Shared project launch/shutdown behavior
was moved to a runtime module, while version checking, downloader
implementations, watch and REPL code are loaded only by development paths.

project start preserves -p/--project, -e/--env, -c/--concurrency,
--verbose, -h/--help, and the existing project/environment/verbose
environment-variable fallbacks. No ajs-start binary or command is added.

The branch remains based on
795dd1363d91549189bc2cc9f1e62d71155c8ab6 and retains #97, #98, #100,
#101 and #95.

Corrected cold-start benchmark

The previous benchmark's baseline was already ajs project start (not a dev
command), but its candidate incorrectly used a separate ajs-start binary.
This revision replaces that comparison. Both sides now execute the exact same
public command:

ajs project start -e production

Method: same orb and representative two-local-module playground; production
artifact built in each worktree; Node.js 22.14.0 and pnpm 10.6.5; 15 fresh
processes per variant in strict baseline→candidate pairs (30 processes total).
A monotonic clock measured spawn to the first application lifecycle response
([module-b] Started). GNU time %M measured maximum RSS. Quartiles use the
median-of-halves method. There were 0 errors.

Variant Spawn → first response Maximum RSS
main 795dd136 median 1,051.5 ms; IQR 56.8 ms (Q1 1,012.3, Q3 1,069.1); min–max 975.6–1,260.7 median 125.8 MiB; IQR 0.7 MiB; min–max 124.8–126.8 MiB
PR 4edb705 median 150.8 ms; IQR 49.5 ms (Q1 137.3, Q3 186.7); min–max 133.0–218.0 median 67.0 MiB; IQR 1.5 MiB; min–max 63.7–67.7 MiB
Change in median −85.7% / 6.97× faster −46.7% / −58.8 MiB

Exact measurement setup:

# In each worktree
pnpm install --frozen-lockfile
pnpm run build
pnpm --dir playground install
ajs project build --project playground -e production

# From each playground directory, alternated 15 times each
/usr/bin/time -q -f %M -o "$rss_file" \
  ajs project start -e production

The harness selected each worktree's built ajs entry through an isolated
PATH, timestamped immediately before spawn, and stopped the response timer at
the application marker while still waiting for clean process exit.

Packaged-consumer and hot-path verification

A final pnpm pack tarball was installed in a clean pnpm consumer. Verification
confirmed:

  • manifest declares only {"ajs":"dist/core/cli/index.js"};
  • tarball CLI payload and installed .bin/ajs shim are executable;
  • installed ajs project build -e production creates the real artifact;
  • installed ajs project start -e production reaches [module-b] Started.

The real packaged start ran under a preload guard that throws if the process
loads Commander, the full CLI or command trees, child_process, either version
checker, downloader implementations, watch code, or REPL code. Startup passed,
proving that this hot path creates no package-manager subprocess and does not
load development/download command paths.

Validation

  • pnpm install --frozen-lockfile: passed
  • pnpm run build: passed
  • pnpm run test: passed
    • unit suite: 670 passing
    • packed package-consumer/provider routing: passed
    • playground launch/build/launchFromBuild: passed
  • pnpm run test:coverage: passed all 90% gates
    • statements 94.63%, branches 92.33%, functions 92.11%, lines 94.63%
  • pnpm run lint: passed; only two pre-existing warnings and one pre-existing info remain
  • final isolated tarball build/start with module-load guard: passed

Limits

  • The fixture has two local modules. Absolute gains vary with application and
    module count.
  • “Cold start” means a fresh Node process; filesystem and OS caches were not
    dropped. Fixed baseline-first pair ordering may retain a small order effect.
  • The readiness marker is synchronous stdout from a representative module's
    start() hook, not an HTTP request measurement.
  • GNU time reports the launcher's process maximum RSS, not summed process-tree
    memory; this may understate the baseline npm subprocess cost.
  • Production start still checks whether the build is stale and uses the normal
    AntelopeJS runtime/logging stack. This PR does not refactor those contracts.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.
  • I have run ajs module exports generate and committed any updated interface files. (Not applicable: no interface changes.)

@Upd4ting
Upd4ting force-pushed the perf/production-launcher branch from 5d24a75 to 718d192 Compare August 20, 2026 09:25
ampagent and others added 3 commits August 20, 2026 10:02
Co-authored-by: Upd4ting <upd4ting@gmail.com>
Co-authored-by: Upd4ting <upd4ting@gmail.com>
Co-authored-by: Upd4ting <upd4ting@gmail.com>
@Upd4ting Upd4ting changed the title perf(cli): add dedicated production launcher perf(cli): fast-path project start in production Aug 20, 2026
@Upd4ting
Upd4ting merged commit 04c70aa into main Aug 20, 2026
2 checks passed
@Upd4ting
Upd4ting deleted the perf/production-launcher branch August 20, 2026 14:17
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