@codetreker/daynight
v0.54.0
Published
A client command toolkit for development workflows
Readme
Daynight CLI
The @codetreker/daynight package provides the daynight command and its dn
alias. Use it to manage server-backed projects, tasks, discussion threads,
attachments, Webhooks and Bot definitions, inspect remote Workers, install the
using-daynight skill for coding agents, run foreground task workers through
Herdr or browser-connected native Controllers, and run a local GitHub PR reviewer
through Copilot CLI. Both command names share configuration and behavior. Supported native platforms are Linux, Windows
and Apple Silicon (ARM64) macOS. Intel macOS is unsupported.
See the project overview for the browser workspace and service,
and the development guide for source builds,
validation, package versions and npm publication. The
CLI test isolation guide describes
the private test home and parent/child protection of real Daynight state
(~/.daynight and the inherited DN_CONFIG_DIR) against writes and cleanup,
including symbolic-link aliases. Ordinary test and installed acceptance suites exclude stress
workloads. From this package, pnpm test:stress builds the CLI and runs the
rendering and full Session-v2 .stress.ts suites. The command is local-only
and refuses CI. The local stress guide owns
selection and evidence interpretation. Each command's --help owns its exact
usage. Review execution additionally requires Git, an authenticated
GitHub CLI and Copilot CLI on PATH.
- Install and update
- Configuration root
- Client commands
- CLI usage manual
- Agent skill installation
- Shell completion
- Configuration setup
- Project management
- Task management
- Task deletion
- Task discussion threads
- Task attachments
- Webhook management
- Bot management
- Remote Worker queries
- Worker configuration and startup
- Worker manual management
- Review configuration and startup
- Review status listing
- Durable review state
- GitHub observations
- Repository clones and worktrees
- Copilot execution
- Coordination and shutdown
Install and update
Use the latest patch of Node.js 22 or newer (>=22, with no upper major-version
limit). SQLite requires Node.js 22.14.0 or newer. Install the CLI with npm:
npm install --global @codetreker/daynight
dn --versionThe installation provides both daynight and dn; every command works with
either name, for example dn task list or dn skill install. Help and diagnostics
use the canonical daynight spelling.
Update that npm global installation with:
dn updateThe command checks @codetreker/daynight's latest version in the configured npm
registry and installs that exact version only when it is newer. It updates the
installation that is running, even if npm's current default global prefix has
changed. An equal or newer installed version succeeds without installation or
downgrade. User and global npm registry/authentication settings apply; the current
working directory's project .npmrc does not select the update source.
daynight update --help explains the command. Self-update requires an npm-owned
global package and launcher. Source checkouts, local dependencies, npx, pnpm and
npm link installations receive guidance to use their original package manager.
If an update is needed, run the command from outside its installation directory.
The installer streams its output, enforces the target's Node.js engine requirement
and reports permission, network and installation errors. It does not request
administrator privileges automatically. npm owns replacement and recovery; a
failed installation is not a promise that every original file remains unchanged.
The command verifies the installed manifest, launcher and a fresh invocation's
version, then refreshes existing using-daynight skills from that installed
package. It checks User destinations and the current Git worktree's Project
destinations, including calls from subdirectories and linked worktrees. Outside
Git it checks User destinations only. It does not search other projects or need
agent launchers on PATH. Missing skills remain uninstalled. The same refresh
runs when the CLI is already current or ahead, using its installed bundle.
Refresh replaces complete skill directories, including local edits and obsolete
files. Shared physical destinations are written once. Each result identifies
its agents, scope, path and package version. A skill failure exits nonzero and
reports the package outcome separately; a successfully installed npm package is
retained, and rerunning update retries the skill refresh. All phases must
succeed before the command reports success. It requires no review configuration and does
not open SQLite, modify sessions or restart a running reviewer or worker. The next CLI
invocation uses the installed version. Restart any running reviewer or worker to use it;
on Windows, a reviewer or worker holding a native addon open can prevent npm from replacing
that file and cause the update to fail. The
self-update decision
records installation ownership and verification requirements.
Configuration root
DN_CONFIG_DIR selects the absolute directory containing config.yml and all
Daynight user-local state. When unset, it remains ~/.daynight. Empty or relative
values and paths containing control characters are rejected; use an expanded
absolute path such as DN_CONFIG_DIR="$HOME/.daynight-test". Paths shown under
~/.daynight in this manual describe that default and follow the selected root.
The root includes credentials, worker identity, Worker/Review SQLite databases,
locks, logs, caches, Controller launch tickets, journals, content and resume leases.
Controller IPC identities are scoped to this root; long Unix socket paths use a
private owner-checked temporary directory. Herdr retains its native socket length
limit and reports an error for overly long roots; select a shorter root for
Herdr mode. Native home and Provider session directories remain unchanged.
Project .daynight bindings, Git worktrees, installed skills, npm installations
and remote service data are not isolated by this setting.
Top-level agentCliAliases optionally maps daynight and/or dn to another
executable for newly launched Worker/Controller Agents. It defaults to disabled.
The development channel guide
explains the mapping, platform limits, fixed build lifetime and shell verification.
Client commands
daynight # Show root help
daynight --help # Also -h
daynight --version # Also -v
daynight --skill # Print the CLI usage manual
daynight update
daynight login [--no-browser] # Authorize CLI access through the browser
daynight logout # Revoke and remove the current CLI credential
daynight worker # Show worker help
daynight worker list [--json] # Query this account's remote Workers
daynight worker show <worker-id> [--json]
daynight worker setup # Check prerequisites and choose an agent and Projects
daynight worker run # Run until interrupted
daynight worker attach # Connect to an existing Herdr task runtime
daynight worker repo list [--json]
daynight worker repo add [--project <project-id>]
daynight worker repo remove [--project <project-id>]
daynight worker resources list # Inspect retained Herdr recordings and stop evidence
daynight worker retry <task-id> --claim-id <claim-id> [--project <project-id>]
daynight worker release <task-id> --claim-id <claim-id> --if-version <version> [--project <project-id>]
daynight review # Show review help
daynight review run
daynight review list # Also review ls
daynight review add-repo <remote> [--path <path>]
daynight completion # Show completion help
daynight completion bash
daynight completion zsh
daynight completion setup [--shell bash|zsh] [--rc-file <path>]
daynight skill # Show skill help
daynight skill install # Select Agents, then User or Project scope
daynight project
daynight project create <name> [--repo <repo>] [--team <uuid|personal>] [--confirm]
daynight project list [--json]
daynight project show <project-id> [--json]
daynight project transfer --to-team <uuid|same-service-link> [--project <uuid>] [--if-version <version>] [--confirm] [--json]
daynight project delete [--project <uuid>] [--confirm] [--json]
daynight team list [--json]
daynight team show [--team <uuid|personal>] [--json]
daynight team create <name> [--confirm] [--json]
daynight team rename <name> [--team <uuid|personal>] [--if-version <version>] [--confirm] [--json]
daynight team delete [--team <uuid|personal>] [--if-version <version>] [--confirm] [--json]
daynight team invitation create [--team <uuid|personal>] [--confirm] [--json]
daynight team invitation list [--team <uuid|personal>] [--json]
daynight team invitation revoke <invite-id> [--team <uuid|personal>] [--confirm] [--json]
daynight team member list [--team <uuid|personal>] [--json]
daynight team member set-role <user-id> <member|admin> [--team <uuid|personal>] [--if-version <version>] [--confirm] [--json]
daynight team member remove <user-id> [--team <uuid|personal>] [--if-version <version>] [--confirm] [--json]
daynight team leave [--team <uuid|personal>] [--if-version <version>] [--confirm] [--json]
daynight team projects [--team <uuid|personal>] [--json]
daynight team default show [--json]
daynight team default set <uuid|personal> [--confirm] [--json]
daynight invitation inspect [--stdin] [--json]
daynight invitation accept [--stdin] [--confirm] [--json]
daynight webhook # Show Webhook help
daynight webhook catalog [--json]
daynight webhook list --personal [--json]
daynight webhook show <endpoint-id> --team <team-id> [--json]
daynight webhook create --personal --file <path> --confirm [--json]
daynight webhook subscription --help
daynight webhook secret --help
daynight webhook delivery --help
daynight webhook attempt --help
daynight webhook operation --help
daynight bot list [--json]
daynight bot show <bot-id> [--json]
daynight bot create --name <name> [--worker <worker-id>] [--cwd <path>] [--agent <codex|claude|copilot>] [--request-id <uuid>] [--json]
daynight bot delete <bot-id> --if-version <version> [--request-id <uuid>] [--json]
daynight task
daynight task create --title <title> [options]
daynight task list [--all | --status <status>] [--ready] [--assigned-to <assignee>] [--json] [--project <project-id>]
daynight task list --status in_progress --group-by chain [--assigned-to <uuid|me>] [--limit <1-50>] [--cursor <cursor> | --group-id <group-id> --targets-cursor <cursor>] [--json] [--project <project-id>]
daynight task search <expression> [--status <status>] [--assigned-to <assignee>] [--ready] [--allow-agents <true|false>] [--compatible-platform <platform>] [--json] [--project <project-id>]
daynight task ready [--limit <N>] [--json] [--project <project-id>]
daynight task show <task-id> [--json] [--project <project-id>]
daynight task step
daynight task step list <task-id> [--json] [--project <project-id>]
daynight task step show <task-id> <step-id> [--json] [--project <project-id>]
daynight task step add <task-id> --title <text> [--id <step-id>] [--description <markdown>] [--status <todo|in_progress|done|skipped>] [--before <step-id> | --after <step-id>] [--if-version <version>] [--json] [--project <project-id>]
daynight task step update <task-id> <step-id> [--title <text>] [--description <markdown>] [--if-version <version>] [--json] [--project <project-id>]
daynight task step set-status <task-id> <step-id> <todo|in_progress|done|skipped> [--if-version <version>] [--json] [--project <project-id>]
daynight task step move <task-id> <step-id> (--before <step-id> | --after <step-id> | --first | --last) [--if-version <version>] [--json] [--project <project-id>]
daynight task step delete <task-id> <step-id> [--if-version <version>] [--json] [--project <project-id>]
daynight task update <task-id> [options]
daynight task set-status <task-id> <status> [--claim-id <claim-id>] [--if-version <version>] [--force] [--project <project-id>]
daynight task delete <task-id> [--remove-depends] [--if-version <version>] [--force] [--project <project-id>]
daynight task graph <task-id> [--depends-only] [--json] [--project <project-id>]
daynight task thread read <task-id> [--before-id <message-id> | --after-id <message-id>] [--count=N] [--details] [--project <project-id>]
daynight task thread post <task-id> --body <text> [--reply-to <message-id>] [--claim-id <claim-id>] [--project <project-id>]
daynight task attachment
daynight task attachment put <task-id> <file> [--path <relative-path>] [--project <project-id>]
daynight task attachment list <task-id> [--tree | --json] [--project <project-id>]
daynight task attachment read <task-id> <relative-path> [--project <project-id>]
daynight task attachment remove <task-id> <relative-path> [--project <project-id>]Groups and operations show help when --help or -h is their sole argument.
Help, version, usage-manual output and completion generation do not resolve the
user home, load review configuration, open SQLite or require review tools. review add-repo accepts one
--path <path> before or after its remote; --path=value and -- are invalid.
Unknown commands and invalid arguments exit with status 2; operation failures
exit with status 1 and retain their cause. Task reads with partial Session
observations print the available result and exit with status 3. Explicit Session
read commands exit 130 on user signal cancellation. The old --daemon-review and root
add-repo forms are invalid. The
client design owns command composition and lazy loading;
the composition decision
records module ownership and the preserved data layout.
CLI usage manual
daynight --skill
dn --skill--skill prints the complete standalone English CLI usage manual from the
current package. The build generates it from the same topic sources installed
with using-daynight, in a fixed order with topic and section links converted
to internal anchors. It covers connection and Projects, Tasks, Steps, materials,
write safety, Session reads and messages, Webhooks and Worker operations. Exact
arguments remain in each subcommand's help. The output preserves the generated
artifact's bytes, including YAML frontmatter and the final newline. The document
has no package-relative references to read separately and requires no installed
skill or individual topic files.
The option must be the sole argument. Extra arguments or another option exit with status 2 and empty stdout before the manual is read. A missing file, read failure, blank content or invalid UTF-8 exits with status 1 and retains its cause. Reading and validation complete before output; an output failure can leave partial stdout. The command requires no login, Git repository, configuration, launcher or interactive terminal, and creates no files.
The topic files are the only edited product-manual source; there is no separately maintained aggregate. Repository workflow and Worker execution constraints remain separate from this manual.
Agent skill installation
The public skill contains a short navigation entry and independently readable
topic files. The entry directs an Agent to the files needed for its requested
operation; writes also require the common write-safety rules and the target
resource's conditions and recovery rules. daynight --skill exposes the complete
generated manual offline. Installation validates every required topic and its
internal file and section links before replacing a target. Whole-directory
replacement removes obsolete references as well as local edits.
The Worker supplies its execution constraints and original assignment in its prompt; each repository's rules and actual authorization govern delivery.
Install the skill through an interactive terminal:
daynight skill installThe command detects available codex, copilot and claude launchers without
starting them or checking login. Select one or more detected Agents with Space,
then Enter; the initial selection is empty. Next select User or Project,
with User initially selected. Installation starts after the scope is submitted.
Repeating the command refreshes the full bundle from the running package.
daynight update automatically refreshes existing User and current-worktree
Project copies with the same replacement semantics; it also repairs existing
skill directories whose entrypoint was removed and replaces dangling leaf links.
A regular file at the expected skill-directory path is an error. See
CLI updates for package ownership and failure handling.
| Agent | User destination | Project destination |
|---|---|---|
| Codex | ~/.agents/skills/using-daynight/ | <worktree>/.agents/skills/using-daynight/ |
| Copilot CLI | ~/.agents/skills/using-daynight/ | <worktree>/.agents/skills/using-daynight/ |
| Claude Code | ~/.claude/skills/using-daynight/ | <worktree>/.claude/skills/using-daynight/ |
User scope works outside Git. Project scope uses the current Git worktree root, including calls from subdirectories or linked worktrees, without requiring an origin, server configuration or project association. Installing the skill and associating a project remain separate operations. Terminal stdin and stderr are required; prompts use stderr and installation results use stdout. Help and installation do not depend on review configuration or credentials.
Each installation replaces the complete using-daynight leaf, including local edits and obsolete files. It then removes the legacy daynight leaf in the same selected physical skill root. The old name is retained until publication succeeds. Other skills, opposite-scope copies and parent-directory links are preserved; leaf links are replaced or removed without following their targets. Several Agent paths resolving to one physical root share one write. Destructive nesting involving an installation or legacy-cleanup path is rejected before writing. Discovery paths may be shared with unselected Agents, and host precedence continues to govern copies at other scopes.
The command reports per-Agent destinations and results. Failure stops later targets, retains earlier completed installations and exits nonzero. If legacy cleanup fails after publication, the new bundle stays installed and the command reports the incomplete migration. Replacement failure after removing an existing using-daynight leaf may leave that destination absent; diagnostics preserve the actual phase and reason. Rerunning installs the complete packaged bundle. Cancellation before publication cleans its stage and newly created empty parents.
Codex normally discovers changed skills automatically; restart its session if
needed. For Copilot CLI run /skills reload and inspect
/skills info using-daynight. Claude Code watches existing roots; use
/reload-skills when a top-level skills directory was created during the session.
The skill design owns mechanisms, routing
and the simulated-launcher native installation matrix.
Shell completion
Bash 4.2 or newer and zsh have native completion scripts. Install startup configuration with:
daynight completion setupSetup detects the calling shell from its direct parent process. If it cannot identify Bash or zsh reliably, select one explicitly:
daynight completion setup --shell bash
daynight completion setup --shell zshThe login-shell preference in SHELL does not establish which shell is running.
For a custom startup file, use --rc-file; only that file is managed:
daynight completion setup --shell bash --rc-file /path/to/bashrcBash setup manages .bashrc and the first readable existing login file in the
order .bash_profile, .bash_login, .profile. It creates .bash_profile only
when none of those files exists; if existing profiles are all unreadable, it
reports an error. The login block runs only in interactive Bash and can safely
appear in a .profile shared with other POSIX shells. It does not
make the login shell load the rest of .bashrc.
zsh setup uses $ZDOTDIR/.zshrc, or $HOME/.zshrc when ZDOTDIR is unset.
An exported empty ZDOTDIR selects /.zshrc; setup resolves a relative value
from its current working directory. A later zsh started in another directory
resolves that relative value from its own startup directory. A value set only
inside zsh is not visible to the installer; use --rc-file in that case.
The managed block reuses an initialized completion system or runs compinit
with its normal security checks before loading daynight.
Setup recognizes its managed block and the documented standalone manual loading
statement. Repeating it leaves an installed file unchanged. A managed block
checks that both daynight and dn use the expected callable completion
function before skipping loading. A missing or replaced registration for either
command reloads the shared script and restores both commands. Complete
registrations are reused, including when startup files load each other. Preserved
manual loading statements keep their unconditional behavior: if one runs after a managed block, it generates and loads the script
again. Existing content, line endings, permissions and startup-file symbolic
links are retained. Added blocks use LF line endings because a carriage return
is shell token data. Malformed managed blocks, invalid targets and file access failures produce
explicit errors. Setup does not migrate blocks from earlier templates. If an
earlier block is reported as unrecognized, remove its marked section and rerun
setup, or use the source command below to activate the current script directly.
Setup reports the startup files it handled. It installs persistent configuration; an ordinary CLI child process cannot inspect or change its parent shell's loaded completion functions. Use the existing loading command to enable completion in the current session:
source <(daynight completion bash)For zsh, initialize its completion system first if the session has not already done so:
autoload -Uz compinit
compinit
source <(daynight completion zsh)The bash and zsh generation operations write only scripts to stdout and do
not change startup files. Loading the zsh script without initialized compinit
fails with a diagnostic. The outputs are designed for source; using the same
output directly as an fpath autoload file is outside the loading contract.
Setup checks file contents without executing them. Custom early returns or later
commands that remove registrations can prevent a startup file from enabling
completion; verify such configuration by starting the shell.
The generated scripts register completion for both daynight and dn.
Completion suggests commands, nested operations, aliases, options, shell names
and local directories for review add-repo --path.
zsh also displays descriptions.
The scripts run in the shell on each Tab without starting Node or reading review
configuration, SQLite or the network. Directory suggestions preserve quoted and
special-character paths; an uncreated target directory remains valid input.
New shells generate definitions from the currently installed package. After an
update, run the applicable source command again to refresh an existing shell.
A saved generated script must be regenerated after updating. The
completion design explains the shared grammar
and shell integration. The
completion decision
records compatibility and execution trade-offs; the
setup decision
records startup-file ownership and installation limits.
Configuration setup
The shared configuration file is ~/.daynight/config.yml. The complete
config.example.yml covers service access, Team defaults, review and worker
settings with their defaults and optional overrides. It is included at the root
of the npm package. For an npm global installation, locate it with:
npm root --globalOpen @codetreker/daynight/config.example.yml beneath that directory. Select the
sections needed for your commands and replace the example repositories and local
paths. For a new configuration, save the selected settings to
~/.daynight/config.yml; for an existing file, merge them while preserving its
credential, generated workerId and unrelated settings. The example itself is
not loaded automatically. Repository paths resolve from the configuration
directory, with the rules in the worker and
review guides.
Unknown fields at the root, in review or worker, and in their repository
entries are ignored at runtime and preserved by CLI configuration edits. Known
fields retain their type and value checks. Invalid YAML, duplicate keys and
invalid mapping structures remain errors. Every CLI configuration write, including
first-time workerId creation, preserves decoded values outside the fields it owns. If shared YAML aliases would change an unrelated value, the write fails
and retains the original file; separate those aliases before retrying. Unaffected
aliases remain valid.
Project and task commands use https://daynight.cc when the configuration file or
serverUrl is absent. A production connection needs no server configuration.
Run daynight login to display an authorization code and open the verification
page. Check that the page's code matches the terminal, confirm the account and
approve access. The CLI saves the resulting credential without displaying its
secret. daynight login --no-browser displays the URL and code for authorization
in another browser. The device authorization expires after ten minutes; rejection, expiry and
cancellation leave an existing saved credential unchanged.
The CLI credential is named Daynight CLI (<hostname>), using the machine that
runs daynight login, including when another device approves access. Hostnames
longer than 85 Unicode characters are shortened to their first 85 characters to
keep the credential name within 100 characters. The credential never expires by default.
The Web account's token manager can set a future expiration, restore “Never expires”, or
revoke it. Changing expiration keeps the same credential, so the saved CLI login
continues without replacing its secret. Expired or revoked credentials cannot be
revived. A credential
represents the account's current project permissions. daynight logout revokes the current credential and removes
its local value after a confirmed response; an already invalid credential is
removed locally. Network or unconfirmed failures remain visible. Configuration
changes made during login or logout cannot overwrite another service origin or
another saved credential. A lost successful login response requires a fresh
login; the account token list can revoke a credential whose response was lost.
Without a local credential, a service command fails before dispatch and directs
the user to daynight login. A server 401 gives the same guidance. Business
commands do not start login, follow redirects with credentials, or automatically
repeat a write. Reconcile an unconfirmed business mutation before another one.
The first review run, review list or review ls asks for a repository when
the file, review section or review.repositories field is absent. To configure
one in advance, run:
daynight review add-repo https://github.com/OWNER/REPO.git
daynight review add-repo [email protected]:OWNER/OTHER.git --path ./review-otherInteractive guidance requires terminal stdin and stderr. Prompts and save
messages use stderr so stdout retains its normal text or JSON format.
Noninteractive missing review configuration fails with a review add-repo
command. Shared YAML/schema errors, invalid selected values, explicit empty
review lists and read failures retain their errors. Unrelated capability values
remain outside the current command's validation. Help, version, usage-manual
output, completion, update and invalid arguments do not prompt.
Test services and noninteractive automation use the existing
~/.daynight/config.yml fields. For a test service, provision its origin before
running daynight login:
serverUrl: http://127.0.0.1:8787For unattended access, a secret-provisioning process can write serverToken
together with its intended serverUrl; omit serverUrl only when the credential
belongs to https://daynight.cc. Keep that file private, with mode 0600 on
POSIX, and never put credentials in command arguments, logs or repository files.
Provisioners must preserve unrelated settings and pair the origin with its own
credential. Replacing serverUrl manually does not clear an old token; remove
or replace it before sending another request. External editors and provisioners
do not participate in the CLI's configuration lock.
Tokens are opaque visible ASCII and require HTTPS except for HTTP origins whose
host is literal localhost, a numeric IPv4 address in 127.0.0.0/8, or ::1.
Invalid explicit origins and credentials remain errors. Normal CLI use requires
no manual PAT creation. There is no top-level daynight setup command; shell
startup installation remains available through daynight completion setup.
Review guidance collects values before one atomic save under the configuration
write lock, preserving comments, unrelated settings and completed concurrent
changes to unrelated fields. A selected review-field conflict requires a fresh
decision. Login and logout check the observed origin and credential together
under the same lock. Credential-bearing files use POSIX mode 0600, including
review writes; files without a token retain existing permissions. Symlink
rejection and atomic replacement apply to CLI configuration writers.
Ctrl+C, termination signals or EOF cancel prompts without partial saves or
business execution. Human input consumes no business timeout. Review guidance
saves configuration without network, login or authentication checks; cloning and
review state initialization belong to the business operation.
The configuration decision records the review-guidance and persistence choices; the device-login decision records the rationale for the default service, explicit login/logout and credential lifecycle. The top-level setup removal decision records the command removal and configuration-file provisioning boundary.
Project management
After daynight login, create, list or inspect projects on https://daynight.cc.
To use a test server, set serverUrl in ~/.daynight/config.yml:
serverUrl: http://127.0.0.1:8787The origin includes its protocol, host and optional port; the client adds
/api/v1. When changing the origin externally, remove the old serverToken
before logging in to the new service; manual edits do not run CLI credential
cleanup. Then use the same commands:
daynight project create "Example"
daynight project create "Example" --repo https://github.com/OWNER/REPO.git --team personal --confirm
daynight project list
daynight project list --json
daynight project show <project-id> --jsonCreation requires one positional name; quote names containing spaces. Omit
--repo to use the current Git worktree's effective origin, including Git
insteadOf expansion. Supply --repo to use that address without inspecting Git;
this form, listing and details work outside Git repositories. For a name beginning
with -, use daynight project create -- -name or put an explicit repository
option before the terminator: daynight project create --repo <repo> -- -name.
The name is sent unchanged.
Creation first scans every accessible project page and compares canonical repository
identities. With one match it reports Project already exists. and the existing
project, without resolving a Team, confirming or writing. Multiple matches fail
with their IDs. With no match, --team <uuid|personal> selects the target; without
it, the CLI uses the configured default for the current service and account, or
Personal when no default is configured. An invalid or inaccessible default fails
without falling back. The target must be accessible to the current user.
Creation requires confirmation: --confirm skips the interactive prompt, and a
noninteractive invocation without it fails before writing. The CLI binds the
request and response to the current user and submits the original name and
repository address. The creator receives a direct admin grant. An unknown write is
not automatically replayed. Lookup failures and exhausted command budgets stop
before creation.
This client preflight does not provide atomic uniqueness against concurrent
creators, and the service continues to allow duplicate repository registrations.
Project commands do not write repository bindings or ignore rules. Lists traverse
all pages. Human output uses complete labeled project blocks with visible
terminal-control escapes. JSON preserves resource fields and nanosecond timestamp
strings; a later-page failure produces an error with empty stdout. The
project/task requirements own the complete
behavior and remaining task-command scope.
project transfer moves a Project to a Team identified by UUID or a same-service
/teams/<uuid> link. It resolves the explicit Project or current repository
without changing its binding or default Team. Only the current owner Team admin
can transfer; destination membership is not required. The preview identifies the
source, destination and expected access before confirmation. --confirm skips
the prompt but retains the preview's exact versions and identity checks. An
optional --if-version rejects a preview with a different ownership version.
A successful receipt may report no remaining access. Conflicts require a fresh
preview and decision; a lost receipt remains unknown even if a later read is 404.
Project grants and invitations are preserved.
project delete selects an explicit Project or the current repository's Project,
then reads the complete deletion preview. Only an administrator of the current
owner Team can delete it. The Project becomes unavailable without a product
recovery option; server history and files are retained. Active Worker claims
block deletion. Interactive use requires the displayed JSON string literal of the
Project name, even with --confirm; noninteractive use requires --confirm.
The preview is an observation, not a condition on the deletion. JSON output
contains only the confirmed receipt; preview text goes to stderr. An unknown
outcome is never automatically retried, and a later 404 cannot prove success.
Team context
team list reads all Teams joined by the current account. team show and
team projects use --team <uuid|personal> when supplied; otherwise they use
the configured teamDefaults entry for the normalized service origin and current
account, or the account's Personal Team when that entry is absent. team default
show verifies and displays the resolved target. An invalid or inaccessible
configured target fails explicitly; team list and an explicit --team remain
available. These read commands do not change configuration or remote resources.
Lists finish and validate every page before producing output. Use --json for
complete resources. Project discovery and project list still use all accessible
projects, independently of this default.
team default set <uuid|personal> validates the target and current membership,
then saves it for the current service and account. It does not depend on the old
default, so it can repair an invalid or inaccessible selection. personal saves
the account's actual Personal Team UUID. Without --confirm, an interactive
confirmation shows the target and role; non-interactive calls fail before writing.
Cancellation or an identity mismatch leaves the configuration unchanged. The
command does not alter remote preferences or repository bindings.
The saved map uses canonical UUIDs and the normalized service origin as keys:
teamDefaults:
https://daynight.cc:
80be22c3-96d8-4ed1-bcd3-b820f2508c62: b95baeff-1522-4d99-a9b4-dfcb58392ecateam default show --json and team default set --json return configured
(the saved ID, or null for an absent entry on show) and the verified team
resource. A token rotation for the same account retains its selection; other
accounts and services have independent entries. The write preserves comments,
unknown fields and other entries. It refuses to overwrite a changed credential
or current entry, or to change unrelated settings through YAML aliases. Resolve
the conflict or separate the aliases before retrying. When a local replacement
result is uncertain, the command reads the current entry and does not replay the
write automatically.
team create creates an ordinary Team, team rename changes its name, and
team delete removes an empty ordinary Team. Names preserve their original
characters and whitespace and may be duplicated. Rename and delete resolve the
explicit or default Team and use an observed version; --if-version retains the
specified positive int64 version, rejecting a mismatch with the observed version
before submission. Personal Teams cannot be renamed or deleted.
Each write requires interactive confirmation or the boolean --confirm flag.
Without it, non-interactive calls fail before writing. Delete prompts for the
displayed JSON string literal and compares its decoded value exactly with the
raw Team name; create and rename accept y or yes case-insensitively.
Cancellation, refusal or a mismatch does not submit. Even with
--confirm, delete sends the real name and version; the service still checks
identity, authority and preconditions. Success uses the validated receipt;
conflicts require a fresh decision, and unknown outcomes are never replayed.
Reading current facts does not recover a lost receipt. A later output or cleanup
failure retains a confirmed receipt. Use --json for the confirmed resource or
deletion receipt.
team invitation create creates a single-use link for an ordinary Team. The
link is disclosed once on stdout; save it securely before sharing it. Listing
invitations returns metadata only and cannot recover the link. revoke disables
an invitation; an unchanged receipt can also mean it was already revoked,
consumed, or absent. Create
and revoke require confirmation or --confirm, and use the explicit or default
Team context. Personal Teams cannot have invitations. An unknown create result
does not cause a replacement invitation to be created automatically.
team member list reads the selected Team's complete member directory, including
nullable profile fields, roles and membership versions. team member set-role
changes an existing member's role; team member remove removes one, and team
leave removes the current user. Only a Team admin can manage other members or
change roles; any member can leave. Personal membership is immutable and an
ordinary Team must retain an admin. These operations do not change Project grants
or the configured default Team.
Membership writes use the target member's observed positive int64 membership
version, not the Team or Project grant version. Supply its exact digits with
--if-version to retain an earlier decision; a mismatch with the current
observation is rejected before submission. Writes require interactive confirmation
or --confirm, and bind the current user to the request and response. A validated
receipt reports the actor's remaining Team role, including null after leaving;
a successful self-exit uses that receipt without a follow-up Team read. Unknown
outcomes are not automatically replayed. A later read only establishes current
facts and cannot recover a lost receipt.
Accept an invitation
Use invitation inspect to preview a Project or Team invitation without
consuming it. Use invitation accept to accept for the currently signed-in
account; neither command resolves the configured default Team. Supply the
same-service invitation link through the hidden terminal prompt, or through
standard input with --stdin. Standard input is read to EOF, accepts up to
4096 bytes and may end in one LF or CRLF. Do not put links or tokens in
arguments, flags, shell history, or logs. The CLI does not persist the secret.
The link fragment is sent only in the request body.
Acceptance displays the target and current account for confirmation. A
non-interactive acceptance requires --confirm; without confirmation it does
not write. An existing direct Project grant or Team membership retains its
role and does not consume the invitation. Inherited-only Project access does
not replace a direct grant: accepting creates a direct member grant. Invalid,
expired, revoked, consumed or deleted-target invitations are unavailable.
Identity mismatch is a refusal. A lost or malformed acceptance response may
follow a commit and is reported as an unknown outcome; the CLI does not replay
it automatically. Reading current membership cannot recover the original
receipt. Use --json for the validated preview or acceptance receipt.
Webhook management
webhook manages event types, endpoints, subscriptions, signing secrets,
delivery history, payloads, redelivery and operation receipts through the
authenticated service. Run daynight webhook --help and each leaf's --help
for the complete command and option list. The dn alias has the same commands.
Every leaf except catalog requires exactly one explicit owner: --personal
selects the authenticated User, and --team <team-id> selects a Team UUID.
The current Git directory and default Team do not select an owner; --team personal
is not accepted. The CLI verifies the authenticated user once and
checks the response identity throughout the command. IDs are canonical UUIDs;
versions and generations are positive decimal int64 values, preserved exactly.
daynight webhook catalog --json
daynight webhook list --personal --json
daynight webhook create --personal --file ./endpoint.json --confirm --json
daynight webhook update <endpoint-id> --team <team-id> --if-version <version> --file ./patch.json --confirm --json
daynight webhook subscription reconfirm <endpoint-id> --personal --if-version <version> --project <project-id> --confirm
daynight webhook secret show <endpoint-id> --personal --reveal
daynight webhook delivery list <endpoint-id> --personal --limit 50 --json
daynight webhook delivery payload <endpoint-id> <delivery-id> --personal --output ./payload.json
daynight webhook delivery redeliver <endpoint-id> <delivery-id> --personal --if-version <version> --if-generation <generation> --confirm --json
daynight webhook operation show <operation-id> --personal --jsonCreate, update and subscription replacement take exactly one of --file or
--stdin. Inputs are strict UTF-8 JSON with no duplicate or unknown keys,
at most 32 levels and 256 KiB; the final request including control fields is
also limited to 256 KiB. Files must be regular files. Supply URL and adapter
configuration in the JSON, not command arguments. Update is a nonempty partial
object; subscription replacement is a complete array. Reconfirmation accepts
one or more distinct --project values. All writes except create require the
observed --if-version; redelivery also requires --if-generation. No write
implicitly reads the latest version or retries a conflict. Noninteractive and
stdin writes require --confirm; an interactive confirmation contains only
the owner, operation, opaque targets and versions.
Writes preserve an operation ID and original issued time. Supply both
--operation-id and --issued-at, or let the CLI generate both after
confirmation. --operation-out <path> exclusively creates a private prepared
record before sending; it contains the scope, versions and request hash, but no
body, URL, credentials or secret. Private prepared-file creation is unavailable
on Windows and fails before sending. An unknown result retains the original
identity and is never automatically replayed. Inspect the original receipt with
operation show; current resource values or a missing receipt do not establish
the original outcome. To resume, use --resume-operation <path> on the original
write command and supply the same owner, targets, versions, mode and input. It
verifies the record and exact request hash before reading the receipt. A matching
receipt confirms the original operation without another write. The CLI rejects a
receipt whose expiry is at or before the local clock. The service also enforces
expiry with its database clock: expired receipt reads return 404 not_found,
and matching retained expired replays return 410 operation_expired. Rotation
receipts retain their original keyId and nullable overlapUntil even after
later rotations or endpoint deletion. A missing receipt
permits at most one identical submission only with --confirm, complete original
input and an issued time within the service's admission window (five minutes
past and sixty seconds future). An inaccessible receipt or expired window leaves
the outcome unknown. A prepared record alone cannot reconstruct the body.
Endpoint list validates every page before producing a complete result; delivery
and attempt lists return one page, defaulting to 50 items, with --limit from 1
to 100 and an explicit --cursor for continuation. History can be incomplete
because of retention. Secret show reports metadata unless --reveal is explicitly
requested; rotation does not reveal the new secret. A successful redelivery only
registers it and does not mean delivery has completed.
Payload output defaults to the exact original bytes without an added newline.
--json returns its validated Base64 wrapper; --output <path> writes a private
file after validation and never overwrites an existing target. File publication
requires Linux with procfs and glibc; it fails when inode-bound publication is unavailable.
These two options are mutually exclusive. Payload access and retention are independently enforced
by the service. Normal JSON output is one value followed by LF. Runtime errors
with --json go to stderr and distinguish invocation from original operation
outcomes; a confirmed write remains confirmed if local output fails. Exit status
is 0 for success, 2 for usage errors and 1 for runtime failures or unknown results.
Task management
daynight task search <expression> searches Task IDs, complete titles and Markdown
descriptions in one project, including completed Tasks by default. Supply the
entire expression as one shell argument; -- permits an expression beginning
with a dash. For example:
daynight task search 'title:缓存 AND NOT description:废弃' --status done
daynight task search -- '-worker'Words and quoted phrases match literal substrings, with ASCII case folding. ID
queries match the canonical hyphenated UUID, including prefixes and middle fragments.
A positive exact full ID match ranks before a title match; fragments do not.
Uppercase NOT, AND, and OR, parentheses, implicit AND, and the id:,
title: and description: fields form expressions. Inside quotes, \" and \\
escape a quote and a backslash. --status, --assigned-to, --ready,
--allow-agents, --compatible-platform, --type, and --parent intersect the expression; search
does not accept --all. Explicit --project searches that project directly;
otherwise the current repository resolves the project.
Search reads and validates every page before producing output, preserving the
server's order. Text shows the full Task ID and title, type, parent, status, actual
parent Goal or none, positive match fields, and a description snippet when present. A
negative-only match is identified as such; text escapes terminal controls.
--json emits one newline-terminated array whose entries contain only id,
type, parentId, projectId, title, status, cancelledAt, context, and match. Both formats omit the
assignee and update time; use task show for complete Task details. An empty
result is No matching tasks. in text or [] in JSON. Invalid arguments and
expression syntax exit 2; read, permission, protocol, cancellation, budget and
search_changed failures exit 1. Errors go to stderr, and a failed search emits
no partial results on stdout. A changed search must be started again.
Task commands use the same serverUrl configuration as project commands:
daynight task create --title "Implement sign-in" --description '## Sign-in
Implement OAuth sign-in for the web workspace. Deliver the callback flow and
visible failure recovery; preserve the existing session and provider rules.
Complete when a valid login opens the workspace and a rejected login can retry.'
daynight task create --title "Build the sign-in page" --depends-on <design-task-id> --external-depends-on <authentication-task-id>
daynight task create --type goal --title "Improve installation"
daynight task create --type goal --title "Unassigned Goal" --clear-assigned-to
daynight task create --title "Document prerequisites" --parent <goal-id> --status todo
daynight task ready
daynight task ready --parent <goal-id> --limit 5 --json
daynight task ready --allow-agents true --compatible-platform linux --json
daynight task list --allow-agents false --ready
daynight task list --ready
daynight task list --all --json
daynight task list --type goal --json
daynight task list --parent none --json
daynight task list --status in_progress --json
daynight task list --status in_progress --group-by chain --assigned-to me --json
daynight task list --ready --assigned-to me --json
daynight task list --assigned-to unassigned --json
daynight task show <task-id> --json
daynight task properties <task-id> --json
daynight task properties --schema --json
daynight task set-property <task-id> pullRequests '[{"url":"https://github.com/owner/repo/pull/123","title":"Fix synchronization"}]' --if-version <observed-version>
daynight task remove-property <task-id> pullRequests --if-version <observed-version>
daynight task update <task-id> --parent <goal-id> --if-version <version>
daynight task update <task-id> --parent none --if-version <version>
daynight task update <task-id> --description=
daynight task update <task-id> --allow-agents true --if-version <version>
daynight task create --title "Check Windows build" --required-platform windows
daynight task update <task-id> --required-platform macos --if-version <version>
daynight task update <task-id> --clear-required-platform --if-version <version>
daynight task create --title "Review installation" --assigned-to <user-uuid>
daynight task update <task-id> --assigned-to <user-uuid> --if-version <version>
daynight task update <task-id> --clear-assigned-to --if-version <version>
daynight task set-status <task-id> <status> [--claim-id <claim-id>] [--if-version <version>] [--force] [--project <project-id>]
daynight task update <task-id> --depends-on <task-a> --depends-on <task-b>
daynight task update <task-id> --clear-dependencies
daynight task graph <task-id> --json
daynight task graph <task-id> --depends-only
daynight task graph <task-id> --depends-only --jsontask graph requires a task ID. It returns every member of that task's ordinary
undirected dependency component, including completed tasks and sibling branches,
plus one layer of external prerequisites declared by those members. External
tasks that depend on the chain do not enter the result. Added external tasks do
not expand their own prerequisites or chain. The service applies its 1,000-task
and 5,000-dependency-reference limits to this returned set; unrelated chains do
not count toward this query's limits.
Every returned task retains its full dependsOn, externalDependsOn, blockedBy
and ready. An external context task can therefore reference an ID with no task
row in this response. Those references remain available for dependency audits.
The ordinary graph output includes the project, statistics for all returned
nodes, compact node facts and each node's Session observation. relation marks
ordinary members and external context; sessionSummary aggregates only
in-progress ordinary members. Its observation time is independent of the graph
snapshot's observedAt. --depends-only does not request Session observations;
it uses the same tasks but prints
only ID, Depends on and External dependencies, with full UUIDs and none
for empty sets. With --json, this mode returns a bare array of objects containing
only id, dependsOn and externalDependsOn.
Project-scoped operations accept --project <project-id>, which selects a project
for one invocation without reading Git or local bindings. task properties --schema
uses only the authenticated service and rejects project selection. Otherwise, the CLI reads the
current worktree's effective origin, normalizes equivalent HTTPS/SSH/SCP
addresses, and matches the configured server's projects. A missing match fails
with Project does not exist; multiple matches require explicit selection.
A unique discovery is saved in the worktree's .daynight/project.yml with the
server origin and repository identity, after ensuring /.daynight/ is effective
in the root .gitignore. A cached binding is verified against the server on each
use and remains stable if another project later shares that repository.
Task resources require type (task or goal) and a nullable parentId. Create,
list and search default to task; --type goal selects a Goal. List, search and
ready accept --parent <goal-id|none>: omission does not filter by parent, none
selects Tasks without a Goal, and a Goal UUID selects its direct children. Filters apply
before pagination and persist across pages. Create defaults to no parent; on update,
omission preserves the current parent. --parent none sends null, and a Goal UUID
sets the parent. A Goal cannot have a parent. Membership does not change Task
identity, status, assignee, materials, dependencies or their classifications.
A Goal uses todo, in_progress, done or cancelled and is never ready. Full
Goal reads include progress; its Session registration is not_applicable. Graph
nodes are ordinary Tasks, and dependency IDs may refer to unavailable resources
without exposing their details. Ready remains a dependency fact; it does not apply
the additional parent-state restrictions used for automatic claims.
Before creating a Goal in done or cancelled, or setting a Goal to either status, the CLI explains on stderr that child Task states are retained and future automatic claims are excluded. Before deleting a Goal, it explains that the Goal and all its Tasks become invisible, membership remains, and running Tasks stop through the existing process after a successful observation. Confirm interactively or supply --force; noninteractive calls without it do not submit. Status and delete read the target type and identity even with --if-version, and retain the caller’s exact version for the write. --force skips only the Goal prompt; the service still applies its business and version checks.
Ordinary Task creation defaults to proposed; --status proposed|todo explicitly
selects the initial state, so confirmed internal multi-step work can start in todo.
Goal creation defaults to todo and accepts todo, in_progress, done and
cancelled. Both default to the signed-in assignee; --assigned-to <user-uuid>
overrides it, and --clear-assigned-to explicitly creates an unassigned resource.
These two options conflict.
Ordinary creation uses allowAgents=false and unrestricted requiredPlatform=null
unless explicitly set. Goal execution fields are not applicable. Unset properties remain absent;
creation does not inject a PR array or worker null. task set-status <id> <status>
sets proposed, todo, in_progress, done or cancelled for ordinary Tasks. The nonterminal states and done allow direct setting without a mandatory proposed or todo stage, retaining
reopening and direct completion; ordinary Task cancellation is irreversible and does not prove
delivery. Goal-specific lifecycle effects remain subject to the service's business checks. Cancelled records and materials remain readable unless effective parent deletion hides them.
Every project member may use ordinary status setting. Active worker completion
requires the current owner and an explicit --claim-id <claim-id> with target
done; the CLI uses the existing typed completion operation. The option is
validated before configuration or network access, is rejected for other targets,
and is never inferred from a task or environment. Without it, ordinary status
setting is unchanged. Release uses its protected operation; a later execution uses ordinary claim eligibility. Status does not grant execution or delivery authority. Generic updates cannot write status; old lifecycle commands and routes
are removed without aliases. --if-version uses the exact reviewed int64 value;
without it, the CLI reads the target before submitting. No write retries
occur. A controller-bounded worker assignment executes its supplied claim in the
provided worktree, finishes with the explicit claim ID after delivery, and leaves
system worktree cleanup and next-task selection to its controller. Version is
checked before same-state handling: current same-state keeps
version, update time and timing unchanged; actual changes increment once.
Actual cancellation records required nullable cancelledAt, preserves existing
execution times and materials, and satisfies dependencies without deleting edges.
Active ownership must first be released; cancelled tasks cannot be claimed or
withdrawn back to todo.
Entering in_progress or done requires all direct prerequisites, ordinary and external, to be done or cancelled. Reopening done requires no direct in-progress or done dependents; cancelled dependents do not add a reopen restriction. Refusals return sorted blocking task IDs without cascading changes. The project transaction serializes status and dependency writes and preserves materials, assignedTo, properties/PRs, permission, both dependency sets and attachments.
Migration 014_task_status_assignment.sql converts historical proposed rows
to todo, increments only those versions and updates their update time while
preserving every other field, including requiredPlatform and historical execution timestamps. Default,
data, CHECK and ledger change atomically. Other rows and applied migrations remain
unchanged; restart does not repeat the conversion. A subsequent migration restores proposed as a current status and the creation default without changing existing rows or historical migrations.
Task resources expose required nullable startedAt, completedAt and cancelledAt.
Cancellation preserves both execution endpoints and records its own database
time; a cancelled task never resumes execution or starts a new duration. Actual entry
into in_progress starts a new interval and clears the end; return to proposed or todo clears
both. In-progress to done preserves a nullable start and records a real end;
proposed/todo to done records only an end, leaving duration unknown. Metadata and same-state
writes preserve time. Task-graph and task-sync responses supply a database
observedAt sample; Web synchronization updates its separate clock without
rebuilding unchanged graph/index data.
Read-only timing fields remain in JSON; human CLI output keeps its field choices.
The status requirements and
architecture own the complete rules.
Task and graph resources also require externalDependsOn, a sorted,
duplicate-free subset of all dependsOn IDs. CLI JSON preserves it and the
shared human dependency block shows External dependencies (N): .... Current
API dependency fields are independently optional: a dependsOn-only PATCH
retains classification on surviving edges, while an externalDependsOn-only PATCH
replaces the exact external subset. CLI --depends-on and --external-depends-on
compile both complete sets whenever either option is supplied; ordinary-only
clears the external subset and external-only replaces all relationships. Omit
both CLI options to preserve them. Metadata and lifecycle actions retain
unmodified classification. Every edge still participates in blocking and cycles.
Every Project resource includes settings with an exact positive int64 version
and executionWarningMinutes from 1 through 2147483647, initially 60. Project
create/read/list, the project in graph responses, and a successful settings PATCH
return this same shape. The member-readable settings page lets administrators
save or cancel a draft; ordinary members see the saved value without editing.
The server checks current administrator authority after the project lock, then
the observed settings version. An equal-value save preserves version and
updatedAt; a real change increments version and updates updatedAt. Migration
preserves historical project timestamps. CLI JSON preserves settings and nested
versions without rounding; human output keeps its established fields.
An unconfirmed settings PATCH response requires a Project and membership reread before another write. Failed reconciliation keeps Save blocked and offers read retry; network, protocol, 5xx or navigation cancellation never prove rollback. Confirmed refusals and unsaved/canceled drafts do not apply local settings. Project-only changes update graph metadata while retaining the task index and layout when tasks and summary are unchanged. Running known-start tasks subscribe to one visible-page ticker; completed duration uses stored endpoints and unknown starts show no inferred duration. Warnings use an unrounded strict comparison and disappear on completion without changing task status. The server-sample clock avoids client wall-clock skew but does not remove network sampling delay.
The Web shared status row offers todo, in progress, done and cancelled on every material tab. Cancelled tasks retain readable status and materials without reopen, resume or withdraw actions. The current original-state item remains selectable. Cancellation uses the existing confirmation with the task name, transition, irreversibility, retained readability and dependency consequence. Active claims mark cancellation unavailable and expose the existing release requirement on hover or keyboard focus without submitting. Dismissing the confirmation or pressing Escape sends no write.
Status, Automatic execution / 自动执行 and platform confirmation share one per-task mutation owner. Pending, stale or unknown results block conflicting writes. Current-version same-state responses confirm no stored change; actual cancellation requires cancelledAt and preserves both execution endpoints and other Task fields. Confirmed changes refresh the normal graph, retaining the cancelled node and materials. Unknown outcomes use GET-only reconciliation, preserving errors and never attributing observed state to the uncertain request. Closing details does not roll back a submission.
Task details use one platform select in the left status group to display the confirmed requirement and offer Any platform, Windows, Linux and macOS. Choosing a different value opens confirmation showing the current and target platforms; only confirmation submits the reviewed exact task version. Choosing the saved value, Cancel, close, backdrop dismissal and Escape send no request. Cancellation returns focus to the select. The confirmed value remains displayed until success, and Any platform clears requiredPlatform. Overview has no se
