argledger
Reusable, class-based command registry that turns validated JSON specs into real
argparseparsers — with reproducible default resolution and automatic execution history.
argledger gives you one source of truth for every command:
- parser construction (
argparse.ArgumentParser) - default resolution
CLI > env > config file > spec defaultwith source tracking - deterministic default
argv/ shell rendering - automatic
ExecutionContextrecording (timestamps, duration, resolved args, provenance, git, outputs, metrics, success/failure) - JSONL + SQLite history, query, and replay
- guide generation & shell completion hooks
No domain coupling. Your specs live with your project via Registry(user_root=...).
Installation
pip install argledger
Requires Python ≥3.11. No mandatory dependencies.
pip install argledger # from PyPI
# or for development
pip install -e ".[dev]"
Quick start
1. Define a spec (my_project/specs/demo/greet.json):
{
"name": "demo.greet",
"description": "Greet someone a number of times.",
"version": "1.0.0",
"groups": ["common"],
"arguments": {
"name": { "type": "str", "default": "world", "help": "Name to greet." },
"count": { "type": "int", "default": 1, "minimum": 1, "maximum": 10 },
"excited": { "action": "store_true", "default": false }
}
}
2. Use it:
from pathlib import Path
from argledger import Registry, History, ExecutionContext
registry = Registry(user_root=Path("my_project")) # loads specs/my_project via importlib.resources + user_root
command = registry.load("demo.greet")
# resolves CLI > env > config > default, tracks source for each arg
resolved = command.parse_args(["--name", "Alice", "--count", "2"])
print(resolved.values) # {'name': 'Alice', 'count': 2, 'excited': False, ...}
print(resolved.sources) # {'name': 'cli', 'count': 'cli', ...}
print(resolved.namespace) # argparse.Namespace
history = History(jsonl=Path(".run-registry/history.jsonl"), sqlite=Path(".run-registry/history.db"))
with ExecutionContext(command, resolved, history=history) as ctx:
for _ in range(resolved.values["count"]):
print(f"Hello, {resolved.values['name']}!")
ctx.add_output(Path("out.txt"))
ctx.set_metric("greetings", resolved.values["count"])
ctx.set_data_version("my-data-v1")
Normal code stays simple:
args = command.parser().parse_args()
also works (legacy, source=unknown).
CLI
# list/show/defaults (pure package – no builtins – so pass where your specs live)
python -m argledger list --user-root my_project
python -m argledger show demo.greet --user-root my_project
python -m argledger defaults demo.greet --user-root my_project
# history query / replay
python -m argledger query --command demo.greet --success --limit 5
python -m argledger replay <execution-id> # exact argv
python -m argledger replay <execution-id> --expanded # fully expanded, reproducible argv
# guide generation (marker-based, never overwrites hand-written docs)
python -m argledger guide --output docs/COMMAND_GUIDE.md --user-root my_project
# shell completion
python -m argledger completion --shell bash
Features
- Validated models
Argument/Command– reject malformed names, unknown types/actions,minimum>maximum, invalidpattern,defaultnot inchoices, etc. (seeArgument.from_spec) - Field-level group merge – groups listed in order, then spec overrides field-by-field (
{**group, **spec}), e.g. a spec can override only"default"while keeping group'stype/help/env. - Precedence
CLI > env > config (TOML) > spec default. TOML layout:[groups.common] workers = 1 [commands."demo.greet"] count = 5
Configure viaRegistry(config_path=Path("argledger.toml"))orRUN_REGISTRY_CONFIGenv. - Default argv
Command.default_argv()/default_argument_string()– deterministic,shlex.join'd, respectsinclude_in_default_argv/include_empty/include_false_flags. All docs delegate to this. - History – JSONL is canonical, SQLite is mirror. Queries by
command/since/until/success/tags/limit; fallback to JSONL scan if SQLite disabled. Sensitive args stored as"<redacted>", expanded replay raisesReplayUnavailableError. - Provenance – UTC timestamps, monotonic duration, hostname/pid/cwd/python/platform/cpu_count,
git commit/branch/dirty(never crashes outside a repo), optional peak RSS. - Compatibility
argledger.compat.parser_from_spec(__file__, "demo/greet.json", user_root=...)wrapsRegistry().load(...).parser()with deprecation warning.
See examples/ for runnable demos (demo.greet, demo.counter, demo.file_processor) and tests/fixtures/ for the minimal spec used in 74 core tests.
Why
Research and product CLIs usually duplicate: arg definitions vs. parser vs. docs vs. history append vs. replay. argledger collapses them to one validated spec, so your script stays
command = registry.load(NAME)
resolved = command.parse_args()
with ExecutionContext(command, resolved, history=history) as run:
result = do_the_actual_work(resolved.namespace)
run.add_output(result.path)
— everything else (parser, defaults, env/config, docs, timing, history, replay, provenance) belongs to the framework.
Links
- Repository: https://github.com/GrayJou/argledger
- Issues: https://github.com/GrayJou/argledger/issues
- License: MIT – see
LICENSE
Publishing / Development
pip install -e ".[dev]"
pytest -q
python -m build
twine check dist/*
Metadata
Release files for argledger 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| argledger-0.1.2.tar.gz | 52.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| argledger-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 95.3 kB
Release files / argledger-0.1.2.tar.gz
| Download URL | argledger-0.1.2.tar.gz |
|---|---|
| Size | 52.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8e2921ffc97c1bed9066063530bb7b9f4c6fa1875b9082388fd859b835f20b6f
|
|
BLAKE2b-256 checksum How to use checksums |
3837f422fd9d34267d53d822aeb28fdba4a2feadbf7c015716e6faf99085e863
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / argledger-0.1.2-py3-none-any.whl
| Download URL | argledger-0.1.2-py3-none-any.whl |
|---|---|
| Size | 42.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f42b57a4624983b2555731ef85b5396f352563e370774d258090e5ff84ee1b35
|
|
BLAKE2b-256 checksum How to use checksums |
489cce72eb607d2c8bec9f2e327f0fe0a5ac58ab58060bb72fb141c23445ef2b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Security for argledger 0.1.2
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.