batchwizard 0.2.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. batchwizard-0.5.0/.github/workflows/ci.yml +52 -0
  2. batchwizard-0.5.0/.github/workflows/publish.yml +37 -0
  3. batchwizard-0.5.0/.gitignore +162 -0
  4. batchwizard-0.5.0/PKG-INFO +205 -0
  5. batchwizard-0.5.0/README.md +175 -0
  6. batchwizard-0.5.0/docs/anthropic.md +78 -0
  7. batchwizard-0.5.0/docs/job-lifecycle.md +121 -0
  8. batchwizard-0.5.0/pyproject.toml +74 -0
  9. batchwizard-0.5.0/src/batchwizard/__init__.py +24 -0
  10. batchwizard-0.5.0/src/batchwizard/cli.py +648 -0
  11. batchwizard-0.5.0/src/batchwizard/config.py +90 -0
  12. batchwizard-0.5.0/src/batchwizard/models.py +155 -0
  13. batchwizard-0.5.0/src/batchwizard/processor.py +275 -0
  14. batchwizard-0.5.0/src/batchwizard/providers/__init__.py +33 -0
  15. batchwizard-0.5.0/src/batchwizard/providers/anthropic.py +331 -0
  16. batchwizard-0.5.0/src/batchwizard/providers/base.py +50 -0
  17. batchwizard-0.5.0/src/batchwizard/providers/openai.py +196 -0
  18. batchwizard-0.5.0/src/batchwizard/store.py +310 -0
  19. batchwizard-0.5.0/src/batchwizard/ui.py +198 -0
  20. {batchwizard-0.2.0 → batchwizard-0.5.0}/src/batchwizard/utils.py +19 -5
  21. batchwizard-0.5.0/tests/conftest.py +25 -0
  22. batchwizard-0.5.0/tests/test_anthropic_provider.py +427 -0
  23. batchwizard-0.5.0/tests/test_anthropic_sdk_contract.py +134 -0
  24. batchwizard-0.5.0/tests/test_cli.py +444 -0
  25. batchwizard-0.5.0/tests/test_config.py +40 -0
  26. batchwizard-0.5.0/tests/test_openai_provider.py +341 -0
  27. batchwizard-0.5.0/tests/test_openai_sdk_contract.py +112 -0
  28. batchwizard-0.5.0/tests/test_orchestrator.py +453 -0
  29. batchwizard-0.5.0/tests/test_store.py +201 -0
  30. batchwizard-0.5.0/tests/test_ui.py +50 -0
  31. batchwizard-0.5.0/uv.lock +1252 -0
  32. batchwizard-0.2.0/PKG-INFO +0 -206
  33. batchwizard-0.2.0/README.md +0 -179
  34. batchwizard-0.2.0/pyproject.toml +0 -37
  35. batchwizard-0.2.0/src/batchwizard/__init__.py +0 -6
  36. batchwizard-0.2.0/src/batchwizard/cli.py +0 -192
  37. batchwizard-0.2.0/src/batchwizard/config.py +0 -48
  38. batchwizard-0.2.0/src/batchwizard/models.py +0 -18
  39. batchwizard-0.2.0/src/batchwizard/processor.py +0 -153
  40. batchwizard-0.2.0/src/batchwizard/ui.py +0 -258
  41. {batchwizard-0.2.0 → batchwizard-0.5.0}/LICENSE +0 -0
@@ -0,0 +1,52 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v7.0.0
16
+ with:
17
+ fetch-depth: 0
18
+ persist-credentials: false
19
+ - uses: astral-sh/setup-uv@v8.3.2
20
+ - run: uv sync --frozen --group dev
21
+ - run: uv run --frozen ruff check .
22
+ - run: uv run --frozen ruff format --check .
23
+
24
+ test:
25
+ runs-on: ubuntu-latest
26
+ strategy:
27
+ matrix:
28
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
29
+ steps:
30
+ - uses: actions/checkout@v7.0.0
31
+ with:
32
+ fetch-depth: 0
33
+ persist-credentials: false
34
+ - uses: astral-sh/setup-uv@v8.3.2
35
+ with:
36
+ python-version: ${{ matrix.python-version }}
37
+ - run: uv sync --frozen --group dev
38
+ - run: uv run --frozen pytest tests/
39
+
40
+ build:
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v7.0.0
44
+ with:
45
+ fetch-depth: 0
46
+ persist-credentials: false
47
+ - uses: astral-sh/setup-uv@v8.3.2
48
+ - run: uv build
49
+ - uses: actions/upload-artifact@v7.0.1
50
+ with:
51
+ name: dist
52
+ path: dist/
@@ -0,0 +1,37 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v7.0.0
15
+ with:
16
+ fetch-depth: 0
17
+ persist-credentials: false
18
+ - uses: astral-sh/setup-uv@v8.3.2
19
+ - run: uv build
20
+ - uses: actions/upload-artifact@v7.0.1
21
+ with:
22
+ name: dist
23
+ path: dist/
24
+
25
+ publish:
26
+ needs: build
27
+ runs-on: ubuntu-latest
28
+ environment: pypi
29
+ permissions:
30
+ # Required for PyPI Trusted Publishing (OIDC) — no API token needed
31
+ id-token: write
32
+ steps:
33
+ - uses: actions/download-artifact@v8.0.1
34
+ with:
35
+ name: dist
36
+ path: dist/
37
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,162 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110
+ .pdm.toml
111
+ .pdm-python
112
+ .pdm-build/
113
+
114
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115
+ __pypackages__/
116
+
117
+ # Celery stuff
118
+ celerybeat-schedule
119
+ celerybeat.pid
120
+
121
+ # SageMath parsed files
122
+ *.sage.py
123
+
124
+ # Environments
125
+ .env
126
+ .venv
127
+ env/
128
+ venv/
129
+ ENV/
130
+ env.bak/
131
+ venv.bak/
132
+
133
+ # Spyder project settings
134
+ .spyderproject
135
+ .spyproject
136
+
137
+ # Rope project settings
138
+ .ropeproject
139
+
140
+ # mkdocs documentation
141
+ /site
142
+
143
+ # mypy
144
+ .mypy_cache/
145
+ .dmypy.json
146
+ dmypy.json
147
+
148
+ # Pyre type checker
149
+ .pyre/
150
+
151
+ # pytype static type analyzer
152
+ .pytype/
153
+
154
+ # Cython debug symbols
155
+ cython_debug/
156
+
157
+ # PyCharm
158
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
161
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
162
+ #.idea/
@@ -0,0 +1,205 @@
1
+ Metadata-Version: 2.4
2
+ Name: batchwizard
3
+ Version: 0.5.0
4
+ Summary: Durable batch orchestration across OpenAI and Anthropic
5
+ Project-URL: Homepage, https://github.com/cmakafui/batchwizard
6
+ Project-URL: Repository, https://github.com/cmakafui/batchwizard
7
+ Project-URL: Issues, https://github.com/cmakafui/batchwizard/issues
8
+ Author: Carl Kugblenu
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: anthropic,async,batch,cli,openai
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: anthropic[aiohttp]<1,>=0.117
22
+ Requires-Dist: loguru>=0.7
23
+ Requires-Dist: openai[aiohttp]<3,>=2.46
24
+ Requires-Dist: pydantic-settings>=2.3
25
+ Requires-Dist: pydantic>=2.8
26
+ Requires-Dist: python-dotenv>=1.0
27
+ Requires-Dist: rich>=13.7
28
+ Requires-Dist: typer>=0.12
29
+ Description-Content-Type: text/markdown
30
+
31
+ # BatchWizard
32
+
33
+ BatchWizard is one durable CLI for OpenAI and Anthropic batch jobs. Submit
34
+ provider-native JSONL, close the terminal, and come back later: a local SQLite
35
+ manifest remembers what is running, what still needs to be downloaded, and what
36
+ needs your attention.
37
+
38
+ It deliberately does not translate prompts between APIs. OpenAI and Anthropic
39
+ have different request formats and capabilities; BatchWizard gives them one
40
+ operational lifecycle without pretending they are the same protocol.
41
+
42
+ ## Quickstart
43
+
44
+ Install BatchWizard as an isolated Python 3.11+ tool:
45
+
46
+ ```bash
47
+ uv tool install batchwizard
48
+ ```
49
+
50
+ Provide one or both standard API-key environment variables:
51
+
52
+ ```bash
53
+ export OPENAI_API_KEY="..."
54
+ export ANTHROPIC_API_KEY="..."
55
+ ```
56
+
57
+ Submit native JSONL to either provider:
58
+
59
+ ```bash
60
+ batchwizard submit openai.jsonl --endpoint /v1/responses
61
+ batchwizard submit --provider anthropic anthropic.jsonl
62
+ ```
63
+
64
+ The submit process can exit once the providers accept the work. One later
65
+ command resumes every actionable job, grouped by provider:
66
+
67
+ ```bash
68
+ batchwizard watch --output-directory ./results
69
+ batchwizard status --all
70
+ ```
71
+
72
+ `watch` is intentionally provider-free. The manifest records which adapter owns
73
+ each batch, so a single invocation can resume a mixture of OpenAI and Anthropic
74
+ jobs. Missing credentials or a temporary download failure for one provider do
75
+ not erase work or prevent other provider groups from advancing.
76
+
77
+ ## Input formats
78
+
79
+ BatchWizard accepts each provider's native JSONL rather than maintaining a lossy
80
+ common prompt schema.
81
+
82
+ | | OpenAI | Anthropic |
83
+ | --- | --- | --- |
84
+ | Select with | default, or `--provider openai` | `--provider anthropic` |
85
+ | JSONL row | `{"custom_id", "method", "url", "body"}` | `{"custom_id", "params"}` |
86
+ | Model location | `body.model` | `params.model` |
87
+ | Submission | file upload, then Batch creation | requests sent inline to Message Batches |
88
+ | Provider status | Batch `status` | Message Batch `processing_status` |
89
+ | Results | provider output and error files | unordered result stream split by outcome |
90
+ | Recovery after an uncertain submit | automatic intent matching through Batch metadata | manual attachment by batch ID |
91
+
92
+ ### OpenAI
93
+
94
+ ```jsonl
95
+ {"custom_id":"ticket-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-5.4","input":"Classify this ticket as billing, technical, or other."}}
96
+ ```
97
+
98
+ The endpoint passed to BatchWizard must match the `url` in every row:
99
+
100
+ ```bash
101
+ batchwizard submit openai.jsonl --endpoint /v1/responses
102
+ ```
103
+
104
+ `/v1/chat/completions` is the default. BatchWizard also accepts the Responses,
105
+ Embeddings, Completions, Moderations, Images, and Videos Batch API endpoints.
106
+
107
+ ### Anthropic
108
+
109
+ ```jsonl
110
+ {"custom_id":"ticket-1","params":{"model":"claude-opus-4-8","max_tokens":256,"messages":[{"role":"user","content":"Classify this ticket as billing, technical, or other."}]}}
111
+ ```
112
+
113
+ ```bash
114
+ batchwizard submit --provider anthropic anthropic.jsonl
115
+ ```
116
+
117
+ BatchWizard validates the batch envelope, `custom_id` syntax and uniqueness,
118
+ batch size, `max_tokens`, and the non-streaming requirement before submission.
119
+ Anthropic remains responsible for validating its evolving Messages parameter
120
+ surface. See [Anthropic Message Batches](docs/anthropic.md) for result routing,
121
+ prompt caching, cancellation, and retention behavior.
122
+
123
+ ## Durable jobs and recovery
124
+
125
+ The manifest separates remote execution from local artifact collection. A
126
+ provider can report a batch complete while its result files are still pending
127
+ locally; that row remains actionable until collection succeeds or the provider
128
+ confirms that the artifacts are no longer available.
129
+
130
+ Submission is durable too. BatchWizard writes an intent before making provider
131
+ requests. If a connection fails after the remote service may have accepted the
132
+ batch, it keeps that intent instead of blindly submitting a duplicate:
133
+
134
+ ```bash
135
+ batchwizard reconcile
136
+ batchwizard reconcile INTENT
137
+ batchwizard reconcile INTENT --batch-id MSGBATCH_ID
138
+ ```
139
+
140
+ OpenAI intents can be matched through Batch metadata. Anthropic does not expose
141
+ equivalent batch metadata, so its uncertain submissions are attached after the
142
+ matching batch is identified with `list-jobs`.
143
+
144
+ The lifecycle and SQLite migrations are documented in
145
+ [Job lifecycle](docs/job-lifecycle.md).
146
+
147
+ ## Result files
148
+
149
+ Provider output stays JSONL and is written atomically:
150
+
151
+ - `<batch_id>_results.jsonl` contains successful rows.
152
+ - `<batch_id>_errors.jsonl` contains request-level failures when present.
153
+
154
+ Anthropic result rows can arrive in any order. BatchWizard preserves each raw row
155
+ and routes `succeeded` results to the results file and `errored`, `expired`, or
156
+ `canceled` results to the errors file.
157
+
158
+ ## Credentials and configuration
159
+
160
+ Environment variables are the preferred way to supply credentials. Keys can
161
+ also be persisted for convenience:
162
+
163
+ ```bash
164
+ batchwizard configure --provider openai --set-key "$OPENAI_API_KEY"
165
+ batchwizard configure --provider anthropic --set-key "$ANTHROPIC_API_KEY"
166
+ batchwizard configure --show --provider openai
167
+ ```
168
+
169
+ Persisted keys are plaintext JSON. BatchWizard writes the configuration
170
+ atomically with owner-only file permissions, but it does not use the operating
171
+ system keychain in v0.5. Treat that file as a secret; keyring-backed storage is
172
+ deferred to v0.6.
173
+
174
+ ## Commands
175
+
176
+ | Command | Purpose |
177
+ | --- | --- |
178
+ | `submit` | Submit files and return after provider acceptance. |
179
+ | `watch` | Resume actionable jobs and collect terminal artifacts. |
180
+ | `process` | Submit, watch, and collect in one invocation. |
181
+ | `status` | Inspect the local SQLite manifest. |
182
+ | `reconcile` | Recover a submission with an uncertain provider outcome. |
183
+ | `list-jobs` | List recent jobs directly from one provider. |
184
+ | `cancel` | Request cancellation for a tracked or provider-native batch ID. |
185
+ | `download` | Collect result artifacts for one batch. |
186
+ | `configure` | Store, inspect, or reset local settings. |
187
+
188
+ Use `batchwizard <command> --help` for the exact arguments and options.
189
+
190
+ ## Development
191
+
192
+ ```bash
193
+ uv sync --all-groups
194
+ uv run pytest
195
+ uv run ruff format --check .
196
+ uv run ruff check .
197
+ uv build
198
+ ```
199
+
200
+ The supported runtime matrix is Python 3.11 through 3.14. The lockfile is
201
+ committed; update it intentionally with `uv lock --upgrade-package <package>`.
202
+
203
+ ## License
204
+
205
+ [MIT](LICENSE)
@@ -0,0 +1,175 @@
1
+ # BatchWizard
2
+
3
+ BatchWizard is one durable CLI for OpenAI and Anthropic batch jobs. Submit
4
+ provider-native JSONL, close the terminal, and come back later: a local SQLite
5
+ manifest remembers what is running, what still needs to be downloaded, and what
6
+ needs your attention.
7
+
8
+ It deliberately does not translate prompts between APIs. OpenAI and Anthropic
9
+ have different request formats and capabilities; BatchWizard gives them one
10
+ operational lifecycle without pretending they are the same protocol.
11
+
12
+ ## Quickstart
13
+
14
+ Install BatchWizard as an isolated Python 3.11+ tool:
15
+
16
+ ```bash
17
+ uv tool install batchwizard
18
+ ```
19
+
20
+ Provide one or both standard API-key environment variables:
21
+
22
+ ```bash
23
+ export OPENAI_API_KEY="..."
24
+ export ANTHROPIC_API_KEY="..."
25
+ ```
26
+
27
+ Submit native JSONL to either provider:
28
+
29
+ ```bash
30
+ batchwizard submit openai.jsonl --endpoint /v1/responses
31
+ batchwizard submit --provider anthropic anthropic.jsonl
32
+ ```
33
+
34
+ The submit process can exit once the providers accept the work. One later
35
+ command resumes every actionable job, grouped by provider:
36
+
37
+ ```bash
38
+ batchwizard watch --output-directory ./results
39
+ batchwizard status --all
40
+ ```
41
+
42
+ `watch` is intentionally provider-free. The manifest records which adapter owns
43
+ each batch, so a single invocation can resume a mixture of OpenAI and Anthropic
44
+ jobs. Missing credentials or a temporary download failure for one provider do
45
+ not erase work or prevent other provider groups from advancing.
46
+
47
+ ## Input formats
48
+
49
+ BatchWizard accepts each provider's native JSONL rather than maintaining a lossy
50
+ common prompt schema.
51
+
52
+ | | OpenAI | Anthropic |
53
+ | --- | --- | --- |
54
+ | Select with | default, or `--provider openai` | `--provider anthropic` |
55
+ | JSONL row | `{"custom_id", "method", "url", "body"}` | `{"custom_id", "params"}` |
56
+ | Model location | `body.model` | `params.model` |
57
+ | Submission | file upload, then Batch creation | requests sent inline to Message Batches |
58
+ | Provider status | Batch `status` | Message Batch `processing_status` |
59
+ | Results | provider output and error files | unordered result stream split by outcome |
60
+ | Recovery after an uncertain submit | automatic intent matching through Batch metadata | manual attachment by batch ID |
61
+
62
+ ### OpenAI
63
+
64
+ ```jsonl
65
+ {"custom_id":"ticket-1","method":"POST","url":"/v1/responses","body":{"model":"gpt-5.4","input":"Classify this ticket as billing, technical, or other."}}
66
+ ```
67
+
68
+ The endpoint passed to BatchWizard must match the `url` in every row:
69
+
70
+ ```bash
71
+ batchwizard submit openai.jsonl --endpoint /v1/responses
72
+ ```
73
+
74
+ `/v1/chat/completions` is the default. BatchWizard also accepts the Responses,
75
+ Embeddings, Completions, Moderations, Images, and Videos Batch API endpoints.
76
+
77
+ ### Anthropic
78
+
79
+ ```jsonl
80
+ {"custom_id":"ticket-1","params":{"model":"claude-opus-4-8","max_tokens":256,"messages":[{"role":"user","content":"Classify this ticket as billing, technical, or other."}]}}
81
+ ```
82
+
83
+ ```bash
84
+ batchwizard submit --provider anthropic anthropic.jsonl
85
+ ```
86
+
87
+ BatchWizard validates the batch envelope, `custom_id` syntax and uniqueness,
88
+ batch size, `max_tokens`, and the non-streaming requirement before submission.
89
+ Anthropic remains responsible for validating its evolving Messages parameter
90
+ surface. See [Anthropic Message Batches](docs/anthropic.md) for result routing,
91
+ prompt caching, cancellation, and retention behavior.
92
+
93
+ ## Durable jobs and recovery
94
+
95
+ The manifest separates remote execution from local artifact collection. A
96
+ provider can report a batch complete while its result files are still pending
97
+ locally; that row remains actionable until collection succeeds or the provider
98
+ confirms that the artifacts are no longer available.
99
+
100
+ Submission is durable too. BatchWizard writes an intent before making provider
101
+ requests. If a connection fails after the remote service may have accepted the
102
+ batch, it keeps that intent instead of blindly submitting a duplicate:
103
+
104
+ ```bash
105
+ batchwizard reconcile
106
+ batchwizard reconcile INTENT
107
+ batchwizard reconcile INTENT --batch-id MSGBATCH_ID
108
+ ```
109
+
110
+ OpenAI intents can be matched through Batch metadata. Anthropic does not expose
111
+ equivalent batch metadata, so its uncertain submissions are attached after the
112
+ matching batch is identified with `list-jobs`.
113
+
114
+ The lifecycle and SQLite migrations are documented in
115
+ [Job lifecycle](docs/job-lifecycle.md).
116
+
117
+ ## Result files
118
+
119
+ Provider output stays JSONL and is written atomically:
120
+
121
+ - `<batch_id>_results.jsonl` contains successful rows.
122
+ - `<batch_id>_errors.jsonl` contains request-level failures when present.
123
+
124
+ Anthropic result rows can arrive in any order. BatchWizard preserves each raw row
125
+ and routes `succeeded` results to the results file and `errored`, `expired`, or
126
+ `canceled` results to the errors file.
127
+
128
+ ## Credentials and configuration
129
+
130
+ Environment variables are the preferred way to supply credentials. Keys can
131
+ also be persisted for convenience:
132
+
133
+ ```bash
134
+ batchwizard configure --provider openai --set-key "$OPENAI_API_KEY"
135
+ batchwizard configure --provider anthropic --set-key "$ANTHROPIC_API_KEY"
136
+ batchwizard configure --show --provider openai
137
+ ```
138
+
139
+ Persisted keys are plaintext JSON. BatchWizard writes the configuration
140
+ atomically with owner-only file permissions, but it does not use the operating
141
+ system keychain in v0.5. Treat that file as a secret; keyring-backed storage is
142
+ deferred to v0.6.
143
+
144
+ ## Commands
145
+
146
+ | Command | Purpose |
147
+ | --- | --- |
148
+ | `submit` | Submit files and return after provider acceptance. |
149
+ | `watch` | Resume actionable jobs and collect terminal artifacts. |
150
+ | `process` | Submit, watch, and collect in one invocation. |
151
+ | `status` | Inspect the local SQLite manifest. |
152
+ | `reconcile` | Recover a submission with an uncertain provider outcome. |
153
+ | `list-jobs` | List recent jobs directly from one provider. |
154
+ | `cancel` | Request cancellation for a tracked or provider-native batch ID. |
155
+ | `download` | Collect result artifacts for one batch. |
156
+ | `configure` | Store, inspect, or reset local settings. |
157
+
158
+ Use `batchwizard <command> --help` for the exact arguments and options.
159
+
160
+ ## Development
161
+
162
+ ```bash
163
+ uv sync --all-groups
164
+ uv run pytest
165
+ uv run ruff format --check .
166
+ uv run ruff check .
167
+ uv build
168
+ ```
169
+
170
+ The supported runtime matrix is Python 3.11 through 3.14. The lockfile is
171
+ committed; update it intentionally with `uv lock --upgrade-package <package>`.
172
+
173
+ ## License
174
+
175
+ [MIT](LICENSE)