Skip to content

cli

FeatCopilot command-line interface.

Provides a stable, agent-friendly CLI for invoking FeatCopilot from shells, notebooks, agentic workflows (e.g. Copilot/LLM tool-use), and CI pipelines without writing Python glue code.

Subcommands

info Print version and supported engines/methods. Always machine-readable when --json is passed. transform Run :class:featcopilot.AutoFeatureEngineer on a tabular input file (CSV / Parquet / JSON) and write engineered features to an output file. Emits a JSON status line on stdout when --json is passed so that agents can parse the result deterministically. explain Fit the engineer and print a JSON document describing each generated feature (name, explanation, code) for downstream LLM consumption.

Examples:

Agentic usage (machine-readable result on stdout, errors on stderr)::

featcopilot info --json
featcopilot transform \
    --input data.csv --target label --output features.csv \
    --engines tabular --max-features 50 --json
featcopilot explain --input data.csv --target label --json

Equivalent module invocation::

python -m featcopilot info --json

Parquet I/O is supported only when pyarrow or fastparquet is installed (FeatCopilot's base distribution does not pin either); info reports the runtime availability via parquet_available.

main(argv=None)

CLI entry point.

Returns the process exit code; suitable for both the console_scripts entry point (featcopilot) and python -m featcopilot. Argparse usage errors (missing subcommand, unknown flag) and the cooperative --help / --version actions all normally raise :class:SystemExit; we trap those here and return their exit code so that programmatic callers (and agent harnesses) get a consistent integer-returning API.

Source code in featcopilot/cli.py
def main(argv: list[str] | None = None) -> int:
    """CLI entry point.

    Returns the process exit code; suitable for both the ``console_scripts``
    entry point (``featcopilot``) and ``python -m featcopilot``. Argparse
    usage errors (missing subcommand, unknown flag) and the cooperative
    ``--help`` / ``--version`` actions all normally raise :class:`SystemExit`;
    we trap those here and return their exit code so that programmatic
    callers (and agent harnesses) get a consistent integer-returning API.
    """
    parser = _build_parser()

    try:
        args = parser.parse_args(argv)
    except SystemExit as exc:
        # argparse uses SystemExit(0) for ``--help`` / ``--version`` and
        # SystemExit(2) for usage errors (also writing to stderr). We let the
        # output through but convert the exit into a return value so
        # ``main(argv) -> int`` is honored even on parse-time failures.
        code = exc.code
        if code is None:
            return 0
        if isinstance(code, int):
            return code
        # Non-int code (e.g. error string): print to stderr, return 2.
        sys.stderr.write(f"{code}\n")
        return 2

    try:
        return args.func(args)
    except (FileNotFoundError, ValueError) as exc:
        # User-facing input/config errors: print a clean message to stderr
        # without a traceback so agents can parse the failure.
        sys.stderr.write(f"featcopilot: error: {exc}\n")
        return 2
    except KeyboardInterrupt:
        sys.stderr.write("featcopilot: interrupted\n")
        return 130
    except Exception as exc:  # pragma: no cover - defensive backstop
        # Single deterministic stderr line so agents can parse the failure.
        # We deliberately do NOT call ``logger.exception(...)`` here:
        # FeatCopilot loggers write to stderr, which would append a second
        # timestamped traceback after our structured line and break the
        # CLI's "stderr is exactly one error message" contract. Internal
        # failure introspection is the caller's job (e.g. set
        # ``PYTHONFAULTHANDLER=1`` or attach a debugger).
        sys.stderr.write(f"featcopilot: unexpected error: {type(exc).__name__}: {exc}\n")
        return 1