TL;DR
Running a batch of jobs across a few machines can be a pain. You have to manage several SSH sessions, keep track of the logs, and synchronize the results.
nextask is built to handle it for you.
It is a lightweight distributed task queue written in Go.
nextask lets you locally run commands as you would on your machine, while under the hood delegating each run to the next available worker.
It can also snapshot your code, upload run artifacts, and store the logs, for maximum reproducibility.
Background
During the first year of my PhD, I collaborated on a research project that required us to run many experiments within a short rebuttal period. We used whatever compute we had, including local machines and a shared SLURM cluster. During that period, we managed to obtain the results we desperately needed, but only after many messy runs.
That review process ended in rejection. We later submitted the paper again and waited almost a year for a decision. Apparently, it had been lost midway through the process. After about eight months, the paper was assigned to a new area chair, and the entire review process started over.
Once the reviews finally arrived, the reviewers asked for more experiments, as expected. I dug into the nearly 18-month-old codebase and tried to recover the code and results from the original runs. The whole setup was a mess. We had to rerun the experiments and could not fully reproduce the results we had reported in the paper. Fortunately, after I spent far more time than I should have, we produced the additional results and the paper was accepted.
nextask was born out of this experience.
It provides reproducible, automated runtime management by keeping logs, results, and the code used to generate them in a single persistent location. The following sections explain how it works and describe some common use cases.
How it works
nextask has three main components. The CLI runs on the local machine, the queue ideally runs on a persistent, network-accessible host, and the workers execute tasks.
The diagram below shows how these components fit together.
A task through its lifecycle: (1) the CLI enqueues it into the
Postgres-backed queue, (2) --with git pushes the working tree to the
remote Git repository, (3) a matching worker claims it atomically, and
(4) logs stream live to the attached client. Green dots indicate worker
heartbeats, and the status chip moves from pending to running to completed.
The CLI lets us enqueue, list, monitor, and inspect logs for tasks. Before looking at individual commands, let’s walk through an example of how it works once everything is set up.
Let’s begin with a project. To send its code to the worker with --with git, it must be a Git repository with at least one commit and a configured remote.
Suppose we want to delegate a task to an available worker running on a powerful GPU server, a remote workstation, or a production server to which we have secure access.
To run the task on a worker, enqueue it from the project directory:
nextask enqueue "python script.py" --with gitThis adds the task to the queue. When a matching worker becomes available, it runs the task and streams the logs back to the database.
To follow the task as if it were running locally, add the --attach flag:
nextask enqueue "python script.py" --with git --attachThis streams the logs to your terminal in real time while also storing them in the database.
Commands
Here, we cover some of the basic commands in nextask.
Each command touches only the part of the system it needs.
nextask list reads the current tasks directly from the queue and shows each task’s status and the worker that claimed it.
nextask log <id> prints a task’s buffered output and exits. Add --attach to stream new output until the task finishes.
Tags route tasks to matching workers. For example, enqueuing with --tag image=pytorch sends a task only to a worker with a matching filter.
--with git captures the working tree, including uncommitted changes, and pushes it to a remote Git repository so the worker can clone the exact code for the run.
Each snapshot is tagged with the task ID and pushed as a separate branch to the remote repository configured in nextask.
No snapshot branch is created in the local repository.
Without --with git, tasks do not require a Git repository, but local project files are not transferred to the worker.
The worker needs the dependencies required by the task; the snapshot only preserves project files.
Workers
You can view registered workers from the CLI or register one on the current machine with:
nextask worker--taglets the worker accept only tasks with matching tag values.--exit-if-idle <time>stops the worker after being idle for<time>.--oncestops the worker after the first task.
To start a worker that accepts only tasks matching image=pytorch gpu=a100 and exits after one hour of idleness, run:
nextask worker --tag image=pytorch,gpu=a100 --exit-if-idle 1hUse the following commands to manage registered workers:
nextask worker list # list workersnextask worker stop <workerId> # stop workerTasks
The remaining commands cover task management and monitoring.
nextask list --status running --tag sweep=exp3 # list & filter tasksnextask log <taskId> --attach # stream live outputnextask show <taskId> # task detailsnextask cancel <taskId> # cancel taskAgent-ready
nextask is agent-ready by design. Its skills guide agents through setting up services such as Postgres, deploying workers, and managing tasks.
They prompt you for preferences with multiple-choice questions.
To install the skills, run this command in your agent directory:
npx skills add https://github.com/TolgaOk/nextask/skillsUse cases
In agentic workflows, especially those involving sub-agents, several tasks often run in parallel.
This can lead to resource contention and even freeze the system.
nextask handles this by queuing tasks and dispatching them as matching workers become available, even when the local machine is the only worker.
Agents can monitor tasks, be awakened when a task finishes, and easily access the results.
A common use case for nextask is running a batch of tasks, such as a hyperparameter sweep, and waiting for them to finish.
Agents can wait for all tasks to finish or just the first one.
The following example runs a hyperparameter sweep:
for lr in 0.1 0.01 0.001; do nextask enqueue "python train.py --lr $lr" --with git --tag exp=sweep,lr=$lrdone
nextask wait --tag exp=sweep # block until all `exp=sweep` tasks are finishedThe final command wakes the agent only after all tasks have finished. When an agent enqueues long-running tasks, you and other agents can independently monitor their progress, stream their logs, check their status, and track their results without interrupting the submitting agent.
Install
To install nextask, run:
curl -fsSL https://raw.githubusercontent.com/TolgaOk/nextask/main/install | bashBefore submitting tasks, configure the PostgreSQL connection, run nextask init db, and start a worker.
See the configuration guide for setup instructions.