cli
tit.cli ¶
The tit console command.
Installed by pyproject.toml's [project.scripts], so pip install tit
(or pipx run tit) on any host with CPython >= 3.11 and the docker CLI
gets a working launcher — no SimNIBS, no Electron, no Node.
Today there is one subcommand, launch. It is a subcommand rather than a
second console script because the natural next ones (tit doctor,
tit version) belong under the same name, and adding them later must not
change how launch is spelled.
release_base_url ¶
release_base_url() -> str
Where release assets are fetched from; overridable so tests never touch the network.
desktop_data_dir ¶
desktop_data_dir() -> Path
Per-user data root that holds managed desktop installs (<data>/app/<version>).
Source code in tit/cli.py
no_desktop_reason ¶
no_desktop_reason() -> str
Why this host gets the browser: one printable line, the same one loader.sh prints.
WSL is a Windows host to this launcher — the Linux AppImage cannot run there and no Linux browser exists — so the desktop app is the Windows installer, never a download.
Source code in tit/cli.py
desktop_asset_name ¶
The release asset for this platform, or "" where no managed install exists.
Empty on WSL: the Linux build cannot run there (see :func:no_desktop_reason).
Source code in tit/cli.py
managed_executable ¶
Where the executable lands inside one managed <data>/app/<version> directory.
Source code in tit/cli.py
resolve_desktop_executable ¶
resolve_desktop_executable() -> str
TIT_ELECTRON_EXECUTABLE -> managed install -> "download" -> "".
loader.sh implements the same three steps in a function of the same name; the two
must agree, which --print-config's desktop_executable line lets a test assert
without any network.
Source code in tit/cli.py
install_desktop_executable ¶
install_desktop_executable() -> str
Download, verify and atomically install the desktop app; return its path.
Raises :class:LaunchError with one printable reason; the caller falls back to the
browser unless --desktop was explicit.
Source code in tit/cli.py
launch_arguments ¶
launch_arguments() -> ArgumentParser
The launch options, as a reusable parent parser.
Declared once and shared by the two front doors so they cannot drift: the tit
launch subcommand below and loader.py at the repository root (loader.sh
hand-writes the same set, and a parity test holds them together). add_help=False
because a parent parser must not install a second -h.
Source code in tit/cli.py
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 | |
launch_parser ¶
launch_parser(prog: str = 'tit launch') -> ArgumentParser
A standalone parser for the launch options, for front doors with no subcommand.
loader.py uses this so that its --help is the same one screen tit launch
--help prints, under its own name.
Source code in tit/cli.py
prompt_launch ¶
Collect launch settings before Docker is touched; explicit CLI runs stay scriptable.
Source code in tit/cli.py
dev_repo ¶
The checkout --dev selects, or None for a regular user run.
--dev with no value means "the checkout this launcher lives in"; TIT_DEV_REPO_DIR
(or TIT_DEV=1) is the environment spelling of the same flag. Only the source of
the server and renderer differs between the two modes; nothing else does.
Source code in tit/cli.py
dev_overrides ¶
(repo_dir, static_dir, server_reload) — the only three settings --dev changes.
They are the same three the root docker-compose.yml exposes as ${TIT_REPO_DIR:-},
${TIT_STATIC_DIR:-} and ${TIT_SERVER_RELOAD:-}. All three are empty for a user run.
Source code in tit/cli.py
prepare_launch ¶
Return an exit code on cancelled/unavailable input, otherwise prepare the options.
Source code in tit/cli.py
build_parser ¶
build_parser() -> ArgumentParser
The whole CLI surface, built separately so a test can assert it without running it.
Source code in tit/cli.py
launch_command ¶
Run one launch invocation, turning every failure into one actionable line.
invocation is how this front door is spelled (tit launch, python
loader.py); it appears in the follow-up hints and in error messages, so the line
printed is a line the user can actually retype.
The dev overrides come from --dev via :func:dev_overrides, so every front door
computes them the same way.
Source code in tit/cli.py
build_image ¶
container/blueprint/build.sh --tag <image> — the only way to get a v3 image today.
Source code in tit/cli.py
run_dev_web ¶
Hand over to desktop/scripts/dev.ts — the one dev-loop implementation.
Source code in tit/cli.py
ensure_dev_bundle ¶
ensure_dev_bundle(root: Path) -> None
Build the checkout's renderer when --dev needs it, instead of asking for it.
The container serves desktop/out/renderer from the mounted checkout, so a missing
or stale bundle is a broken window, not an instruction to print. loader.sh's
ensure_dev_bundle is the same three steps; TIT_DEV_NO_BUILD=1 skips them
(tests, CI, or a npm run dev session that owns the directory).
Source code in tit/cli.py
wants_desktop ¶
The desktop app is the default UI; the browser is the fallback and the opt-out.
--browser and --no-open mean the browser explicitly. --dev does not:
it changes only where the server and renderer code comes from, so developers see the
same window users do (docs/dev/DECISIONS.md, 2026-09-17). On WSL the default is the
browser — opened on the Windows side — because no desktop build can run there
(:func:no_desktop_reason); --desktop still asks and is refused with that reason.
loader.sh resolves ui the same way.
Source code in tit/cli.py
desktop_without_project ¶
True when the desktop app should open its own project page instead of one project.
The app has a project-entry page and starts its own container; a Dock launch carries no
TIT_LAUNCH_PROJECT_DIR at all. So --desktop without --project is not an error:
neither the prompt nor the project requirement applies. loader.sh's desktop_no_project
is the same predicate.
Source code in tit/cli.py
main ¶
Entry point; every :class:~tit.launch.LaunchError becomes one actionable line.