1. Orchestrator
core/orchestrator.py converts the resolved configuration into a ScienceAgent or LNR solver, constructs model clients and callbacks, attaches time tracing, and returns the run result. The orchestrator is the assembly layer; task-specific scoring belongs to task packages and the Gate service.
2. Task-package registry
core/task_package.py recursively discovers tasks/**/task.yaml, merges optional provider-family defaults from _shared/task_defaults.yaml, and builds a domain-neutral TaskPackageSpec.
| Responsibility | Behavior |
|---|---|
| Discovery | Find exactly one package for a task id and reject ambiguous registrations. |
| Contract resolution | Expose description, artifact path/kind, metric name/type/direction, evaluator entry point, and timeout. |
| Runtime isolation | Copy the package or provider family to task_runtime/, record entry-point and tree hashes, and run the evaluator outside the writable worker source tree. |
| Domain boundary | The registry contains no MLE-bench, optimization, or scientific-modeling scoring logic. |
3. ParallelRunner
core/parallel_runner.py parses the manifest, resolves task text and workspace paths, launches child processes, applies task-level CPU/GPU boundaries, assigns model endpoints, records task state, and terminates process groups during cancellation.
| Layer | Current behavior |
|---|---|
| Concurrency | max_concurrent or -j bounds the number of simultaneously active tasks. |
| CPU | cpu_list establishes the task boundary and exports SCIENCEFLOW_TASK_CPU_LIST; LNR may subdivide it among workers. |
| GPU | gpu_list constrains task visibility. The LNR resource runtime manages task-local leases within that boundary. |
| Configuration | General config patches are serialized through SCIENCEFLOW_PARALLEL_MANIFEST_CFG_JSON; agent and LNR blocks have dedicated override paths. |
| Final state | task_logs/state.json records success, failure, timeout, or stopped_by_user, plus elapsed and resume-budget accounting. |
4. Model clients and tracing
core/llm_http.py, core/key_pool.py, and core/llm_usage.py provide controlled asynchronous clients, retry/cooldown behavior, round-robin or sticky routing across configured keys and base URLs, and token/cost accounting. utils/time_trace.py writes scienceflow_time_trace.csv through the orchestrator callback.
5. Process lifecycle
Subprocess helpers register live process groups. CLI signal handlers send SIGTERM, wait for cleanup, then send SIGKILL to surviving groups. Bash execution, the full-run policy, and ParallelRunner share this process-tree discipline so interrupted research does not leave orphan training jobs.
stopped_by_user, not failed. Resume logic can reuse its workspace and charged elapsed time.6. Core memory utilities
core/mem/memory_context.py manages prompt and memory fragments, while core/mem/source_snapshot.py builds source views and code maps. Agent-specific compression and replay live under core/agent/memory/; LNR stage-memory folding remains in solver/lnr/stage_memory.py.