@backburner/cli 0.1.4 → 0.1.7

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.
package/README.md CHANGED
@@ -1,154 +1,138 @@
1
- # Backburner CLI
1
+ # Backburner
2
2
 
3
- Backburner is a local GitHub-driven agent orchestration CLI. It uses GitHub labels, issues, and pull requests as the control plane, keeps configuration and state as readable JSON on your machine, and dispatches eligible work to provider CLIs that you already have installed locally.
3
+ Backburner turns GitHub issues into reviewable pull requests using coding agents running on your own machine.
4
4
 
5
- Backburner supports:
5
+ Open an issue from your phone, get back to your day, and manage the work through GitHub comments, labels, and PR reviews. Your computer does the planning, coding, testing, committing, and pushing through the agent CLIs and credentials you already use. GitHub is the control plane; your computer is the worker.
6
6
 
7
- - `backburner init` for interactive or non-interactive local setup
8
- - `backburner run` for one orchestration cycle
9
- - `backburner run-loop` for repeated cycles on a fixed interval
10
- - `backburner journal` for reading persisted run and workflow events
11
- - `backburner broker` for a local GitHub broker MCP endpoint
12
- - a plan-first label workflow for product approval, plan approval, review requests, and parent-branch sync approval
13
- - local provider CLIs for Antigravity, Codex, Gemini, Claude, and OpenCode
7
+ ## How it works
14
8
 
15
- ## Prerequisites
9
+ 1. You open an issue in a repository managed by Backburner.
10
+ 2. A product agent can clarify the problem and propose a product direction in the issue.
11
+ 3. Once product direction is approved, Backburner creates an isolated git worktree and a planning PR with a Product Spec and implementation plan.
12
+ 4. You approve the plan with a GitHub label. Local agents implement it, run the repository's checks, commit, and push.
13
+ 5. You review comments, request changes, and merge from GitHub—including from your phone.
16
14
 
17
- - Node.js `>=20`
18
- - npm
19
- - git
20
- - GitHub CLI authenticated for the account and repositories you want Backburner to manage:
15
+ Backburner never silently merges the final PR. You remain in control of approvals and the merge.
21
16
 
22
- ```sh
23
- gh auth status
24
- ```
17
+ ## Quick start
25
18
 
26
- - at least one supported provider CLI on `PATH`: `agy`, `codex`, `gemini`, `claude`, or `opencode`
19
+ You need Node.js 20 or newer, `git`, an authenticated [GitHub CLI](https://cli.github.com/), and at least one supported agent CLI on your `PATH`: `agy`, `codex`, `gemini`, `claude`, or `opencode`.
27
20
 
28
- Backburner uses your local `git`, `gh`, and provider CLI credentials. It does not provide hosted execution or cloud credentials.
21
+ Install Backburner from npm:
29
22
 
30
- ## Install
23
+ ~~~sh
24
+ npm install --global @backburner/cli
25
+ gh auth status
26
+ backburner init
27
+ ~~~
31
28
 
32
- From a source checkout:
29
+ Onboarding walks you through:
33
30
 
34
- ```sh
35
- npm install
36
- npm run build
37
- node dist/src/cli/run.js init
38
- ```
31
+ - checking Node.js, `git`, GitHub authentication, and local write access;
32
+ - choosing the directories Backburner will use;
33
+ - creating a private `backburner-demo` repository or selecting existing repositories;
34
+ - detecting your installed agent CLIs and configuring models and roles;
35
+ - writing readable local configuration; and
36
+ - creating the configured Backburner labels in each selected repository.
39
37
 
40
- Windows PowerShell:
41
-
42
- ```powershell
43
- npm install
44
- npm run build
45
- node .\dist\src\cli\run.js init
46
- ```
38
+ When onboarding finishes:
47
39
 
48
- For active local development, link this checkout into your global npm bin directory:
40
+ 1. Open the first configured repository—usually `backburner-demo` if you created it.
41
+ 2. Follow the printed prefilled issue link or scan the QR code, then submit the issue.
42
+ 3. Back on your Mac, start Backburner and leave it running:
49
43
 
50
- ```sh
51
- npm run link:local
52
- backburner init
53
- ```
54
-
55
- To install and verify the locally packed package:
44
+ ~~~sh
45
+ backburner run
46
+ ~~~
56
47
 
57
- ```sh
58
- npm run install:local
59
- backburner journal --json
60
- ```
48
+ That is the handoff. Keep the Mac awake and online, and continue from GitHub on your phone while local agents do the work. The interactive terminal UI runs an initial cycle automatically and keeps polling; you do not need to press `r`.
61
49
 
62
- To install the local package into a temporary npm prefix:
50
+ For an unattended terminal without the interactive UI:
63
51
 
64
- macOS/Linux:
52
+ ~~~sh
53
+ backburner run-loop --headless --interval-minutes 5
54
+ ~~~
65
55
 
66
- ```sh
67
- npm run install:local -- --prefix /tmp/backburner-local
68
- /tmp/backburner-local/bin/backburner journal --json
69
- ```
56
+ The prefilled first issue includes the configured product-approval label, so it enters the Product Spec and planning path immediately. An ordinary unlabeled issue starts with Product Discovery instead.
70
57
 
71
- Windows PowerShell:
58
+ ## Before onboarding a real repository
72
59
 
73
- ```powershell
74
- npm run install:local -- --prefix "$env:TEMP\backburner-local"
75
- & "$env:TEMP\backburner-local\backburner.cmd" journal --json
76
- ```
60
+ Backburner intentionally gives coding agents meaningful access to selected repositories. Before you run it:
77
61
 
78
- Install from npm:
62
+ - select only repositories whose code and issue content you trust;
63
+ - keep `allowedUsers` limited to GitHub users you trust to trigger agent work;
64
+ - understand the permission mode used by each provider CLI;
65
+ - expect prompts, repository content, and tool results to be sent to the configured model provider;
66
+ - treat `~/.backburner/outputs` as sensitive because state, journal entries, and logs can contain repository and provider output; and
67
+ - start with the private demo repository if you want to observe the workflow before granting access to production code.
79
68
 
80
- ```sh
81
- npm install -g @backburner/cli
82
- backburner init
83
- ```
69
+ Local execution means the worker and credentials stay on your machine; it does not mean the workflow is offline or that model providers never receive code. See [SECURITY.md](SECURITY.md) for the threat model, trust boundaries, and vulnerability-reporting process.
84
70
 
85
- The package bin is `backburner`.
71
+ ## What onboarding writes
86
72
 
87
- The npm package intentionally includes the compiled CLI under `dist/src`, `README.md`, `LICENSE`, and package metadata. Contributor docs and generated docs are kept in the source repository and are not part of the install tarball.
73
+ By default, Backburner stores its data under `~/.backburner`:
88
74
 
89
- ## Quick Start
75
+ - code root: `~/.backburner/code`
76
+ - management directory: `~/.backburner/management`
77
+ - outputs directory: `~/.backburner/outputs`
78
+ - state directory: `~/.backburner/outputs/state`
79
+ - journal directory: `~/.backburner/outputs/journal`
80
+ - log directory: `~/.backburner/outputs/logs`
81
+ - onboarding workspaces directory: `<code-root>/_worktrees`
90
82
 
91
- Run onboarding:
83
+ Set `BACKBURNER_ROOT` to change the root used for the default code, management, and outputs directories.
92
84
 
93
- ```sh
94
- backburner init
95
- ```
85
+ Backburner writes two human-readable configuration files in the management directory:
96
86
 
97
- Source checkout equivalent:
87
+ - `repos.json`: repositories, allowed GitHub users, and workflow labels
88
+ - `agents.json`: enabled provider CLIs, models, roles, and capabilities
98
89
 
99
- ```sh
100
- node dist/src/cli/run.js init
101
- ```
90
+ If either file already exists, interactive onboarding asks before overwriting it. Repository label creation is best-effort; if GitHub rejects a write, onboarding prints the labels page and exact names to create manually.
102
91
 
103
- Non-interactive setup accepts defaults:
92
+ Non-interactive onboarding is available:
104
93
 
105
- ```sh
94
+ ~~~sh
106
95
  backburner init --yes
107
- ```
96
+ ~~~
97
+
98
+ `--yes` accepts broad defaults: it selects discovered repositories, enables discovered providers, creates default agent configurations, and creates or updates labels. It does not create a private demo repository. Review the generated configuration before running Backburner.
108
99
 
109
100
  Useful `init` flags:
110
101
 
111
- ```text
102
+ ~~~text
112
103
  --code-root <path> Root where managed repos are cloned
113
104
  --management-dir <path> Directory for configuration files
114
105
  --outputs-dir <path> Directory for generated state, journal, and logs
115
106
  --log-dir <path> Directory for execution logs
116
107
  --workspaces-dir <path> Directory used by onboarding readiness checks
117
108
  --yes, -y Accept defaults without prompts
118
- ```
119
-
120
- `backburner init` checks local requirements, confirms `gh auth status`, discovers repositories, detects provider CLIs, attempts model-list discovery when supported by those CLIs, writes configuration, and creates the configured Backburner labels on each selected repository.
109
+ ~~~
121
110
 
122
- - `repos.json`
123
- - `agents.json`
111
+ ## GitHub control plane
124
112
 
125
- If either file already exists, onboarding asks before overwriting it. With `--yes`, defaults are accepted non-interactively, including selecting existing discovered repositories, enabling every discovered provider, creating strong and cheap agents for each one, and creating or updating labels on selected repositories. `--yes` does not create a private demo repository.
113
+ Backburner uses configurable labels to turn GitHub into a small, phone-friendly workflow:
126
114
 
127
- Repository setup first asks whether to create a private Backburner demo repository, select existing repositories, or skip repository setup for now. When GitHub authentication is available, the private demo repository is the interactive default. Before choosing existing repositories, onboarding tells you that Backburner will create or update its labels on those repositories. In an interactive terminal, repository and provider selection use a checkbox picker: arrow keys move, space toggles, and enter confirms. Non-TTY sessions fall back to text input and accept comma-separated numbers. If you are authenticated with GitHub but do not want to onboard an existing local clone yet, onboarding can explicitly create a private `backburner-demo` repository and clone it under the configured code root.
115
+ - `agentProductApproved` approves product direction and allows the worktree/PR flow to begin.
116
+ - `agentPlanApproved` approves the implementation plan and allows implementation to run.
117
+ - `agentReview` requests an explicit code review after the PR head SHA changes.
118
+ - `agentSyncParentBranch` authorizes syncing a blocked parent branch from the default branch.
119
+ - `agentInProgress`, `planBreakdownNeeded`, and `prepareForMerge` communicate other workflow states.
128
120
 
129
- Label creation is best-effort. If GitHub rejects a label write because of permissions or repository policy, onboarding continues and prints the repository labels URL plus the exact label names to create manually. The final summary prints the next `backburner run` command, a prefilled GitHub issue URL for the first configured repository, and a terminal QR code for opening that repository's issues page from a phone.
121
+ The default label names are:
130
122
 
131
- ## Default Directories
123
+ - `backburner:product-approved`
124
+ - `backburner:plan-approved`
125
+ - `backburner:review`
126
+ - `backburner:sync-parent-branch`
127
+ - `backburner:in-progress`
128
+ - `backburner:plan-breakdown-needed`
129
+ - `backburner:prepare-for-merge`
132
130
 
133
- By default, Backburner stores data under `~/.backburner`:
134
-
135
- - code root: `~/.backburner/code`
136
- - management directory: `~/.backburner/management`
137
- - outputs directory: `~/.backburner/outputs`
138
- - state directory: `~/.backburner/outputs/state`
139
- - journal directory: `~/.backburner/outputs/journal`
140
- - log directory: `~/.backburner/outputs/logs`
141
- - onboarding workspaces directory: `<code-root>/_worktrees`
142
-
143
- Set `BACKBURNER_ROOT` to change the root used for the default code, management, and outputs directories.
144
-
145
- ## Configuration
146
-
147
- Backburner configuration lives in the management directory.
131
+ Custom names are supported in `repos.json` and are used in generated plans and PR instructions.
148
132
 
149
133
  Minimal `repos.json`:
150
134
 
151
- ```json
135
+ ~~~json
152
136
  {
153
137
  "allowedUsers": [
154
138
  "your-github-user"
@@ -173,11 +157,15 @@ Minimal `repos.json`:
173
157
  }
174
158
  ]
175
159
  }
176
- ```
160
+ ~~~
161
+
162
+ `allowedUsers` limits which GitHub users can feed issues, comments, reviews, and pull requests into task derivation. It is a trust allowlist, not a sandbox. `localPath` must be relative to `--code-root`.
163
+
164
+ ## Agent configuration
177
165
 
178
166
  Minimal `agents.json`:
179
167
 
180
- ```json
168
+ ~~~json
181
169
  {
182
170
  "agents": [
183
171
  {
@@ -209,125 +197,103 @@ Minimal `agents.json`:
209
197
  }
210
198
  ]
211
199
  }
212
- ```
213
-
214
- `allowedUsers` limits which GitHub users can feed issues, comments, reviews, and pull requests into task derivation. `localPath` must be relative to `--code-root`.
215
-
216
- Agent selection filters enabled agents by required role and `modelClass`, then breaks ties by lowest agent `id`. Provider model names are passed through to the provider CLI and are not validated against vendor catalogs. During onboarding, model setup shows discovered model options when available, marks strong and cheap defaults, and pressing enter accepts the default. Backburner prefers discovered `sol` for strong, `terra` for balanced/default, and `luna` for cheap model names; Codex defaults are `sol` and `luna`. OpenCode may use discovered OpenRouter model IDs such as `openrouter/openai/gpt-5.6-sol` and `openrouter/openai/gpt-5.6-luna`.
200
+ ~~~
217
201
 
218
- ## Label Control Plane
202
+ Agent selection filters enabled agents by role and `modelClass`, then breaks ties by the lowest agent ID. Model names are passed through to the provider CLI and are not validated against vendor catalogs.
219
203
 
220
- Configure labels per repository in `repos.json`. The workflow labels are:
204
+ ## Commands
221
205
 
222
- - `agentProductApproved`: approves product discovery and allows Backburner to create the implementation PR/worktree flow for an issue
223
- - `agentPlanApproved`: approves an implementation plan and allows implementation tasks to run
224
- - `agentReview`: requests an explicit code review; review tasks are dispatched when the PR has this label and its head SHA changed since the last review
225
- - `agentSyncParentBranch`: authorizes Backburner to sync a blocked parent implementation branch from the repository default branch
206
+ Start the persistent interactive terminal UI:
226
207
 
227
- Backburner also uses `agentInProgress`, `planBreakdownNeeded`, and `prepareForMerge` when those labels are configured. Onboarding writes `repos.json` with these label values by default: `backburner:product-approved`, `backburner:plan-approved`, `backburner:review`, `backburner:in-progress`, `backburner:plan-breakdown-needed`, `backburner:sync-parent-branch`, and `backburner:prepare-for-merge`. It creates or updates the configured labels through `gh label create --force`. Custom label names, including older unprefixed names, are supported when configured in `repos.json`.
208
+ ~~~sh
209
+ backburner run
210
+ ~~~
228
211
 
229
- ## Commands
212
+ Run exactly one orchestration cycle:
230
213
 
231
- Run one cycle:
214
+ ~~~sh
215
+ backburner run --once
216
+ ~~~
232
217
 
233
- ```sh
234
- backburner run
235
- ```
218
+ Run continuously without the interactive UI:
236
219
 
237
- Source checkout:
220
+ ~~~sh
221
+ backburner run-loop --headless --interval-minutes 5
222
+ ~~~
238
223
 
239
- ```sh
240
- node dist/src/cli/run.js run
241
- ```
224
+ `run-loop` also accepts `--interval-seconds <seconds>`. Its default interval is five minutes. `SIGINT` and `SIGTERM` request a graceful stop after the current cycle.
242
225
 
243
- Common run flags:
226
+ Common path flags:
244
227
 
245
- ```text
228
+ ~~~text
246
229
  --code-root <path>
247
230
  --management-dir <path>
248
231
  --outputs-dir <path>
249
232
  --log-dir <path>
250
233
  --broker-port <port>
251
- --headless
252
- --once
253
- ```
234
+ ~~~
254
235
 
255
- Run continuously:
236
+ Read the persisted journal:
256
237
 
257
- ```sh
258
- backburner run-loop --interval-minutes 5
259
- ```
260
-
261
- `run-loop` accepts the same path and broker flags as `run`, plus either `--interval-seconds <seconds>` or `--interval-minutes <minutes>`. The default interval is 5 minutes. `SIGINT` and `SIGTERM` request a graceful stop after the current cycle.
262
-
263
- Read the journal:
264
-
265
- ```sh
238
+ ~~~sh
266
239
  backburner journal --last 20
267
240
  backburner journal --repo your-github-user-example-repo --json
268
- ```
241
+ ~~~
269
242
 
270
- Journal filters:
243
+ Start the standalone local GitHub broker MCP endpoint:
271
244
 
272
- ```text
273
- --outputs-dir <path>
274
- --repo <id>
275
- --workstream <id>
276
- --issue <number>
277
- --pr <number>
278
- --since <ISO timestamp>
279
- --last <number>
280
- --json
281
- --verbose
282
- ```
283
-
284
- Start the GitHub broker MCP:
285
-
286
- ```sh
245
+ ~~~sh
287
246
  backburner broker --port 4444
288
- ```
247
+ ~~~
289
248
 
290
- Broker flags:
249
+ The normal orchestrator starts its own broker on loopback. The standalone broker supports `--host` and `--port` and serves `POST /mcp` and `GET /health`. Do not expose it to an untrusted network.
291
250
 
292
- ```text
293
- --management-dir <path>
294
- --host <host>
295
- --port <port>
296
- ```
297
-
298
- The broker serves:
299
-
300
- - `POST /mcp`
301
- - `GET /health`
302
-
303
- It exposes managed-repository tools for issue, PR, comment, check-run, code-search, PR creation, and PR review-comment reply workflows, plus plan-breakdown and wave-assessment tools used by Backburner providers.
251
+ ## What a run does
304
252
 
305
- Smoke-test the broker after building:
253
+ Each cycle loads configuration and state, syncs enabled repositories, scans GitHub through `gh`, derives eligible tasks, starts a local GitHub broker for provider access, dispatches work to provider CLIs, and writes state, journal events, and execution logs.
306
254
 
307
- ```sh
308
- npm run smoke:github-broker
309
- npm run smoke:github-broker -- --repo your-github-user/example-repo --issue-number 123
310
- ```
255
+ Backburner uses isolated git worktrees as implementation units. Generated control-plane state is readable JSON under `<outputs-dir>/state`; execution logs and artifacts are under `<outputs-dir>/logs`; journal events are under `<outputs-dir>/journal`.
311
256
 
312
- ## What A Run Does
257
+ ## Install from source
313
258
 
314
- `backburner run` loads configuration, prepares local management and outputs directories, loads state, syncs enabled repositories, scans GitHub through `gh`, derives tasks, starts a local GitHub broker for provider access, dispatches eligible tasks to configured provider CLIs, writes state and logs, and prints a run summary.
259
+ ~~~sh
260
+ git clone https://github.com/eladav/backburner.git
261
+ cd backburner
262
+ npm install
263
+ npm run build
264
+ npm link
265
+ backburner init
266
+ ~~~
315
267
 
316
- Generated files are readable JSON. Control-plane state is written under `<outputs-dir>/state`, including repository sync status, issues, PRs, comments, tasks, worktrees, attention records, MCP status, provider limits, and job memory. Execution logs and artifacts are written under `<outputs-dir>/logs`. Journal events are written under `<outputs-dir>/journal`.
268
+ Windows PowerShell:
317
269
 
318
- ## Platform Support
270
+ ~~~powershell
271
+ npm install
272
+ npm run build
273
+ npm link
274
+ backburner init
275
+ ~~~
319
276
 
320
- Backburner is intended to run on macOS, Linux, and Windows with Node.js 20 or newer. The CI workflow runs on Ubuntu, macOS, and Windows with Node 20 and 22, and includes build, typecheck, tests, package dry-run, and local package install smoke checks.
277
+ ## Platform support
321
278
 
322
- ## Verification
279
+ Backburner is intended for macOS, Linux, and Windows with Node.js 20 or newer. It is currently used on macOS. Automated CI runs the build, typecheck, tests, package dry-run, and local-install smoke checks on Ubuntu and Windows with Node.js 20 and 22.
323
280
 
324
- Use these checks before publishing or changing behavior:
281
+ ## Development and verification
325
282
 
326
- ```sh
283
+ ~~~sh
284
+ npm install
327
285
  npm run build
328
286
  npm run typecheck
329
287
  npm test
330
288
  npm pack --dry-run
331
- ```
289
+ ~~~
290
+
291
+ The npm package includes the compiled CLI under `dist/src`, `README.md`, `SECURITY.md`, `LICENSE`, and package metadata.
292
+
293
+ ## Security
294
+
295
+ Please read [SECURITY.md](SECURITY.md) before granting Backburner access to important repositories. Report suspected vulnerabilities privately using the process described there.
296
+
297
+ ## License
332
298
 
333
- For docs-only changes, at minimum verify that documented commands, package contents, and public-safety scrub patterns still match the repository.
299
+ [MIT](LICENSE)
package/SECURITY.md ADDED
@@ -0,0 +1,146 @@
1
+ # Security Policy
2
+
3
+ Backburner coordinates coding agents that run on your machine with access to source code, local tools, GitHub credentials, and model-provider credentials. That is the product's core capability and its primary security boundary.
4
+
5
+ Read this document before granting Backburner access to an important repository.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please do not disclose a suspected vulnerability in a public issue, discussion, pull request, or Hacker News thread.
10
+
11
+ Use GitHub's private vulnerability reporting for this repository when it is available. If the repository does not show a **Report a vulnerability** option on its Security page, open a public issue containing only a request for a private security contact channel—do not include exploit details, secrets, affected repository names, or logs.
12
+
13
+ Include, when possible:
14
+
15
+ - the affected Backburner version and operating system;
16
+ - the impact and the trust boundary that was crossed;
17
+ - minimal reproduction steps;
18
+ - whether credentials or private repository data may have been exposed; and
19
+ - any suggested mitigation.
20
+
21
+ You should receive an acknowledgement within seven days. This is a best-effort policy for a pre-1.0 open source project, not a service-level agreement.
22
+
23
+ ## Supported versions
24
+
25
+ Backburner is pre-1.0. Security fixes are applied to the latest published version and the current default branch. Older versions are not supported unless a release note explicitly says otherwise.
26
+
27
+ ## Threat model
28
+
29
+ ### Assets to protect
30
+
31
+ - GitHub authentication available through `gh`
32
+ - provider credentials and any other environment variables inherited by local subprocesses
33
+ - private repository source, history, issues, comments, and pull requests
34
+ - the integrity of branches, commits, comments, labels, and pull requests
35
+ - the developer machine and files reachable by provider tools
36
+ - local Backburner configuration, state, journal entries, and execution logs
37
+
38
+ ### Trusted components and people
39
+
40
+ Backburner assumes that you trust:
41
+
42
+ - the machine and operating-system account running it;
43
+ - the selected repositories and their existing build/test tooling;
44
+ - the GitHub users listed in `allowedUsers`;
45
+ - the installed `git`, `gh`, Node.js, npm, and provider CLIs;
46
+ - the configured model providers and the accounts used to reach them; and
47
+ - the npm package or source revision you installed.
48
+
49
+ If any of these are compromised, Backburner is not designed to contain that compromise.
50
+
51
+ ### Untrusted input
52
+
53
+ Treat all of the following as potentially adversarial:
54
+
55
+ - issue bodies, comments, PR descriptions, reviews, code, and repository documentation;
56
+ - generated model output;
57
+ - dependency install scripts, test commands, git hooks, and other repository tooling;
58
+ - MCP/tool responses and provider output; and
59
+ - network traffic that can reach a broker bound outside loopback.
60
+
61
+ GitHub content can contain prompt-injection instructions. `allowedUsers` reduces who can feed content into task derivation, but it does not make that content safe and it is not an operating-system sandbox.
62
+
63
+ ### Current security controls
64
+
65
+ - Repositories must be explicitly configured and enabled.
66
+ - GitHub actors are filtered through `allowedUsers` before their issues, PRs, comments, reviews, or label actions drive normal workflow decisions.
67
+ - Product approval, plan approval, review, parent-sync, and merge-preparation actions use configurable labels.
68
+ - Implementation happens in dedicated git worktrees instead of directly in the primary checkout.
69
+ - GitHub operations are routed through the authenticated `gh` CLI and constrained to configured repositories by Backburner's gateway and broker services.
70
+ - The orchestrator's broker binds to `127.0.0.1` by default.
71
+ - Read-only and workspace-write tasks are distinguished and mapped to provider-specific modes.
72
+ - Backburner creates and updates branches and pull requests, but does not silently perform the final merge.
73
+ - Configuration and state remain readable local JSON so operators can inspect them.
74
+
75
+ These are defense-in-depth controls, not a guarantee that an agent cannot make a harmful change.
76
+
77
+ ### Important limitations
78
+
79
+ #### Coding-agent permissions
80
+
81
+ Workspace-write tasks are intentionally powerful. Depending on the provider, Backburner may select modes that allow unattended edits and command execution—for example Codex workspace-write, Claude `bypassPermissions`, or Gemini `yolo`. Provider implementations and semantics can change independently of Backburner.
82
+
83
+ An agent can run repository commands, and those commands can execute arbitrary code available to your user account. Backburner is not a virtual machine or a security sandbox. Use a dedicated machine, operating-system account, container, or VM when you need a stronger boundary.
84
+
85
+ #### Credentials and environment
86
+
87
+ Local subprocesses normally inherit the Backburner process environment. Avoid launching Backburner from a shell containing unrelated long-lived secrets. Prefer narrowly scoped GitHub and provider credentials, enable MFA, and periodically review active tokens and sessions.
88
+
89
+ #### Model-provider data
90
+
91
+ Local-first does not mean offline. Prompts can include source code and GitHub content, and provider CLIs may send them to third-party services under those providers' terms, retention settings, and account policies. Do not onboard a repository whose data policy forbids that transfer.
92
+
93
+ #### Local broker
94
+
95
+ The HTTP broker has no application-level authentication. Its default loopback binding is the expected trust boundary. Do not run `backburner broker --host 0.0.0.0`, publish its port, place it behind a public tunnel, or expose it to an untrusted local network.
96
+
97
+ Other processes running as your user may be able to reach a loopback service. If your local account is not trusted, use a separate account or stronger isolation.
98
+
99
+ #### Logs and persisted state
100
+
101
+ Files under `~/.backburner` can include repository paths, issue and PR content, agent output, errors, and command results. Restrict filesystem access to your user, do not commit this directory, redact logs before sharing them, and remove it securely when retiring the installation.
102
+
103
+ #### Generated code
104
+
105
+ Backburner does not guarantee that generated changes are correct or secure. Keep repository branch protection and CI checks enabled, review the diff, and own the final merge decision.
106
+
107
+ ## Safe onboarding checklist
108
+
109
+ Before the first real run:
110
+
111
+ 1. Start with the private demo repository.
112
+ 2. Review the repositories and `allowedUsers` in `repos.json`.
113
+ 3. Review the configured provider commands, models, and roles in `agents.json`.
114
+ 4. Confirm what data each provider CLI sends remotely and what permission mode it uses.
115
+ 5. Remove unrelated secrets from the launching shell environment.
116
+ 6. Confirm the configured code, management, output, and log directories are private to your user.
117
+ 7. Keep the broker on its default loopback address.
118
+ 8. Keep branch protection, required CI, and human review on important repositories.
119
+ 9. Leave final merging to a trusted human.
120
+
121
+ ## Repository and package supply chain
122
+
123
+ For maintainers:
124
+
125
+ - require MFA for GitHub and npm maintainer accounts;
126
+ - use branch protection or repository rulesets for the default branch once public;
127
+ - enable private vulnerability reporting, dependency alerts, secret scanning, and push protection where available;
128
+ - review lockfile changes and keep `npm audit` results visible;
129
+ - publish releases from a protected GitHub Actions workflow using npm trusted publishing or `npm publish --provenance`;
130
+ - tag each published npm version and attach release notes to the same commit;
131
+ - keep workflow permissions minimal and pin or deliberately review third-party actions; and
132
+ - never publish from a dirty working tree.
133
+
134
+ npm provenance makes the package's source and build origin verifiable. It does not prove the source is benign or remove the need for review.
135
+
136
+ ## Out of scope
137
+
138
+ The following are not security vulnerabilities by themselves:
139
+
140
+ - a model producing incorrect, insecure, or low-quality code without crossing an advertised security boundary;
141
+ - provider rate limits, exhausted budgets, or unavailable third-party services;
142
+ - actions performed by a GitHub user intentionally listed in `allowedUsers`;
143
+ - damage caused by intentionally running a malicious repository's own scripts with agent write permissions; or
144
+ - disclosure that is already inherent in sending configured repository context to the chosen model provider.
145
+
146
+ Reports showing a bypass of repository scoping, actor filtering, task permission gates, broker boundaries, or credential isolation are in scope.
@@ -28,7 +28,7 @@ export function buildAntigravityCliArgs(options) {
28
28
  else {
29
29
  args.push("--dangerously-skip-permissions");
30
30
  }
31
- args.push("--print", "-");
31
+ args.push("--print", options.promptText);
32
32
  return args;
33
33
  }
34
34
  export async function writeAntigravitySettings(settingsPath, options) {
@@ -64,7 +64,8 @@ export class AntigravityCliAgent {
64
64
  ...(agentConfig.model ? { model: agentConfig.model } : {}),
65
65
  ...(resumeConversationId ? { conversationId: resumeConversationId } : {}),
66
66
  printTimeout: this.printTimeout,
67
- logFilePath
67
+ logFilePath,
68
+ promptText
68
69
  });
69
70
  this.logger?.info(JSON.stringify({
70
71
  component: "antigravity-launch",
@@ -102,7 +103,6 @@ export class AntigravityCliAgent {
102
103
  }
103
104
  const result = await this.options.commandRunner.run(agentConfig.command, args, {
104
105
  cwd,
105
- input: promptText,
106
106
  env: getAntigravityEnvOverrides(),
107
107
  timeoutMs: this.timeoutMs
108
108
  });
@@ -68,19 +68,21 @@ export class ShowSummaryStep {
68
68
  const issueTarget = buildFirstIssueTarget(ctx);
69
69
  lines.push("");
70
70
  lines.push("Next steps:");
71
- lines.push(" 1. Start the orchestrator:");
72
- lines.push(` ${buildRunCommand(ctx)}`);
73
71
  if (issueTarget !== undefined) {
74
- lines.push(" 2. Open a Backburner issue:");
72
+ lines.push(" 1. Open and submit your first Backburner issue:");
75
73
  lines.push(` ${issueTarget.prefilledIssueUrl}`);
76
- lines.push(" 3. Watch Backburner pick it up on the next orchestration cycle");
74
+ lines.push(" 2. Start the orchestrator and leave it running:");
75
+ lines.push(` ${buildRunCommand(ctx)}`);
76
+ lines.push(" 3. Continue from GitHub on your phone while this machine does the work");
77
77
  lines.push("");
78
78
  lines.push("Repository issues QR:");
79
79
  lines.push(renderQr(issueTarget.repositoryIssuesUrl));
80
80
  }
81
81
  else {
82
- lines.push(" 2. Add a repository to repos.json");
83
- lines.push(" 3. Open an issue on a managed repo with the configured product-approved label");
82
+ lines.push(" 1. Add a repository to repos.json");
83
+ lines.push(" 2. Open an issue on a managed repo with the configured product-approved label");
84
+ lines.push(" 3. Start the orchestrator and leave it running:");
85
+ lines.push(` ${buildRunCommand(ctx)}`);
84
86
  }
85
87
  }
86
88
  else {
@@ -24,7 +24,7 @@ export class ImplementationWorkflowService {
24
24
  const existing = input.existingWorktrees.find((worktree) => worktree.repoId === input.repo.id && worktree.issueNumber === input.issue.number) ??
25
25
  input.existingWorktrees.find((worktree) => worktree.repoId === input.repo.id && worktree.branchName === branchName);
26
26
  if (existing) {
27
- const preparedPaths = await preparePlanDocuments(existing.path, input.issue, input.decision, existing.branchName);
27
+ const preparedPaths = await preparePlanDocuments(existing.path, input.issue, input.decision, existing.branchName, input.repo.labels.agentPlanApproved);
28
28
  return {
29
29
  worktree: {
30
30
  ...existing,
@@ -45,7 +45,7 @@ export class ImplementationWorkflowService {
45
45
  const worktreePath = this.gitGateway.validatePathWithinCodeRoot(input.codeRoot, buildWorktreeRelativePath(input.repo, input.issue.number));
46
46
  const startPoint = input.repo.defaultBranch ? `origin/${input.repo.defaultBranch}` : "origin/HEAD";
47
47
  const createdPath = await this.gitGateway.createWorktree(input.repoPath, input.codeRoot, worktreePath, branchName, startPoint);
48
- const preparedPaths = await preparePlanDocuments(createdPath, input.issue, input.decision, branchName);
48
+ const preparedPaths = await preparePlanDocuments(createdPath, input.issue, input.decision, branchName, input.repo.labels.agentPlanApproved);
49
49
  const timestamp = this.now();
50
50
  return {
51
51
  created: true,
@@ -91,7 +91,7 @@ export class ImplementationWorkflowService {
91
91
  headBranch: worktree.branchName,
92
92
  baseBranch,
93
93
  title: buildPullRequestTitle(issue),
94
- body: buildPullRequestBody(issue, worktree)
94
+ body: buildPullRequestBody(issue, worktree, repo.labels.agentPlanApproved)
95
95
  });
96
96
  const timestamp = this.now();
97
97
  return {
@@ -153,6 +153,7 @@ export class ImplementationWorkflowService {
153
153
  packet,
154
154
  waveIndex,
155
155
  branchName,
156
+ planApprovalLabel: repo.labels.agentPlanApproved,
156
157
  now: this.now,
157
158
  existingPaths: {
158
159
  planDocumentPath: existing.planDocumentPath,
@@ -186,6 +187,7 @@ export class ImplementationWorkflowService {
186
187
  packet,
187
188
  waveIndex,
188
189
  branchName,
190
+ planApprovalLabel: repo.labels.agentPlanApproved,
189
191
  now: this.now
190
192
  });
191
193
  const timestamp = this.now();
@@ -243,7 +245,12 @@ export class ImplementationWorkflowService {
243
245
  headBranch: worktree.branchName,
244
246
  baseBranch,
245
247
  title: buildPacketPullRequestTitle({ parentWorkstream, packetId: packet.id }),
246
- body: buildPacketPullRequestBody({ parentWorkstream, packet, worktree })
248
+ body: buildPacketPullRequestBody({
249
+ parentWorkstream,
250
+ packet,
251
+ worktree,
252
+ planApprovalLabel: repo.labels.agentPlanApproved
253
+ })
247
254
  });
248
255
  const timestamp = this.now();
249
256
  return {
@@ -555,7 +562,7 @@ export function buildPacketWorktreeRelativePath(input) {
555
562
  const { type, number } = input.parentWorkstream.origin;
556
563
  return path.join(WORKTREE_ROOT_DIR, slugify(owner), slugify(name), `workstream-${type}-${number}`, `packet-${getPacketSlug(input.packetId)}`);
557
564
  }
558
- async function preparePlanDocuments(worktreePath, issue, decision, branchName) {
565
+ async function preparePlanDocuments(worktreePath, issue, decision, branchName, planApprovalLabel) {
559
566
  const relativePaths = buildAgentDocumentRelativePaths(issue.number, branchName);
560
567
  const planDocumentPath = path.join(worktreePath, relativePaths.planDocumentPath);
561
568
  const productSpecDocumentPath = path.join(worktreePath, relativePaths.productSpecDocumentPath);
@@ -575,6 +582,7 @@ async function preparePlanDocuments(worktreePath, issue, decision, branchName) {
575
582
  "",
576
583
  "## Notes",
577
584
  "- Planning document created by the orchestrator workflow.",
585
+ `- Implementation must not begin until the \`${planApprovalLabel}\` label is present.`,
578
586
  ""
579
587
  ].join("\n"), "utf8");
580
588
  }
@@ -593,7 +601,7 @@ async function preparePlanDocuments(worktreePath, issue, decision, branchName) {
593
601
  };
594
602
  }
595
603
  async function preparePacketPlanDocuments(input) {
596
- const { worktreePath, parentWorkstream, packet, branchName, now, existingPaths } = input;
604
+ const { worktreePath, parentWorkstream, packet, branchName, planApprovalLabel, now, existingPaths } = input;
597
605
  const relativePaths = existingPaths
598
606
  ? undefined
599
607
  : buildPacketAgentDocumentRelativePaths(packet.id, branchName);
@@ -627,7 +635,7 @@ async function preparePacketPlanDocuments(input) {
627
635
  "",
628
636
  "## Notes",
629
637
  `- This is a packet planning PR targeting \`${integrationBranch}\`.`,
630
- "- Implementation must not begin until the `agent-plan-approved` label is present.",
638
+ `- Implementation must not begin until the \`${planApprovalLabel}\` label is present.`,
631
639
  ""
632
640
  ].join("\n"), "utf8");
633
641
  }
@@ -658,7 +666,7 @@ function compareWorktrees(left, right) {
658
666
  function buildPullRequestTitle(issue) {
659
667
  return `agent: plan for issue #${issue.number} - ${issue.title}`;
660
668
  }
661
- function buildPullRequestBody(issue, worktree) {
669
+ function buildPullRequestBody(issue, worktree, planApprovalLabel) {
662
670
  const planPath = toRepoRelativePath(worktree.path, worktree.planDocumentPath);
663
671
  const productSpecPath = worktree.productSpecDocumentPath
664
672
  ? toRepoRelativePath(worktree.path, worktree.productSpecDocumentPath)
@@ -672,7 +680,7 @@ function buildPullRequestBody(issue, worktree) {
672
680
  ...(productSpecPath ? [`- Product Spec: \`${productSpecPath}\``] : []),
673
681
  `- Plan document: \`${planPath}\``,
674
682
  `- Agent log: \`${logPath}\``,
675
- "- Implementation must not begin until the `agent-plan-approved` label is present."
683
+ `- Implementation must not begin until the \`${planApprovalLabel}\` label is present.`
676
684
  ].join("\n");
677
685
  }
678
686
  function buildPacketPullRequestTitle(input) {
@@ -683,7 +691,7 @@ function buildPacketPullRequestTitle(input) {
683
691
  return `agent: plan packet ${packetId} for ${source}`;
684
692
  }
685
693
  function buildPacketPullRequestBody(input) {
686
- const { parentWorkstream, packet, worktree } = input;
694
+ const { parentWorkstream, packet, worktree, planApprovalLabel } = input;
687
695
  if (!worktree.packet)
688
696
  throw new Error("Missing packet metadata");
689
697
  const planPath = toRepoRelativePath(worktree.path, worktree.planDocumentPath);
@@ -710,7 +718,7 @@ function buildPacketPullRequestBody(input) {
710
718
  ...packet.dependsOn.map((d) => `- ${d}`),
711
719
  "",
712
720
  "This PR was created by the orchestrator as a packet planning PR.",
713
- "Implementation must not begin until the `agent-plan-approved` label is present."
721
+ `Implementation must not begin until the \`${planApprovalLabel}\` label is present.`
714
722
  ].join("\n");
715
723
  }
716
724
  function buildAgentDocumentRelativePaths(issueNumber, branchName) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backburner/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Local GitHub-based agent orchestration CLI",
6
6
  "license": "MIT",
@@ -25,7 +25,8 @@
25
25
  },
26
26
  "files": [
27
27
  "dist/src",
28
- "README.md"
28
+ "README.md",
29
+ "SECURITY.md"
29
30
  ],
30
31
  "bin": {
31
32
  "backburner": "dist/src/cli/run.js"
@@ -39,7 +40,7 @@
39
40
  "link:local": "npm run build && npm link",
40
41
  "install:local": "node scripts/install-local-package.mjs",
41
42
  "typecheck": "tsc -p tsconfig.json --noEmit",
42
- "test": "npm run build && node --import ./dist/test/setup.js --test --test-concurrency=1 dist/test/*.test.js",
43
+ "test": "npm run build && node scripts/run-tests.mjs",
43
44
  "run:backburner": "node dist/src/cli/run.js run",
44
45
  "run:github-broker": "node dist/src/cli/run.js broker",
45
46
  "smoke:github-broker": "node dist/src/cli/run.js broker-smoke",