Documentation Index
Fetch the complete documentation index at: https://mintlify.com/techjarves/Odysseus-Portable/llms.txt
Use this file to discover all available pages before exploring further.
src/start.js is the single entry point for the entire Odysseus Portable runtime. It is a 700-line async Node.js module that sequences every phase of startup — from reading configuration and detecting free ports, through bootstrapping Python and Git, to spawning the inference backend and Odysseus web server — and then remains alive as a supervisor that shuts everything down cleanly when the user presses Ctrl+C. Understanding this file is the fastest path to understanding how the whole system behaves.
Entry Points
The shell wrappersstart.bat (Windows) and start.sh (macOS/Linux) are thin bootstraps. They detect the current OS and architecture, download the correct Node.js 22 tarball to bin/node-<os>-<arch>/ if not already present, and then invoke node src/start.js from the project root. From that point on, everything is JavaScript.
- Windows (start.bat)
- macOS / Linux (start.sh)
Downloads a Node.js 22
.zip for win-x64 to bin/node-win-x64/, extracts it with tar.exe, and runs node.exe src/start.js.Port Management
Three ports are used: the Odysseus web application port, an HTTP proxy port for the inference backend, and the llama.cpp server port. Each has a configurable base value drawn from environment variables, then from the launcher config, and finally from the built-in default:findFreePort(startPort) increments from the base port until a TCP connect attempt to 127.0.0.1:<port> fails (meaning nothing is listening), at which point that port is considered free:
findFreePort runs, cleanupOwnedPortProcesses() kills any processes from a previous session that are still holding the preferred ports, using lsof (macOS/Linux) or Get-NetTCPConnection (Windows) to look up the owning PID, and then verifying that the process command line contains the project root before killing it.
Launcher Config Loading
data/launcher_config.json is a simple JSON file that persists user preferences between launches. It is loaded on startup and re-saved whenever a new preference is recorded (e.g., the backend selection):
saveLauncherConfig(config) merges the supplied object into the existing file contents, so callers only need to pass the keys they want to update.
Backend Selection Logic
The backend is resolved from four sources in priority order:getBackendChoice() returns the hard-coded string 'llama' — it never returns a falsy value. An interactive prompt block guarded by if (!backendChoice) exists immediately after the call site in main(), but it is unreachable in practice because the function always returns either 'llama' or 'ollama'. The selected backend is always saved to launcher_config.json via saveLauncherConfig({ backend: backendChoice }) regardless of which source resolved it.
Combined Logging
Every byte written toprocess.stdout or process.stderr — from the orchestrator itself, from subprocess output piped into the main process, and from the Node.js backend modules — is duplicated to a single log file at logs/combined_<timestamp>.log. This is implemented by replacing the built-in write methods:
restoreStdoutStderr(), which is called during shutdown so that the final “Shutdown complete” messages reach the terminal even after the log stream has been closed.
Runtime Tracker Integration
createRuntimeTracker(projectRoot) (from src/runtime.js) returns an object that reads and writes data/runtime.json. Every spawned subprocess is registered immediately after it is created:
cleanupPrevious() reads this file, checks whether each PID is still alive (process.kill(pid, 0)), verifies the command line contains the project root (safety guard against killing unrelated processes with a coincidentally matching PID), and then kills survivors before clearing the file.
Git Bootstrap
TheensureOdysseusSource() function in src/bootstrap/git.js handles the first-run clone and all subsequent updates. On Windows, it downloads MinGit from the Git for Windows GitHub release API if no portable Git binary is found in bin/git/. On macOS and Linux it falls back to the system git if available, since no official portable binary exists for those platforms.
Before running git pull --ff-only, it calls git restore -- <patchFiles> to discard any modifications made by the previous session’s patch functions, ensuring the pull applies cleanly against the upstream state:
downloadOdysseusArchive() fetches the repository as a .zip (Windows) or .tar.gz (Unix) from the GitHub archive endpoint and extracts it directly.
Python Environments
- Windows (Embedded Python)
- macOS / Linux (uv)
The orchestrator downloads
python-3.12.9-embed-amd64.zip from python.org to odysseus/bin/python/. After extraction it:- Edits
python312._pthto uncommentimport site, enabling installed packages to be found. - Downloads
get-pip.pyand runs it to bootstrap pip. - Creates a mock
venvmodule atLib/site-packages/venv/__init__.pyso HuggingFace libraries that probe forvenv.EnvBuilderdo not crash. - Copies
python.exetopython3.exefor Git Bash subshell compatibility.
setupTmux() also downloads a portable tmux binary from tmux/tmux-builds releases for background service management. Like uv, a platform-specific copy is kept in odysseus/bin/tmux-<os>-<arch> and activated by copying to odysseus/bin/tmux.
Shutdown Sequence
SIGINT and SIGTERM are both handled by the sameshutdown(exitCode) function, which is guarded by an isExiting flag so re-entrant calls are ignored:
Terminate backend processes
Iterates
backend.processes and calls runtimeTracker.terminate(pid) for each, which kills the process and removes its entry from runtime.json.Close proxy HTTP servers
Iterates
backend.servers (the in-process Node.js HTTP proxy servers) and calls .close() on each.Restore stdout / stderr
Calls
restoreStdoutStderr() so remaining console output goes directly to the terminal.Clear runtime.json
Calls
runtimeTracker.clear() to write an empty process list, preventing stale entries from affecting the next launch.Error Handling
Two top-level handlers catch errors that escape the asyncmain() call:
printLogTail(combinedLogPath, 40) to surface the last 40 lines of the combined log to the terminal before triggering shutdown, making the root cause visible without needing to open a separate log file.