Containerized task-bundle CLI for LLM coding benchmarks (SWE-bench style).
Project description
Taskbundle
Author, validate, and run SWE-bench-style coding tasks in reproducible containers.
A task is a bundle: a directory with a repo at a commit, a problem statement, a golden patch, and hidden pass2pass / fail2pass tests. Taskbundle packages it into a Docker image and runs those hidden tests before and after a solver (an LLM agent, a script, anything that edits files), so you know exactly which tests it fixed and which it broke.
The loop: init (build the image) → validate (assert the baseline guardrail) → run (solve in isolation, then score) → query (inspect any past run).
Full documentation, design rationale, and examples live in the GitHub repo: https://github.com/yatharthk2/taskbundle
How it works
┌────────────────────────────────────────┐
│ BUNDLE │
│ repo · problem · patch · tests │
└────────────────────────────────────────┘
│ init
▼
┌────────────────────────────────────────┐
│ Docker image │
└────────────────────────────────────────┘
│ run
▼
┌────────────────────────────────────────┐
│ 1) SOLVE box │
│ sees repo + problem │
│ NEVER sees the hidden tests │
└────────────────────────────────────────┘
│ captured patch (git diff)
▼
┌────────────────────────────────────────┐ ┌──────────────┐
│ 2) SCORE box │ │ hidden tests │
│ apply patch, run tests │ ◀───── │ p2p / f2p │
│ hermetic, no network │ only └──────────────┘
└────────────────────────────────────────┘ here
│
▼
resolved?
Two isolated containers: SOLVE edits the repo but never sees the hidden tests; they're injected only into the separate, hermetic SCORE box that grades the captured patch, so a solver can't peek at or game them.
Install
Python ≥ 3.9. Built with Typer; everything else is stdlib.
pip install taskbundle
task --help
Docker (or Podman / colima / nerdctl) is needed to build & run images. task query and task init --no-build work without it.
Quickstart
The whole loop on a tiny, self-contained bundle (hello-task, no external repo, ~1 min):
task init cli/examples/hello-task # build the image + smoke-check
task validate cli/examples/hello-task --check-patch # baseline: p2p pass / f2p fail; golden flips f2p
task run cli/examples/hello-task # golden solver → RESOLVED (exit 0)
task run cli/examples/hello-task --solver noop # makes no edits → not resolved (exit 9)
task query # the ledger, every run newest first
task query 1 # full detail for command #1
(Clone the repo to get the example bundles.)
Commands
| Command | What it does | Exit |
|---|---|---|
init |
Resolve a Dockerfile + build the image (clone/copy the repo at the commit) + smoke-check | 0 ok · 3/4/5/6/11 setup |
validate |
Run the hidden buckets on the baseline → assert p2p pass, f2p fail | 0 holds · 7 violated · 8 no tests |
run |
Run a solver (it never sees the buckets), capture its diff, score it in a hermetic box | 0 resolved · 9 not · 8/12 setup |
query |
Read-only ledger inspection: by id, filtered list, or --stats scoreboard |
0 · 10 unknown id |
Any unexpected error is caught, logged to the ledger, and shown as one line with exit 70 (TASKBUNDLE_DEBUG=1 for the traceback). Step-by-step docs:
init ·
validate ·
run ·
query.
Bundle layout
my-task/
task.json # which code: repo, commit, id (+ optional install/build/test/smoke overrides)
description.md # the problem statement shown to the solver
patch.diff # golden solution (unified diff)
Dockerfile # OPTIONAL — owns the environment; auto-generated if absent
tests/
pass2pass/ # must pass before AND after the golden patch
fail2pass/ # must fail on baseline, pass after the golden patch
task.json says which code; the Dockerfile owns the environment (base image included). Its optional test_cmd sets how the buckets run — any framework that writes JUnit to $TASKBUNDLE_JUNIT (tests at $TASKBUNDLE_BUCKET), default pytest — so non-Python tasks run too.
Use an LLM as the solver
--solver is just a command that edits files, so an LLM agent is one too. The repo ships a stdlib-only OpenAI agent (openai_agent.py); the openai-demo bundle vendors it and COPYs it into the image, so you run it as an ordinary solver command:
export OPENAI_API_KEY=sk-... # in your shell, never an arg, never committed
task run cli/examples/openai-demo \
--solver 'python /opt/openai_agent.py' \
--solver-env OPENAI_API_KEY # forward the key BY NAME (-e NAME)
The key is forwarded by name: its value never hits the argv, a log, or the ledger. Isolation is unchanged — it runs in the same solve box and never sees the hidden buckets.
References
The task structure and evaluation methodology (hidden fail2pass / pass2pass tests, golden patches, containerized per-instance environments) take inspiration from:
- Jimenez et al., "SWE-bench: Can Language Models Resolve Real-World GitHub Issues?" ICLR 2024 — arXiv:2310.06770.
- Deng et al. (Scale AI), "SWE-Bench Pro: Can AI Agents Solve Long-Horizon Software Engineering Tasks?" — arXiv:2509.16941.
License
MIT © Yatharth Kapadia
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file taskbundle-0.1.0.tar.gz.
File metadata
- Download URL: taskbundle-0.1.0.tar.gz
- Upload date:
- Size: 44.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f987c4611b5ea34e97eafa830aa673550c057481fedb8bbddc3c7fe34412f19c
|
|
| MD5 |
8b86910634070ba261af7b0f9bdc506d
|
|
| BLAKE2b-256 |
2345ba289b19854a6da247829aed0382934e2b5d95484d85fa9f3c2bee7dfe8c
|
Provenance
The following attestation bundles were made for taskbundle-0.1.0.tar.gz:
Publisher:
publish.yml on yatharthk2/taskbundle
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
taskbundle-0.1.0.tar.gz -
Subject digest:
f987c4611b5ea34e97eafa830aa673550c057481fedb8bbddc3c7fe34412f19c - Sigstore transparency entry: 1876916185
- Sigstore integration time:
-
Permalink:
yatharthk2/taskbundle@e7b33cda04c2ccf10c132d28ee6f92e0de0308e5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/yatharthk2
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e7b33cda04c2ccf10c132d28ee6f92e0de0308e5 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file taskbundle-0.1.0-py3-none-any.whl.
File metadata
- Download URL: taskbundle-0.1.0-py3-none-any.whl
- Upload date:
- Size: 34.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5a864a60770dbf62638948d94aaadfd8e8dcf39b25f2c29f7699243a9d187bc
|
|
| MD5 |
2123c4272e2d9c8fb80588289aad2b01
|
|
| BLAKE2b-256 |
9f32686d159ac346b92cd4c1ef143779c712cb5f862e8b216b0c6e23f722341c
|
Provenance
The following attestation bundles were made for taskbundle-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on yatharthk2/taskbundle
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
taskbundle-0.1.0-py3-none-any.whl -
Subject digest:
d5a864a60770dbf62638948d94aaadfd8e8dcf39b25f2c29f7699243a9d187bc - Sigstore transparency entry: 1876916320
- Sigstore integration time:
-
Permalink:
yatharthk2/taskbundle@e7b33cda04c2ccf10c132d28ee6f92e0de0308e5 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/yatharthk2
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e7b33cda04c2ccf10c132d28ee6f92e0de0308e5 -
Trigger Event:
workflow_dispatch
-
Statement type: