Command line interface
The freemocap package ships exactly one installed command and one runnable diagnostic
module. There is no general-purpose argument parser. The main entry point takes
no options at all, because the desktop (Electron) app is the intended
user interface and the command exists to start the backend server.
The freemocap command
pyproject.toml declares a single console script:
[project.scripts]
freemocap = "freemocap.__main__:run_main"
After installing the package (or running uv sync in a clone), the freemocap
command starts the FreeMoCap backend server. It accepts no arguments or
flags: run_main() calls main() with its default parameters, and none of
those parameters are exposed on the command line.
What starting it does, in order:
- Repairs
sys.stdout/sys.stderrif they areNone(a PyInstaller frozen subprocess quirk that breaks libraries writing to stderr). - Binds to the preferred port,
53117, killing whatever process currently occupies it. (The alternative, scanning upward through 50 candidate ports, exists infind_available_port()but is only reachable as a function parameter, not from the command line.) - Prints a port sentinel line to stdout:
FREEMOCAP_PORT=<port>. - Creates the FastAPI app and serves it with uvicorn on
localhost.
The port sentinel contract
The sentinel line exists so the Electron shell can discover which port the
Python server actually bound to. The Electron PythonServer.start() launches
the executable as a subprocess and reads its stdout until a line beginning with
FREEMOCAP_PORT= appears, timing out after 30 seconds; if no sentinel arrives,
starting the server fails with an error instead of falling back. Note that in
the current code the discovered port is stored on the Electron side but never
consumed: the renderer builds every HTTP and websocket URL from its own
host/port settings, which default to the same 53117. Because the backend
always forces that preferred port, the sentinel effectively acts as a readiness
signal today rather than as the source of the port.
The relevant constants live in freemocap/api/server_constants.py and are not
configurable:
| Constant | Value |
|---|---|
PROTOCOL | http |
HOSTNAME | localhost |
PREFERRED_PORT | 53117 |
MAX_PORT_ATTEMPTS | 50 |
PORT_SENTINEL | FREEMOCAP_PORT |
Shutdown behavior
The process registers handlers for SIGINT and SIGTERM; either signal sets a
global shutdown flag, asks uvicorn to exit, shuts down all registered worker
processes, and flushes telemetry. On Windows, multiprocessing.freeze_support()
is invoked before startup, as required for PyInstaller executables that spawn
child processes.
Running without installing
The FreeMoCap-UI README documents launching the server from a source checkout with:
python -m freemocap
This runs the same __main__.py module and behaves identically to the
installed command. When started this way (outside Electron), the
FREEMOCAP_BASE_FOLDER environment variable is typically unset and the data
folder falls back to ~/freemocap_data, see
configuration.
Diagnostic CLI: segment-length report
A second, genuinely interactive command-line tool lives in the kinematics module:
python -m freemocap.core.kinematics.segment_lengths [PATH]
It measures limb-segment lengths from a processed recording and assesses whether the result is human-shaped: segments in anthropometric proportion (relative to SkellyForge's canonical body model), rigid over time, and left/right symmetric.
PATH is a single optional positional argument accepting any of:
- a recording folder,
- an
output_datafolder, - a
*_body_3d_xyz.csvfile directly.
When resolving a folder, the tool prefers mediapipe_body_3d_xyz.csv and falls
back to the first matching *body_3d_xyz.csv. Both wide CSV layouts
({name}_x/_y/_z columns) and long layouts (frame, keypoint, x, y, z) are
supported. Omitting the path defaults to the bundled test recording at
~/freemocap_data/recordings/freemocap_test_data (adjusted if
FREEMOCAP_BASE_FOLDER is set).
Output is an ASCII statistics table (per-segment mean/median/std/CV/min/max and implied standing height, plus aggregate symmetry and coverage figures) followed by a verdict.
Exit codes:
| Code | Meaning |
|---|---|
0 | Human-shaped (pass) |
1 | Not human-shaped (fail; violations are listed) |
2 | No usable data found at the given path |
Legacy migration script (not a supported command)
freemocap/utilities/update_1_4_path_names.py reads an optional path from
sys.argv and renames pre-1.5 data files (for example
mediapipe2dData_numCams...npy to mediapipe_2dData_numCams...npy). It is a
migration utility for old recordings, not part of the supported interface, and
note that on this branch it imports from
freemocap.system.paths_and_filenames, a package that no longer exists in the
tree, so it does not run unmodified.
What does not exist
To set expectations for scripting:
- No
click,typer, orargparsehandling on the main entry point, no--help,--version,--port, or similar flags. - No subcommands (no
freemocap calibrate,freemocap export, and so on). - No headless record/process pipeline driven purely from the command line; recording and processing are driven through the REST/websocket API that the desktop UI consumes (see REST API and websocket API).