invoke-toolkit
A set of extensions for rich output, more options in collection/config discovery through entry-points.
This extends the Collection from Invoke so it can create automatically collections.
Table of Contents
Features
- Task discovery by namespace for extendable/composable CLIs
- Discovery to plain old tasks.py (or any other name)
- Local tasks discovery from
local_tasks.pyin the current directory - Integration with stand alone binaries for specific tasks
- Task result caching with TTL support via
diskcache(optional) - Future Download binaries
Do I need this package
If you have...
- Used
invokefor a while and... - Have a large
tasks.pythat needs to be modularized - Have a lot of copy/pasted code in multiple
tasks.pyacross multiple repos. - Have exceeded the approach of a repository cloned as
~/tasks/with more .py files that you want to manage. - Or you want to combine various tasks defined in multiple directories
- You want to create a zipped (shiv) redistribute script for container environments like Kubernetes based CI environments with only requiring the Python interpreter.
Installation
pip install invoke-toolkit
Quick Start
Using Local Tasks
Create a local_tasks.py file in your project directory with your tasks:
from invoke_toolkit import task
@task()
def my_task(ctx):
"""Do something useful"""
print("Hello from local tasks!")
Then run it with:
intk local.my-task
Local tasks are automatically discovered and added to the local namespace, allowing you to keep project-specific tasks separate from your main task collection.
Using Task Caching
Cache expensive task results with the cache parameter:
from invoke_toolkit import task
# Simple caching (no expiration)
@task(cache=True)
def expensive_task(ctx, param: str) -> str:
"""Results are cached across invocations."""
return do_expensive_computation(param)
# Caching with TTL (1 hour)
@task(cache={"ttl": 3600})
def cached_task(ctx, name: str) -> dict:
"""Results cached for 1 hour."""
return fetch_data(name)
# Caching with ignored arguments
@task(cache={"ttl": 600, "ignore_args": ["verbose"]})
def cached_with_options(ctx, query: str, verbose: bool = False) -> list:
"""Cache key ignores verbose flag."""
return search(query, verbose=verbose)
Cache features:
- Cache location is computed from git repository root + platformdirs
- Debug logging (
-dflag) shows cache hits/misses - Graceful degradation when
diskcacheis not installed
To enable caching, install with the cache extra:
pip install invoke-toolkit[cache]
Dynamic task defaults
Use Field when an argument default must be computed from the final task
context or resolved from a URI. Explicit command-line values always take
precedence.
Bind a resolver once, then reuse the resulting callable for scalar and file defaults. A local resolver always returns one string value per request. The resolver receives every URI using that callback and scheme in one batch.
from invoke_toolkit import Context, Field, FilePath, task
def resolve_bw(ctx: Context, requests: list) -> dict[str, str]:
return {
request.parameter: ctx.run("bw get password ...", hide=True).stdout.strip()
for request in requests
}
BitwardenField = Field(resolver=resolve_bw)
ExistingFile = FilePath(exists=True, dir_okay=False)
@task
def deploy(
ctx: Context,
password: str = BitwardenField(default="bw://PASSWORD_ID"),
config: ExistingFile = BitwardenField(
default="bw://CONFIG_ID", cleanup="task"
),
) -> None:
...
For str fields, the resolver string reaches the task unchanged. For Path or
FilePath fields, Field.create_temporary_file() writes that string to a
managed temporary file and passes its Path to the task. Override that method
in a Field subclass to control file creation; resolvers do not return paths.
For omitted arguments, lookup precedence is explicit CLI/Python/call value,
then INVOKE_<PARAMETER> environment value, then the resolved ctx.config
value, then the declared Field default or factory. URI values from config use
the same local or entry-point resolver dispatch as declared URI defaults.
Field(default_factory=callback) runs only if no higher-precedence value is
available. Factories and resolvers never run during help, listing, or shell
completion; Path/FilePath completion continues to work normally for
explicit values.
Temporary Path files from resolver-bound Field instances are owned by
invoke-toolkit. cleanup="pipeline" is the default and keeps the file through
expanded pre/main/post execution; cleanup="task" removes it when that task
returns. Cleanup runs after failures and cancellation.
Installed invoke_toolkit.field_resolver entry points remain supported for
compatibility but issue a warning recommending a task-local resolver. Generate a
resolver-only provider package with:
intk -x create.package --provider op
Provider packages expose no task collection. Providers return text only; for
Path fields invoke-toolkit materializes and cleans the resulting temporary
file according to that Field's cleanup lifetime.
Development
This project utilizes the pre-commit framework, make sure you run:
pre-commit install
With uvx:
uvx --with pre-commit-uv pre-commit install
License
invoke-toolkit is distributed under the terms of the MIT license.
Metadata
Release files for invoke-toolkit 0.0.70
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| invoke_toolkit-0.0.70.tar.gz | 186.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| invoke_toolkit-0.0.70-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 306.4 kB
Release files / invoke_toolkit-0.0.70.tar.gz
| Download URL | invoke_toolkit-0.0.70.tar.gz |
|---|---|
| Size | 186.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f8a7cb82d73394c9d1fba862587dd86bb7967faef277e8607b83ccb53ae1e4cf
|
|
BLAKE2b-256 checksum How to use checksums |
7b0396f388139c07531bd01fe32742c97fdd5d6e1dc24a09437c6de812e9141c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / invoke_toolkit-0.0.70-py3-none-any.whl
| Download URL | invoke_toolkit-0.0.70-py3-none-any.whl |
|---|---|
| Size | 119.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2ef506924ededb30ca7ff006565d096028583616f24a4b6e511d7e21ac539885
|
|
BLAKE2b-256 checksum How to use checksums |
893edd23ed875e82a4df7be59f9e618b2a8874f84744d60be401e7453b40318b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency log