Edit on GitHub

starplast.discover

The discovery search from a terminal, with no window anywhere in it.

The Discover tab is the wrong place to start a search that takes an hour. A window has to stay open, the machine has to stay awake, and the run dies with the session -- which is exactly what happened the first time this was run at scale. A search is a batch job that happens to have a GUI, not a GUI feature, so it gets a command.

starplast-discover --task guilt:compartment_best --budget 100
starplast-discover --task disagreement:compartment_best:fit_invitro_hff --task knn:lopit_unified
starplast-discover --list
starplast-discover --read big_00_localisation

Nothing here imports Qt. That is the point and it is worth stating: a headless option that pulls in a GUI toolkit fails on the machine it exists for, which is a server with no display.

Why one process per task rather than a loop inside one

Each --task is saved the moment it finishes, and a task already saved under the same name is skipped. So a run that is interrupted -- killed, timed out, or force-quit by somebody who saw an unfamiliar process eating a GPU -- costs the task in flight and nothing else, and the same command run again continues where it stopped. That property matters more than tidiness here: the failure this is built around is a long job dying two thirds of the way through.

TASK_HELP = 'what to search for, as mode:layer or mode:layer:against -- e.g. guilt:compartment_best, conjunction:compartment_best:cellcycle_phase. Repeatable; each is saved separately as it finishes.'
def parse_task(text: str) -> dict:

mode:layer[:against] as a dict, or raise with what was wrong.

def load_nodes(path: str = None):

The node table, without importing the window.

app.load_graph is the usual way in and it imports Qt on the way past, which is exactly what a machine with no display cannot do. The parquet is read directly here, and the error names the command that builds it rather than letting pandas raise from inside a constructor.

def store_for(root: str = None):

Where searches are kept: the same place the window looks, unless told otherwise.

def run_task( nodes, task: dict, budget: int = 100, restarts: int = 3, seed: int = 42, blocks=None, exclude=(), name: str = '', store=None, log=<built-in function print>) -> object:

One search, saved under name. Returns the Search, or None if it was already done.

def main(argv=None) -> int:

starplast-discover. Returns a process exit code.