taskproof 0.3.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 (77) hide show
  1. taskproof-0.3.0/LICENSE +201 -0
  2. taskproof-0.3.0/PKG-INFO +470 -0
  3. taskproof-0.3.0/README.md +450 -0
  4. taskproof-0.3.0/pyproject.toml +46 -0
  5. taskproof-0.3.0/setup.cfg +4 -0
  6. taskproof-0.3.0/src/taskproof/__init__.py +23 -0
  7. taskproof-0.3.0/src/taskproof/__main__.py +8 -0
  8. taskproof-0.3.0/src/taskproof/adapters/__init__.py +101 -0
  9. taskproof-0.3.0/src/taskproof/adapters/base.py +228 -0
  10. taskproof-0.3.0/src/taskproof/adapters/claude.py +46 -0
  11. taskproof-0.3.0/src/taskproof/adapters/codex.py +140 -0
  12. taskproof-0.3.0/src/taskproof/adapters/custom.py +61 -0
  13. taskproof-0.3.0/src/taskproof/adapters/gemini.py +45 -0
  14. taskproof-0.3.0/src/taskproof/adapters/opencode.py +46 -0
  15. taskproof-0.3.0/src/taskproof/api/__init__.py +1 -0
  16. taskproof-0.3.0/src/taskproof/api/server.py +822 -0
  17. taskproof-0.3.0/src/taskproof/cli.py +1400 -0
  18. taskproof-0.3.0/src/taskproof/concurrency.py +329 -0
  19. taskproof-0.3.0/src/taskproof/dispatch.py +2289 -0
  20. taskproof-0.3.0/src/taskproof/errors.py +55 -0
  21. taskproof-0.3.0/src/taskproof/ledger.py +185 -0
  22. taskproof-0.3.0/src/taskproof/models.py +155 -0
  23. taskproof-0.3.0/src/taskproof/registry.py +1585 -0
  24. taskproof-0.3.0/src/taskproof/schemas/result.json +58 -0
  25. taskproof-0.3.0/src/taskproof/sql/schema.sql +70 -0
  26. taskproof-0.3.0/src/taskproof/storage.py +372 -0
  27. taskproof-0.3.0/src/taskproof/verify.py +615 -0
  28. taskproof-0.3.0/src/taskproof/web/assets/MatrixView-BM8nu9s2.css +446 -0
  29. taskproof-0.3.0/src/taskproof/web/assets/MatrixView-BM8nu9s2.css.gz +0 -0
  30. taskproof-0.3.0/src/taskproof/web/assets/MatrixView-BMsawnxh.js +475 -0
  31. taskproof-0.3.0/src/taskproof/web/assets/MatrixView-BMsawnxh.js.gz +0 -0
  32. taskproof-0.3.0/src/taskproof/web/assets/ProjectsView-BcXcx5Gw.js +302 -0
  33. taskproof-0.3.0/src/taskproof/web/assets/ProjectsView-BcXcx5Gw.js.gz +0 -0
  34. taskproof-0.3.0/src/taskproof/web/assets/ProjectsView-CqNFL-fi.css +23 -0
  35. taskproof-0.3.0/src/taskproof/web/assets/SettingsView-D_-waf0s.js +585 -0
  36. taskproof-0.3.0/src/taskproof/web/assets/SettingsView-D_-waf0s.js.gz +0 -0
  37. taskproof-0.3.0/src/taskproof/web/assets/SettingsView-aqTS3ubB.css +19 -0
  38. taskproof-0.3.0/src/taskproof/web/assets/TaskDrawer-6JoGTH0s.js +597 -0
  39. taskproof-0.3.0/src/taskproof/web/assets/TaskDrawer-6JoGTH0s.js.gz +0 -0
  40. taskproof-0.3.0/src/taskproof/web/assets/TaskDrawer-N299VKzd.css +465 -0
  41. taskproof-0.3.0/src/taskproof/web/assets/TaskDrawer-N299VKzd.css.gz +0 -0
  42. taskproof-0.3.0/src/taskproof/web/assets/TasksView-BWhSHCHi.js +114 -0
  43. taskproof-0.3.0/src/taskproof/web/assets/TasksView-BWhSHCHi.js.gz +0 -0
  44. taskproof-0.3.0/src/taskproof/web/assets/TasksView-Bn08731V.css +30 -0
  45. taskproof-0.3.0/src/taskproof/web/assets/icon-Dw-ohsdc.png +0 -0
  46. taskproof-0.3.0/src/taskproof/web/assets/index-B-PLdDbR.js +75421 -0
  47. taskproof-0.3.0/src/taskproof/web/assets/index-B-PLdDbR.js.gz +0 -0
  48. taskproof-0.3.0/src/taskproof/web/assets/index-NKj7kbYl.css +1234 -0
  49. taskproof-0.3.0/src/taskproof/web/assets/index-NKj7kbYl.css.gz +0 -0
  50. taskproof-0.3.0/src/taskproof/web/index.html +23 -0
  51. taskproof-0.3.0/src/taskproof.egg-info/PKG-INFO +470 -0
  52. taskproof-0.3.0/src/taskproof.egg-info/SOURCES.txt +75 -0
  53. taskproof-0.3.0/src/taskproof.egg-info/dependency_links.txt +1 -0
  54. taskproof-0.3.0/src/taskproof.egg-info/entry_points.txt +2 -0
  55. taskproof-0.3.0/src/taskproof.egg-info/top_level.txt +1 -0
  56. taskproof-0.3.0/tests/test_accept_rerun.py +529 -0
  57. taskproof-0.3.0/tests/test_adapters.py +195 -0
  58. taskproof-0.3.0/tests/test_adapters_parse.py +43 -0
  59. taskproof-0.3.0/tests/test_api.py +355 -0
  60. taskproof-0.3.0/tests/test_api_cors.py +179 -0
  61. taskproof-0.3.0/tests/test_api_log.py +493 -0
  62. taskproof-0.3.0/tests/test_board_cli.py +215 -0
  63. taskproof-0.3.0/tests/test_board_serve.py +292 -0
  64. taskproof-0.3.0/tests/test_cli.py +823 -0
  65. taskproof-0.3.0/tests/test_concurrency.py +147 -0
  66. taskproof-0.3.0/tests/test_concurrency_race.py +98 -0
  67. taskproof-0.3.0/tests/test_control_surface.py +630 -0
  68. taskproof-0.3.0/tests/test_dispatch.py +1784 -0
  69. taskproof-0.3.0/tests/test_ledger.py +70 -0
  70. taskproof-0.3.0/tests/test_project_view.py +248 -0
  71. taskproof-0.3.0/tests/test_registry.py +644 -0
  72. taskproof-0.3.0/tests/test_registry_write.py +373 -0
  73. taskproof-0.3.0/tests/test_result_schema.py +359 -0
  74. taskproof-0.3.0/tests/test_scan_assets.py +119 -0
  75. taskproof-0.3.0/tests/test_scope.py +257 -0
  76. taskproof-0.3.0/tests/test_storage.py +195 -0
  77. taskproof-0.3.0/tests/test_verify.py +524 -0
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,470 @@
1
+ Metadata-Version: 2.4
2
+ Name: taskproof
3
+ Version: 0.3.0
4
+ Summary: A conveyor belt for AI coding agents: dispatch, independently verify, record.
5
+ Author-email: HaoHaoP <HaoHaoP@HaoHaoP.com>
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/HaoHaoP/taskproof
8
+ Project-URL: Issues, https://github.com/HaoHaoP/taskproof/issues
9
+ Keywords: ai-agents,orchestration,verification,codex,claude-code,cli
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: Apache Software License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown
18
+ License-File: LICENSE
19
+ Dynamic: license-file
20
+
21
+ # taskproof
22
+
23
+ **English** · [简体中文](README.zh-CN.md)
24
+
25
+ <p align="center"><img src="docs/assets/icon.png" width="128" alt="taskproof"></p>
26
+
27
+ A conveyor belt for AI coding agents.
28
+
29
+ It does not decide *what* to do. It guarantees that whatever gets dispatched is
30
+ **independently verified** and **recorded** — so you never have to trust an
31
+ agent's own claim that it finished.
32
+
33
+ <p align="center"><img src="docs/assets/demo.gif" width="820" alt="A card is dispatched, the agent claims it is done, and the machine disagrees."></p>
34
+
35
+ *A card is dispatched. The agent says it finished. The record says it changed nothing — the acceptance command is what decides.*
36
+
37
+ **Status: stage 1 is usable, and the stage-2 desktop console is here.** The
38
+ engine, CLI, a browser board, a local read-only REST API, and an Electron console
39
+ in `desktop/` are implemented. See [`docs/DESIGN.md`](docs/DESIGN.md) for the
40
+ full design and the decision log, and
41
+ [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for how each mechanism works today,
42
+ with diagrams.
43
+
44
+ ## Install
45
+
46
+ Two ways in: the desktop console if you do not write code, the command line if
47
+ you do.
48
+
49
+ ### Desktop console
50
+
51
+ Download the installer for your platform from the
52
+ [GitHub Releases](https://github.com/HaoHaoP/taskproof/releases) page:
53
+
54
+ - macOS arm64 (Apple silicon) — `.dmg`
55
+ - Windows x64 — `.exe`
56
+ - Linux x64 — `.AppImage` / `.deb`
57
+
58
+ The installers are **not signed and not notarised**:
59
+
60
+ - **macOS is arm64 only** (no Intel or Rosetta build): on first launch,
61
+ right-click the app → Open, or run
62
+ `xattr -d com.apple.quarantine /Applications/Taskproof.app`.
63
+ - **Windows 10+**: SmartScreen shows a warning on first launch.
64
+
65
+ Minimum versions are macOS 11+, Windows 10+, or a current mainstream Linux
66
+ distribution. Each installer **ships its own Python runtime**, so there is
67
+ nothing to `pip install` — but it does need a system **`git`** for worktrees and
68
+ the protected-path gate. Without git the settings page says so, and everything
69
+ else keeps working.
70
+
71
+ ### Command line
72
+
73
+ ```bash
74
+ pipx install git+https://github.com/HaoHaoP/taskproof
75
+ ```
76
+
77
+ Or download the wheel from the same Release and install the local file:
78
+
79
+ ```bash
80
+ pipx install ./taskproof-<version>-py3-none-any.whl
81
+ ```
82
+
83
+ The wheel's filename carries the version — take it from the Release you just
84
+ downloaded; there is no unpinned wheel name to copy.
85
+
86
+ Or run from a source checkout:
87
+
88
+ ```bash
89
+ pip install -e .
90
+ ```
91
+
92
+ **There is no `taskproof` package on PyPI.** Do not look for it there; use one of
93
+ the three installs above.
94
+
95
+ ## Run a task
96
+
97
+ ```bash
98
+ taskproof init
99
+ taskproof register /absolute/path/to/your/repo
100
+ taskproof run <project> "fix the failing test"
101
+ ```
102
+
103
+ `run` is the whole lifecycle in one line: it **dispatches** the card to a
104
+ pluggable adapter (codex / claude / gemini / opencode, or `custom:<cmd>`), then
105
+ **independently runs the acceptance command** from the registry once the agent
106
+ exits, and finally **records** every step in the audit ledger. The agent's own
107
+ "done" is never the verdict.
108
+
109
+ `taskproof tasks` lists what is in flight; `taskproof show <id>` and
110
+ `taskproof log <id>` read one card back.
111
+
112
+ The desktop console shares the same ledger. On first launch it creates
113
+ `~/.taskproof` as an **empty workspace** — a `[defaults]` table and a commented
114
+ example, with **no sample projects and no sample tasks** — and the board's empty
115
+ state points you at the Projects page (or `taskproof register <path>`). Because
116
+ the console and the CLI read the same `~/.taskproof`, either one sees the other's
117
+ cards.
118
+
119
+ [`docs/WALKTHROUGH.md`](docs/WALKTHROUGH.md) runs this end to end on a throwaway
120
+ example — including the case where the agent reports success and the acceptance
121
+ command disagrees.
122
+
123
+ ---
124
+
125
+ ## Dispatching work
126
+
127
+ The usage this project is extracted from is a *discipline for the agent that
128
+ hands out the cards*, and it now ships in the repository as a skill:
129
+
130
+ ```
131
+ skills/taskproof-dispatch/SKILL.md
132
+ skills/taskproof-dispatch/SKILL.zh-CN.md
133
+ ```
134
+
135
+ It is the **operating manual for an AI coding agent** — the orchestrating one
136
+ that plans the work, registers the repositories, writes each card, and dispatches
137
+ it to a worker. Taskproof itself does not plan anything (see Non-goals); this
138
+ skill is the missing half: how to drive the tool without the failure modes the
139
+ hard way. Both languages ship: `SKILL.md` (English) and `SKILL.zh-CN.md`
140
+ (简体中文).
141
+
142
+ The rules in it are not invented; each is a lesson from breaking something.
143
+ `pkill -f` is the classic one, for instance: a card is passed as process argv, so
144
+ the pattern also matches the dispatcher itself and kills the run — exactly the
145
+ kind of practical rule the skill exists to record. It turns the
146
+ lessons of this build into steps you can copy: register a project,
147
+ put a card in a file and pass it with `$(cat …)`, fire it with an explicit
148
+ `--adapter` and `--timeout`, then read state back with `taskproof tasks --all`
149
+ and `taskproof log <id>`. Above all it pins four things that were learned by
150
+ breaking them:
151
+
152
+ - **Serialisation is a property of the group, not a habit.** Different groups
153
+ are meant to run in parallel up to the global cap; the only reason to serialise
154
+ is "same group *and* overlapping files".
155
+ - **The real registry is never a test target.** UI verification runs against a
156
+ throwaway profile and workspace under `/tmp`; a worker that deletes against the
157
+ live `~/.taskproof/projects.toml` takes a user's project with it.
158
+ - **Never `pkill -f`.** A card is passed as process argv, so its text is in the
159
+ dispatcher's own command line — `pkill -f` matches the dispatcher and kills the
160
+ run (exit -15, no task, empty log). Kill by PID.
161
+ - **Review is not a self-report.** The main agent reads the acceptance result the
162
+ machine already produced and asserts the dimensions it cannot see; re-running the
163
+ command is for the three exceptions only — `SKIPPED`, a coverage gap, a green that
164
+ smells false. "The worker said done" is not evidence.
165
+
166
+ ## The problem
167
+
168
+ Every orchestration project on GitHub competes on *how many agents it can run*,
169
+ *how many CLIs it supports*, and *how pretty the UI is*. Almost none of them
170
+ talk about the thing that actually bites you in daily use:
171
+
172
+ **Agents lie.**
173
+
174
+ Real incidents from the workflow this project is extracted from:
175
+
176
+ | What the agent said | What actually happened |
177
+ |---|---|
178
+ | "Verified in browser, screenshots attached" | Event stream contained zero browser activity |
179
+ | (silently, beyond scope) | Attempted an HTTP login against a local app using a guessed weak credential |
180
+ | Task complete, result file written | The JSON had been wrapped in a markdown fence, so the structured parse failed and the run looked like it did nothing |
181
+ | Task complete | The acceptance command failed when run independently |
182
+
183
+ None of these are exotic. They are the normal failure mode of handing file-writing
184
+ work to an autonomous process.
185
+
186
+ ## What taskproof is
187
+
188
+ A small, mechanical dispatch layer that wraps every agent invocation in
189
+ discipline:
190
+
191
+ - **Independent verification** — the agent's self-report never counts as success.
192
+ The acceptance command from the project registry is run afterwards, by taskproof.
193
+ - **Protected paths** — a registry entry can declare paths an agent must not touch.
194
+ - **Structured result contract** — a defined output shape, with documented
195
+ degradation for CLIs that cannot produce it.
196
+ - **Append-only audit trail** — every dispatch, verification, failure and retry is
197
+ recorded, so "what happened yesterday" is a query, not a memory exercise.
198
+ - **Meaningful exit codes** — callers can distinguish "the agent failed" from
199
+ "the agent succeeded but verification failed".
200
+ - **No LLM inside** — taskproof does not plan, decompose, or decide. Any agent
201
+ (or a human, or a script) can drive it.
202
+
203
+ ## Shape
204
+
205
+ ```
206
+ taskproof run <project> "<task>" # dispatch, then verify, then record
207
+ taskproof wait <id> # block until a card reaches a terminal state
208
+ taskproof tasks / show / log # inspect state
209
+ taskproof board # serve the board and open a browser (blocks)
210
+ taskproof board --serve 8788 # serve the board only, no browser (blocks)
211
+ taskproof api --port 8787 # local read-only REST API for clients
212
+ ```
213
+
214
+ - Python, standard library only, `pipx install`-able
215
+ - SQLite for state (transactional claims, not lock files)
216
+ - JSONL audit stream, write-only, rotated monthly
217
+ - Pluggable adapters (codex / claude / gemini / opencode + any command)
218
+
219
+ ## The concurrency cap
220
+
221
+ The global cap is workspace-level and is always reported as a **value plus where
222
+ it came from**, never a bare number. It has three sources, in precedence order:
223
+
224
+ 1. `run --cap N` — a one-off for this dispatch only, never persisted;
225
+ 2. `[defaults] concurrency` in the registry;
226
+ 3. auto-detected from the machine.
227
+
228
+ The auto fallback is deliberately conservative — one slot is a whole extra
229
+ coding agent:
230
+
231
+ ```
232
+ cap = clamp(2, cores // 4, 6) # at most one slot per four cores
233
+ if RAM < 8 GiB: cap = 2 # a small box cannot afford cores // 4
234
+ if the core count is unknown: cap = 3
235
+ ```
236
+
237
+ Inspect the effective value and its source:
238
+
239
+ ```bash
240
+ taskproof config --show
241
+ ```
242
+
243
+ Change the persisted value, comment-preserving:
244
+
245
+ ```bash
246
+ taskproof config --concurrency N
247
+ ```
248
+
249
+ `run --cap N` overrides it for one dispatch only. **Lowering the cap is not
250
+ retroactive**: it never touches a card already running — the CLI prints the cards
251
+ that now exceed the new cap and leaves the decision to you.
252
+
253
+ ## Terminal states and the two gates
254
+
255
+ Two terminal states are deliberately different:
256
+
257
+ - **`blocked`** — a boundary breach: the run touched a path the registry forbids.
258
+ The acceptance may even have passed; the gate is what stopped it.
259
+ - **`failed`** — the acceptance ran and went red, or the adapter itself failed;
260
+ the work went wrong.
261
+
262
+ Both are cleared by `accept`, which is a human registration, not a fresh verdict:
263
+
264
+ ```bash
265
+ taskproof accept <id> # blocked: a note is optional
266
+ taskproof accept <id> --note "why" # failed: a note is required
267
+ ```
268
+
269
+ `accept` **never re-runs acceptance and never rewrites the recorded verdict** —
270
+ the run's own facts stay authoritative. Closing a `failed` card requires a note,
271
+ because that is a human sign-off and the reason has to survive in the ledger.
272
+ `taskproof rerun <id>` starts a fresh card from a terminal one and links the two
273
+ both ways (`rerun_of` / `rerun_as`).
274
+
275
+ On the board, `blocked` gets its own **Needs review** column, kept out of the
276
+ failure column.
277
+
278
+ ## The desktop console
279
+
280
+ `desktop/` is the stage-2 console: an **Electron + Vue 3** app (Element Plus,
281
+ UnoCSS, Pinia, vue-i18n). It is the same renderer `taskproof board` serves in a
282
+ browser — one rendering layer with two hosts. It is bilingual — zh-CN and en, following the system locale with an
283
+ English fallback.
284
+
285
+ <p align="center"><img src="docs/assets/board.png" width="900" alt="The board: a not-passing column next to a done column."></p>
286
+
287
+ *The board — the run the agent called done sits under **not passing**; the run that really changed the file sits under **done**.*
288
+
289
+ The process model is the interesting part. The app spawns the local service
290
+ itself — `taskproof api --port 0` — reads the bound port from the child's stdout,
291
+ and terminates the child on exit. Data comes from that loopback, **read-only**
292
+ REST API; nothing leaves `127.0.0.1`.
293
+
294
+ The REST surface is **read-only**. Every mutation lives in the CLI — registering
295
+ a project, editing its registry entry, dispatching, cancelling, accepting and
296
+ removing. The API itself only serves reads: it mints no session token and exposes
297
+ no write endpoint, so a write-shaped request to an old path is a plain **404**.
298
+
299
+ What the console does today:
300
+
301
+ - **Columns** — running / verifying / done / cancelled / needs review / not
302
+ passing. A column header can be hidden with the `?hide=` query parameter.
303
+ - **Every column's display cap is yours to set**, in the column's own header
304
+ (`- 10 +`, five choices: 5 / 10 / 20 / 50 / All). The defaults are the board
305
+ you already know -- done and cancelled fold to the ten most recent, the live
306
+ columns stay unfolded. To show a whole column, choose **All**; there is no
307
+ separate expand switch.
308
+ - A **"acceptance passed"** badge on a blocked card whose acceptance went green.
309
+ - **Writes are CLI-only.** The console is a viewer over the read-only API:
310
+ dispatch, accept and registry edits all go through `taskproof`, never the UI.
311
+ - A settings page that shows the **effective cap and where it came from**, plus
312
+ the resolved launcher (bundled runtime / `taskproof` on PATH / a custom
313
+ command).
314
+ - A **tray icon**, a **Dock badge** (the not-passing count) and a
315
+ **launch-at-login** switch.
316
+
317
+ ## Registry
318
+
319
+ Everything taskproof may dispatch is declared in one TOML file in the workspace
320
+ (`~/.taskproof/projects.toml`) in two layers: a **project** (the repository and
321
+ its default path) and one or more **taskgroups** (the lanes it dispatches onto,
322
+ each with its own acceptance command and lock).
323
+
324
+ A lane may also declare a **workspace of its own** (`workspace = "worktree"`):
325
+ one git worktree beside the repository, created the first time a card actually
326
+ fires into that lane and reused from then on, with dependency directories
327
+ symlinked in from the main checkout (`link = [...]`) so nothing is reinstalled.
328
+ `taskproof workspaces` lists them; `taskproof workspace-rm <lane>` prints the
329
+ evidence and deletes one. `--worktree` remains the one-off. The fields are in
330
+ `docs/REGISTRY.md`.
331
+
332
+ ```toml
333
+ [[project]]
334
+ id = "my-app"
335
+ path = "/absolute/path/to/my-app"
336
+
337
+ [[taskgroup]]
338
+ id = "my-app"
339
+ project = "my-app"
340
+ verify = "npm run build" # run by taskproof, after the agent exits
341
+ verify_kind = "build" # check | build | none
342
+ ```
343
+
344
+ A flat, older `[[project]]` block that carries the acceptance command still
345
+ works unchanged: it reads as a project plus a same-named lane. `taskproof
346
+ register <path>` appends a `[[taskgroup]]` (add `--project` to hang it off an
347
+ existing project). See
348
+ [`examples/projects.example.toml`](examples/projects.example.toml) for a
349
+ commented starting point, and [`docs/REGISTRY.md`](docs/REGISTRY.md) for the
350
+ field reference and the list of hard errors.
351
+
352
+ The board's left rail groups by **project** — one row per project,
353
+ with the lanes it owns shown on hover — and each task card names the lane it
354
+ ran on.
355
+
356
+ ## Safety and hygiene
357
+
358
+ - **Protected paths are fingerprinted, not just diffed.** Forbidden paths are
359
+ snapshotted before and after a run, so a change inside `.git/` or an ignored
360
+ build/dependency directory is caught too, not only what `git status` happens to
361
+ report. A tree larger than 20000 entries is sampled, and the audit event records
362
+ `snapshot_truncated: true`.
363
+ - **An asset scan runs before every push** (`tools/scan_assets.py`, wired through
364
+ `core.hooksPath`). It ships generic **shape** rules only, so the scanner is
365
+ never a no-op.
366
+ - **The organisation-specific words live outside the repository**
367
+ (`~/.taskproof/asset-patterns.txt`, or `$TASKPROOF_ASSET_PATTERNS`). A scanner
368
+ that embedded the names it protects would leak exactly those names.
369
+
370
+ ## The enum contract
371
+
372
+ Status words, `verify_kind` values and exit-code meanings are one generated
373
+ artefact — [`contract/enums.json`](contract/enums.json) — produced from the
374
+ Python constants by `tools/gen_contract.py`. The TypeScript side imports it
375
+ instead of re-typing it; a status that exists in Python but not in the frontend
376
+ is a task that silently vanishes from the board. CI runs the check, so the two
377
+ languages cannot drift:
378
+
379
+ ```bash
380
+ PYTHONPATH=src python3 tools/gen_contract.py --check
381
+ ```
382
+
383
+ ## Development
384
+
385
+ Run the CLI from a source checkout:
386
+
387
+ ```bash
388
+ pip install -e .
389
+ taskproof --version
390
+ ```
391
+
392
+ Or, without installing:
393
+
394
+ ```bash
395
+ PYTHONPATH=src python3 -m taskproof doctor
396
+ ```
397
+
398
+ Two test suites, both green at the time of writing:
399
+
400
+ - **Python** — `PYTHONPATH=src python3 -m unittest discover -s tests` (448 tests).
401
+ - **Desktop** — `cd desktop && npm install && npm test` (258 tests). `npm run
402
+ build` runs the type-check and a production build of all three targets.
403
+
404
+ CI runs three checks: the asset scan (`tools/scan_assets.py`), the enum-contract
405
+ consistency check (`PYTHONPATH=src python3 tools/gen_contract.py --check`), and
406
+ the desktop build + tests.
407
+
408
+ The animation at the top of this page is reproducible: `tools/demo/` holds the
409
+ throwaway `/tmp` workspace builder and the `vhs` tape.
410
+
411
+ ## Known limitations
412
+
413
+ - **Unsigned and not notarised.** macOS shows a Gatekeeper prompt on first launch
414
+ (right-click → Open, or clear the quarantine bit); Windows shows a SmartScreen
415
+ warning.
416
+ - **macOS is arm64 only.** There is no Intel build and no Rosetta path.
417
+ - **The gate needs `git`.** Without a system `git`, worktrees and the
418
+ protected-path gate are unavailable; the settings page says so and everything
419
+ else runs as usual.
420
+ - **The board fetches at most 2000 rows at a time.** At that ceiling it shows
421
+ **"fetch limit reached"** rather than implying it has everything.
422
+ - **Windows and Linux installers are built by CI's native runners.** A local
423
+ machine can only build the macOS package.
424
+
425
+ ## Documentation
426
+
427
+ The docs ship in pairs, English and Simplified Chinese:
428
+
429
+ | English | 中文 |
430
+ |---|---|
431
+ | [`README.md`](README.md) | [`README.zh-CN.md`](README.zh-CN.md) |
432
+ | [`docs/DESIGN.md`](docs/DESIGN.md) | [`docs/DESIGN.zh-CN.md`](docs/DESIGN.zh-CN.md) |
433
+ | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | [`docs/ARCHITECTURE.zh-CN.md`](docs/ARCHITECTURE.zh-CN.md) |
434
+ | [`docs/REGISTRY.md`](docs/REGISTRY.md) | [`docs/REGISTRY.zh-CN.md`](docs/REGISTRY.zh-CN.md) |
435
+ | [`docs/WALKTHROUGH.md`](docs/WALKTHROUGH.md) | [`docs/WALKTHROUGH.zh-CN.md`](docs/WALKTHROUGH.zh-CN.md) |
436
+
437
+ The dispatch discipline is a skill, in [`skills/taskproof-dispatch/SKILL.md`](skills/taskproof-dispatch/SKILL.md) (English) and [`skills/taskproof-dispatch/SKILL.zh-CN.md`](skills/taskproof-dispatch/SKILL.zh-CN.md) (简体中文).
438
+
439
+ ## Icon
440
+
441
+ `docs/assets/icon.png` is a 256 px copy of the app icon, small enough to live in
442
+ the repository. The source was an AI-generated mark; the checkerboard that got
443
+ baked into the PNG was cut out, the artwork was laid on Apple's 824/1024 grid
444
+ (the mark occupies 824 of the 1024 px canvas so the rounded-corner margin is
445
+ correct), and `sips` produced the 256 px copy used at the top of this page.
446
+
447
+ ## Non-goals
448
+
449
+ - No built-in LLM orchestration
450
+ - No agent-to-agent conversation layer
451
+ - No code generation or editing of its own
452
+ - No automated `git` write operations
453
+
454
+ ## Exit codes
455
+
456
+ Exit codes are part of the contract for callers (scripts, agents, CI): they tell
457
+ you *why* a run ended without parsing stdout.
458
+
459
+ | Code | Meaning |
460
+ |---|---|
461
+ | 0 | success |
462
+ | 2 | registry problem (unknown project, missing/malformed registry, duplicate id) |
463
+ | 64 | usage error (bad flags, missing path, unknown task or adapter) |
464
+ | 70 | adapter (agent) failure — the CLI failed to run, or its result could not be parsed |
465
+ | 71 | verification or artifact self-check failure (acceptance command failed) |
466
+ | 75 | concurrency limit reached (same-group busy, or the global cap is full) |
467
+
468
+ ## License
469
+
470
+ Apache-2.0. See [`LICENSE`](LICENSE).