diff --git a/.hgignore b/.hgignore
index 6f4d65d08ac0636898dbb9e5525e60ab37dc1d7f_LmhnaWdub3Jl..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_LmhnaWdub3Jl 100644
--- a/.hgignore
+++ b/.hgignore
@@ -2,4 +2,3 @@
 ^tmp/
 ^cache/
 ^datasets/new.toml
-
diff --git a/bin/bin-env-util b/bin/bin-env-util
new file mode 100755
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_YmluL2Jpbi1lbnYtdXRpbA==
--- /dev/null
+++ b/bin/bin-env-util
@@ -0,0 +1,318 @@
+#!/bin/env python3
+#
+# Small tool to manipulaote
+import argparse
+import os
+import subprocess
+import sys
+import tempfile
+import toml
+
+ERR_CODE_NO_KEY = 1
+ERR_CODE_NO_BIN_ENV_SHELL = 2
+ERR_CODE_NO_BIN_ENV_DESC = 3
+ERR_CODE_EXISTS = 4
+ERR_CODE_NO_SETUP_SCRIPT = 6
+ERR_CODE_SETUP_SCRIPT_FAILED = 7
+
+BIN_ENV_FILE = 'bin-env.poulpe'
+SHELL_FILE = 'bin-env.shell'
+
+
+def _bin_env_file(env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(env_path, BIN_ENV_FILE)
+
+
+def create_empty(env_path, method="manual"):
+    """create a new environ (in a non-ready state)"""
+    os.makedirs(env_path, exist_ok=True)
+    base_data = {
+        'poulpe-environment': {
+            'format-version': 0,
+            'environment-type': 'binary',
+            'setup-method': method,
+        },
+        'ready': False,
+    }
+    file_path = _bin_env_file(env_path)
+    if os.path.exists(file_path):
+        err('This is already a bin-env, aborting')
+        return ERR_CODE_EXISTS
+    _write_data(file_path, base_data)
+    return 0
+
+
+def setup_one(env_path, script):
+    if not os.access(script, os.X_OK):
+        err(f'no executable setup scrip at: "{script}"')
+        return ERR_CODE_NO_SETUP_SCRIPT
+    create_empty(env_path, method="script")
+    script = os.path.abspath(script)
+    try:
+        subprocess.check_call(script, cwd=env_path)
+    except subprocess.CalledProcessError as exc:
+        err(f'script returned with status {exc.returncode}: {script}')
+        return ERR_CODE_SETUP_SCRIPT_FAILED
+
+    env_file = _bin_env_file(env_path)
+    data = _get_data(env_file)
+    vars_file = os.path.join(env_path, "POULPE-VARS")
+    if os.path.exists(vars_file):
+        with open(vars_file) as f:
+            for line in f:
+                k, v = line.split('=', 1)
+                k = k.strip()
+                v = v.strip()
+                k = f'bin-env-vars.{k}'
+                _set_one_value(data, k, v)
+    _write_data(env_file, data)
+    return mark_ready(env_path)
+
+
+def mark_ready(env_path):
+    shell_path = os.path.join(env_path, SHELL_FILE)
+    if not os.access(shell_path, os.X_OK):
+        err(f'cannot find an executable file at: "{shell_path}"')
+        return ERR_CODE_NO_BIN_ENV_SHELL
+
+    path = _bin_env_file(env_path)
+    data = _get_data(path)
+    if data is None:
+        err(f'missing file: "{path}"')
+        return ERR_CODE_NO_BIN_ENV_DESC
+    data['ready'] = True
+    _write_data(path, data)
+    return 0
+
+
+def _get_data(path):
+    try:
+        with open(path) as f:
+            return toml.load(f)
+    except FileNotFoundError:
+        return None
+
+
+def _write_data(path, data):
+    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
+        toml.dump(data, f)
+    os.replace(f.name, path)
+
+
+def _show_one_level(data, indent=''):
+    for k, v in sorted(data.items()):
+        if not isinstance(v, dict):
+            print(f"{indent}{k} = {v}")
+        else:
+            print(f"{indent}{k}:")
+            _show_one_level(v, indent + '  ')
+
+
+def show(env_path):
+    path = _bin_env_file(env_path)
+    data = _get_data(path)
+    if data is None:
+        err(f'missing file: "{path}"')
+        return ERR_CODE_NO_BIN_ENV_DESC
+    _show_one_level(data)
+    return 0
+
+
+def get_value(path, key):
+    data = _get_data(path)
+    if data is None:
+        err(f'missing file: "{path}"')
+        return ERR_CODE_NO_BIN_ENV_DESC
+
+    key_path = key.split('.')
+    sub = data
+    for k in key_path:
+        sub = sub.get(k)
+        if sub is None:
+            return ERR_CODE_NO_KEY
+    return 0
+
+
+def _set_one_value(data, key, value):
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        val = sub.setdefault(k, {})
+        sub = val
+    sub[key_path[-1]] = value
+
+
+def set_value(path, key, value):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    _set_one_value(data, key, value)
+
+    _write_data(path, data)
+    return 0
+
+
+def del_value(path, key):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        sub = sub.setdefault(k, {})
+    sub.pop(key_path[-1], None)
+
+    _write_data(path, data)
+    return 0
+
+
+def err(*args, **kwargs):
+    """print something on stderr"""
+    print(*args, **kwargs, file=sys.stderr)
+
+
+def _parsers():
+    top_parser = argparse.ArgumentParser(prog='poulpe-bin-env-util')
+    subparsers = top_parser.add_subparsers(
+        help='available sub-command',
+        dest='command',
+        required=True
+    )
+
+    # XXX having PATH everywhere is not great
+
+    ### bin-env-util create-empty PATH
+    cmd_parser = subparsers.add_parser(
+        'create-empty',
+        help='create a new empty bin-env'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the (future) environment",
+    )
+
+    ### bin-env-util setup-one-sh PATH SCRIPT
+    cmd_parser = subparsers.add_parser(
+        'setup-one',
+        help='create a new empty bin-env'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path of the environment",
+    )
+    cmd_parser.add_argument(
+        'SCRIPT',
+        help="the path to the script to setup the env",
+    )
+
+    ### bin-env-util mark-ready PATH
+    cmd_parser = subparsers.add_parser(
+        'mark-ready',
+        help='mark a bin-env as ready'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the environment",
+    )
+
+    ### bin-env-util show PATH
+    cmd_parser = subparsers.add_parser(
+        'show',
+        help='Show all data we have about this environment'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the environment",
+    )
+
+    ### bin-env-util get PATH KEY
+    cmd_parser = subparsers.add_parser(
+        'get',
+        help='Show a specific bin-env variable'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the environment",
+    )
+    cmd_parser.add_argument(
+        'KEY',
+        help="the path to the variable",
+    )
+
+    ### bin-env-util set PATH KEY VALUE
+    cmd_parser = subparsers.add_parser(
+        'set',
+        help='Show a specific bin-env variable'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the environment",
+    )
+    cmd_parser.add_argument(
+        'KEY',
+        help="the path to the variable",
+    )
+    cmd_parser.add_argument(
+        'VALUE',
+        help="the value to set",
+    )
+
+    ### bin-env-util del PATH KEY
+    cmd_parser = subparsers.add_parser(
+        'del',
+        help='Show a specific bin-env variable'
+    )
+    cmd_parser.add_argument(
+        'PATH',
+        help="the path to the environment",
+    )
+    cmd_parser.add_argument(
+        'KEY',
+        help="the path to the variable",
+    )
+
+    return top_parser
+
+
+def main(args):
+    parser = _parsers()
+    param = parser.parse_args(args)
+    if param.command == 'create-empty':
+        ret = create_empty(param.PATH)
+    elif param.command == 'setup-one':
+        ret = setup_one(param.PATH, param.SCRIPT)
+    elif param.command == 'mark-ready':
+        ret = mark_ready(param.PATH)
+    elif param.command == 'show':
+        ret = show(param.PATH)
+    elif param.command == 'get':
+        ret = get_value(
+            _bin_env_file(param.PATH),
+            f'bin-env-vars.{param.KEY}',
+        )
+    elif param.command == 'set':
+        ret = set_value(
+            _bin_env_file(param.PATH),
+            f'bin-env-vars.{param.KEY}',
+            param.VALUE,
+        )
+    elif param.command == 'del':
+        ret = del_value(
+            _bin_env_file(param.PATH),
+            f'bin-env-vars.{param.KEY}',
+        )
+    else:
+        assert False
+    return ret
+    print(param)
+
+
+if __name__ == "__main__":
+    ret = main(sys.argv[1:])
+    assert ret is not None
+    sys.exit(ret)
diff --git a/bin/diff-result b/bin/diff-result
new file mode 100755
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_YmluL2RpZmYtcmVzdWx0
--- /dev/null
+++ b/bin/diff-result
@@ -0,0 +1,127 @@
+#!/bin/env python3
+#
+# Small tool to manipulaote
+import argparse
+import json
+import os
+import stat
+import subprocess
+import sys
+import tempfile
+import toml
+
+
+ERR_CODE_NO_KEY = 1
+ERR_CODE_NO_BIN_ENV_SHELL = 2
+ERR_CODE_NO_BIN_ENV_DESC = 3
+ERR_CODE_EXISTS = 4
+ERR_CODE_NO_SETUP_SCRIPT = 6
+ERR_CODE_SETUP_SCRIPT_FAILED = 7
+
+BIN_ENV_FILE = 'bin-env.poulpe'
+DATA_ENV_FILE = 'data-env.poulpe'
+SHELL_FILE = 'bin-env.shell'
+
+
+def _bin_env_file(bin_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(bin_env_path, BIN_ENV_FILE)
+
+def _bin_env_script(bin_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(bin_env_path, SHELL_FILE)
+
+
+def _data_env_file(data_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(data_env_path, DATA_ENV_FILE)
+
+
+def _get_data(path):
+    try:
+        with open(path) as f:
+            return toml.load(f)
+    except FileNotFoundError:
+        return None
+
+def _write_data(path, data):
+    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
+        toml.dump(data, f)
+    os.replace(f.name, path)
+
+def _get_one_value(data, key):
+    key_path = key.split('.')
+    sub = data
+    for k in key_path:
+        sub = sub.get(k)
+        if sub is None:
+            break
+    return sub
+
+def _set_one_value(data, key, value):
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        val = sub.setdefault(k, {})
+        sub = val
+    sub[key_path[-1]] = value
+
+
+def set_value(path, key, value):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    _set_one_value(data, key, value)
+
+    _write_data(path, data)
+    return 0
+
+
+def err(*args, **kwargs):
+    """print something on stderr"""
+    print(*args, **kwargs, file=sys.stderr)
+
+
+def compare(old_path, new_path):
+    old = _get_data(old_path)
+    assert old is not None
+    new = _get_data(new_path)
+    assert new is not None
+
+    old_median = old['result']['time']['median']
+    new_median = new['result']['time']['median']
+
+    diff = new_median - old_median
+    ratio = new_median / old_median
+
+    print(f"{old_median:.4f} -> {new_median:.4f}: {diff:.4f} ({ratio:.2f})")
+
+    return 0
+
+
+def _parsers():
+    cmd_parser = argparse.ArgumentParser(prog='poulpe-bin-env-util')
+
+    cmd_parser.add_argument(
+        'OLD_RESULT',
+        help="the path to the binary environment directory",
+    )
+    cmd_parser.add_argument(
+        'NEW_RESULT',
+        help="the path to the data environment directory",
+    )
+    return cmd_parser
+
+
+def main(args):
+    parser = _parsers()
+    param = parser.parse_args(args)
+    ret = compare(param.OLD_RESULT, param.NEW_RESULT)
+    return ret
+
+if __name__ == "__main__":
+    ret = main(sys.argv[1:])
+    assert ret is not None
+    sys.exit(ret)
diff --git a/bin/env-desc b/bin/env-desc
new file mode 100755
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_YmluL2Vudi1kZXNj
--- /dev/null
+++ b/bin/env-desc
@@ -0,0 +1,147 @@
+#!/bin/env python3
+#
+# Small tool to manipulaote
+import os
+import sys
+import tempfile
+import toml
+
+ACTION_SHOW = 'show'
+ACTION_SET = 'set'
+ACTION_GET = 'get'
+ACTION_DEL = 'del'
+ALL_ACTIONS = {
+    ACTION_SHOW,
+    ACTION_SET,
+    ACTION_GET,
+    ACTION_DEL,
+}
+
+
+def _get_data(path):
+    try:
+        with open(path) as f:
+            return toml.load(f)
+    except FileNotFoundError:
+        return None
+
+def _write_data(path, data):
+    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
+        toml.dump(data, f)
+    os.replace(f.name, path)
+
+
+def _show_one_level(data, indent=''):
+    if not isinstance(data, dict):
+        print(f"{indent}{data}")
+        return
+    for k, v in sorted(data.items()):
+        if isinstance(v, dict):
+            print(f"{indent}{k}:")
+            _show_one_level(v, indent + '  ')
+        elif isinstance(v, list):
+            print(f"{indent}{k}:")
+            for i in v:
+                _show_one_level(i, indent + '- ')
+        else:
+            print(f"{indent}{k} = {v}")
+
+
+def show(path):
+    data = _get_data(path)
+    if data is None:
+        err(f'missing file: "{path}"')
+        return 3
+    _show_one_level(data)
+
+
+def get_value(path, key):
+    data = _get_data(path)
+    if data is None:
+        err(f'missing file: "{path}"')
+        return 3
+
+    key_path = key.split('.')
+    sub = data
+    for k in key_path:
+        sub = sub.get(k)
+        if sub is None:
+            return 1
+    print(sub)
+    return 0
+
+
+def set_value(path, key, value):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        sub = sub.setdefault(k, {})
+    sub[key_path[-1]] = value
+
+    _write_data(path, data)
+    return 0
+
+
+def del_value(path, key):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        sub = sub.setdefault(k, {})
+    sub.pop(key_path[-1], None)
+
+    _write_data(path, data)
+    return 0
+
+def err(*args, **kwargs):
+    print(*args, **kwargs, file=sys.stderr)
+
+
+if __name__ == "__main__":
+    if len(sys.argv) < 3:
+        t = os.path.split(sys.argv[0])[-1]
+        err(f"{t}: small utility to manipulate environment description")
+        err("")
+        err(f"  $ {t} show PATH - Display description content")
+        err(f"  $ {t} get PATH key - Display key value")
+        err(f"  $ {t} set PATH key value - Set key value")
+        err(f"  $ {t} del PATH key - Remove key")
+        sys.exit(2)
+    action = sys.argv[1]
+    path = sys.argv[2]
+    key = value = None
+
+    if action not in ALL_ACTIONS:
+        err(f"unknown action: {action}")
+        err("(use one of: %s)" % ', '.join(sorted(ALL_ACTIONS)))
+        sys.exit(2)
+
+    if action != ACTION_SHOW:
+        if len(sys.argv) < 4:
+            err("missing key")
+            sys.exit(2)
+        key = sys.argv[3]
+        if action == ACTION_SET:
+            if len(sys.argv) < 5:
+                err("missing value")
+                sys.exit(2)
+            value = sys.argv[4]
+
+    if action == ACTION_SHOW:
+        ret = show(path)
+    elif action == ACTION_GET:
+        ret = get_value(path, key)
+    elif action == ACTION_SET:
+        ret = set_value(path, key, value)
+    elif action == ACTION_DEL:
+        ret = del_value(path, key)
+sys.exit(ret)
diff --git a/bin/run-util b/bin/run-util
new file mode 100755
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_YmluL3J1bi11dGls
--- /dev/null
+++ b/bin/run-util
@@ -0,0 +1,189 @@
+#!/bin/env python3
+#
+# Small tool to manipulaote
+import argparse
+import json
+import os
+import stat
+import subprocess
+import sys
+import tempfile
+import toml
+
+
+ERR_CODE_NO_KEY = 1
+ERR_CODE_NO_BIN_ENV_SHELL = 2
+ERR_CODE_NO_BIN_ENV_DESC = 3
+ERR_CODE_EXISTS = 4
+ERR_CODE_NO_SETUP_SCRIPT = 6
+ERR_CODE_SETUP_SCRIPT_FAILED = 7
+
+BIN_ENV_FILE = 'bin-env.poulpe'
+DATA_ENV_FILE = 'data-env.poulpe'
+SHELL_FILE = 'bin-env.shell'
+
+
+def _bin_env_file(bin_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(bin_env_path, BIN_ENV_FILE)
+
+def _bin_env_script(bin_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(bin_env_path, SHELL_FILE)
+
+
+def _data_env_file(data_env_path):
+    """given the path of env, return the file of description file"""
+    return os.path.join(data_env_path, DATA_ENV_FILE)
+
+
+def _get_data(path):
+    try:
+        with open(path) as f:
+            return toml.load(f)
+    except FileNotFoundError:
+        return None
+
+def _write_data(path, data):
+    with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
+        toml.dump(data, f)
+    os.replace(f.name, path)
+
+def _get_one_value(data, key):
+    key_path = key.split('.')
+    sub = data
+    for k in key_path:
+        sub = sub.get(k)
+        if sub is None:
+            break
+    return sub
+
+def _set_one_value(data, key, value):
+    key_path = key.split('.')
+    sub = data
+    for k in key_path[:-1]:
+        val = sub.setdefault(k, {})
+        sub = val
+    sub[key_path[-1]] = value
+
+
+def set_value(path, key, value):
+    data = _get_data(path)
+    if data is None:
+        err(f'creating new file: "{path}"')
+        data = {}
+
+    _set_one_value(data, key, value)
+
+    _write_data(path, data)
+    return 0
+
+
+def err(*args, **kwargs):
+    """print something on stderr"""
+    print(*args, **kwargs, file=sys.stderr)
+
+
+def run_one(bin_env_path, data_env_path, benchmark, result):
+    result_data = {}
+
+    # gather info about the binary environment
+    bin_env_desc = _bin_env_file(bin_env_path)
+    bin_env_data = _get_data(bin_env_desc)
+    result_data['bin-env-vars'] = bin_env_data['bin-env-vars']
+
+    # gather info about the data environment
+    data_env_desc = _data_env_file(data_env_path)
+    data_env_data = _get_data(data_env_desc)
+    result_data['data-env-vars'] = data_env_data['data-env-vars']
+
+    benchmark_data = _get_data(benchmark)
+    assert benchmark_data is not None, benchmark
+    result_data['benchmark'] = {}
+    result_data['benchmark']['name'] = benchmark_data['meta']['name']
+
+    # building the benchmark scenarion, that will likely changes often and quickly
+
+    cmd = benchmark_data['simple-command']['command']
+
+    variables_data = benchmark_data['simple-command']['variables']
+
+    variables = {}
+    for name, value in variables_data.items():
+        if value.startswith('DATA-VARS:'):
+            key = value.split(':', 1)[1]
+            value = _get_one_value(data_env_data, f'bench-input-vars.{key}')
+            assert value is not None
+        variables[name] = value
+
+    cmd = cmd.format(**variables)
+
+    r = _time_command(bin_env_path, data_env_path, cmd)
+
+    # we should store more
+    result_data['result'] = {}
+    result_data['result']['time'] = {}
+    result_data['result']['time']['median'] = r['results'][0]['median']
+
+    _write_data(result, result_data)
+    return 0
+
+
+def _time_command(bin_env_path, data_env_path, cmd):
+    bin_env_path = os.path.abspath(bin_env_path)
+    data_env_path = os.path.abspath(data_env_path)
+    shell_path = _bin_env_script(bin_env_path)
+
+    with tempfile.NamedTemporaryFile('w') as tmp_result:
+        time_cmd = [
+            shell_path,
+            "hyperfine",
+            cmd,
+            "--export-json",
+            tmp_result.name,
+            "--ignore-failure",
+        ]
+
+        subprocess.check_call(
+            time_cmd,
+            cwd=data_env_path,
+            stdout=subprocess.DEVNULL,
+            stderr=subprocess.DEVNULL,
+        )
+
+        with open(tmp_result.name) as f:
+            return json.load(f)
+
+
+def _parsers():
+    cmd_parser = argparse.ArgumentParser(prog='poulpe-bin-env-util')
+
+    cmd_parser.add_argument(
+        'BIN_ENV',
+        help="the path to the binary environment directory",
+    )
+    cmd_parser.add_argument(
+        'DATA_ENV',
+        help="the path to the data environment directory",
+    )
+    cmd_parser.add_argument(
+        'BENCHMARK',
+        help="the path to the benchmark description file",
+    )
+    cmd_parser.add_argument(
+        'RESULT',
+        help="the path to result file",
+    )
+    return cmd_parser
+
+
+def main(args):
+    parser = _parsers()
+    param = parser.parse_args(args)
+    ret = run_one(param.BIN_ENV, param.DATA_ENV, param.BENCHMARK, param.RESULT)
+    return ret
+
+if __name__ == "__main__":
+    ret = main(sys.argv[1:])
+    assert ret is not None
+    sys.exit(ret)
diff --git a/tests/test-bin-env-util.t b/tests/test-bin-env-util.t
new file mode 100644
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_dGVzdHMvdGVzdC1iaW4tZW52LXV0aWwudA==
--- /dev/null
+++ b/tests/test-bin-env-util.t
@@ -0,0 +1,216 @@
+Test the utility that manage bin-env creation
+---------------------------------------------
+
+  $ PATH="${TESTDIR}/../bin:$PATH"
+
+Check basic invocation
+
+  $ bin-env-util --help
+  usage: poulpe-bin-env-util [-h]
+                             {create-empty,setup-one,mark-ready,show,get,set,del}
+                             ...
+  
+  positional arguments:
+    {create-empty,setup-one,mark-ready,show,get,set,del}
+                          available sub-command
+      create-empty        create a new empty bin-env
+      setup-one           create a new empty bin-env
+      mark-ready          mark a bin-env as ready
+      show                Show all data we have about this environment
+      get                 Show a specific bin-env variable
+      set                 Show a specific bin-env variable
+      del                 Show a specific bin-env variable
+  
+  optional arguments:
+    -h, --help            show this help message and exit
+
+
+Check repository creation
+
+simple creation
+
+  $ bin-env-util create-empty test-create
+  $ ls -1 test-create
+  bin-env.poulpe
+  $ bin-env-util show test-create
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = False
+
+Running on an existing repo abort and does not destroy it
+
+  $ bin-env-util create-empty test-create
+  This is already a bin-env, aborting
+  [4]
+  $ bin-env-util show test-create
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = False
+
+Creating a repository on an existing dir
+
+  $ mkdir test-existing-dir
+  $ bin-env-util create-empty test-existing-dir
+  $ bin-env-util show test-existing-dir
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = False
+
+Check manual setup
+------------------
+
+Check changing variable manually
+
+  $ python3 -m venv test-existing-dir
+  $ cd test-existing-dir
+  $ bin/pip3 install --quiet black==18.6b4
+  $ bin-env-util set . python.version "`bin/python --version | egrep -o '\S+$'`"
+  $ bin-env-util set . black.version "`bin/black --version | egrep -o '\S+$'`"
+  $ bin-env-util set . black.install-method pip
+  $ bin-env-util show .
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.* (glob)
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = False
+
+Marking it ready when it is not
+
+  $ bin-env-util mark-ready .
+  cannot find an executable file at: "./bin-env.shell"
+  [2]
+  $ bin-env-util show .
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.* (glob)
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = False
+
+Manually create an activate script
+
+  $ cat > bin-env.shell << EOF
+  > #!/bin/bash
+  > BIN_ENV_PATH="\`dirname \"\$0\"\`"
+  > . "\$BIN_ENV_PATH"/bin/activate
+  > "\$@"
+  > EOF
+  $ bin-env-util mark-ready .
+  cannot find an executable file at: "./bin-env.shell"
+  [2]
+  $ chmod +x bin-env.shell
+
+Marking it ready when it is
+
+  $ bin-env-util mark-ready .
+  $ bin-env-util show .
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.* (glob)
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = manual
+  ready = True
+
+Basic test of the result
+
+  $ ./bin-env.shell echo babar
+  babar
+  $ ./bin-env.shell black --version
+  black, version 18.6b4
+  $ cd ..
+
+Test scripted setup
+-------------------
+
+Create setup scripts
+
+  $ cat > setup-error.sh << EOF
+  > #!/bin/bash
+  > exit 2
+  > EOF
+  $ chmod +x setup-error.sh
+
+  $ grep -v 'chmod' $TESTDIR/test-data/setup-black.sh > setup-black-bad-activate.sh
+  $ chmod +x setup-black-bad-activate.sh
+
+Test a missing script
+
+  $ bin-env-util setup-one env-missing setup-missing.sh
+  no executable setup scrip at: "setup-missing.sh"
+  [6]
+
+Test a setup error
+
+  $ bin-env-util setup-one env-error setup-error.sh
+  script returned with status 2: $TESTTMP/setup-error.sh
+  [7]
+
+Test an invalid activate
+
+  $ bin-env-util setup-one env-bad-activate setup-black-bad-activate.sh
+  $TESTTMP/setup-black-bad-activate.sh: line 5: BLACK_VERSION: unbound variable
+  script returned with status 1: $TESTTMP/setup-black-bad-activate.sh
+  [7]
+  $ rm -rf env-bad-activate
+  $ BLACK_VERSION="18.6b4" bin-env-util setup-one  env-bad-activate setup-black-bad-activate.sh
+  cannot find an executable file at: "env-bad-activate/bin-env.shell"
+  [2]
+
+Test a succesfull script
+
+  $ BLACK_VERSION="18.6b4" bin-env-util setup-one  env-black-18.6b4 \
+  > $TESTDIR/test-data/setup-black.sh
+  $ BLACK_VERSION="18.6b1" bin-env-util setup-one  env-black-18.6b1 \
+  > $TESTDIR/test-data/setup-black.sh
+
+  $ bin-env-util show env-black-18.6b1
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b1
+    python:
+      version = 3.9.9
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = script
+  ready = True
+  $ env-black-18.6b1/bin-env.shell black --version
+  black, version 18.6b1
+
+  $ bin-env-util show env-black-18.6b4
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.9.9
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = script
+  ready = True
+  $ env-black-18.6b4/bin-env.shell black --version
+  black, version 18.6b4
diff --git a/tests/test-data/setup-black.sh b/tests/test-data/setup-black.sh
new file mode 100755
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_dGVzdHMvdGVzdC1kYXRhL3NldHVwLWJsYWNrLnNo
--- /dev/null
+++ b/tests/test-data/setup-black.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+set -euo pipefail
+
+python3 -m venv .
+bin/pip3 install --quiet black=="$BLACK_VERSION"
+
+echo python.version="`bin/python --version | egrep -o '\S+$'`" > POULPE-VARS
+echo black.version="`bin/black --version | egrep -o '\S+$'`" >> POULPE-VARS
+echo black.install-method=pip >> POULPE-VARS
+
+touch bin-env.shell
+chmod +x bin-env.shell
+
+cat >> bin-env.shell << EOF
+#!/bin/bash
+set -euo pipefail
+BIN_ENV_PATH="\`dirname \"\$0\"\`"
+. "\$BIN_ENV_PATH"/bin/activate
+"\$@"
+EOF
diff --git a/tests/test-env-desc.t b/tests/test-env-desc.t
new file mode 100644
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_dGVzdHMvdGVzdC1lbnYtZGVzYy50
--- /dev/null
+++ b/tests/test-env-desc.t
@@ -0,0 +1,108 @@
+Test the small utility that access environment description
+----------------------------------------------------------
+
+  $ PATH="${TESTDIR}/../bin:$PATH"
+
+Check basic error
+----------------
+
+no args
+
+  $ env-desc
+  env-desc: small utility to manipulate environment description
+  
+    $ env-desc show PATH - Display description content
+    $ env-desc get PATH key - Display key value
+    $ env-desc set PATH key value - Set key value
+    $ env-desc del PATH key - Remove key
+  [2]
+
+too few args
+
+  $ env-desc foo
+  env-desc: small utility to manipulate environment description
+  
+    $ env-desc show PATH - Display description content
+    $ env-desc get PATH key - Display key value
+    $ env-desc set PATH key value - Set key value
+    $ env-desc del PATH key - Remove key
+  [2]
+
+bad action
+
+  $ env-desc foo bar
+  unknown action: foo
+  (use one of: del, get, set, show)
+  [2]
+
+missing GET key
+
+  $ env-desc get no-file
+  missing key
+  [2]
+
+missing SET key
+
+  $ env-desc set no-file
+  missing key
+  [2]
+
+missing SET value
+
+  $ env-desc set no-file key
+  missing value
+  [2]
+
+missing DEL key
+
+  $ env-desc del no-file
+  missing key
+  [2]
+
+Missing file when reading
+
+  $ env-desc show no-file
+  missing file: "no-file"
+  [3]
+
+  $ env-desc get no-file no-key
+  missing file: "no-file"
+  [3]
+
+Writing and reading files
+-------------------------
+
+Small and basic usage to smoke test the script
+
+  $ env-desc set bin-env.pe vars.hg.version 6.1.0
+  creating new file: "bin-env.pe"
+  $ env-desc set bin-env.pe vars.hg.flavor pure
+  $ env-desc set bin-env.pe vars.oops babar
+  $ env-desc get bin-env.pe vars.hg.version
+  6.1.0
+  $ env-desc get bin-env.pe vars.hg.flavor
+  pure
+  $ env-desc get bin-env.pe vars.oops
+  babar
+  $ env-desc show bin-env.pe
+  vars:
+    hg:
+      flavor = pure
+      version = 6.1.0
+    oops = babar
+
+Modify the file more
+
+  $ env-desc set bin-env.pe vars.hg.version 4.3.0
+  $ env-desc del bin-env.pe vars.oops
+  $ env-desc get bin-env.pe vars.hg.version
+  4.3.0
+  $ env-desc get bin-env.pe vars.hg.flavor
+  pure
+  $ env-desc get bin-env.pe vars.oops
+  [1]
+  $ env-desc show bin-env.pe
+  vars:
+    hg:
+      flavor = pure
+      version = 4.3.0
diff --git a/tests/test-simple-run.t b/tests/test-simple-run.t
new file mode 100644
index 0000000000000000000000000000000000000000..fd546c6ebd9c1ca773b9d83d52a9f43b30b190c0_dGVzdHMvdGVzdC1zaW1wbGUtcnVuLnQ=
--- /dev/null
+++ b/tests/test-simple-run.t
@@ -0,0 +1,130 @@
+Check we have enough simple pieces together to do a simple run
+--------------------------------------------------------------
+
+  $ PATH="${TESTDIR}/../bin:$PATH"
+
+Setup the bin-env
+-----------------
+
+  $ BLACK_VERSION="18.6b4" bin-env-util setup-one  bin-env-black-18.6b4 \
+  > $TESTDIR/test-data/setup-black.sh
+  $ bin-env-util show bin-env-black-18.6b4
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.* (glob)
+  poulpe-environment:
+    environment-type = binary
+    format-version = 0
+    setup-method = script
+  ready = True
+
+
+Setup a data-env
+----------------
+
+(currently built by hand as it simple and mostly innert)
+
+  $ mkdir data-env
+  $ env-desc set data-env/data-env.poulpe poulpe-environment.environment-type data
+  creating new file: "data-env/data-env.poulpe"
+  $ env-desc set data-env/data-env.poulpe poulpe-environment.format-version 0
+  $ env-desc set data-env/data-env.poulpe poulpe-environment.setup-method manual
+  $ env-desc set data-env/data-env.poulpe data-env-vars.name black-bench
+  $ mkdir data-env/py-files
+  $ cat << EOF > data-env/py-files/good.py
+  > foo = [1, 2, 3, 4, 5]
+  > EOF
+  $ cat << EOF > data-env/py-files/bad.py
+  > foo = [1,
+  >    2,
+  >   3,
+  >     4,
+  >  5]
+  > EOF
+  $ env-desc set data-env/data-env.poulpe bench-input-vars.black.check.tiny.good py-files/good.py
+  $ env-desc set data-env/data-env.poulpe bench-input-vars.black.check.tiny.bad py-files/bad.py
+
+(that one will be a string, so its not good.)
+
+  $ env-desc set data-env/data-env.poulpe ready 1
+
+  $ env-desc show data-env/data-env.poulpe
+  bench-input-vars:
+    black:
+      check:
+        tiny:
+          bad = py-files/bad.py
+          good = py-files/good.py
+  data-env-vars:
+    name = black-bench
+  poulpe-environment:
+    environment-type = data
+    format-version = 0
+    setup-method = manual
+  ready = 1
+
+Define a benchmark
+------------------
+
+  $ env-desc set black-tiny-bad.pbd meta.format 0
+  creating new file: "black-tiny-bad.pbd"
+  $ env-desc set black-tiny-bad.pbd meta.name black.check.tiny
+  $ env-desc set black-tiny-bad.pbd meta.method simple-command
+  $ env-desc set black-tiny-bad.pbd simple-command.command "black --check {file}"
+  $ env-desc set black-tiny-bad.pbd simple-command.variables.file DATA-VARS:black.check.tiny.bad
+
+  $ env-desc show black-tiny-bad.pbd
+  meta:
+    format = 0
+    method = simple-command
+    name = black.check.tiny
+  simple-command:
+    command = black --check {file}
+    variables:
+      file = DATA-VARS:black.check.tiny.bad
+
+Run the benchmark
+-----------------
+  $ run-util bin-env-black-18.6b4 data-env black-tiny-bad.pbd test-result-18.6b4-bad.pbr
+  $ env-desc show test-result-18.6b4-bad.pbr
+  benchmark:
+    name = black.check.tiny
+  bin-env-vars:
+    black:
+      install-method = pip
+      version = 18.6b4
+    python:
+      version = 3.* (glob)
+  data-env-vars:
+    name = black-bench
+  result:
+    time:
+      median = * (glob)
+
+Quick comparision of values
+---------------------------
+
+Get another result
+(the sed if likely to not be a viable option in the future)
+
+  $ cp black-tiny-bad.pbd black-tiny-good.pbd
+  $ sed -i 's/bad/good/g' black-tiny-good.pbd
+  $ env-desc show black-tiny-good.pbd
+  meta:
+    format = 0
+    method = simple-command
+    name = black.check.tiny
+  simple-command:
+    command = black --check {file}
+    variables:
+      file = DATA-VARS:black.check.tiny.good
+
+  $ run-util bin-env-black-18.6b4 data-env black-tiny-good.pbd test-result-18.6b4-good.pbr
+
+Compare the result
+
+  $ diff-result test-result-18.6b4-bad.pbr test-result-18.6b4-good.pbr
+  \d+.\d+ -> \d+.\d+: -?\d+.\d+ \(\d+.\d+\) (re)