Skip to content

Supporting APIs

Remote directories, configuration, SSH discovery, lifecycle callbacks, and the exception hierarchy.

Workspace dataclass

Workspace(cluster, name, path)

Bases: _RemoteDir

A base directory on the cluster's filesystem.

Project dataclass

Project(workspace, name)

Bases: _RemoteDir

A sub-namespace under a :class:Workspace.

submit_job

submit_job(submitor, **submit_kwargs)

Submit a job whose working directory is this project's path.

Forwards to :meth:~molq.submitor.Submitor.submit_job, overriding execution.cwd to self.path. Other execution fields the caller passes pass through unchanged.

MolqProfile dataclass

MolqProfile(name, scheduler, cluster_name, defaults=SubmitorDefaults(), scheduler_options=None, retry=None, retention=RetentionPolicy(), jobs_dir=None, host=None)

Named profile loaded from the molq config file (molcfg path).

MolqConfig dataclass

MolqConfig(profiles, plugins=dict())

Loaded molq configuration.

load_config

load_config(path=None)

load_profile

load_profile(name, path=None)

SshHost dataclass

SshHost(alias, hostname=None, user=None, port=None, identity_file=None, proxy_jump=None, forward_agent=False, extra=dict())

A named entry from ~/.ssh/config resolved for molq.

alias is what the user typed under Host; hostname is the effective remote hostname (Hostname directive or alias if absent). All effective fields come from ssh -G so we honor includes, globs, and Match blocks without re-parsing.

target property

target

user@hostname[:port] shorthand for display.

list_ssh_hosts

list_ssh_hosts(config_path=None)

Return concrete Host aliases discovered in ~/.ssh/config.

Wildcard patterns (Host *) and Match blocks are skipped — they are templates, not nameable destinations. Each surviving alias is resolved through :func:resolve_ssh_host so the returned objects carry the effective hostname/user/port/identityfile, including anything pulled in via Include directives.

Parameters:

Name Type Description Default
config_path str | Path | None

Override the default ~/.ssh/config location.

None

Returns:

Type Description
list[SshHost]

Hosts in declaration order (deduplicated). Empty list when the

list[SshHost]

config file does not exist.

ssh_alias_names

ssh_alias_names(config_path=None)

Return the concrete Host alias names declared in ~/.ssh/config.

Parse-only: unlike :func:list_ssh_hosts this does not shell out to ssh -G per alias, so it is cheap enough to call on every CLI invocation. Use it to answer "is this name a destination the user actually configured?" — ssh -G cannot answer that, because it happily prints a config block for any string you hand it.

Wildcard patterns (Host *) and Match blocks are skipped; they are templates, not nameable destinations. Include directives are followed.

Parameters:

Name Type Description Default
config_path str | Path | None

Override the default ~/.ssh/config location.

None

Returns:

Type Description
list[str]

Alias names in declaration order (deduplicated). Empty list when the

list[str]

config file does not exist.

resolve_ssh_host

resolve_ssh_host(alias, *, config_path=None, ssh_bin='ssh')

Return the effective ssh config for alias.

Shells out to ssh -G <alias> — the canonical way to ask OpenSSH "what would happen if I ran ssh <alias>" without actually connecting. Output is key value pairs, one per line.

Parameters:

Name Type Description Default
alias str

Host alias to resolve.

required
config_path str | Path | None

Optional explicit config file (ssh -F <path>). Default reads ~/.ssh/config plus system config like ssh itself does.

None
ssh_bin str

Override the ssh binary (mostly for tests).

'ssh'

Raises:

Type Description
OSError

When the ssh binary is not on PATH.

SshTransportOptions dataclass

SshTransportOptions(host, port=None, identity_file=None, ssh_opts=(), rsync_opts=('-a', '--partial', '--inplace'), control_master=True, control_persist='60s', connect_timeout=15, control_path=None)

Options for :class:molq.transport.SshTransport.

host is the only required field — everything else falls back to the user's ~/.ssh/config. rsync_opts defaults preserve partial transfers across flaky links and avoid extra renames on busy schedulers.

Connection multiplexing (control_master) is on by default: molq performs many small remote operations per job, and without a shared master connection each one pays a full TCP + authentication handshake. Set control_master=False for hosts that refuse multiplexed sessions.

molq does not fight your SSH config over where that socket lives. When ~/.ssh/config already sets a ControlPath for the host, molq inherits it, so molq and your own ssh share one master connection. Only when no ControlPath is configured does molq supply its own (~/.ssh/molq-%C). control_path overrides both.

EventType

Bases: StrEnum

Job lifecycle event types.

EventPayload dataclass

EventPayload(event, job_id=None, transition=None, record=None, data=None)

Lifecycle event payload.

EventBus

EventBus()

Pub/sub bus for job lifecycle events.

Handlers are called synchronously in registration order. Exceptions in handlers are logged but do not propagate.

on

on(event, handler)

Register a callback for an event type.

Parameters:

Name Type Description Default
event EventType

Event type to listen for.

required
handler Callable

Callable that receives the event data.

required

off

off(event, handler)

Remove a previously registered callback.

Parameters:

Name Type Description Default
event EventType

Event type.

required
handler Callable

The handler to remove.

required

emit

emit(event, data=None)

Dispatch an event to all registered handlers.

Parameters:

Name Type Description Default
event EventType

Event type to emit.

required
data Any

Event payload (StatusChange, JobRecord, or None).

None

MolqPlugin

Bases: Protocol

Lifecycle observer attached to a Submitor session.

name property

name

Stable plugin id (config key / entry-point name).

attach

attach(ctx)

Subscribe to events; must be fail-open and non-blocking.

detach

detach()

Unsubscribe and release resources. Safe to call multiple times.

PluginContext dataclass

PluginContext(event_bus, cluster_name, config, get_record, list_active_records, list_records)

Read-only surface a plugin may use after attach.

Intentionally narrow: no scheduler/store write path.

PluginManager

PluginManager()

Owns attached plugin instances for one Submitor.

load

load(names, *, ctx_factory, configs=None)

Attach plugins by name. Returns names successfully attached.

Failures are logged and skipped (fail-open for observability plugins).

available_plugins

available_plugins()

Return {name: source} for builtin + discovered third-party plugins.

BUILTIN_PLUGIN_FACTORIES maps each official plugin name to the factory that builds it. Official names win over third-party entry points of the same name.

create_plugin

create_plugin(name)

Instantiate a plugin by name (builtin first, then entry points).

enabled_plugin_names

enabled_plugin_names(plugins, *, default_official=None)

Names to load: explicit enabled plugins, or default_official when empty.

A plugin with enabled = false is never loaded. When the config has no [plugins] entries at all, default_official (e.g. ["nerve"] for daemon) is used.

dependency_relation_state

dependency_relation_state(dependency_type, related_state, related_started_at)

Evaluate whether a single dependency edge is satisfied, pending, or impossible.

Parameters:

Name Type Description Default
dependency_type str

One of the canonical DependencyCondition values ("after_success", "after_failure", "after_started", "after").

required
related_state JobState

Current JobState of the upstream job.

required
related_started_at float | None

Unix timestamp of when the upstream job started executing, or None if it has not started yet.

required

Returns:

Type Description
str

"satisfied" — the condition is already met.

str

"pending" — the upstream job has not reached the required state.

str

"impossible" — the upstream job reached a terminal state that can never satisfy the condition (e.g. after_success on a failed job).

Raises:

Type Description
ValueError

If dependency_type is not a recognised condition name.

errors

Unified exception hierarchy for molq.

MolqError

MolqError(message, **context)

Bases: Exception

Base exception for all molq errors.

ConfigError

ConfigError(message, **context)

Bases: MolqError

Submitor initialization parameter error.

SubmitError

SubmitError(message, **context)

Bases: MolqError

Job submission failed.

CommandError

CommandError(message, **context)

Bases: SubmitError

Command validation failed (argv/command/script exclusion, newline in command).

ScriptError

ScriptError(message, **context)

Bases: SubmitError

Script materialization failed (file not found, copy failure).

SchedulerError

SchedulerError(message, *, stderr=None, command=None, **context)

Bases: MolqError

Scheduler communication failed.

JobNotFoundError

JobNotFoundError(job_id, cluster_name=None)

Bases: MolqError

Requested job_id does not exist.

MolqTimeoutError

MolqTimeoutError(message, **context)

Bases: TimeoutError, MolqError

Watch/wait timeout exceeded.

Inherits from both builtins.TimeoutError and MolqError so that except TimeoutError and except MolqError both catch it.

StoreError

StoreError(message, **context)

Bases: MolqError

Database operation failed.

Dashboard

The full-screen monitor behind molq monitor. These names are exported lazily — importing molq does not pull in the terminal UI.

MolqMonitor

MolqMonitor(db_path=None, *, include_terminal=False, limit=200, refresh_interval=2.0)

Full-screen dashboard for all molq jobs across all clusters.

Reads from :class:~molq.store.JobStore on every refresh tick.

Parameters:

Name Type Description Default
db_path str | None

SQLite database path. None resolves to the molcrafts-standard location via :func:molq.store.default_jobs_db_path.

None
include_terminal bool

Show completed/failed jobs too. Default False.

False
limit int

Maximum job rows displayed. Default 200.

200
refresh_interval float

Seconds between data refreshes.

2.0

watch

watch()

Open the full-screen dashboard and block until q is pressed.

RunDashboard

RunDashboard(console=None)

Full-screen terminal dashboard.

Layout::

┌─────────────────────────────────────────┐  header   (3 lines)
│  ⟳ title  [RUNNING]   updated 14:32:07  │
├─────────────────────────────────────────┤  overview (4 lines)
│  Overview                               │
│  12 total  2 running  …   ████████░░░   │
├─────────────────────────────────────────┤  jobs / detail (remaining)
│  Jobs                                   │
│  ▶ RUNNING  abc123  hpc  88001  1m 23s  │  ← selected
│    PENDING  def456  hpc  —      —       │
├─────────────────────────────────────────┤  footer (1 line)
│  [q] quit  [↑↓] navigate  [↵] detail   │
└─────────────────────────────────────────┘

watch

watch(data_fn, *, refresh_interval=2.0)

Open the full-screen dashboard and block until q is pressed.

Closing the monitor does not cancel any running jobs.

Parameters:

Name Type Description Default
data_fn Callable[[], DashboardState]

Returns a fresh :class:DashboardState on each tick.

required
refresh_interval float

Seconds between data refreshes.

2.0

DashboardState dataclass

DashboardState(title, overall_status, total, running, pending, done, failed, updated_at, jobs=())

Immutable snapshot passed to :class:RunDashboard on every tick.

JobRow dataclass

JobRow(state, run_id, cluster=None, scheduler_id=None, elapsed=None, message=None, dependency_summary=None, upstream=(), downstream=(), extras=())

A single job/run entry in the dashboard.

Attributes:

Name Type Description
state str

Status string, e.g. "running", "pending", "succeeded".

run_id str

Job or run identifier shown in the list and detail title.

cluster str | None

Cluster name; None for local runs.

scheduler_id str | None

Scheduler-assigned job ID; None if unknown.

elapsed str | None

Human-readable elapsed time, e.g. "1m 23s".

message str | None

Short note or error summary; None if none.

extras tuple[tuple[str, str], ...]

Additional key-value pairs shown only in the detail view (e.g. command, cwd, exit code). Use an empty tuple if not needed.