do-again 0.2.0__tar.gz → 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 (55) hide show
  1. {do_again-0.2.0 → do_again-0.3.0}/.github/workflows/ci.yml +35 -0
  2. {do_again-0.2.0 → do_again-0.3.0}/.gitignore +2 -0
  3. do_again-0.3.0/PKG-INFO +237 -0
  4. do_again-0.3.0/README.md +202 -0
  5. do_again-0.3.0/ROADMAP.md +61 -0
  6. {do_again-0.2.0 → do_again-0.3.0}/package-lock.json +2 -2
  7. {do_again-0.2.0 → do_again-0.3.0}/package.json +3 -2
  8. {do_again-0.2.0 → do_again-0.3.0}/pyproject.toml +1 -1
  9. do_again-0.3.0/src/do_again/browser/__init__.py +35 -0
  10. do_again-0.3.0/src/do_again/browser/cdp.py +373 -0
  11. do_again-0.3.0/src/do_again/browser/errors.py +6 -0
  12. do_again-0.3.0/src/do_again/browser/runtime.py +1200 -0
  13. do_again-0.3.0/src/do_again/cli.py +537 -0
  14. do_again-0.3.0/src/do_again/core/agent.py +740 -0
  15. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/core/executor.py +75 -48
  16. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/core/schema.py +13 -3
  17. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/default_policy.json +43 -61
  18. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/detect.py +1 -1
  19. do_again-0.3.0/src/do_again/platforms/process.py +37 -0
  20. do_again-0.3.0/src/do_again/service/daemon.py +240 -0
  21. do_again-0.3.0/src/do_again/service/runtime.py +826 -0
  22. {do_again-0.2.0 → do_again-0.3.0}/templates/policy.json +43 -61
  23. do_again-0.3.0/tests/test_agent_claims.py +169 -0
  24. do_again-0.3.0/tests/test_browser.py +576 -0
  25. do_again-0.3.0/tests/test_browser_hardening.py +289 -0
  26. do_again-0.3.0/tests/test_cdp.py +59 -0
  27. do_again-0.3.0/tests/test_cli.py +230 -0
  28. do_again-0.3.0/tests/test_daemon.py +80 -0
  29. {do_again-0.2.0 → do_again-0.3.0}/tests/test_executor.py +181 -8
  30. {do_again-0.2.0 → do_again-0.3.0}/tests/test_platforms.py +11 -1
  31. do_again-0.3.0/tests/test_service.py +248 -0
  32. do_again-0.3.0/tools/browser_smoke.py +234 -0
  33. do_again-0.3.0/tools/verify_artifacts.py +62 -0
  34. do_again-0.2.0/PKG-INFO +0 -166
  35. do_again-0.2.0/README.md +0 -131
  36. do_again-0.2.0/src/do_again/cli.py +0 -137
  37. do_again-0.2.0/src/do_again/core/agent.py +0 -402
  38. do_again-0.2.0/src/do_again/service/runtime.py +0 -372
  39. do_again-0.2.0/tests/test_service.py +0 -62
  40. {do_again-0.2.0 → do_again-0.3.0}/.github/dependabot.yml +0 -0
  41. {do_again-0.2.0 → do_again-0.3.0}/.github/workflows/npm-release.yml +0 -0
  42. {do_again-0.2.0 → do_again-0.3.0}/.github/workflows/release.yml +0 -0
  43. {do_again-0.2.0 → do_again-0.3.0}/.npmignore +0 -0
  44. {do_again-0.2.0 → do_again-0.3.0}/LICENSE +0 -0
  45. {do_again-0.2.0 → do_again-0.3.0}/bin/do-again.js +0 -0
  46. {do_again-0.2.0 → do_again-0.3.0}/npm-tests/launcher.test.js +0 -0
  47. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/__init__.py +0 -0
  48. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/core/__init__.py +0 -0
  49. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/__init__.py +0 -0
  50. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/base.py +0 -0
  51. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/linux.py +0 -0
  52. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/macos.py +0 -0
  53. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/platforms/windows.py +0 -0
  54. {do_again-0.2.0 → do_again-0.3.0}/src/do_again/service/__init__.py +0 -0
  55. {do_again-0.2.0 → do_again-0.3.0}/tools/check_release_version.py +0 -0
@@ -39,6 +39,23 @@ jobs:
39
39
  - run: python -m pip check
40
40
  - run: python -m unittest discover -s tests -v
41
41
  - run: do-again doctor
42
+ - run: do-again status
43
+
44
+ browser-smoke:
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ os: [ubuntu-latest, macos-latest, windows-latest]
49
+ runs-on: ${{ matrix.os }}
50
+ steps:
51
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
52
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
53
+ with:
54
+ python-version: "3.13"
55
+ - run: python -m pip install .
56
+ - run: python tools/browser_smoke.py
57
+ - if: runner.os == 'macOS'
58
+ run: python tools/browser_smoke.py --background
42
59
 
43
60
  npm-package:
44
61
  strategy:
@@ -58,3 +75,21 @@ jobs:
58
75
  - run: npm ci
59
76
  - run: npm test
60
77
  - run: npm pack --dry-run --ignore-scripts
78
+
79
+ artifact-installs:
80
+ runs-on: ubuntu-latest
81
+ steps:
82
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
83
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
84
+ with:
85
+ python-version: "3.13"
86
+ - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38
87
+ with:
88
+ node-version: "24"
89
+ package-manager-cache: false
90
+ - run: python -m pip install build twine
91
+ - run: python -m build
92
+ - run: python -m twine check dist/*
93
+ - run: npm ci
94
+ - run: npm test
95
+ - run: python tools/verify_artifacts.py
@@ -7,3 +7,5 @@ build/
7
7
  .DS_Store
8
8
  .env
9
9
  .env.*
10
+ *.tgz
11
+ .do_again/
@@ -0,0 +1,237 @@
1
+ Metadata-Version: 2.5
2
+ Name: do-again
3
+ Version: 0.3.0
4
+ Summary: Policy-controlled local execution for agent-driven development workflows
5
+ Project-URL: Homepage, https://github.com/Tran-Steven/do-again
6
+ Project-URL: Repository, https://github.com/Tran-Steven/do-again
7
+ Project-URL: Issues, https://github.com/Tran-Steven/do-again/issues
8
+ Author: Steven Tran
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Steven Tran
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
+ License-File: LICENSE
19
+ Keywords: agents,automation,developer-tools,github,local-execution,orchestration
20
+ Classifier: Development Status :: 3 - Alpha
21
+ Classifier: Environment :: Console
22
+ Classifier: Intended Audience :: Developers
23
+ Classifier: License :: OSI Approved :: MIT License
24
+ Classifier: Operating System :: MacOS
25
+ Classifier: Operating System :: Microsoft :: Windows
26
+ Classifier: Operating System :: POSIX :: Linux
27
+ Classifier: Programming Language :: Python :: 3
28
+ Classifier: Programming Language :: Python :: 3.11
29
+ Classifier: Programming Language :: Python :: 3.12
30
+ Classifier: Programming Language :: Python :: 3.13
31
+ Classifier: Topic :: Software Development :: Build Tools
32
+ Classifier: Topic :: Software Development :: Version Control :: Git
33
+ Requires-Python: >=3.11
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Do Again
37
+
38
+ [![CI](https://github.com/Tran-Steven/do-again/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Tran-Steven/do-again/actions/workflows/ci.yml)
39
+ [![PyPI](https://img.shields.io/pypi/v/do-again.svg?cacheSeconds=300)](https://pypi.org/project/do-again/)
40
+ [![npm](https://img.shields.io/npm/v/do-again.svg?cacheSeconds=300)](https://www.npmjs.com/package/do-again)
41
+ [![Python](https://img.shields.io/pypi/pyversions/do-again.svg?cacheSeconds=300)](https://pypi.org/project/do-again/)
42
+ [![License](https://img.shields.io/github/license/Tran-Steven/do-again.svg?cacheSeconds=300)](LICENSE)
43
+
44
+ Do Again gives AI coding agents a policy-controlled way to execute work on a local development machine, return auditable receipts and artifacts, and keep iterating when another pass is needed.
45
+
46
+ ## How it works
47
+
48
+ ```text
49
+ agent
50
+ |
51
+ | request
52
+ v
53
+ operator-control branch
54
+ |
55
+ v
56
+ Do Again -> policy validation -> local command / file / test / git action
57
+ ^ |
58
+ | |
59
+ +----------- receipt / artifact -----------+
60
+ ```
61
+
62
+ The agent can inspect the result, decide what still needs work, and submit another scoped action instead of stopping at the first attempt.
63
+
64
+ ## Install
65
+
66
+ ### Python / PyPI
67
+
68
+ ```bash
69
+ pip install do-again
70
+ ```
71
+
72
+ ### Node / npm
73
+
74
+ ```bash
75
+ npm install -g do-again
76
+ ```
77
+
78
+ or run it without a global install:
79
+
80
+ ```bash
81
+ npx do-again setup
82
+ ```
83
+
84
+ Both distributions expose the same command:
85
+
86
+ ```bash
87
+ do-again
88
+ ```
89
+
90
+ The npm package ships the same Python runtime from this repository behind a small Node launcher. It requires Node.js 18+ and Python 3.11+.
91
+
92
+ ## Quick start
93
+
94
+ From the Git repository you want an agent to work on:
95
+
96
+ ```bash
97
+ pip install do-again
98
+ cd my-project
99
+ do-again setup
100
+ do-again start
101
+ do-again status
102
+ ```
103
+
104
+ On the first browser-enabled setup, Do Again creates a dedicated automation Chrome/Chromium profile and opens it visibly so you can sign into ChatGPT and complete any human verification. Do Again watches for the real composer and continues automatically when sign-in is complete; you do not need to return to the terminal and confirm it. Do Again does not ask for or store your ChatGPT username or password.
105
+
106
+ After that one-time authentication step, setup automatically:
107
+
108
+ - verifies the real ChatGPT composer through CDP;
109
+ - tests the saved session with Chrome's current `--headless=new` mode;
110
+ - uses true headless mode when it is reliable, otherwise falls back to a real background Chrome instance;
111
+ - creates and binds a dedicated automation conversation for the project;
112
+ - creates the Git control branch and project policy;
113
+ - installs the native user-level background service; and
114
+ - verifies the local runtime.
115
+
116
+ Normal use is intentionally small:
117
+
118
+ ```bash
119
+ do-again start
120
+ do-again status
121
+ do-again stop
122
+ do-again list
123
+ ```
124
+
125
+ `setup` already starts the project, so `start` is mainly for bringing it back later. Multiple projects can run at the same time; they share one dedicated authenticated browser runtime while keeping separate project conversations, service state, control worktrees, policies, and receipt queues.
126
+
127
+ If you do not want ChatGPT browser automation for a project:
128
+
129
+ ```bash
130
+ do-again setup --no-browser
131
+ ```
132
+
133
+ For attended use without installing a native background service:
134
+
135
+ ```bash
136
+ do-again setup --no-service
137
+ do-again run
138
+ ```
139
+
140
+ ## Browser runtime
141
+
142
+ The browser is an implementation detail during normal operation. Do Again never attaches to your everyday Chrome/Chromium profile and does not touch your normal tabs, cookies, extensions, Firefox session, or browser history.
143
+
144
+ The shared automation profile lives under `~/.do_again/browser/profile` by default. CDP listens only on loopback, and Do Again chooses another local port if its preferred port is occupied.
145
+
146
+ The default browser mode is `auto`:
147
+
148
+ 1. first authentication is visible and interactive;
149
+ 2. Do Again restarts the same persistent profile with `--headless=new`;
150
+ 3. if the authenticated ChatGPT session is not reliable in true headless mode, it automatically falls back to a real Chrome process running without a startup window;
151
+ 4. later starts reuse the verified mode without opening a foreground window.
152
+
153
+ The daemon monitors the browser and restarts it after crashes. Browser delivery uses a durable per-project outbox, so a receipt is retried after browser/network failures instead of being lost. Receipt markers make retries idempotent. If ChatGPT reports that a conversation reached its maximum length, Do Again creates a fresh background conversation, carries over recent conversation excerpts, bootstraps it from the Git control state, rebinds the project, and continues there.
154
+
155
+ If headless authentication fails, Do Again first checks the background browser with the same profile. If both modes fail, Do Again reports `auth_required` and waits for interactive setup. It does not repeatedly launch browsers or bypass verification. Local request execution continues, and browser receipts stay queued. Re-run `do-again setup` to reopen only the dedicated automation profile for human interaction.
156
+
157
+ Advanced/debug controls remain available when needed:
158
+
159
+ ```bash
160
+ do-again browser status
161
+ do-again browser test
162
+ do-again browser login
163
+ do-again browser stop
164
+ ```
165
+
166
+ You can force a browser mode during setup with `--browser-mode headless` or `--browser-mode background`; `auto` is recommended.
167
+
168
+ ## Service lifecycle
169
+
170
+ Do Again installs a per-repository background agent using the native user-level service manager:
171
+
172
+ ```bash
173
+ do-again start
174
+ do-again status
175
+ do-again restart
176
+ do-again stop
177
+ ```
178
+
179
+ Low-level `install`, `uninstall`, `init`, and foreground `run` commands remain available for advanced use and backward compatibility, but they are intentionally omitted from the primary help surface.
180
+
181
+ Each repository gets an isolated runtime, control worktree, state directory, policy copy, and service label under `~/.do_again`. The installed service runs from a copied runtime so installs made through either PyPI or npm remain stable after the invoking shell exits. `do-again init` also creates `do-again-policy.json` for project-specific operation, binary, root, timeout, and execution controls. The control branch must be dedicated and cannot be `main`, `master`, `trunk`, or the currently checked-out branch.
182
+
183
+ ## Why Do Again
184
+
185
+ - Explicit policy-based command permissions
186
+ - GitHub-backed request and receipt transport
187
+ - Project-scoped filesystem and command access
188
+ - Deterministic audit trail and recovery
189
+ - No agent API keys embedded in the project
190
+ - Dedicated ChatGPT browser profile with headless-first operation
191
+ - Durable retry/recovery when the browser crashes or a send fails
192
+ - One shared browser runtime for multiple concurrent projects
193
+ - A shared platform interface for macOS, Linux, and Windows
194
+ - CI-tested on Python 3.11, 3.12, and 3.13 across all three platforms
195
+
196
+ ## Platform status
197
+
198
+ | Platform | Service backend | Browser runtime |
199
+ | --- | --- | --- |
200
+ | macOS | launchd | Chrome/Chromium CDP, headless-first |
201
+ | Linux | systemd user service | Chrome/Chromium CDP, headless-first |
202
+ | Windows | per-user Task Scheduler | Chrome/Chromium CDP, headless-first |
203
+
204
+ Do Again is currently alpha software. The foreground runner, per-repository service lifecycle, browser discovery, persistent profile model, and CDP runtime are implemented behind the same interface on macOS, Linux, and Windows. Browser availability still depends on a compatible local Chrome/Chromium installation and ChatGPT authentication.
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ git clone https://github.com/Tran-Steven/do-again.git
210
+ cd do-again
211
+ python -m pip install .
212
+ python -m unittest discover -s tests -v
213
+ python tools/browser_smoke.py
214
+ do-again doctor
215
+ ```
216
+
217
+ Disposable-profile smoke tests verify real Chrome CDP, profile persistence, and crash recovery without signing into ChatGPT. Authenticated ChatGPT round trips are a separate manual integration check; mocked tests cannot establish that a real session works in headless mode. Linux background Chrome requires a graphical session or virtual display.
218
+
219
+ ## Release model
220
+
221
+ Releases use semantic versioning. Pushing a version tag validates the shared release version, publishes the Python distribution to PyPI and the Node launcher to npm through Trusted Publishing, and creates the matching GitHub Release.
222
+
223
+ PyPI distribution name: `do-again`
224
+
225
+ npm package name: `do-again`
226
+
227
+ CLI command: `do-again`
228
+
229
+ Python package: `do_again`
230
+
231
+ ## Security
232
+
233
+ Do Again is designed around explicit allowlists, scoped filesystem roots, bounded execution, and auditable request/receipt records. Browser cookies and session data remain in the dedicated local automation profile; credentials are never requested or stored by Do Again, and CDP is bound to localhost. It should not be configured as unrestricted shell access.
234
+
235
+ ## License
236
+
237
+ MIT
@@ -0,0 +1,202 @@
1
+ # Do Again
2
+
3
+ [![CI](https://github.com/Tran-Steven/do-again/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Tran-Steven/do-again/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/do-again.svg?cacheSeconds=300)](https://pypi.org/project/do-again/)
5
+ [![npm](https://img.shields.io/npm/v/do-again.svg?cacheSeconds=300)](https://www.npmjs.com/package/do-again)
6
+ [![Python](https://img.shields.io/pypi/pyversions/do-again.svg?cacheSeconds=300)](https://pypi.org/project/do-again/)
7
+ [![License](https://img.shields.io/github/license/Tran-Steven/do-again.svg?cacheSeconds=300)](LICENSE)
8
+
9
+ Do Again gives AI coding agents a policy-controlled way to execute work on a local development machine, return auditable receipts and artifacts, and keep iterating when another pass is needed.
10
+
11
+ ## How it works
12
+
13
+ ```text
14
+ agent
15
+ |
16
+ | request
17
+ v
18
+ operator-control branch
19
+ |
20
+ v
21
+ Do Again -> policy validation -> local command / file / test / git action
22
+ ^ |
23
+ | |
24
+ +----------- receipt / artifact -----------+
25
+ ```
26
+
27
+ The agent can inspect the result, decide what still needs work, and submit another scoped action instead of stopping at the first attempt.
28
+
29
+ ## Install
30
+
31
+ ### Python / PyPI
32
+
33
+ ```bash
34
+ pip install do-again
35
+ ```
36
+
37
+ ### Node / npm
38
+
39
+ ```bash
40
+ npm install -g do-again
41
+ ```
42
+
43
+ or run it without a global install:
44
+
45
+ ```bash
46
+ npx do-again setup
47
+ ```
48
+
49
+ Both distributions expose the same command:
50
+
51
+ ```bash
52
+ do-again
53
+ ```
54
+
55
+ The npm package ships the same Python runtime from this repository behind a small Node launcher. It requires Node.js 18+ and Python 3.11+.
56
+
57
+ ## Quick start
58
+
59
+ From the Git repository you want an agent to work on:
60
+
61
+ ```bash
62
+ pip install do-again
63
+ cd my-project
64
+ do-again setup
65
+ do-again start
66
+ do-again status
67
+ ```
68
+
69
+ On the first browser-enabled setup, Do Again creates a dedicated automation Chrome/Chromium profile and opens it visibly so you can sign into ChatGPT and complete any human verification. Do Again watches for the real composer and continues automatically when sign-in is complete; you do not need to return to the terminal and confirm it. Do Again does not ask for or store your ChatGPT username or password.
70
+
71
+ After that one-time authentication step, setup automatically:
72
+
73
+ - verifies the real ChatGPT composer through CDP;
74
+ - tests the saved session with Chrome's current `--headless=new` mode;
75
+ - uses true headless mode when it is reliable, otherwise falls back to a real background Chrome instance;
76
+ - creates and binds a dedicated automation conversation for the project;
77
+ - creates the Git control branch and project policy;
78
+ - installs the native user-level background service; and
79
+ - verifies the local runtime.
80
+
81
+ Normal use is intentionally small:
82
+
83
+ ```bash
84
+ do-again start
85
+ do-again status
86
+ do-again stop
87
+ do-again list
88
+ ```
89
+
90
+ `setup` already starts the project, so `start` is mainly for bringing it back later. Multiple projects can run at the same time; they share one dedicated authenticated browser runtime while keeping separate project conversations, service state, control worktrees, policies, and receipt queues.
91
+
92
+ If you do not want ChatGPT browser automation for a project:
93
+
94
+ ```bash
95
+ do-again setup --no-browser
96
+ ```
97
+
98
+ For attended use without installing a native background service:
99
+
100
+ ```bash
101
+ do-again setup --no-service
102
+ do-again run
103
+ ```
104
+
105
+ ## Browser runtime
106
+
107
+ The browser is an implementation detail during normal operation. Do Again never attaches to your everyday Chrome/Chromium profile and does not touch your normal tabs, cookies, extensions, Firefox session, or browser history.
108
+
109
+ The shared automation profile lives under `~/.do_again/browser/profile` by default. CDP listens only on loopback, and Do Again chooses another local port if its preferred port is occupied.
110
+
111
+ The default browser mode is `auto`:
112
+
113
+ 1. first authentication is visible and interactive;
114
+ 2. Do Again restarts the same persistent profile with `--headless=new`;
115
+ 3. if the authenticated ChatGPT session is not reliable in true headless mode, it automatically falls back to a real Chrome process running without a startup window;
116
+ 4. later starts reuse the verified mode without opening a foreground window.
117
+
118
+ The daemon monitors the browser and restarts it after crashes. Browser delivery uses a durable per-project outbox, so a receipt is retried after browser/network failures instead of being lost. Receipt markers make retries idempotent. If ChatGPT reports that a conversation reached its maximum length, Do Again creates a fresh background conversation, carries over recent conversation excerpts, bootstraps it from the Git control state, rebinds the project, and continues there.
119
+
120
+ If headless authentication fails, Do Again first checks the background browser with the same profile. If both modes fail, Do Again reports `auth_required` and waits for interactive setup. It does not repeatedly launch browsers or bypass verification. Local request execution continues, and browser receipts stay queued. Re-run `do-again setup` to reopen only the dedicated automation profile for human interaction.
121
+
122
+ Advanced/debug controls remain available when needed:
123
+
124
+ ```bash
125
+ do-again browser status
126
+ do-again browser test
127
+ do-again browser login
128
+ do-again browser stop
129
+ ```
130
+
131
+ You can force a browser mode during setup with `--browser-mode headless` or `--browser-mode background`; `auto` is recommended.
132
+
133
+ ## Service lifecycle
134
+
135
+ Do Again installs a per-repository background agent using the native user-level service manager:
136
+
137
+ ```bash
138
+ do-again start
139
+ do-again status
140
+ do-again restart
141
+ do-again stop
142
+ ```
143
+
144
+ Low-level `install`, `uninstall`, `init`, and foreground `run` commands remain available for advanced use and backward compatibility, but they are intentionally omitted from the primary help surface.
145
+
146
+ Each repository gets an isolated runtime, control worktree, state directory, policy copy, and service label under `~/.do_again`. The installed service runs from a copied runtime so installs made through either PyPI or npm remain stable after the invoking shell exits. `do-again init` also creates `do-again-policy.json` for project-specific operation, binary, root, timeout, and execution controls. The control branch must be dedicated and cannot be `main`, `master`, `trunk`, or the currently checked-out branch.
147
+
148
+ ## Why Do Again
149
+
150
+ - Explicit policy-based command permissions
151
+ - GitHub-backed request and receipt transport
152
+ - Project-scoped filesystem and command access
153
+ - Deterministic audit trail and recovery
154
+ - No agent API keys embedded in the project
155
+ - Dedicated ChatGPT browser profile with headless-first operation
156
+ - Durable retry/recovery when the browser crashes or a send fails
157
+ - One shared browser runtime for multiple concurrent projects
158
+ - A shared platform interface for macOS, Linux, and Windows
159
+ - CI-tested on Python 3.11, 3.12, and 3.13 across all three platforms
160
+
161
+ ## Platform status
162
+
163
+ | Platform | Service backend | Browser runtime |
164
+ | --- | --- | --- |
165
+ | macOS | launchd | Chrome/Chromium CDP, headless-first |
166
+ | Linux | systemd user service | Chrome/Chromium CDP, headless-first |
167
+ | Windows | per-user Task Scheduler | Chrome/Chromium CDP, headless-first |
168
+
169
+ Do Again is currently alpha software. The foreground runner, per-repository service lifecycle, browser discovery, persistent profile model, and CDP runtime are implemented behind the same interface on macOS, Linux, and Windows. Browser availability still depends on a compatible local Chrome/Chromium installation and ChatGPT authentication.
170
+
171
+ ## Development
172
+
173
+ ```bash
174
+ git clone https://github.com/Tran-Steven/do-again.git
175
+ cd do-again
176
+ python -m pip install .
177
+ python -m unittest discover -s tests -v
178
+ python tools/browser_smoke.py
179
+ do-again doctor
180
+ ```
181
+
182
+ Disposable-profile smoke tests verify real Chrome CDP, profile persistence, and crash recovery without signing into ChatGPT. Authenticated ChatGPT round trips are a separate manual integration check; mocked tests cannot establish that a real session works in headless mode. Linux background Chrome requires a graphical session or virtual display.
183
+
184
+ ## Release model
185
+
186
+ Releases use semantic versioning. Pushing a version tag validates the shared release version, publishes the Python distribution to PyPI and the Node launcher to npm through Trusted Publishing, and creates the matching GitHub Release.
187
+
188
+ PyPI distribution name: `do-again`
189
+
190
+ npm package name: `do-again`
191
+
192
+ CLI command: `do-again`
193
+
194
+ Python package: `do_again`
195
+
196
+ ## Security
197
+
198
+ Do Again is designed around explicit allowlists, scoped filesystem roots, bounded execution, and auditable request/receipt records. Browser cookies and session data remain in the dedicated local automation profile; credentials are never requested or stored by Do Again, and CDP is bound to localhost. It should not be configured as unrestricted shell access.
199
+
200
+ ## License
201
+
202
+ MIT
@@ -0,0 +1,61 @@
1
+ # Do Again Roadmap
2
+
3
+ Do Again should be easy on the first run and still expose lower-level controls for advanced users.
4
+
5
+ ## P0 — reliable core
6
+
7
+ - [x] One-command local onboarding with `do-again setup`
8
+ - [x] Project-specific policy file created by `do-again init` / `setup`
9
+ - [x] Safe dedicated control-branch validation
10
+ - [x] Custom Git remote support
11
+ - [x] Future-dated request rejection
12
+ - [x] Request-ID collision detection
13
+ - [x] Durable local request locks
14
+ - [x] Distributed Git-backed request claims
15
+ - [x] Observable malformed-request records
16
+ - [x] Chronological request ordering across timezone offsets
17
+ - [x] macOS launchd lifecycle
18
+ - [x] Linux systemd user-service lifecycle
19
+ - [x] Windows per-user Task Scheduler lifecycle
20
+
21
+ ## P1 — frictionless ChatGPT connection
22
+
23
+ - [x] Dedicated persistent automation Chrome/Chromium profile
24
+ - [x] One-time visible ChatGPT sign-in / human-verification flow
25
+ - [x] Real composer/session verification over localhost CDP
26
+ - [x] True `--headless=new` operation when the authenticated session supports it
27
+ - [x] Automatic background-headed fallback when true headless is unreliable
28
+ - [x] No normal-profile attachment and no post-setup foreground focus requirement
29
+ - [x] Per-project automation conversation binding
30
+ - [x] Shared browser runtime across concurrent projects
31
+ - [x] Browser crash detection and automatic restart
32
+ - [x] Durable browser-delivery outbox with idempotent receipt retries
33
+ - [x] Explicit `auth_required` state instead of challenge/auth bypass loops
34
+ - [x] Automatic safe new-chat rollover on conversation-length limits
35
+ - [x] Browser state remains local; credentials are never requested or stored
36
+ - [x] Git-backed request/receipt transport remains independent of the browser layer
37
+
38
+ ## P1 — diagnostics and recovery
39
+
40
+ - [x] Make `doctor` repository-aware and report browser/runtime repair information.
41
+ - [x] Surface browser delivery failures and pending receipt count through `status`.
42
+ - [ ] Surface recent core request/receipt failures without requiring users to inspect the control branch manually.
43
+ - [ ] Add safe repair/reinstall behavior for damaged service definitions and runtime copies.
44
+ - [ ] Add upgrade-path tests from older Do Again releases.
45
+
46
+ ## P2 — broader integration
47
+
48
+ - [ ] Pluggable transports beyond Git-backed control branches.
49
+ - [ ] More end-to-end service tests on real Linux and Windows hosts, not only CI-level mocks/contracts.
50
+ - [ ] Stable machine-readable CLI output for external agent integrations.
51
+ - [ ] Signed release/install verification guidance.
52
+
53
+ ## 0.3.0 release validation
54
+
55
+ - [x] Unit and regression tests for shared startup, stale PID/port protection, auth recovery, rollover, and durable delivery.
56
+ - [x] Real macOS Chrome smoke tests with disposable profiles, persistence, forced crash recovery, and background launch.
57
+ - [x] Clean wheel, sdist, and npm installation verification.
58
+ - [x] Browser hardening tests executed through a real Do Again request/receipt loop.
59
+ - [x] Real Chrome smoke tests pass in Linux and Windows CI.
60
+ - [x] Authenticated ChatGPT message/response succeeds after human verification and runtime restart (macOS background fallback).
61
+ - [ ] Publish 0.3.0 through Trusted Publishing after validation passes.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "do-again",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "do-again",
9
- "version": "0.2.0",
9
+ "version": "0.3.0",
10
10
  "license": "MIT",
11
11
  "bin": {
12
12
  "do-again": "bin/do-again.js"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "do-again",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Policy-controlled local execution for AI coding agents",
5
5
  "license": "MIT",
6
6
  "author": "Steven Tran",
@@ -13,7 +13,8 @@
13
13
  "src/do_again/**/*.py",
14
14
  "README.md",
15
15
  "LICENSE",
16
- "src/do_again/default_policy.json"
16
+ "src/do_again/default_policy.json",
17
+ "ROADMAP.md"
17
18
  ],
18
19
  "engines": {
19
20
  "node": ">=18"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "do-again"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Policy-controlled local execution for agent-driven development workflows"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1,35 @@
1
+ from .runtime import (
2
+ BrowserAuthRequired,
3
+ BrowserError,
4
+ activate_project,
5
+ browser_self_test,
6
+ browser_status,
7
+ deactivate_project,
8
+ discover_browser,
9
+ ensure_browser_running,
10
+ ensure_project_chat,
11
+ notify_receipt,
12
+ project_record,
13
+ register_project,
14
+ setup_browser,
15
+ stop_browser,
16
+ stop_if_unused,
17
+ )
18
+
19
+ __all__ = [
20
+ "BrowserAuthRequired",
21
+ "BrowserError",
22
+ "activate_project",
23
+ "browser_self_test",
24
+ "browser_status",
25
+ "deactivate_project",
26
+ "discover_browser",
27
+ "ensure_browser_running",
28
+ "ensure_project_chat",
29
+ "notify_receipt",
30
+ "project_record",
31
+ "register_project",
32
+ "setup_browser",
33
+ "stop_browser",
34
+ "stop_if_unused",
35
+ ]