@codetreker/daynight 0.21.1 → 0.21.3

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 ADDED
@@ -0,0 +1,1153 @@
1
+ # Daynight CLI
2
+
3
+ The `@codetreker/daynight` package provides the `daynight` command and its `dn`
4
+ alias. Use it to manage server-backed projects, tasks and attachments, install
5
+ the `using-daynight` skill for coding agents, and run a local GitHub PR reviewer
6
+ through Copilot CLI. Both command names share configuration and behavior.
7
+
8
+ See the [project overview](../../README.md) for the browser workspace and service,
9
+ and the [development guide](../../docs/development.md) for source builds,
10
+ validation, package versions and npm publication. Each command's `--help` owns
11
+ its exact usage. Review execution additionally requires Git, an authenticated
12
+ GitHub CLI and Copilot CLI on `PATH`.
13
+
14
+ - [Install and update](#install-and-update)
15
+ - [Client commands](#client-commands)
16
+ - [Agent skill installation](#agent-skill-installation)
17
+ - [Shell completion](#shell-completion)
18
+ - [Configuration setup](#configuration-setup)
19
+ - [Project management](#project-management)
20
+ - [Task management](#task-management)
21
+ - [Task deletion](#task-deletion)
22
+ - [Task attachments](#task-attachments)
23
+ - [Review configuration and startup](#review-configuration-and-startup)
24
+ - [Review status listing](#review-status-listing)
25
+ - [Durable review state](#durable-review-state)
26
+ - [GitHub observations](#github-observations)
27
+ - [Repository clones and worktrees](#repository-clones-and-worktrees)
28
+ - [Copilot execution](#copilot-execution)
29
+ - [Coordination and shutdown](#coordination-and-shutdown)
30
+
31
+ ## Install and update
32
+
33
+ Use Node.js 24 LTS. Install the CLI with npm:
34
+
35
+ ```bash
36
+ npm install --global @codetreker/daynight
37
+ dn --version
38
+ ```
39
+
40
+ The installation provides both `daynight` and `dn`; every command works with
41
+ either name, for example `dn task list` or `dn skill install`. Help and diagnostics
42
+ use the canonical `daynight` spelling.
43
+
44
+ Update that npm global installation with:
45
+
46
+ ```bash
47
+ dn update
48
+ ```
49
+
50
+ The command checks `@codetreker/daynight`'s `latest` version in the configured npm
51
+ registry and installs that exact version only when it is newer. It updates the
52
+ installation that is running, even if npm's current default global prefix has
53
+ changed. An equal or newer installed version succeeds without installation or
54
+ downgrade. User and global npm registry/authentication settings apply; the current
55
+ working directory's project `.npmrc` does not select the update source.
56
+
57
+ `daynight update --help` explains the command. Self-update requires an npm-owned
58
+ global package and launcher. Source checkouts, local dependencies, `npx`, pnpm and
59
+ `npm link` installations receive guidance to use their original package manager.
60
+ If an update is needed, run the command from outside its installation directory.
61
+ The installer streams its output, enforces the target's Node.js engine requirement
62
+ and reports permission, network and installation errors. It does not request
63
+ administrator privileges automatically. npm owns replacement and recovery; a
64
+ failed installation is not a promise that every original file remains unchanged.
65
+
66
+ The command verifies the installed manifest, launcher and a fresh invocation's
67
+ version, then refreshes existing `using-daynight` skills from that installed
68
+ package. It checks User destinations and the current Git worktree's Project
69
+ destinations, including calls from subdirectories and linked worktrees. Outside
70
+ Git it checks User destinations only. It does not search other projects or need
71
+ agent launchers on PATH. Missing skills remain uninstalled. The same refresh
72
+ runs when the CLI is already current or ahead, using its installed bundle.
73
+
74
+ Refresh replaces complete skill directories, including local edits and obsolete
75
+ files. Shared physical destinations are written once. Each result identifies
76
+ its agents, scope, path and package version. A skill failure exits nonzero and
77
+ reports the package outcome separately; a successfully installed npm package is
78
+ retained, and rerunning `update` retries the skill refresh. All phases must
79
+ succeed before the command reports success. It requires no review configuration and does
80
+ not open SQLite, modify sessions or restart a running reviewer. The next CLI
81
+ invocation uses the installed version. Restart any running reviewer to use it;
82
+ on Windows, a reviewer holding a native addon open can prevent npm from replacing
83
+ that file and cause the update to fail. The
84
+ [self-update decision](../../.agents/notes/implemented/feature/2026-10-20-cli-self-update.md)
85
+ records installation ownership and verification requirements.
86
+
87
+ ## Client commands
88
+
89
+ ```text
90
+ daynight # Show root help
91
+ daynight --help # Also -h
92
+ daynight --version # Also -v
93
+ daynight update
94
+ daynight login [--no-browser] # Authorize CLI access through the browser
95
+ daynight logout # Revoke and remove the current CLI credential
96
+ daynight review # Show review help
97
+ daynight review run
98
+ daynight review list # Also review ls
99
+ daynight review add-repo <remote> [--path <path>]
100
+ daynight completion # Show completion help
101
+ daynight completion bash
102
+ daynight completion zsh
103
+ daynight completion setup [--shell bash|zsh] [--rc-file <path>]
104
+ daynight skill # Show skill help
105
+ daynight skill install # Select Agents, then User or Project scope
106
+ daynight project
107
+ daynight project create <name> [--repo <repo>]
108
+ daynight project list [--json]
109
+ daynight project show <project-id> [--json]
110
+ daynight task
111
+ daynight task create --title <title> [options]
112
+ daynight task list [--all | --status <status>] [--ready] [--json] [--project <project-id>]
113
+ daynight task ready [--limit <N>] [--json] [--project <project-id>]
114
+ daynight task show <task-id> [--json] [--project <project-id>]
115
+ daynight task update <task-id> [options]
116
+ daynight task set-status <task-id> <status> [--if-version <version>] [--project <project-id>]
117
+ daynight task delete <task-id> [--remove-depends] [--if-version <version>] [--project <project-id>]
118
+ daynight task graph [--json] [--project <project-id>]
119
+ daynight task attachment
120
+ daynight task attachment put <task-id> <file> [--path <relative-path>] [--project <project-id>]
121
+ daynight task attachment list <task-id> [--tree | --json] [--project <project-id>]
122
+ daynight task attachment read <task-id> <relative-path> [--project <project-id>]
123
+ daynight task attachment remove <task-id> <relative-path> [--project <project-id>]
124
+ ```
125
+
126
+ Groups and operations show help when `--help` or `-h` is their sole argument.
127
+ Help, version and completion generation do not resolve the user home, load review
128
+ configuration, open SQLite or require review tools. `review add-repo` accepts one
129
+ `--path <path>` before or after its remote; `--path=value` and `--` are invalid.
130
+ Unknown commands and invalid arguments exit with status 2; operation failures
131
+ exit with status 1 and retain their cause. The old `--daemon-review` and root
132
+ `add-repo` forms are invalid. The
133
+ [client design](../../docs/design/daynight.md) owns command composition and lazy loading;
134
+ the [composition decision](../../.agents/notes/implemented/architecture/2026-10-20-client-command-composition.md)
135
+ records module ownership and the preserved data layout.
136
+
137
+ ## Agent skill installation
138
+
139
+ Install the public `using-daynight` skill through an interactive terminal:
140
+
141
+ ```bash
142
+ daynight skill install
143
+ ```
144
+
145
+ The command detects available codex, copilot and claude launchers without
146
+ starting them or checking login. Select one or more detected Agents with Space,
147
+ then Enter; the initial selection is empty. Next select User or Project,
148
+ with User initially selected. Installation starts after the scope is submitted.
149
+ Repeating the command refreshes the full bundle from the running package.
150
+ `daynight update` automatically refreshes existing User and current-worktree
151
+ Project copies with the same replacement semantics; it also repairs existing
152
+ skill directories whose entrypoint was removed and replaces dangling leaf links.
153
+ A regular file at the expected skill-directory path is an error. See
154
+ [CLI updates](#install-and-update) for package ownership and failure handling.
155
+
156
+ | Agent | User destination | Project destination |
157
+ |---|---|---|
158
+ | Codex | `~/.agents/skills/using-daynight/` | `<worktree>/.agents/skills/using-daynight/` |
159
+ | Copilot CLI | `~/.agents/skills/using-daynight/` | `<worktree>/.agents/skills/using-daynight/` |
160
+ | Claude Code | `~/.claude/skills/using-daynight/` | `<worktree>/.claude/skills/using-daynight/` |
161
+
162
+ User scope works outside Git. Project scope uses the current Git worktree root,
163
+ including calls from subdirectories or linked worktrees, without requiring an
164
+ origin, server configuration or project association. Installing the skill and
165
+ associating a project remain separate operations. Terminal stdin and stderr are
166
+ required; prompts use stderr and installation results use stdout. Help and
167
+ installation do not depend on review configuration or credentials.
168
+
169
+ Each installation replaces the complete using-daynight leaf, including local
170
+ edits and obsolete files. It then removes the legacy daynight leaf in the same
171
+ selected physical skill root. The old name is retained until publication
172
+ succeeds. Other skills, opposite-scope copies and parent-directory links are
173
+ preserved; leaf links are replaced or removed without following their targets.
174
+ Several Agent paths resolving to one physical root share one write. Destructive
175
+ nesting involving an installation or legacy-cleanup path is rejected before
176
+ writing. Discovery paths may be shared with unselected Agents, and host precedence
177
+ continues to govern copies at other scopes.
178
+
179
+ The command reports per-Agent destinations and results. Failure stops later
180
+ targets, retains earlier completed installations and exits nonzero. If legacy
181
+ cleanup fails after publication, the new bundle stays installed and the command
182
+ reports the incomplete migration. Replacement failure after removing an existing
183
+ using-daynight leaf may leave that destination absent; diagnostics preserve the
184
+ actual phase and reason. Rerunning installs the complete packaged bundle.
185
+ Cancellation before publication cleans its stage and newly created empty parents.
186
+
187
+ Codex normally discovers changed skills automatically; restart its session if
188
+ needed. For Copilot CLI run `/skills reload` and inspect
189
+ `/skills info using-daynight`. Claude Code watches existing roots; use
190
+ `/reload-skills` when a top-level skills directory was created during the session.
191
+ The [skill design](../../docs/design/daynight-agent-skill.md) owns mechanisms, routing
192
+ and the simulated-launcher native installation matrix.
193
+
194
+ ## Shell completion
195
+
196
+ Bash 4.2 or newer and zsh have native completion scripts. Install startup
197
+ configuration with:
198
+
199
+ ```bash
200
+ daynight completion setup
201
+ ```
202
+
203
+ Setup detects the calling shell from its direct parent process. If it cannot
204
+ identify Bash or zsh reliably, select one explicitly:
205
+
206
+ ```bash
207
+ daynight completion setup --shell bash
208
+ daynight completion setup --shell zsh
209
+ ```
210
+
211
+ The login-shell preference in `SHELL` does not establish which shell is running.
212
+ For a custom startup file, use `--rc-file`; only that file is managed:
213
+
214
+ ```bash
215
+ daynight completion setup --shell bash --rc-file /path/to/bashrc
216
+ ```
217
+
218
+ Bash setup manages `.bashrc` and the first readable existing login file in the
219
+ order `.bash_profile`, `.bash_login`, `.profile`. It creates `.bash_profile` only
220
+ when none of those files exists; if existing profiles are all unreadable, it
221
+ reports an error. The login block runs only in interactive Bash and can safely
222
+ appear in a `.profile` shared with other POSIX shells. It does not
223
+ make the login shell load the rest of `.bashrc`.
224
+
225
+ zsh setup uses `$ZDOTDIR/.zshrc`, or `$HOME/.zshrc` when `ZDOTDIR` is unset.
226
+ An exported empty `ZDOTDIR` selects `/.zshrc`; setup resolves a relative value
227
+ from its current working directory. A later zsh started in another directory
228
+ resolves that relative value from its own startup directory. A value set only
229
+ inside zsh is not visible to the installer; use `--rc-file` in that case.
230
+ The managed block reuses an initialized completion system or runs `compinit`
231
+ with its normal security checks before loading daynight.
232
+
233
+ Setup recognizes its managed block and the documented standalone manual loading
234
+ statement. Repeating it leaves an installed file unchanged. A managed block
235
+ checks that both `daynight` and `dn` use the expected callable completion
236
+ function before skipping loading. A missing or replaced registration for either
237
+ command reloads the shared script and restores both commands. Complete
238
+ registrations are reused, including when startup files load each other. Preserved
239
+ manual loading statements keep their unconditional behavior: if one runs after a managed block, it generates and loads the script
240
+ again. Existing content, line endings, permissions and startup-file symbolic
241
+ links are retained. Added blocks use LF line endings because a carriage return
242
+ is shell token data. Malformed managed blocks, invalid targets and file access failures produce
243
+ explicit errors. Setup does not migrate blocks from earlier templates. If an
244
+ earlier block is reported as unrecognized, remove its marked section and rerun
245
+ setup, or use the source command below to activate the current script directly.
246
+
247
+ Setup reports the startup files it handled. It installs persistent configuration;
248
+ an ordinary CLI child process cannot inspect or change its parent shell's loaded
249
+ completion functions. Use the existing loading command to enable completion in
250
+ the current session:
251
+
252
+ ```bash
253
+ source <(daynight completion bash)
254
+ ```
255
+
256
+ For zsh, initialize its completion system first if the session has not already
257
+ done so:
258
+
259
+ ```zsh
260
+ autoload -Uz compinit
261
+ compinit
262
+ source <(daynight completion zsh)
263
+ ```
264
+
265
+ The `bash` and `zsh` generation operations write only scripts to stdout and do
266
+ not change startup files. Loading the zsh script without initialized `compinit`
267
+ fails with a diagnostic. The outputs are designed for `source`; using the same
268
+ output directly as an `fpath` autoload file is outside the loading contract.
269
+ Setup checks file contents without executing them. Custom early returns or later
270
+ commands that remove registrations can prevent a startup file from enabling
271
+ completion; verify such configuration by starting the shell.
272
+
273
+ The generated scripts register completion for both `daynight` and `dn`.
274
+ Completion suggests commands, nested operations, aliases, options, shell names
275
+ and local directories for `review add-repo --path`.
276
+ zsh also displays descriptions.
277
+ The scripts run in the shell on each Tab without starting Node or reading review
278
+ configuration, SQLite or the network. Directory suggestions preserve quoted and
279
+ special-character paths; an uncreated target directory remains valid input.
280
+
281
+ New shells generate definitions from the currently installed package. After an
282
+ update, run the applicable `source` command again to refresh an existing shell.
283
+ A saved generated script must be regenerated after updating. The
284
+ [completion design](../../docs/design/daynight-completion.md) explains the shared grammar
285
+ and shell integration. The
286
+ [completion decision](../../.agents/notes/implemented/feature/2026-10-20-shell-completion.md)
287
+ records compatibility and execution trade-offs; the
288
+ [setup decision](../../.agents/notes/implemented/feature/2026-10-21-completion-setup.md)
289
+ records startup-file ownership and installation limits.
290
+
291
+ ## Configuration setup
292
+
293
+ Project and task commands use `https://daynight.cc` when the configuration file or
294
+ `serverUrl` is absent. A production connection needs no server configuration.
295
+ Run `daynight login` to display an authorization code and open the verification
296
+ page. Check that the page's code matches the terminal, confirm the account and
297
+ approve access. The CLI saves the resulting credential without displaying its
298
+ secret. `daynight login --no-browser` displays the URL and code for authorization
299
+ in another browser. The device authorization expires after ten minutes; rejection, expiry and
300
+ cancellation leave an existing saved credential unchanged.
301
+
302
+ The CLI credential is named `Daynight CLI (<hostname>)`, using the machine that
303
+ runs `daynight login`, including when another device approves access. Hostnames
304
+ longer than 85 Unicode characters are shortened to their first 85 characters to
305
+ keep the credential name within 100 characters. The credential never expires by default.
306
+ The Web account's token manager can set a future expiration, restore “Never expires”, or
307
+ revoke it. Changing expiration keeps the same credential, so the saved CLI login
308
+ continues without replacing its secret. Expired or revoked credentials cannot be
309
+ revived. The [token manager mockup](../../packages/daynight-web/tests/mockups/tokens.html)
310
+ shares the production components and styles for creating tokens and editing
311
+ expiration, including conflict and uncertain-result states. A credential
312
+ represents the account's current project permissions. `daynight logout` revokes the current credential and removes
313
+ its local value after a confirmed response; an already invalid credential is
314
+ removed locally. Network or unconfirmed failures remain visible. Configuration
315
+ changes made during login or logout cannot overwrite another service origin or
316
+ another saved credential. A lost successful login response requires a fresh
317
+ login; the account token list can revoke a credential whose response was lost.
318
+
319
+ Without a local credential, a service command fails before dispatch and directs
320
+ the user to `daynight login`. A server `401` gives the same guidance. Business
321
+ commands do not start login, follow redirects with credentials, or automatically
322
+ repeat a write. Reconcile an unconfirmed business mutation before another one.
323
+
324
+ The first `review run`, `review list` or `review ls` asks for a repository when
325
+ the file or `repositories` field is absent. To configure one in advance, run:
326
+
327
+ ```bash
328
+ daynight review add-repo https://github.com/OWNER/REPO.git
329
+ daynight review add-repo git@github.com:OWNER/OTHER.git --path ./review-other
330
+ ```
331
+
332
+ Interactive guidance requires terminal stdin and stderr. Prompts and save
333
+ messages use stderr so stdout retains its normal text or JSON format.
334
+ Noninteractive missing review configuration fails with a `review add-repo`
335
+ command. Shared YAML/schema errors, invalid selected values, explicit empty
336
+ review lists and read failures retain their errors. Unrelated capability values
337
+ remain outside the current command's validation. Help, version, completion,
338
+ update and invalid arguments do not prompt.
339
+
340
+ Test services and noninteractive automation use the existing
341
+ `~/.daynight/config.yml` fields. For a test service, provision its origin before
342
+ running `daynight login`:
343
+
344
+ ```yaml
345
+ serverUrl: http://127.0.0.1:8787
346
+ ```
347
+
348
+ For unattended access, a secret-provisioning process can write `serverToken`
349
+ together with its intended `serverUrl`; omit `serverUrl` only when the credential
350
+ belongs to `https://daynight.cc`. Keep that file private, with mode `0600` on
351
+ POSIX, and never put credentials in command arguments, logs or repository files.
352
+ Provisioners must preserve unrelated settings and pair the origin with its own
353
+ credential. Replacing `serverUrl` manually does not clear an old token; remove
354
+ or replace it before sending another request. External editors and provisioners
355
+ do not participate in the CLI's configuration lock.
356
+
357
+ Tokens are opaque visible ASCII and require HTTPS except for HTTP origins whose
358
+ host is literal `localhost`, a numeric IPv4 address in `127.0.0.0/8`, or `::1`.
359
+ Invalid explicit origins and credentials remain errors. Normal CLI use requires
360
+ no manual PAT creation. There is no top-level `daynight setup` command; shell
361
+ startup installation remains available through `daynight completion setup`.
362
+
363
+ Review guidance collects values before one atomic save under the configuration
364
+ write lock, preserving comments, unrelated settings and completed concurrent
365
+ changes to unrelated fields. A selected review-field conflict requires a fresh
366
+ decision. Login and logout check the observed origin and credential together
367
+ under the same lock. Credential-bearing files use POSIX mode `0600`, including
368
+ review writes; files without a token retain existing permissions. Symlink
369
+ rejection and atomic replacement apply to CLI configuration writers.
370
+ Ctrl+C, termination signals or EOF cancel prompts without partial saves or
371
+ business execution. Human input consumes no business timeout. Review guidance
372
+ saves configuration without network, login or authentication checks; cloning and
373
+ review state initialization belong to the business operation.
374
+
375
+ The [configuration decision](../../.agents/notes/implemented/feature/2026-10-21-guided-configuration-setup.md)
376
+ owns review guidance and persistence; the
377
+ [device-login decision](../../.agents/notes/implemented/architecture/2026-10-25-cli-device-login.md)
378
+ owns the default service, explicit login/logout and credential lifecycle. The
379
+ [top-level setup removal decision](../../.agents/notes/implemented/simplification/2026-10-25-remove-top-level-setup.md)
380
+ records the command removal and configuration-file provisioning boundary.
381
+
382
+ ## Project management
383
+
384
+ After `daynight login`, create, list or inspect projects on `https://daynight.cc`.
385
+ To use a test server, set `serverUrl` in `~/.daynight/config.yml`:
386
+
387
+ ```yaml
388
+ serverUrl: http://127.0.0.1:8787
389
+ ```
390
+
391
+ The origin includes its protocol, host and optional port; the client adds
392
+ `/api/v1`. When changing the origin externally, remove the old `serverToken`
393
+ before logging in to the new service; manual edits do not run CLI credential
394
+ cleanup. Then use the same commands:
395
+
396
+ ```bash
397
+ daynight project create "Example"
398
+ daynight project create "Example" --repo https://github.com/OWNER/REPO.git
399
+ daynight project list
400
+ daynight project list --json
401
+ daynight project show <project-id> --json
402
+ ```
403
+
404
+ Creation requires one positional name; quote names containing spaces. Omit
405
+ `--repo` to use the current Git worktree's effective `origin`, including Git
406
+ `insteadOf` expansion. Supply `--repo` to use that address without inspecting Git;
407
+ this form, listing and details work outside Git repositories. For a name beginning
408
+ with `-`, use `daynight project create -- -name` or put an explicit repository
409
+ option before the terminator: `daynight project create --repo <repo> -- -name`.
410
+ The name is sent unchanged.
411
+
412
+ Creation first scans every project page and compares canonical repository
413
+ identities. With no match it registers the original name and repository address.
414
+ With one match it reports `Project already exists.` and the existing project,
415
+ leaving that project's name and address unchanged. Multiple matches fail with
416
+ their IDs; lookup failures and exhausted command budgets stop before creation.
417
+ This client preflight does not provide atomic uniqueness against concurrent
418
+ creators, and the service continues to allow duplicate repository registrations.
419
+ Project commands do not write repository bindings or ignore rules. Lists traverse
420
+ all pages. Human output uses complete labeled project blocks with visible
421
+ terminal-control escapes. JSON preserves resource fields and nanosecond timestamp
422
+ strings; a later-page failure produces an error with empty stdout. The
423
+ [project/task requirements](../../docs/spec/daynight-project-task.md) own the complete
424
+ behavior and remaining task-command scope.
425
+
426
+ ## Task management
427
+
428
+ Task commands use the same `serverUrl` configuration as project commands:
429
+
430
+ ```bash
431
+ daynight task create --title "Implement sign-in" --description '## Sign-in
432
+
433
+ Implement OAuth sign-in for the web workspace. Deliver the callback flow and
434
+ visible failure recovery; preserve the existing session and provider rules.
435
+ Complete when a valid login opens the workspace and a rejected login can retry.'
436
+ daynight task create --title "Build the sign-in page" --depends-on <design-task-id> --external-depends-on <authentication-task-id>
437
+ daynight task ready
438
+ daynight task ready --limit 5 --json
439
+ daynight task ready --allow-agents true --compatible-platform linux --json
440
+ daynight task list --allow-agents false --ready
441
+ daynight task list --ready
442
+ daynight task list --all --json
443
+ daynight task list --status in_progress --json
444
+ daynight task show <task-id> --json
445
+ daynight task update <task-id> --description=
446
+ daynight task update <task-id> --allow-agents true --if-version <version>
447
+ daynight task create --title "Check Windows build" --required-platform windows
448
+ daynight task update <task-id> --required-platform macos --if-version <version>
449
+ daynight task update <task-id> --clear-required-platform --if-version <version>
450
+ daynight task set-status <task-id> <status> [--if-version <version>] [--project <project-id>]
451
+ daynight task update <task-id> --depends-on <task-a> --depends-on <task-b>
452
+ daynight task update <task-id> --clear-dependencies
453
+ daynight task graph --json
454
+ ```
455
+
456
+ Every operation accepts `--project <project-id>`, which selects a project for one
457
+ invocation without reading Git or local bindings. Otherwise, the CLI reads the
458
+ current worktree's effective `origin`, normalizes equivalent HTTPS/SSH/SCP
459
+ addresses, and matches the configured server's projects. A missing match fails
460
+ with `Project does not exist`; multiple matches require explicit selection.
461
+ A unique discovery is saved in the worktree's `.daynight/project.yml` with the
462
+ server origin and repository identity, after ensuring `/.daynight/` is effective
463
+ in the root `.gitignore`. A cached binding is verified against the server on each
464
+ use and remains stable if another project later shares that repository.
465
+
466
+ Creation starts in `todo` with `allowAgents=false` and unrestricted
467
+ `requiredPlatform=null` unless explicitly set. `task set-status <id> <status>`
468
+ sets `todo`, `in_progress` or `done`, including reopening and direct completion.
469
+ Every project member may use ordinary status setting. Active worker completion
470
+ requires the current owner and matching claim ID through the typed completion
471
+ operation; release and continuation of released work use their protected
472
+ operations. Status does not grant execution or delivery authority. Generic updates cannot write status; old lifecycle commands and routes
473
+ are removed without aliases. `--if-version` uses the exact reviewed int64 value;
474
+ without it, the CLI reads once immediately before submitting. No write retries
475
+ occur. Version is checked before same-state handling: current same-state keeps
476
+ version, update time and timing unchanged; actual changes increment once.
477
+
478
+ Entering in_progress or done requires all direct prerequisites, ordinary and
479
+ external, to be done. Reopening done requires no direct in-progress or done
480
+ dependents. Refusals return sorted blocking task IDs without cascading changes.
481
+ The project transaction serializes status and dependency writes and preserves
482
+ materials, properties/PRs, permission, both dependency sets and attachments.
483
+
484
+ Migration `014_task_status_assignment.sql` converts historical proposed rows
485
+ to todo, increments only those versions and updates their update time while
486
+ preserving every other field, including requiredPlatform and historical execution timestamps. Default,
487
+ data, CHECK and ledger change atomically. Other rows and applied migrations remain
488
+ unchanged; restart does not repeat the conversion. Runtime readers reject the old state.
489
+
490
+ Task resources expose required nullable `startedAt` and `completedAt`. Actual entry
491
+ into in_progress starts a new interval and clears the end; return to todo clears
492
+ both. In-progress to done preserves a nullable start and records a real end;
493
+ todo to done records only an end, leaving duration unknown. Metadata and same-state
494
+ writes preserve time. Complete-graph and task-sync responses supply a database
495
+ `observedAt` sample; Web synchronization updates its separate clock without
496
+ rebuilding unchanged graph/index data.
497
+ Read-only timing fields remain in JSON; human CLI output keeps its field choices.
498
+ The [status requirements](../../docs/spec/daynight-task-status.md) and
499
+ [architecture](../../docs/design/daynight-task-status.md) own the complete rules.
500
+
501
+ Task and graph resources also require `externalDependsOn`, a sorted,
502
+ duplicate-free subset of all `dependsOn` IDs. CLI JSON preserves it and the
503
+ shared human dependency block shows `External dependencies (N): ...`. Current
504
+ API dependency fields are independently optional: a dependsOn-only PATCH
505
+ retains classification on surviving edges, while an externalDependsOn-only PATCH
506
+ replaces the exact external subset. CLI --depends-on and --external-depends-on
507
+ compile both complete sets whenever either option is supplied; ordinary-only
508
+ clears the external subset and external-only replaces all relationships. Omit
509
+ both CLI options to preserve them. Metadata and lifecycle actions retain
510
+ unmodified classification. Every edge still participates in blocking and cycles.
511
+
512
+ Every Project resource includes `settings` with an exact positive int64 `version`
513
+ and `executionWarningMinutes` from 1 through 2147483647, initially 60. Project
514
+ create/read/list, the project in graph responses, and a successful settings PATCH
515
+ return this same shape. The member-readable settings page lets administrators
516
+ save or cancel a draft; ordinary members see the saved value without editing.
517
+ The server checks current administrator authority after the project lock, then
518
+ the observed settings version. An equal-value save preserves version and
519
+ `updatedAt`; a real change increments version and updates `updatedAt`. Migration
520
+ preserves historical project timestamps. CLI JSON preserves settings and nested
521
+ versions without rounding; human output keeps its established fields.
522
+
523
+ An unconfirmed settings PATCH response requires a Project and membership reread
524
+ before another write. Failed reconciliation keeps Save blocked and offers read
525
+ retry; network, protocol, 5xx or navigation cancellation never prove rollback.
526
+ Confirmed refusals and unsaved/canceled drafts do not apply local settings.
527
+ Project-only changes update graph metadata while retaining the task index and
528
+ layout when tasks and summary are unchanged. Running known-start tasks subscribe
529
+ to one visible-page ticker; completed duration uses stored endpoints and unknown
530
+ starts show no inferred duration. Warnings use an unrounded strict comparison
531
+ and disappear on completion without changing task status. The server-sample
532
+ clock avoids client wall-clock skew but does not remove network sampling delay.
533
+
534
+
535
+ The Web detail header places a three-item status menu beside the actual task
536
+ title on both tabs. The current item remains selectable. Confirmation names the
537
+ task, current/target states and timing effects; Cancel and Escape send no write.
538
+ Status, **Automatic execution / 自动执行** and platform confirmation share one per-task mutation owner.
539
+ Pending, stale or unknown results block conflicting writes. Current-version same-state responses
540
+ confirm no stored change; actual changes refresh the graph. Unknown outcomes use
541
+ GET-only reconciliation, preserving errors and never attributing the observed
542
+ state to the uncertain request. Closing details does not roll back a submission.
543
+
544
+ Task details use one platform select in the left status group to display the
545
+ confirmed requirement and offer Any platform, Windows, Linux and macOS. Choosing
546
+ a different value opens confirmation showing the current and target platforms;
547
+ only confirmation submits the reviewed exact task version. Choosing the saved
548
+ value, Cancel, close, backdrop dismissal and Escape send no request. Cancellation
549
+ returns focus to the select. The confirmed value remains displayed until success,
550
+ and Any platform clears requiredPlatform. Overview has no separate platform
551
+ editor or Save action. The control stays available on either detail tab, is
552
+ locked during in_progress, and retains shared pending/unknown reconciliation
553
+ across navigation. Rows and graph nodes remain read-only and show each task's
554
+ own requirement; root values do not define chain-wide platform requirements.
555
+ The [confirmed platform control decision](../../.agents/notes/implemented/simplification/2026-10-24-task-platform-confirmation-control.md)
556
+ records its allocation and focus behavior.
557
+
558
+ The permission switch has confirmation in both directions, remains false by
559
+ default and is locked against actual changes while in_progress. It governs
560
+ automatic discovery; explicit task execution may use either value. Rows and graph
561
+ nodes display each task's own permission. Permission does not control worker
562
+ ownership; ordinary status setting cannot release active execution or resume
563
+ released resources. Claim-bound done validates ownership. None of these
564
+ operations stops a remote process or replaces PR review and delivery authority.
565
+ The [status decision](../../.agents/notes/implemented/architecture/2026-10-24-task-status-assignment.md)
566
+ records migration and shared-session trade-offs.
567
+
568
+ `task ready` selects up to 10 actionable tasks by
569
+ default; `--limit <N>` accepts decimal integers from 1 through 100. It makes one
570
+ task-list request with `ready=true`, the chosen limit and optional
571
+ `--allow-agents true|false` and `--compatible-platform windows|linux|macos`
572
+ filters, without fetching later pages. Compatibility includes unrestricted tasks
573
+ and tasks requiring that platform. The service applies all filters before
574
+ pagination and binds them to the cursor. The service orders results by creation time and then task ID, both
575
+ ascending. A ready task is `todo` with all direct dependencies `done`. This
576
+ bounded selection supports choosing the next work without retrieving the whole
577
+ project; `task graph` provides a dependency overview when needed. `task list`
578
+ reads every matching page, including with `--ready`, and excludes `done` by
579
+ default. `--all` includes every status; `--status <status>` selects one status,
580
+ including `done`. These two options conflict. `--ready` intersects the selected
581
+ statuses and can be combined with `--all`. List results place `in_progress`
582
+ first, then ready tasks, other `todo` tasks, and `done`; each group retains
583
+ service order across all pages. This order applies to human and JSON results.
584
+ `task ready` accepts neither `--status` nor `--cursor`. `task list` supports the
585
+ same permission and compatibility filters across every matching page. Both are
586
+ automatic-selection conditions independent of readiness; explicitly designated
587
+ execution retains the manual exception.
588
+
589
+ Updates preserve omitted fields; an empty description clears it. Repeated
590
+ `--depends-on` and `--external-depends-on` declare the complete ordinary and
591
+ external sets. Either option replaces all relationships and classifications;
592
+ ordinary-only makes every supplied edge ordinary, while external-only leaves
593
+ only those external edges. IDs are canonicalized and sorted; malformed and
594
+ case-equivalent duplicate/cross-declared UUIDs fail before configuration or
595
+ network access. `--clear-dependencies` sends two empty sets and conflicts with
596
+ either dependency option. An update needs at least one mutable
597
+ field. `--allow-agents true|false` explicitly changes automatic-execution
598
+ permission; omitted preserves it. Creation rejects the option. Existing tasks
599
+ receive true through migration without changing versions or business timestamps.
600
+ A matching same-value permission PATCH retains version and time, while a stale
601
+ version still conflicts and an actual in-progress toggle fails atomically.
602
+ Create and update accept `--required-platform windows|linux|macos`; update
603
+ accepts `--clear-required-platform` to send null, mutually exclusive with setting
604
+ a platform. Omission preserves an existing requirement. New and migrated tasks
605
+ are unrestricted unless explicitly set. Exact-version equal platform updates
606
+ preserve version and time; stale updates conflict and actual in-progress changes
607
+ are refused atomically. Explicit manual status setting remains available for every
608
+ requirement. The query platform selects candidates; it does not configure or
609
+ prove the environment of a future worker.
610
+ By default the CLI reads the task version before PATCH; `--if-version <n>`
611
+ uses that exact positive int64 version. Conflicts and failed writes are reported
612
+ without automatic retries.
613
+
614
+ Text options accept both separated values and `--option=value`. Inline assignment
615
+ splits at the first equals sign and supports leading dashes, such as
616
+ `--title=-example`; `--description=` is the explicit empty form. Separated values
617
+ starting with a dash are rejected. Directory options, switches and help reject
618
+ inline assignment. Attachment `put` declares its `--path` as text, accepting
619
+ `--path=value`; attachment `put/read/remove` also accept `--` before positional
620
+ paths starting with a dash. Other task operations retain their declared syntax.
621
+
622
+ Human task lists use labeled blocks containing ID, project, title, PR references,
623
+ status, readiness, automatic-execution permission, required platform, dependencies and blocking.
624
+ Description, version and timestamps
625
+ remain available in show, ready, create and update output. Graph nodes include
626
+ state, permission, required platform, dependencies, blocking and title-preview truncation flags.
627
+ Task and graph decoders require a boolean `allowAgents`; missing, null or
628
+ nonboolean values are protocol errors. They also require `requiredPlatform`
629
+ as null or one of the three platform enums; missing keys or other values fail
630
+ without a runtime default. Human output uses `Required platform: any` for null
631
+ and the enum otherwise. Queries support
632
+ `--json`: task `list` returns every matching task in one array, omitting only
633
+ `description` while retaining every other API field, including raw PR strings,
634
+ version and timestamps. This applies to the default list and every filter,
635
+ including `--all`. Project lists retain all API fields. Task `ready` returns its
636
+ selected full tasks as an array, details return one full resource, and graphs
637
+ return the complete API object. An empty human ready result is `No ready tasks.`
638
+ and empty JSON is `[]`. Versions remain JSON numbers with full int64 precision.
639
+ Local preparation fails before any task mutation; a lost write response is
640
+ reported as unconfirmed. Installed CLI integration uses the real Go/PostgreSQL
641
+ service; deadline behavior uses short test-only budgets and byte probes retain
642
+ the full production limits. [PR #55](https://github.com/codetreker/daynight/pull/55)
643
+ records the original integration and real-default-budget validation, with its
644
+ historical source identity.
645
+
646
+ ## Task deletion
647
+
648
+ Read the task and use its observed version when deleting it:
649
+
650
+ ```bash
651
+ daynight task show <task-id> --json
652
+ daynight task delete <task-id> --if-version <version>
653
+ ```
654
+
655
+ Deletion removes the task from normal queries and prevents later reads and
656
+ changes. Stored task data, its own prerequisite references and attachment files
657
+ remain. An active worker claim on the target prevents deletion. Without
658
+ `--remove-depends`, an undeleted task depending on the target also prevents it.
659
+
660
+ To explicitly remove every other task's ordinary and external dependencies on
661
+ the target in the same transaction, use:
662
+
663
+ ```bash
664
+ daynight task delete <task-id> --remove-depends --if-version <version>
665
+ ```
666
+
667
+ This includes references added before that transaction executes and may make
668
+ affected tasks ready. Each changed dependency owner receives a new version;
669
+ its status, timing and other data stay unchanged. Deletion requires explicit
670
+ authorization for the target; removing other tasks' dependencies requires that
671
+ additional authorization.
672
+
673
+ Without `--if-version`, the CLI reads the current version immediately before the
674
+ write. Conflicts and failed writes are not retried. After an interrupted or lost
675
+ response, read the task to reconcile before considering another request. An
676
+ authorized read returning `410 task_deleted` confirms deletion; a live resource
677
+ requires a new decision, while a permission or transport failure leaves the
678
+ outcome unknown. The [deletion requirements](../../docs/spec/daynight-task-deletion.md)
679
+ and [design](../../docs/design/daynight-task-deletion.md) own retained history,
680
+ reference removal and cache invalidation.
681
+
682
+ ## Task attachments
683
+
684
+ Attachment commands use the existing project selection and server configuration:
685
+
686
+ ```bash
687
+ daynight task attachment put <task-id> ./design.md --path docs/design.md
688
+ daynight task attachment put <task-id> ./mockup.html --path mockup/index.html
689
+ daynight task attachment list <task-id> --tree
690
+ daynight task attachment list <task-id> --json
691
+ daynight task attachment read <task-id> docs/design.md
692
+ daynight task attachment read <task-id> images/mockup.png > ./mockup.png
693
+ daynight task attachment remove <task-id> docs/design.md
694
+ ```
695
+
696
+ Each upload accepts one local regular file. Without `--path`, its basename is the
697
+ target path; the same complete task-relative path is overwritten. Names preserve
698
+ case and Unicode spelling, with `/` separators and no absolute or dot-segment
699
+ paths. The content type comes from the target path's extension, even when it
700
+ differs from the local filename; unknown extensions use
701
+ `application/octet-stream`. Uploads and deletions affect one file at a time.
702
+
703
+ `list` reads every page before emitting its complete metadata result. `--tree`
704
+ and `--json` select mutually exclusive formats. `read` writes the original bytes
705
+ without labels, decoding or an added newline. Diagnostics remain on stderr;
706
+ a failed transfer can leave incomplete stdout and exits nonzero. File transfers
707
+ stream with backpressure and retain the shared deadlines and cancellation;
708
+ metadata JSON keeps its existing byte budgets. Use `--` for a dash-prefixed
709
+ positional path, for example:
710
+
711
+ ```bash
712
+ daynight task attachment put --project <project-id> <task-id> -- -design.md
713
+ daynight task attachment read --project <project-id> <task-id> -- -design.md
714
+ ```
715
+
716
+ Failed writes are not retried. File storage and PostgreSQL metadata are not
717
+ atomic; an unsuccessful operation may already have changed storage. The
718
+ [attachment requirements](../../docs/spec/daynight-task-attachments.md) define this
719
+ known issue and the trusted same-origin preview model. The
720
+ [authentication architecture](../../docs/design/daynight-auth.md) defines the required
721
+ authentication and project-membership checks for attachment requests. Trusted
722
+ executable HTML retains the application origin. The
723
+ [CLI delivery decision](../../.agents/notes/implemented/feature/2026-10-21-task-attachment-cli.md)
724
+ records binary transport and output ownership.
725
+
726
+ ## Review configuration and startup
727
+
728
+ Register a repository explicitly, or let the first review operation guide registration:
729
+
730
+ ```text
731
+ daynight review add-repo https://github.com/OWNER/REPO.git
732
+ daynight review add-repo git@github.com:OWNER/OTHER.git --path ./review-other
733
+ daynight review run
734
+ ```
735
+
736
+ For a local build, run `pnpm daynight review run` from the repository root.
737
+ These commands select `~/.daynight/config.yml` using the current OS user's home
738
+ directory. `review add-repo`
739
+ creates the configuration when absent. It reads, validates and saves configuration;
740
+ cloning, authentication checks, GitHub calls, SQLite initialization and PR boundary
741
+ selection belong to review startup. An already running reviewer keeps its loaded
742
+ configuration until its next startup.
743
+
744
+ The same YAML also accepts the server client's `serverUrl` and optional
745
+ `serverToken` fields. Review validates its own fields independently of server
746
+ business values. The server projection requires a valid HTTP(S) origin and
747
+ validates any configured token and its transport. The shared parser still rejects
748
+ invalid YAML, duplicate keys and unknown root fields. Registration can add the
749
+ first review repository to a server-only file while preserving its server
750
+ settings and comments.
751
+
752
+ A configuration with an explicit addition root is:
753
+
754
+ ```yaml
755
+ repositoryRoot: ~/daynights
756
+ copilotModel: auto
757
+ copilotReasoningEffort: high
758
+ repositories:
759
+ - remote: https://github.com/OWNER/REPO.git
760
+ path: ../daynights/github.com/owner/repo
761
+ ```
762
+
763
+ `copilotModel` and `copilotReasoningEffort` are independent optional fields for
764
+ all review repositories in the running process. Each configured value must be a
765
+ string containing non-whitespace text and no NUL; null and other value types are
766
+ rejected. Accepted strings are preserved exactly. Copilot owns model availability,
767
+ effort levels and model/effort compatibility; Daynight maintains no static lists.
768
+ `auto` delegates model selection to Copilot. Omitting either field sends no
769
+ corresponding override and preserves Copilot's choice, so neither, either or both
770
+ may be configured. Changes take effect on the next `review run` startup. Guided configuration
771
+ and repository registration preserve both fields and YAML comments. The server
772
+ configuration projection recognizes these shared keys without validating their
773
+ review-owned values.
774
+
775
+ `repositoryRoot` defaults to `~/daynights`. It is used only when `add-repo` has no
776
+ `--path`: the command derives filesystem-safe components from the normalized
777
+ host/owner/name and saves the resulting absolute repository path. A configured
778
+ root may be absolute, config-directory-relative, or begin with `~` for the current
779
+ OS user's home. Other users' tilde forms are rejected. Changing the root affects
780
+ future additions only. An explicit `--path` resolves against the command's working
781
+ directory and is also saved as an absolute path. Manually written repository paths
782
+ remain absolute or config-directory-relative and do not expand `~`; every repository
783
+ entry requires its own `path`.
784
+
785
+ Adding an existing normalized repository without `--path` reuses its saved path
786
+ and succeeds without rewriting configuration, even after the root changes.
787
+ An explicit path to the same actual location is also idempotent; an explicit
788
+ different path for that repository is an error.
789
+ Existing YAML settings and comments survive additions. The command validates the
790
+ complete resulting configuration before replacing the file atomically. Validation
791
+ and pre-replacement write failures preserve the original configuration; cleanup
792
+ errors after replacement remain visible. A separate
793
+ `~/.daynight/config.yml.lock` excludes another configuration writer and fails
794
+ clearly when occupied; it is independent of the review instance lock. After an
795
+ abnormal exit, confirm no configuration writer remains before removing this lock.
796
+ Configuration mutation rejects symlinks and nonregular files. A resulting
797
+ configuration containing `serverToken` uses POSIX mode `0600`; without a token,
798
+ existing file-mode behavior is preserved.
799
+
800
+ Numeric options use the documented [configuration defaults](../../docs/design/daynight-review.md#使用方式与配置)
801
+ when omitted. Explicit invalid values, unsupported fields, duplicate YAML keys and
802
+ malformed documents produce nonzero exits with useful errors. Missing configuration
803
+ triggers the [configuration setup](#configuration-setup) rules before review
804
+ startup. Duplicate repository identities,
805
+ duplicate local paths, paths overlapping the retained state directory, and paths
806
+ with an existing nondirectory component are rejected. Missing clone directories
807
+ remain valid for later repository creation. Existing paths are compared by
808
+ filesystem identity. Missing destinations with the same existing ancestor and
809
+ component count are compared by temporarily creating one candidate's directory
810
+ names inside a unique probe directory there and looking up the other spelling.
811
+ This observes actual case and Unicode rules. Validation removes only the
812
+ directories it created, using nonrecursive removal. Probe permission, inspection,
813
+ or cleanup failures stop validation with an error.
814
+
815
+ The selected retained-state location is `~/.daynight/` for SQLite, sessions,
816
+ locks, logs, cache, and temporary files. PR worktrees belong to each monitored
817
+ repository root's `.worktrees/` directory. `maxConcurrentWorker` limits concurrent
818
+ review preparation and execution. Startup acquires an exclusive instance lock,
819
+ opens SQLite and prepares the configured clones. Each repository is polled
820
+ independently; access failures retain its last complete observation and remain
821
+ visible in diagnostics. The
822
+ [repository registration decision](../../.agents/notes/implemented/feature/2026-10-18-add-repo-configuration.md)
823
+ records the fixed-path and configuration-only choices.
824
+
825
+ ## Review status listing
826
+
827
+ Print the configured repositories' locally tracked open PRs, including Draft PRs:
828
+
829
+ ```text
830
+ daynight review list
831
+ daynight review ls
832
+ ```
833
+
834
+ Both forms use the same persisted-snapshot operation and print repositories in
835
+ configuration order, with PRs ordered numerically. The columns are `PR`,
836
+ `PR STATE`, `REVIEW` and `ATTEMPTS`. Completed or failed reviews remain listed while their PR is open;
837
+ closed PRs and history belonging to removed configuration entries are omitted.
838
+
839
+ The output identifies its local snapshot source and each repository's
840
+ `Last observed` successful complete poll and saved poll error when present.
841
+ PRs at or below the permanent tracking boundary are not stored individually and
842
+ cannot appear in the listing. `No tracked ongoing PRs.` describes an initialized
843
+ repository with no saved open PRs above the boundary; `Not initialized.` describes
844
+ a missing database, an unregistered repository or an incomplete initialization.
845
+ The listing makes no claim about GitHub changes since the saved observation.
846
+
847
+ Review states are `Preparing`, `Running`, `Pending`, `Retry waiting`, `Completed`,
848
+ `Failed`, `Interrupted` and `Paused` for Draft PRs. `Running` is a saved state,
849
+ not proof that a process remains alive. Retry deadlines and saved errors appear
850
+ under the corresponding row. A newer desired revision remains `Pending` while an
851
+ older revision is active; the older revision's recorded state, attempt budget,
852
+ retry deadline and error are printed separately. The current row's attempt count
853
+ always belongs to its own desired revision, head and target branch. A base-tip
854
+ change alone does not invalidate a completed review.
855
+
856
+ Pending worktree cleanup is a separate saved resource barrier, including after a
857
+ PR reopens. Such rows show `Worktree cleanup: Pending` and any saved cleanup error.
858
+ With no current review, an open non-Draft row shows `Pending (cleanup blocked)`;
859
+ Draft remains `Paused`. Older active reviews retain their separate details. The
860
+ listing reports the barrier without attempting cleanup or recovery.
861
+
862
+ The command loads the current configuration and opens an existing SQLite database
863
+ read-only for one consistent transaction. It needs no Git, GitHub CLI or Copilot
864
+ execution, instance lock, clone or review startup. It does not create an absent
865
+ database, migrate a schema, recover interrupted work or update application state.
866
+ SQLite may create or update its WAL coordination sidecar files while reading an
867
+ existing database. Missing or invalid configuration, unreadable or corrupt state,
868
+ and unsupported schema versions fail visibly. The
869
+ [listing decision](../../.agents/notes/implemented/feature/2026-10-18-review-status-listing.md)
870
+ records status attribution and snapshot limits.
871
+
872
+ ## Durable review state
873
+
874
+ The command and source layout preserve existing YAML fields, retained-state
875
+ locations and resource identities. Runtime opening explicitly migrates earlier
876
+ SQLite state to retain verified review publications and conversation follow-ups;
877
+ existing cutoffs, revision budgets, sessions, process evidence and worktrees remain
878
+ owned by their original records. Read-only listing does not migrate state. The
879
+ review module owns its domain types independently of its SQLite implementation.
880
+
881
+ The SQLite module keeps repository identity, the permanent startup PR boundary,
882
+ observed PRs, captured review targets, completion revisions, sessions, worktree
883
+ registration, retry state, and verified GitHub review/thread identities. Repository
884
+ identity includes the GitHub host and stable repository ID. Completing a captured
885
+ revision leaves later observations pending; retries retain their original review
886
+ identity and consumed budget. Each successful comment result arms one durable
887
+ follow-up that is consumed once when conversations are resolved, even at the same
888
+ commit. A verified approval settles its current target; description edits retain
889
+ that approval. Reusing a stored approval to settle a pending target requires a
890
+ fresh snapshot confirming that exact remote review is still `APPROVED`, with the
891
+ captured actor, commit and stable identity. A dismissed historical review cannot
892
+ suppress that pending work.
893
+
894
+ Runtime database opening applies explicit schema migrations and enables WAL with
895
+ FULL synchronization and a bounded busy timeout. The listing reader checks the
896
+ existing schema, accepting versions 1 and 2 without applying migrations. The
897
+ instance lock checks whether its recorded CLI owner still exists; that check does not establish whether its agents
898
+ or tools have stopped. Interrupted reviews and pending cleanup remain blocked
899
+ after automatic lock recovery until process exclusion is explicitly confirmed.
900
+ Database state does not replace physical Git/worktree or session-history
901
+ verification.
902
+
903
+ See the [review architecture](../../docs/design/daynight-review.md) for transitions and the
904
+ [state decision](../../.agents/notes/implemented/architecture/2026-10-17-durable-review-state.md)
905
+ for persistence choices. The coordinator opens this state before scheduling work
906
+ and advances only the revision captured by each completed attempt.
907
+
908
+ ## GitHub observations
909
+
910
+ The GitHub module reads one repository pass through authenticated `gh api` GET
911
+ requests. Initialization scans every page and PR state before committing the
912
+ permanent cutoff. Later passes track open PRs, including Draft, and confirm
913
+ missing tracked PRs individually before recording closure.
914
+
915
+ Failed pages, malformed responses, and failed closure confirmations preserve
916
+ the previous repository observation. A completed pass commits its observations
917
+ and success time atomically. Rate-limit failures expose the server's retry
918
+ deadline and block later same-host calls in that client; the coordinator schedules
919
+ the next pass after the applicable deadline.
920
+ The [observation decision](../../.agents/notes/implemented/architecture/2026-10-17-github-observation.md)
921
+ records pagination and failure handling.
922
+
923
+ CI admission uses a read-only GraphQL query for the current PR head and
924
+ available test-merge commit. It combines GitHub's check/status rollups with
925
+ registered workflow suites, including approval-blocked workflows without jobs.
926
+ All reported CI must finish successfully; GitHub's `success`, `skipped` and
927
+ `neutral` outcomes pass. No CI allows immediate review. API errors and partial
928
+ results keep the PR waiting. Latest workflow runs replace historical attempts;
929
+ waiting or failing workflows do not consume review capacity.
930
+
931
+ Fresh review also requires a complete, paginated review snapshot with no unresolved
932
+ native `PullRequestReviewThread` from any author. Outdated threads still block
933
+ until resolved. Threads proven to belong to unpublished `PENDING` reviews are
934
+ excluded from this author-facing gate; unknown ownership cannot imply resolution.
935
+ Review summaries and ordinary PR comments have no resolution state. A pending round and no active or uncertain execution are also required, so
936
+ repeated passing-CI/zero-thread observations do not repeatedly review a settled
937
+ target. CI and conversation waiting consume no review Worker or model attempt.
938
+ API failure or incomplete data cannot prove that no conversations remain.
939
+
940
+ ## Repository clones and worktrees
941
+
942
+ The Git module creates missing clones and validates existing repository identity.
943
+ Prepared GitHub CLI authentication supplies command-scoped HTTPS credentials,
944
+ including repositories configured with SSH addresses or API ports. Existing
945
+ checkout files, origin configuration, branches, remote-tracking refs, and
946
+ FETCH_HEAD remain untouched by review preparation.
947
+
948
+ Configured clones and their PR worktrees are dedicated to this system. Each PR
949
+ uses its fixed repository-local `.worktrees/pr-<number>/` directory. Physical
950
+ root/common-directory checks, validated linked administration and backpointers,
951
+ and a session-labelled Git lock establish the target before destructive reuse
952
+ or removal. Initial preparation and new revisions provide a complete checkout
953
+ even when the base checkout uses sparse settings. Confirmation retries retain
954
+ local context. Files, nested clones and administration inside the owned PR
955
+ worktree are disposable; cleanup does not inventory their external consumers.
956
+ Other PR worktrees and retained sessions remain separate. Cleanup rechecks remote
957
+ closure before removal. The [exclusive-environment decision](../../.agents/notes/implemented/architecture/2026-10-17-exclusive-review-environment.md)
958
+ defines this ownership boundary.
959
+
960
+ See the [worktree ownership decision](../../.agents/notes/implemented/architecture/2026-10-17-owned-review-worktrees.md)
961
+ for target validation and recovery boundaries.
962
+
963
+ ## Copilot execution
964
+
965
+ The review module ships `daynight-review` under its own `skills/` directory.
966
+ After taking the instance lock, the daemon captures the installed bundle once
967
+ and prepares an immutable content-addressed snapshot under
968
+ `~/.daynight/cache/review-skills/`. Package updates cannot replace the content
969
+ used by that running daemon. Snapshots remain available for retained sessions
970
+ and uncertain executions; automatic collection is not provided.
971
+
972
+ Each attempt first runs native Copilot skill discovery in the prepared PR
973
+ worktree. A single `--plugin-dir=<snapshot root>` argument supplies a generated
974
+ local plugin wrapper containing `plugin.json` and `skills/daynight-review/`.
975
+ This preserves paths containing commas, spaces and Unicode; inherited
976
+ `COPILOT_SKILLS_DIRS` variables are removed from the child environment.
977
+ Exactly one enabled `daynight-review` must resolve to that snapshot's directory;
978
+ a disabled skill, project override or malformed response fails the attempt.
979
+ The review prompt explicitly invokes the skill and identifies its current
980
+ absolute entrypoint and digest on both new sessions and resume. The bundled
981
+ skill owns review methodology; the prompt owns the immutable target, publication
982
+ eligibility, retry reconciliation and completion protocol. The prompt also
983
+ explicitly requests the skill's native subagent delegation and synthesis when
984
+ fresh review is required; confirming a valid matching submitted result retains
985
+ its reconciliation exception.
986
+
987
+ The Copilot adapter then launches the review child in that same worktree and
988
+ environment. It selects the persisted per-PR UUID on first launch and explicitly resumes that
989
+ same session thereafter. An interrupted first launch also resumes existing
990
+ history; missing established history is an error. Only opaque session-directory
991
+ presence is inspected. Copilot history and agent JSONL are not parsed.
992
+
993
+ Every review child receives configured `copilotModel` as separate `--model` and
994
+ value arguments, and configured `copilotReasoningEffort` as separate
995
+ `--reasoning-effort` and value arguments. New sessions, resumes, retries and later
996
+ PR revisions use the same construction. Skill discovery receives neither override.
997
+ Values pass through the existing `shell: false` execution path; unsupported or
998
+ unavailable models, effort levels or combinations retain Copilot's normal failure
999
+ result and the existing attempt/error handling. The
1000
+ [model options decision](../../.agents/notes/implemented/feature/2026-10-22-review-copilot-model.md)
1001
+ records the validation and default-selection choices.
1002
+
1003
+ Prompts travel through stdin in noninteractive mode. `cross-spawn` handles native
1004
+ commands and Windows command shims; prompt text is not embedded in shell code or
1005
+ command arguments. Runtime paths contain Copilot state, cache, temporary files
1006
+ and per-attempt diagnostics. Existing GitHub CLI authentication remains available
1007
+ through Copilot's supported fallback. Discovery and review are sequential phases
1008
+ of one persisted attempt, sharing one retry budget and timeout deadline. The
1009
+ discovery child must be excluded before its exact persisted PID and identity are
1010
+ cleared and a review child can start. Cancellation, timeout or uncertain process
1011
+ exclusion prevents that next launch. Discovery stdout and stderr stream to
1012
+ separate `skill-list` logs and never enter completion-marker parsing.
1013
+
1014
+ The agent reads the current PR title, description and linked scope requirements,
1015
+ then checks the complete captured diff against one concrete problem and outcome.
1016
+ A clear description and changes within the original scope are independent
1017
+ approval gates. Independent objectives, an unreviewable combined PR or unrelated
1018
+ changes block approval even without a Critical/Major code defect. Necessary
1019
+ implementation, structural changes, tests and documentation for the same outcome
1020
+ remain in scope; fixed line or file counts do not decide reviewability. Expanding
1021
+ the description alone cannot justify unrelated work.
1022
+
1023
+ For every fresh review, the main agent first inspects that complete fixed diff,
1024
+ then chooses at least two complementary perspectives based on the PR's actual
1025
+ changes, contracts and risks. It invokes independent subagents, preferably in
1026
+ parallel, with exact head/base/merge-base context, scope, applicable repository
1027
+ instructions, evidence standards and shared worktree, temporary-file and process
1028
+ rules. Source and Git state remain read-only; subagents return findings and
1029
+ coverage limits to the main agent without publishing or emitting completion
1030
+ markers. The main agent waits for all required perspectives, verifies candidates,
1031
+ resolves disagreements and deduplicates root causes. It records the perspective
1032
+ rationale, completed coverage, limits, fix/defer/reject dispositions and confirmed
1033
+ blockers in attempt output, while GitHub comments contain concise findings only.
1034
+ An unavailable tool, failed child or incomplete required perspective is an
1035
+ operational failure; retries or reassignment stay within the attempt's existing
1036
+ budget. An incomplete review publishes neither a result nor a completion marker.
1037
+
1038
+ These subagents belong to one attempt within the daemon-managed main review
1039
+ session; they do not create more review Workers, PR sessions or worktrees.
1040
+ Reconciliation of a valid matching submitted result confirms that result without
1041
+ repeating delegation. The selected questions must fit each PR, including
1042
+ documentation-only changes.
1043
+
1044
+ Before new publication, the agent rereads the current PR information and
1045
+ reevaluates those gates. A successful review either approves or publishes
1046
+ `COMMENT` with at least one actual resolvable review thread. Suitable code findings
1047
+ use diff lines. Description and other PR-level blockers use a clearly labeled
1048
+ file-level conversation on the principal changed file; a review summary alone
1049
+ cannot satisfy this requirement. `REQUEST_CHANGES` remains unused. The reviewer
1050
+ must verify corrections after authors resolve feedback; resolution is a request
1051
+ for rereview, not evidence that the issue was fixed. Operational failures retain
1052
+ bounded retries and cannot be represented as quality findings.
1053
+
1054
+ The daemon verifies remote publication using its stable review identity, captured
1055
+ commit and publishing actor, without interpreting the quality judgment or parsing
1056
+ findings. Marker acceptance is persisted before this read-only verification; API
1057
+ errors retry verification across restart without another model attempt. A complete
1058
+ lookup with no valid matching publication is a protocol failure and uses the
1059
+ remaining bounded model retry budget. A verified `COMMENT` records its real
1060
+ review/thread IDs and arms exactly one follow-up. Once
1061
+ all submitted native conversations are resolved and the current CI passes, that follow-up
1062
+ runs even without new commits or metadata edits. New targets and feedback wakeups
1063
+ coalesce. Same-round confirmation can proceed through open conversations only
1064
+ when exact-round remote evidence proves an approval, commented review with owned
1065
+ threads, or a recoverable matching pending draft under the captured publisher. A
1066
+ failed attempt alone supplies no exemption. If the authenticated reader changes,
1067
+ it can confirm the captured actor's submitted result; an unpublished result or
1068
+ pending draft waits for that actor without consuming model attempts. Verified
1069
+ approval settles the current target, and
1070
+ description edits do not revoke it or start another round.
1071
+
1072
+ The adapter streams separate stdout/stderr logs and accepts only normal zero
1073
+ exit, complete capture and the exact final nonempty stdout line
1074
+ `PR N Review Completed`. Incomplete output, timeout, cancellation and logging
1075
+ errors cannot assert execution completion. A marker alone is insufficient: the
1076
+ coordinator verifies the corresponding remote approval or resolvable feedback
1077
+ before completing the round. It owns scheduling and final state transitions;
1078
+ runtime process supervision supplies evidence under the foreground execution
1079
+ contract.
1080
+
1081
+ The [execution decision](../../.agents/notes/implemented/architecture/2026-10-17-copilot-session-execution.md)
1082
+ records process and publication boundaries; the
1083
+ [PR-quality decision](../../.agents/notes/implemented/process/2026-10-21-review-pr-quality-gates.md)
1084
+ records the approval policy, and the
1085
+ [multi-perspective decision](../../.agents/notes/implemented/process/2026-10-22-pr-specific-review-perspectives.md)
1086
+ records delegation and synthesis. The
1087
+ [conversation-cycle decision](../../.agents/notes/implemented/architecture/2026-10-21-review-conversation-cycle.md)
1088
+ records durable follow-ups and publication verification. The
1089
+ [skill design](../../docs/design/daynight-review-skill.md) owns packaging, snapshots and
1090
+ loading, with rationale in the
1091
+ [bundled-skill decision](../../.agents/notes/implemented/architecture/2026-10-20-bundled-review-skill.md).
1092
+ Native probes with Copilot CLI 1.0.100 verify actual bundled-skill activation and
1093
+ changed-bundle resume with the same UUID, including comma, space and Unicode
1094
+ paths. The bundled-skill decision records the probe's conditions and limits.
1095
+ Live Copilot/GitHub publication acceptance
1096
+ remains separate from those probes and controlled subprocess tests.
1097
+
1098
+ ## Coordination and shutdown
1099
+
1100
+ A FIFO pending queue coalesces observations for each PR while preventing a
1101
+ frequently updated PR from starving other repositories or PRs. One reservation
1102
+ spans preparation, execution and cleanup for each PR. Fresh-round CI and
1103
+ conversation admission precedes that reservation and is refreshed at
1104
+ `pollIntervalMs`; waiting candidates retain their queue position without blocking
1105
+ ready PRs. Admission evidence is kept in memory for the exact revision, head and
1106
+ base branch and is refreshed after restart. New review launches recheck PR state,
1107
+ CI and conversations after worktree preparation. Same-round reconciliation can
1108
+ confirm proven exact-round publication while its own feedback remains open;
1109
+ matching pending drafts require the captured publishing actor. An unsuccessful
1110
+ attempt without publication still waits for unrelated open conversations. A regression
1111
+ defers fresh preparation without consuming an attempt or losing the retained
1112
+ session. CI changes alone do not retrigger completed revisions.
1113
+ Readiness is a launch-time observation; later CI registration or reruns do not
1114
+ automatically cancel an active agent.
1115
+
1116
+ Cleanup does not consume a review worker slot, but cannot overlap another
1117
+ operation on the same worktree. Draft/closure observations cancel active work; head changes wait for the current
1118
+ attempt and remain pending. Failed revisions retain their exhausted budget.
1119
+
1120
+ Ctrl+C stops new work and polling, terminates current managed execution, waits
1121
+ for operations and closes SQLite before releasing the instance lock. Agents must
1122
+ run tools in the foreground and stop their services before returning. Normal
1123
+ unforced exit and drained streams are evidence under that contract. POSIX uses
1124
+ current process groups; Windows cancels live trees with `taskkill /T /F`.
1125
+ Uncertain termination retains the lock and interrupted state.
1126
+
1127
+ Startup checks the PID in an existing `~/.daynight/instance.lock` with a
1128
+ signal-zero probe. A live owner, permission denial, invalid lock metadata or an
1129
+ unclassified probe error preserves the lock and stops startup. Only an explicit
1130
+ no-such-process result permits automatic replacement of a dead owner's lock.
1131
+ Competing starts and releases serialize through `instance.lock.sqlite`; this
1132
+ guard database remains in place and must not be deleted while a CLI can use it.
1133
+ Lock age never establishes that an owner has stopped. PID reuse conservatively
1134
+ blocks startup until the recorded owner can be inspected.
1135
+
1136
+ A crash with no unresolved review or cleanup can therefore restart directly.
1137
+ When interrupted reviews exist, automatic lock recovery blocks their PRs.
1138
+ Pending cleanup remains recorded with its error even if the PR reopens; only
1139
+ conclusively stopped cleanup operations and excluded agents allow that state to
1140
+ clear. Automatic recovery blocks only each affected PR's cleanup and reuse;
1141
+ polling and other PRs in the same repository continue normally, as do other
1142
+ repositories. Uncertain
1143
+ resources retain the lock on shutdown. After stopping the daemon, confirm that
1144
+ the previous CLI and all its agents/tools have stopped, then remove only
1145
+ `instance.lock` and restart. Keep `instance.lock.sqlite`, SQLite state, sessions
1146
+ and logs. That explicitly confirmed restart reconciles interrupted work with
1147
+ the same captured target and session; it never declares a saved running attempt
1148
+ complete or kills a saved process ID.
1149
+
1150
+ The [coordination decision](../../.agents/notes/implemented/architecture/2026-10-17-foreground-review-coordination.md)
1151
+ explains scheduling and the foreground execution boundary. The
1152
+ [stale-lock recovery decision](../../.agents/notes/implemented/bug-fix/2026-10-18-stale-instance-lock-recovery.md)
1153
+ records owner-liveness checks and the separate process-exclusion requirement.