From 0fd7ade19c6478ec2092c14f02c6236e28ac8c1a Mon Sep 17 00:00:00 2001 From: Greg Gardner Date: Sun, 26 Jul 2026 05:47:26 -0700 Subject: [PATCH 1/3] docs: backfill user documentation Nightshift-Task: docs-backfill Nightshift-Ref: https://github.com/marcus/nightshift --- README.md | 73 +++++++-- website/docs/cli-reference.md | 239 ++++++++++++++++++++-------- website/docs/configuration.md | 268 ++++++++++++++++++++++++-------- website/docs/installation.md | 114 +++++++++++--- website/docs/integrations.md | 123 ++++++++++++--- website/docs/scheduling.md | 135 +++++++++++++--- website/docs/troubleshooting.md | 200 ++++++++++++++++++++---- 7 files changed, 915 insertions(+), 237 deletions(-) diff --git a/README.md b/README.md index 84f92cd..85da0fa 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,19 @@ Or kick off a run immediately: nightshift run ``` +For a non-interactive configuration bootstrap: + +```bash +nightshift init --global # ~/.config/nightshift/config.yaml +nightshift init # ./nightshift.yaml +nightshift config validate +nightshift config get budget.max_percent +nightshift config set budget.max_percent 60 --global +``` + +Configuration precedence is built-in defaults, global config, project `nightshift.yaml`, +environment overrides, then command flags. + ## Common CLI Usage Full reference: [CLI Reference docs](https://nightshift.haplab.com/docs/cli-reference) @@ -72,6 +85,12 @@ nightshift preview --write ./nightshift-prompts # Guided global setup nightshift setup +# Create and validate config +nightshift init --global +nightshift init +nightshift config +nightshift config validate + # Check environment and config health nightshift doctor @@ -93,8 +112,17 @@ nightshift task show lint-fix --prompt-only # Run a task immediately nightshift task run lint-fix --provider claude -nightshift task run skill-groom --provider codex --dry-run -nightshift task run lint-fix --provider codex --dry-run +nightshift task run skill-groom --provider codex --dry-run --branch main +nightshift task run docs-backfill --provider copilot --timeout 45m + +# Persistent scheduler lifecycle +nightshift daemon start +nightshift daemon status +nightshift daemon stop + +# Or install an OS-managed scheduled run +nightshift install +nightshift uninstall ``` If `gum` is available, preview output is shown through the gum pager. Use `--plain` to disable. @@ -116,6 +144,9 @@ daemon, CI) confirmation is auto-skipped. | `--random-task` | `false` | Pick a random task from eligible tasks instead of the highest-scored one | | `--ignore-budget` | `false` | Bypass budget checks (use with caution) | | `--yes`, `-y` | `false` | Skip the confirmation prompt | +| `--branch`, `-b` | _(current branch)_ | Base branch for new task branches | +| `--timeout` | `30m` | Per-agent execution timeout | +| `--no-color` | `false` | Disable colored output (`NO_COLOR` also works) | ```bash # Interactive run with preflight summary + confirmation prompt @@ -138,6 +169,9 @@ nightshift run --ignore-budget # Target a specific project and task directly nightshift run -p ./my-project -t lint-fix + +# Select a base branch and timeout +nightshift run --branch develop --timeout 45m ``` Other useful flags: @@ -146,7 +180,7 @@ Other useful flags: - `--category` — filter tasks by category (pr, analysis, options, safe, map, emergency) - `--cost` — filter by cost tier (low, medium, high, veryhigh) - `--prompt-only` — output just the raw prompt text for piping -- `--provider` — required for `task run`, choose claude or codex +- `--provider` — required for `task run`, choose claude, codex, or copilot - `--dry-run` — preview the prompt without executing - `--timeout` — execution timeout (default 30m) @@ -177,13 +211,19 @@ Supports signing in with ChatGPT or an API key. ### GitHub Copilot ```bash -# Install Copilot CLI +# Preferred: standalone Copilot CLI npm install -g @github/copilot -# or -curl -fsSL https://gh.io/copilot-install | bash +copilot login + +# Also supported: legacy gh copilot extension +gh auth login --web +gh extension install github/gh-copilot --force ``` -Requires GitHub Copilot subscription. See [docs/COPILOT_INTEGRATION.md](docs/COPILOT_INTEGRATION.md) for details. +Nightshift prefers the standalone `copilot` executable, then falls back to `gh` when the +`github/gh-copilot` extension appears in `gh extension list`. The upstream extension is +deprecated, so prefer standalone Copilot for new installations. A Copilot plan and any required +organization policy are prerequisites. If you prefer API-based usage, you can authenticate Claude and Codex CLIs with API keys instead. @@ -198,9 +238,11 @@ Nightshift uses YAML config files to define: - Task priorities - Schedule preferences -Run `nightshift setup` to create/update the global config at `~/.config/nightshift/config.yaml`. +Run `nightshift setup` or `nightshift init --global` to create the global config at +`~/.config/nightshift/config.yaml`. A project config is named exactly `nightshift.yaml`. -See the [full configuration docs](https://nightshift.haplab.com/docs/configuration) or [SPEC.md](docs/SPEC.md) for detailed options. +See the [full configuration docs](https://nightshift.haplab.com/docs/configuration) for detailed +options. Minimal example: @@ -220,14 +262,19 @@ providers: preference: - claude - codex + - copilot claude: enabled: true data_path: "~/.claude" - dangerously_skip_permissions: true + dangerously_skip_permissions: false codex: enabled: true data_path: "~/.codex" - dangerously_bypass_approvals_and_sandbox: true + dangerously_bypass_approvals_and_sandbox: false + copilot: + enabled: true + data_path: "~/.copilot" + dangerously_skip_permissions: false projects: - path: ~/code/sidecar @@ -256,6 +303,10 @@ Each task has a default cooldown interval to prevent the same task from running `skill-groom` is enabled by default. Add it to `tasks.disabled` if you want to opt out. It updates project-local skills under `.claude/skills` and `.codex/skills` using `README.md` as project context and starts Agent Skills docs lookup from `https://agentskills.io/llms.txt`. +Provider executables are discovered through `PATH`; `providers.*.data_path` points to usage and +session data, not to the executable. Automatic selection uses `providers.preference` and skips +disabled, unavailable, or budget-exhausted providers. + ## Development ### Pre-commit hooks diff --git a/website/docs/cli-reference.md b/website/docs/cli-reference.md index d5a2cd4..00bb40f 100644 --- a/website/docs/cli-reference.md +++ b/website/docs/cli-reference.md @@ -5,88 +5,201 @@ title: CLI Reference # CLI Reference -## Core Commands +Run `nightshift --help` or `nightshift COMMAND --help` for the version installed on your machine. + +## Command overview + +| Command | Purpose | +|---------|---------| +| `setup` | Run the interactive global onboarding wizard | +| `init` | Create a global or project configuration file | +| `config` | Show, read, write, or validate configuration | +| `run` | Plan and execute configured tasks immediately | +| `preview` | Preview future runs without changing state | +| `task` | List, inspect, or execute one task | +| `budget` | Show budget status, snapshots, and calibration | +| `daemon` | Start, stop, or inspect the persistent scheduler | +| `install` | Install an OS-managed scheduled service | +| `uninstall` | Remove installed launchd, systemd, and cron entries | +| `status` | Show recent run history or today's activity | +| `report` | Render structured run reports | +| `logs` | Read, filter, follow, or export logs | +| `stats` | Show aggregate run and token statistics | +| `doctor` | Diagnose configuration, providers, scheduling, database, and budget | +| `busfactor` | Analyze code ownership concentration | +| `completion` | Generate shell completion scripts | + +## Configuration bootstrap -| Command | Description | -|---------|-------------| -| `nightshift setup` | Guided global configuration | -| `nightshift run` | Execute scheduled tasks | -| `nightshift preview` | Show upcoming runs | -| `nightshift budget` | Check token budget status | -| `nightshift task` | Browse and run tasks | -| `nightshift doctor` | Check environment health | -| `nightshift status` | View run history | -| `nightshift logs` | Stream or export logs | -| `nightshift stats` | Token usage statistics | -| `nightshift daemon` | Background scheduler | - -## Run Options +```bash +nightshift setup +nightshift init +nightshift init --global +nightshift init --global --force + +nightshift config +nightshift config get budget.max_percent +nightshift config set budget.max_percent 60 +nightshift config set providers.copilot.enabled true --global +nightshift config validate +``` -`nightshift run` shows a preflight summary before executing, then prompts for confirmation in interactive terminals. +`init` creates `nightshift.yaml` in the current directory. `init --global` creates +`~/.config/nightshift/config.yaml`. Without `--global`, `config set` writes to the current +project config when it exists and otherwise writes to the global config. + +## `nightshift run` + +`run` builds a preflight plan, showing the base branch, provider, budget, projects, and tasks. +It prompts before execution in an interactive terminal. Non-interactive invocations, including +cron and system services, skip the prompt automatically. + +| Flag | Default | Behavior | +|------|---------|----------| +| `--dry-run` | `false` | Show the preflight plan and exit without execution | +| `--project`, `-p` | configured projects or current directory | Target one existing directory; ignores `--max-projects` | +| `--task`, `-t` | automatic selection | Run one named task; ignores `--max-tasks` and bypasses the processed-today skip | +| `--max-projects` | `1` | Maximum eligible projects; a positive `schedule.max_projects` supplies the default when the flag is omitted | +| `--max-tasks` | `1` | Maximum selected tasks per project; a positive `schedule.max_tasks` supplies the default when the flag is omitted | +| `--random-task` | `false` | Pick exactly one random eligible task; cannot be combined with `--task` | +| `--ignore-budget` | `false` | Permit selection even when a provider budget is exhausted | +| `--yes`, `-y` | `false` | Skip the interactive confirmation | +| `--branch`, `-b` | current branch of the first project | Set the base branch used for task branches | +| `--timeout` | `30m` | Set the per-agent execution timeout | +| `--no-color` | `false` | Disable colored output; `NO_COLOR` also works | ```bash -nightshift run # Preflight + confirm + execute (1 project, 1 task) -nightshift run --yes # Skip confirmation -nightshift run --dry-run # Show preflight, don't execute -nightshift run --max-projects 3 # Process up to 3 projects -nightshift run --max-tasks 2 # Run up to 2 tasks per project -nightshift run --random-task # Pick a random eligible task -nightshift run --ignore-budget # Bypass budget limits (use with caution) -nightshift run --project ~/code/myapp # Target specific project (ignores --max-projects) -nightshift run --task lint-fix # Run specific task (ignores --max-tasks) +nightshift run --dry-run +nightshift run --yes --max-projects 3 --max-tasks 2 +nightshift run -p ~/code/myapp -t docs-backfill +nightshift run --random-task +nightshift run --branch develop --timeout 45m ``` -| Flag | Default | Description | -|------|---------|-------------| -| `--dry-run` | `false` | Show preflight summary and exit without executing | -| `--yes`, `-y` | `false` | Skip confirmation prompt | -| `--max-projects` | `1` | Max projects to process (ignored when `--project` is set) | -| `--max-tasks` | `1` | Max tasks per project (ignored when `--task` is set) | -| `--random-task` | `false` | Pick a random task from eligible tasks instead of the highest-scored one | -| `--ignore-budget` | `false` | Bypass budget checks with a warning | -| `--project`, `-p` | | Target a specific project directory | -| `--task`, `-t` | | Run a specific task by name | +## `nightshift preview` -Non-interactive contexts (daemon, cron, piped output) skip the confirmation prompt automatically. +Preview never executes tasks or modifies run state. -## Preview Options +| Flag | Default | Behavior | +|------|---------|----------| +| `--runs`, `-n` | `3` | Number of upcoming runs | +| `--project`, `-p` | all | Limit output to a project path | +| `--task`, `-t` | all | Limit output to a task type | +| `--long` | `false` | Show full prompts instead of truncated previews | +| `--write DIR` | unset | Write full prompts to a directory | +| `--explain` | `false` | Include budget and task-filter reasons | +| `--plain` | `false` | Disable the optional `gum` pager | +| `--json` | `false` | Emit JSON, including full prompts | ```bash -nightshift preview # Default view -nightshift preview -n 3 # Next 3 runs -nightshift preview --long # Detailed view -nightshift preview --explain # With prompt previews -nightshift preview --plain # No pager -nightshift preview --json # JSON output -nightshift preview --write ./dir # Write prompts to files +nightshift preview --explain +nightshift preview -n 5 --task lint-fix +nightshift preview --json +nightshift preview --write ./nightshift-prompts ``` -## Task Commands +## `nightshift task` ```bash -nightshift task list # All tasks -nightshift task list --category pr -nightshift task list --cost low --json -nightshift task show lint-fix -nightshift task show lint-fix --prompt-only -nightshift task run lint-fix --provider claude -nightshift task run lint-fix --provider codex --dry-run +nightshift task list +nightshift task list --category analysis --cost medium --json +nightshift task show docs-backfill +nightshift task show docs-backfill --prompt-only +nightshift task show docs-backfill --project ~/code/myapp --json +nightshift task run docs-backfill --provider copilot --project ~/code/myapp --dry-run +nightshift task run docs-backfill --provider codex --branch main --timeout 45m ``` -## Budget Commands +`task list` accepts categories `pr`, `analysis`, `options`, `safe`, `map`, and `emergency`. +Its cost filter accepts `low`, `medium`, `high`, and `veryhigh`. `task run` requires one of +`claude`, `codex`, or `copilot`; its default project is the current directory and its default +timeout is `30m`. + +## `nightshift budget` + +All budget commands accept `--provider`/`-p` with `claude`, `codex`, or `copilot`. ```bash -nightshift budget # Current status -nightshift budget --provider claude -nightshift budget snapshot --local-only +nightshift budget +nightshift budget --provider codex +nightshift budget snapshot +nightshift budget snapshot --provider claude --local-only nightshift budget history -n 10 -nightshift budget calibrate +nightshift budget calibrate --provider copilot +``` + +`budget history` defaults to 20 snapshots. `snapshot --local-only` records provider data without +starting a tmux scraping session. `calibrate` reports inferred budget status; it does not consume +an agent run. + +## Daemon and installed services + +The daemon is a persistent scheduler: + +```bash +nightshift daemon start +nightshift daemon start --foreground --timeout 45m +nightshift daemon status +nightshift daemon stop ``` -## Global Flags +An installed service is OS-managed and invokes `nightshift run` at scheduled times: + +```bash +nightshift install +nightshift install launchd +nightshift install systemd +nightshift install cron +nightshift uninstall +``` + +With no argument, `install` chooses launchd on macOS, systemd on Linux when `systemctl` is +available, and cron otherwise. `uninstall` looks for and removes all three Nightshift service +types. See [Scheduling](/docs/scheduling) for lifecycle details. + +## History, reports, logs, and diagnostics + +```bash +nightshift status --last 10 +nightshift status --today + +nightshift report +nightshift report --report tasks --period last-7d --format markdown +nightshift report --since 2026-07-01 --until 2026-07-08 --runs 0 --paths + +nightshift logs --tail 100 +nightshift logs --follow +nightshift logs --since "2026-07-25 22:00" --level warn --component daemon +nightshift logs --match "budget exhausted" --summary +nightshift logs --export ./nightshift.log --raw --no-color + +nightshift stats --period last-30d +nightshift stats --json +nightshift doctor +``` + +Report types are `overview`, `tasks`, `projects`, `budget`, and `raw`. Report formats are +`fancy`, `plain`, `markdown`, and `json`. `--period` accepts `last-night`, `last-run`, +`last-24h`, `last-7d`, `today`, `yesterday`, or `all`; `--since` and `--until` accept a date, +local date/time, or RFC3339 timestamp. + +`logs --level` accepts `debug`, `info`, `warn`, or `error`. Statistics periods are `all`, +`last-7d`, `last-30d`, and `last-night`. + +## Bus factor analysis + +```bash +nightshift busfactor . +nightshift busfactor --path ~/code/myapp --since 2026-01-01 --json +nightshift busfactor . --file "internal/*.go" --save +nightshift busfactor . --db ~/.local/share/nightshift/nightshift.db +``` + +The optional positional path and `--path`/`-p` select the repository. Date boundaries accept +`YYYY-MM-DD` or RFC3339. + +## Global flags -| Flag | Description | -|------|-------------| -| `--verbose` | Verbose output | -| `--provider` | Select provider (claude, codex) | -| `--timeout` | Execution timeout (default 30m) | +`--verbose` is the only Nightshift-wide behavior flag. Cobra also provides `--help`, and the root +command provides `--version`. Provider, timeout, JSON, and formatting flags belong only to the +commands that list them. diff --git a/website/docs/configuration.md b/website/docs/configuration.md index 4a7ee3d..b56506b 100644 --- a/website/docs/configuration.md +++ b/website/docs/configuration.md @@ -5,126 +5,258 @@ title: Configuration # Configuration -Nightshift uses YAML config files. Run `nightshift setup` for an interactive setup, or edit directly. +Nightshift reads YAML configuration and applies built-in defaults when a field is omitted. -## Config Location +## Create and inspect configuration -- **Global:** `~/.config/nightshift/config.yaml` -- **Per-project:** `nightshift.yaml` or `.nightshift.yaml` in the repo root +Use the guided wizard for a complete global setup: -## Minimal Config +```bash +nightshift setup +``` + +For a generated file you can edit directly: + +```bash +nightshift init --global # ~/.config/nightshift/config.yaml +nightshift init # ./nightshift.yaml +nightshift config validate +``` + +`--force` overwrites an existing file without the confirmation prompt. You can inspect the +effective configuration or change scalar values without opening an editor: + +```bash +nightshift config +nightshift config get providers.preference +nightshift config set budget.max_percent 60 +nightshift config set logging.level debug --global +``` + +`config set` writes to `nightshift.yaml` when that file exists in the current directory; +otherwise it writes to the global file. It parses `true`/`false`, integers, and decimal numbers, +and treats other values as strings. + +## Source precedence + +From lowest to highest precedence: + +1. Built-in defaults. +2. `~/.config/nightshift/config.yaml`. +3. `nightshift.yaml` in the current directory, or in the directory supplied by + `run --project`. +4. `NIGHTSHIFT_` environment overrides. +5. Command-line flags for the command being run. + +The project filename is exactly `nightshift.yaml`; `.nightshift.yaml` is not loaded automatically. +The explicitly bound environment variables are: + +| Variable | Configuration key | +|----------|-------------------| +| `NIGHTSHIFT_BUDGET_MAX_PERCENT` | `budget.max_percent` | +| `NIGHTSHIFT_BUDGET_MODE` | `budget.mode` | +| `NIGHTSHIFT_LOG_LEVEL` | `logging.level` | +| `NIGHTSHIFT_LOG_PATH` | `logging.path` | + +## Complete example ```yaml schedule: cron: "0 2 * * *" + max_projects: 2 + max_tasks: 2 + window: + start: "22:00" + end: "06:00" + timezone: "America/Los_Angeles" budget: mode: daily max_percent: 75 + aggressive_end_of_week: false reserve_percent: 5 + weekly_tokens: 700000 + per_provider: + claude: 700000 + codex: 500000 + copilot: 500000 billing_mode: subscription calibrate_enabled: true snapshot_interval: 30m + snapshot_retention_days: 90 + week_start_day: monday + db_path: ~/.local/share/nightshift/nightshift.db providers: - preference: - - claude - - codex + preference: [claude, codex, copilot] claude: enabled: true - data_path: "~/.claude" - dangerously_skip_permissions: true + data_path: ~/.claude + dangerously_skip_permissions: false codex: enabled: true - data_path: "~/.codex" - dangerously_bypass_approvals_and_sandbox: true + data_path: ~/.codex + dangerously_bypass_approvals_and_sandbox: false + copilot: + enabled: true + data_path: ~/.copilot + dangerously_skip_permissions: false projects: - path: ~/code/sidecar + priority: 2 - path: ~/code/td + priority: 1 + +tasks: + enabled: [lint-fix, docs-backfill, bug-finder] + disabled: [td-review] + priorities: + bug-finder: 3 + docs-backfill: 2 + intervals: + lint-fix: 24h + docs-backfill: 168h + +integrations: + claude_md: true + agents_md: true + task_sources: + - td: + enabled: true + teach_agent: true + - github_issues: true + +logging: + level: info + path: ~/.local/share/nightshift/logs + format: json + +reporting: + morning_summary: true ``` ## Schedule -Use cron syntax or interval-based scheduling: +Choose exactly one scheduler: -```yaml -schedule: - cron: "0 2 * * *" # Every night at 2am - # interval: "8h" # Or run every 8 hours -``` +| Key | Default | Rules | +|-----|---------|-------| +| `schedule.cron` | unset | Five-field minute/hour/day/month/weekday expression | +| `schedule.interval` | unset | Positive Go duration such as `30m`, `8h`, or `24h` | +| `schedule.window.start` | unset | `HH:MM`, hour 00-23 and minute 00-59 | +| `schedule.window.end` | unset | `HH:MM`; the end is exclusive | +| `schedule.window.timezone` | local timezone | IANA name such as `America/Los_Angeles` | +| `schedule.max_projects` | `0` | Positive value supplies the default for `run --max-projects`; otherwise the CLI default is 1 | +| `schedule.max_tasks` | `0` | Positive value supplies the default for `run --max-tasks`; otherwise the CLI default is 1 | + +`cron` and `interval` are mutually exclusive. A missing schedule is valid for manual commands, +but `daemon start` requires one. Windows may stay within one day or cross midnight. ## Budget -Control how much of your token budget Nightshift uses: +| Key | Default | Rules | +|-----|---------|-------| +| `budget.mode` | `daily` | `daily` or `weekly` | +| `budget.max_percent` | `75` | 0-100 | +| `budget.aggressive_end_of_week` | `false` | Increase weekly-mode spending in the final two days | +| `budget.reserve_percent` | `5` | 0-100 | +| `budget.weekly_tokens` | `700000` | Fallback weekly allowance | +| `budget.per_provider` | unset | Provider-specific weekly token overrides | +| `budget.billing_mode` | `subscription` | `subscription` or `api` | +| `budget.calibrate_enabled` | `true` | Enable subscription usage calibration | +| `budget.snapshot_interval` | `30m` | Daemon snapshot cadence | +| `budget.snapshot_retention_days` | `90` | Non-negative snapshot retention | +| `budget.week_start_day` | `monday` | `monday` or `sunday` | +| `budget.db_path` | `~/.local/share/nightshift/nightshift.db` | SQLite state and snapshot database | -| Field | Default | Description | -|-------|---------|-------------| -| `mode` | `daily` | `daily` or `weekly` | -| `max_percent` | `75` | Max budget % to use per run | -| `reserve_percent` | `5` | Always keep this % available | -| `billing_mode` | `subscription` | `subscription` or `api` | -| `calibrate_enabled` | `true` | Auto-calibrate from local CLI data | +API billing automatically disables calibration after configuration is loaded. See +[Budget Management](/docs/budget) for the operational workflow. -## Task Selection +## Providers -Enable/disable tasks and set priorities: +Claude, Codex, and Copilot are enabled by default. The default preference order is: ```yaml -tasks: - enabled: - - lint-fix - - docs-backfill - - bug-finder - priorities: - lint-fix: 1 - bug-finder: 2 - intervals: - lint-fix: "24h" - docs-backfill: "168h" +providers: + preference: [claude, codex, copilot] ``` -Each task has a default cooldown interval to prevent the same task from running too frequently on a project. +At run time, Nightshift walks that order and chooses the first enabled provider whose executable +is available and whose calculated allowance is positive. Preference names are case-insensitive +when used and must be unique values from `claude`, `codex`, and `copilot` during validation. + +`data_path` points to a provider's local usage/session data. It does not select an executable; +executables must be discoverable through `PATH`. The effective data-path defaults are +`~/.claude`, `~/.codex`, and `~/.copilot`. + +The permission-bypass fields opt autonomous runs into the corresponding provider flags. Their +configuration defaults are `false`. Codex execution itself preserves its headless bypass default +when the setting is not enabled, so disable the Codex provider if you do not want it selected for +autonomous execution. -## Multi-Project Setup +## Projects + +Explicit paths are the reliable execution configuration: ```yaml projects: - - path: ~/code/project1 - priority: 1 # Higher priority = processed first - tasks: - - lint - - docs - - path: ~/code/project2 + - path: ~/code/project-one priority: 2 + - path: ~/code/project-two + priority: 1 +``` + +The configuration schema also accepts discovery patterns: - # Or use glob patterns - - pattern: ~/code/oss/* +```yaml +projects: + - pattern: ~/code/open-source/* + priority: 1 exclude: - - ~/code/oss/archived + - ~/code/open-source/archived ``` -## Safe Defaults +Patterns expand `~`, match directories with filepath glob syntax, and exclude exact paths and +their descendants. The current top-level `run` path enumeration uses explicit `path` entries, +so list concrete paths for unattended execution. -| Feature | Default | Override | -|---------|---------|----------| -| Read-only first run | Yes | `--enable-writes` | -| Max budget per run | 75% | `budget.max_percent` | -| Auto-push to remote | No | Manual only | -| Reserve budget | 5% | `budget.reserve_percent` | +When a configured project contains `nightshift.yaml`, project resolution can override +`schedule.cron`, `schedule.interval`, budget max/reserve percentages, task enabled/disabled/ +priorities, Claude/Codex enabled state, and log level. -## File Locations +## Task customization -| Type | Location | -|------|----------| -| Run logs | `~/.local/share/nightshift/logs/nightshift-YYYY-MM-DD.log` | -| Audit logs | `~/.local/share/nightshift/audit/audit-YYYY-MM-DD.jsonl` | -| Summaries | `~/.local/share/nightshift/summaries/` | -| Database | `~/.local/share/nightshift/nightshift.db` | -| PID file | `~/.local/share/nightshift/nightshift.pid` | +An empty `tasks.enabled` list means all built-in tasks are eligible. `tasks.disabled` always wins. +Higher priority numbers increase selection score. Interval values must be valid Go durations. -If `state/state.json` exists from older versions, Nightshift migrates it to the SQLite database and renames the file to `state.json.migrated`. +```yaml +tasks: + custom: + - type: dependency-review + name: Dependency Review + description: | + Review direct dependencies for stale or risky versions. + Open a pull request for safe updates. + category: analysis + cost_tier: medium + risk_level: low + interval: 72h +``` -## Providers +Custom `type` values use lowercase letters, numbers, and hyphens. `type`, `name`, and +`description` are required. Categories are `pr`, `analysis`, `options`, `safe`, `map`, or +`emergency`; cost tiers are `low`, `medium`, `high`, or `very-high`; risk levels are `low`, +`medium`, or `high`. + +## Integrations, logging, and reporting + +`integrations.claude_md` and `integrations.agents_md` default to `true`. They read supported +case variants of `CLAUDE.md` and `AGENTS.md` from each project. `task_sources` can enable td and +open GitHub issues carrying the `nightshift` label. See [Integrations](/docs/integrations). -Nightshift supports Claude Code and Codex as execution providers. It will use whichever has budget remaining, in the order specified by `preference`. +Logging defaults to level `info`, JSON format, and +`~/.local/share/nightshift/logs`. Valid levels are `debug`, `info`, `warn`, and `error`; valid +formats are `json` and `text`. `reporting.morning_summary` defaults to `true`. Email and Slack +webhook fields exist in the configuration schema but are not currently dispatched by the run +implementation. diff --git a/website/docs/installation.md b/website/docs/installation.md index e2b37d2..f10a21e 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -5,50 +5,122 @@ title: Installation # Installation -## Homebrew (Recommended) +## Install Nightshift + +### Homebrew ```bash brew install marcus/tap/nightshift ``` -## Binary Downloads +### Binary release -Pre-built binaries are available on the [GitHub releases page](https://github.com/marcus/nightshift/releases) for macOS and Linux (Intel and ARM). +Download a macOS or Linux archive from the +[GitHub releases page](https://github.com/marcus/nightshift/releases), place the executable in a +directory on `PATH`, and verify it: -## From Source +```bash +nightshift --version +nightshift --help +``` -Requires Go 1.24+: +### From source + +Nightshift requires Go 1.24 or later: ```bash go install github.com/marcus/nightshift/cmd/nightshift@latest ``` -Or build from the repository: +The resulting binary is normally placed in `$GOBIN` or `$GOPATH/bin`. Ensure that directory is +on `PATH`. + +## Install at least one provider + +Nightshift executes work through a local provider CLI. Install and authenticate one or more of +Claude Code, Codex, or GitHub Copilot before running setup. + +### Claude Code + +Claude Code requires Node.js 18 or later for the npm installation: ```bash -git clone https://github.com/marcus/nightshift.git -cd nightshift -go build -o nightshift ./cmd/nightshift -sudo mv nightshift /usr/local/bin/ +npm install -g @anthropic-ai/claude-code +claude ``` -## Verify Installation +Complete the browser login after starting `claude`. Claude.ai plans, Anthropic Console accounts, +and supported enterprise providers can authenticate the CLI. See +[Anthropic's setup guide](https://docs.anthropic.com/en/docs/claude-code/getting-started). + +### Codex ```bash -nightshift --version -nightshift --help +npm install -g @openai/codex +codex --login ``` -## Prerequisites +Choose ChatGPT sign-in, or supply `OPENAI_API_KEY` for API-billed use. See +[OpenAI's Codex CLI setup](https://help.openai.com/en/articles/11381614-api-codex-cli-and-sign-in-with-chatgpt). + +### GitHub Copilot CLI -- **Claude Code CLI** (`claude`) and/or **Codex CLI** (`codex`) installed -- Authenticated via subscription login or API keys: +The standalone `copilot` executable is Nightshift's preferred Copilot mode. The npm package +requires Node.js 22 or later: ```bash -# Claude Code -claude -/login +npm install -g @github/copilot +copilot login +``` -# Codex -codex --login +Homebrew and GitHub's install script are also supported: + +```bash +brew install copilot-cli +curl -fsSL https://gh.io/copilot-install | bash +``` + +An eligible Copilot plan and any required organization policy are prerequisites. Copilot can also +reuse an authenticated GitHub CLI token. See +[GitHub's Copilot CLI installation guide](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli). + +Nightshift also recognizes the legacy `gh copilot` extension when standalone `copilot` is not +installed: + +```bash +gh auth login --web +gh extension install github/gh-copilot --force +gh extension list +``` + +GitHub has deprecated that extension in favor of the standalone CLI, so prefer `copilot` for new +installations. The fallback remains documented because the current Nightshift implementation +detects `github/gh-copilot` in `gh extension list`. + +## Provider discovery + +Nightshift looks for `claude`, `codex`, and `copilot` on `PATH`. For Copilot it prefers +standalone `copilot`, then falls back to `gh` plus the installed extension. Provider +`data_path` settings point to usage data and do not override executable paths. + +When launched by a daemon or service, Nightshift also searches existing directories at: + +- `~/.local/bin` +- `~/go/bin` +- `~/.cargo/bin` +- `~/.npm-global/bin` +- `/usr/local/bin` +- `/opt/homebrew/bin` +- `$GOPATH/bin`, when `GOPATH` is set + +## Finish setup + +```bash +nightshift setup +nightshift doctor +nightshift preview --explain ``` + +The wizard creates or updates the global config, checks provider availability, adds projects, +configures budget and safety options, captures a snapshot, previews a run, and can install a +scheduled service. diff --git a/website/docs/integrations.md b/website/docs/integrations.md index 96d5e3f..f97da02 100644 --- a/website/docs/integrations.md +++ b/website/docs/integrations.md @@ -5,52 +5,135 @@ title: Integrations # Integrations -Nightshift integrates with your existing development workflow. +## Execution providers -## Claude Code +Nightshift supports Claude Code, Codex, and GitHub Copilot. They are enabled by default and tried +in configured preference order: -Nightshift uses the Claude Code CLI to execute tasks. Authenticate via subscription or API key: +```yaml +providers: + preference: [claude, codex, copilot] + claude: + enabled: true + data_path: ~/.claude + dangerously_skip_permissions: false + codex: + enabled: true + data_path: ~/.codex + dangerously_bypass_approvals_and_sandbox: false + copilot: + enabled: true + data_path: ~/.copilot + dangerously_skip_permissions: false +``` + +Nightshift skips a provider when it is disabled, its executable is unavailable, or its allowance +is exhausted. `run --ignore-budget` changes only the exhausted-budget decision. + +### Claude Code + +Install and start the CLI once to authenticate: ```bash +npm install -g @anthropic-ai/claude-code claude -/login ``` -## Codex +Nightshift invokes `claude --print`. When +`providers.claude.dangerously_skip_permissions` is true it also passes +`--dangerously-skip-permissions`. -Nightshift supports OpenAI's Codex CLI as an alternative provider: +### Codex ```bash +npm install -g @openai/codex codex --login ``` -## GitHub +Nightshift invokes `codex exec` for headless work. Codex may use ChatGPT sign-in or +`OPENAI_API_KEY`. Autonomous Codex execution uses its approval-and-sandbox bypass behavior; if +that is inappropriate for your environment, remove Codex from `providers.preference` or set +`providers.codex.enabled: false`. + +### GitHub Copilot + +Standalone Copilot is preferred: + +```bash +npm install -g @github/copilot +copilot login +``` + +Copilot can also authenticate with `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN`, or reuse +an authenticated `gh` session. Nightshift invokes non-interactive prompt mode and, when +`providers.copilot.dangerously_skip_permissions` is true, allows all tools and URLs. + +If `copilot` is absent, Nightshift falls back to `gh` and requires the legacy Copilot extension +to appear in `gh extension list`: + +```bash +gh auth login --web +gh extension install github/gh-copilot --force +gh extension list +``` -All output is PR-based. Nightshift creates branches and pull requests for its findings. +The upstream extension is deprecated, so the standalone CLI is recommended. -## td (Task Management) +## Project instruction files -Nightshift can source tasks from [td](https://td.haplab.com) — task management for AI-assisted development. Tasks tagged with `nightshift` in td will be picked up automatically. +These integrations default to enabled: + +```yaml +integrations: + claude_md: true + agents_md: true +``` + +Nightshift looks in the project root, in order: + +| Integration | Recognized filenames | +|-------------|----------------------| +| Claude context | `claude.md`, `CLAUDE.md`, `.claude.md` | +| Agent instructions | `AGENTS.md`, `agents.md`, `.agents.md` | + +The full file becomes prompt context. Nightshift also extracts task suggestions, conventions, +constraints, safety guidance, and action/tool restrictions as hints. Task types mentioned in +these files receive a selection score bonus. + +## td task source ```yaml integrations: task_sources: - td: enabled: true - teach_agent: true # Include td usage + core workflow in prompts + teach_agent: true ``` -## CLAUDE.md / AGENTS.md - -Nightshift reads project-level instruction files to understand context when executing tasks. Place a `CLAUDE.md` or `AGENTS.md` in your repo root to give Nightshift project-specific guidance. Tasks mentioned in these files get a priority bonus (+2). +When `td` is on `PATH`, Nightshift runs `td list --format json` from each project. A missing or +unconfigured td CLI is non-fatal. `teach_agent: true` adds the core assign, inspect, comment, and +complete workflow to the agent context. -## GitHub Issues - -Source tasks from GitHub issues labeled with `nightshift`: +## GitHub issue source ```yaml integrations: - github_issues: - enabled: true - label: "nightshift" + task_sources: + - github_issues: true ``` + +This reader requires: + +- `gh` on `PATH` and authenticated. +- A GitHub `origin` remote in the project. +- Open issues labeled `nightshift`. + +Nightshift reads issue number, title, body, labels, and state with `gh issue list`. Priority labels +such as `critical`, `high`, `medium`, `low`, or `p0` through `p3` affect the imported task +priority. Authentication or repository failures are non-fatal and leave the source empty. + +## Generated reports + +`reporting.morning_summary` defaults to `true` and writes local summaries after runs. The +`reporting.email` and `reporting.slack_webhook` keys are accepted by the configuration schema, +but the current run implementation does not send those notifications. diff --git a/website/docs/scheduling.md b/website/docs/scheduling.md index b552a79..084a6c6 100644 --- a/website/docs/scheduling.md +++ b/website/docs/scheduling.md @@ -5,52 +5,141 @@ title: Scheduling # Scheduling -Nightshift can run automatically on a schedule. +Nightshift supports a persistent daemon and OS-managed scheduled runs. Configure one schedule +type before starting the daemon. -## Cron-Based +## Cron or interval + +Use a five-field cron expression: + +```yaml +schedule: + cron: "0 2 * * *" +``` + +Or use a positive Go duration: + +```yaml +schedule: + interval: 8h +``` + +Do not set both. `nightshift config validate` rejects a config containing both values. The cron +parser accepts minute, hour, day of month, month, and day of week fields; it does not accept a +seconds field. Interval examples include `30m`, `8h`, and `24h`. + +A schedule is optional for manual `run`, `task run`, and configuration commands. It is required +for `daemon start`. + +## Execution windows + +Restrict scheduler execution to a local or named timezone: ```yaml schedule: - cron: "0 2 * * *" # Every night at 2am + cron: "0 * * * *" + window: + start: "22:00" + end: "06:00" + timezone: "America/Los_Angeles" ``` -## Daemon Mode +Times use `HH:MM`. The start is inclusive and the end is exclusive. When start is later than end, +the window crosses midnight. If `timezone` is omitted, Nightshift uses the machine's local +timezone. Invalid times and unknown IANA timezone names prevent scheduler creation. + +The scheduler moves an out-of-window next-run preview to the next window start. At execution +time it also checks the window before running jobs. + +## Project and task limits + +```yaml +schedule: + cron: "0 2 * * *" + max_projects: 3 + max_tasks: 2 +``` -Run as a persistent background process: +Positive `max_projects` and `max_tasks` values become defaults for `nightshift run` when the +matching CLI flags are omitted. With no positive config value, `run` defaults to one eligible +project and one task per project. `--project` ignores the project limit; `--task` ignores the +task limit. `--random-task` always selects exactly one task. + +Task cooldowns and budget filters can reduce the actual count. Projects already processed today +are skipped during automatic selection; specifying `--task` bypasses that processed-today skip. + +## Persistent daemon ```bash nightshift daemon start -nightshift daemon start --foreground # For debugging +nightshift daemon status nightshift daemon stop ``` -## System Service +`daemon start` detaches a child process. It waits for the next cron or interval time; it does not +run a task immediately. The daemon: + +- Writes `~/.local/share/nightshift/nightshift.pid`. +- Runs scheduled work only inside the configured window. +- Selects providers by preference and remaining budget. +- Captures and prunes calibration snapshots in the background. +- Handles SIGINT and SIGTERM for graceful shutdown. -Install as a system service for automatic startup: +Use foreground mode to see failures directly: ```bash -# macOS (launchd) -nightshift install launchd +nightshift daemon start --foreground --timeout 45m +``` -# Linux (systemd) -nightshift install systemd +`daemon status` reports the PID, schedule, window, and PID-file path. `daemon stop` sends SIGTERM, +waits up to ten seconds, and sends SIGKILL if the process does not exit. + +## OS-managed service + +`install` creates an OS scheduler entry that invokes `nightshift run`; it does not start the +persistent daemon. -# Universal (cron) +```bash +nightshift install # auto-detect +nightshift install launchd +nightshift install systemd nightshift install cron ``` -## Manual Runs +| Type | Installed artifact | Lifecycle | +|------|--------------------|-----------| +| launchd | `~/Library/LaunchAgents/com.nightshift.agent.plist` | Unloads any previous plist, writes it, then loads it | +| systemd | `~/.config/systemd/user/nightshift.service` and `nightshift.timer` | Reloads user units, then enables and starts the timer | +| cron | Managed `# nightshift managed cron entry` in the user's crontab | Replaces an older Nightshift entry | + +With no type, macOS selects launchd. Linux selects systemd when `systemctl` exists and cron +otherwise; other systems select cron. + +The service captures the resolved path of the Nightshift executable. Reinstall after moving or +upgrading a manually placed binary. It also runs non-interactively, so `run` confirmation is +automatically skipped. + +Remove installed services with: + +```bash +nightshift uninstall +``` + +`uninstall` checks launchd, systemd, and cron and removes every Nightshift installation it finds. +Use `daemon stop` separately for a daemon started with `daemon start`. + +## Manual overrides -Skip the scheduler and run immediately: +Manual runs bypass schedule timing and windows: ```bash -nightshift run # Preflight summary + confirm + execute -nightshift run --dry-run # Show preflight summary, don't execute -nightshift run --yes # Skip confirmation prompt -nightshift run --project ~/code/myproject -nightshift run --task lint-fix -nightshift run --max-projects 3 --max-tasks 2 # Process more projects/tasks -nightshift run --ignore-budget # Bypass budget limits +nightshift run --dry-run +nightshift run --yes +nightshift run --project ~/code/myproject --task lint-fix +nightshift run --max-projects 3 --max-tasks 2 +nightshift run --ignore-budget ``` -In interactive terminals, `nightshift run` shows a preflight summary and asks for confirmation before executing. Use `--yes` to skip the prompt (e.g., in scripts). Non-TTY contexts auto-skip confirmation. +They still honor provider availability, task eligibility, cooldowns, and budget unless the +relevant explicit override applies. `--ignore-budget` does not enable a disabled provider or make +a missing executable available. diff --git a/website/docs/troubleshooting.md b/website/docs/troubleshooting.md index e998551..5da7e51 100644 --- a/website/docs/troubleshooting.md +++ b/website/docs/troubleshooting.md @@ -5,57 +5,195 @@ title: Troubleshooting # Troubleshooting -## Common Issues +Start with: -**"Something feels off"** -- Run `nightshift doctor` to check config, schedule, and provider health +```bash +nightshift doctor +nightshift config +nightshift config validate +``` + +`doctor` checks configuration, scheduling, provider data, database health, snapshots, and budget +readiness. `config` shows which global and current-project files exist before printing the merged +configuration. + +## Configuration is missing or loaded from the wrong place + +Create the intended file: + +```bash +nightshift init --global # ~/.config/nightshift/config.yaml +nightshift init # ./nightshift.yaml +``` + +Only `nightshift.yaml` is recognized as a project config. A file named `.nightshift.yaml` is not +loaded. Run commands from the project root or use `run --project PATH` so Nightshift can load that +project's file. + +`config set` writes to the project file only when it already exists in the current directory. +Use `--global` when you intend to change the global file: + +```bash +nightshift config set logging.level debug --global +``` + +## The schedule is invalid + +Typical errors are: + +- Both `schedule.cron` and `schedule.interval` are set. +- Cron does not have the supported five-field form. +- An interval is not a positive Go duration. +- A window time is not valid `HH:MM`. +- A window timezone is not an installed IANA timezone. + +Keep one schedule type and validate: + +```yaml +schedule: + interval: 8h + window: + start: "22:00" + end: "06:00" + timezone: "America/Los_Angeles" +``` + +```bash +nightshift config validate +nightshift preview --explain +``` + +If `daemon start` says no schedule is configured, add `cron` or `interval`. Manual runs do not +require a schedule. + +## Nothing ran + +Use a dry run with explanations: + +```bash +nightshift preview --explain +nightshift run --dry-run --no-color +``` + +Common skip reasons include: + +- The project was already processed today. +- Every enabled task is on cooldown. +- No task fits the remaining token allowance. +- All preferred providers are disabled, unavailable, or out of budget. +- A configured project path does not exist. + +To inspect a task independently of automatic selection: -**"No config file found"** ```bash -nightshift init # Create project config -nightshift init --global # Create global config +nightshift task show docs-backfill --project . +nightshift task run docs-backfill --provider claude --project . --dry-run ``` -**"Insufficient budget"** -- Check current budget: `nightshift budget` -- Increase `max_percent` in config -- Wait for budget reset (check reset time in output) +## Budget is exhausted -**"Calibration confidence is low"** -- Run `nightshift budget snapshot` a few times to collect samples -- Ensure tmux is installed so usage percentages are available -- Keep snapshots running for at least a few days +```bash +nightshift budget +nightshift budget --provider claude +nightshift budget history -n 10 +``` -**"tmux not found"** -- Install tmux or set `budget.billing_mode: api` if you pay per token +Check `budget.max_percent`, `reserve_percent`, `weekly_tokens`, `per_provider`, and the reported +reset boundary. For a deliberate one-off manual run: -**"Week boundary looks wrong"** -- Set `budget.week_start_day` to `monday` or `sunday` +```bash +nightshift run --ignore-budget +``` -**"Provider not available"** -- Ensure Claude/Codex CLI is installed and in PATH -- Check API key environment variables are set +That flag bypasses the exhausted-budget decision, but not provider enablement, executable +discovery, or task validation. -## Debug Mode +## Calibration is missing or low-confidence -Enable verbose logging: +Subscription calibration needs local usage data plus provider usage percentages: ```bash -nightshift run --verbose +nightshift budget snapshot --provider claude +nightshift budget history --provider claude +nightshift budget calibrate --provider claude ``` -Or set log level in config: +Install `tmux`, enable `budget.calibrate_enabled`, and collect several snapshots over time. +`snapshot --local-only` records token counts but cannot by itself infer a budget from a provider +percentage. Verify the provider `data_path` when Nightshift cannot find local session data. + +If you are billed by API token rather than a subscription, avoid scraping and set explicit +limits: ```yaml -logging: - level: debug # debug | info | warn | error +budget: + billing_mode: api + weekly_tokens: 700000 + per_provider: + codex: 500000 ``` -## Getting Help +API billing disables calibration after configuration is loaded. + +## A provider is unavailable or unauthenticated + +Check executable discovery first: ```bash -nightshift --help -nightshift --help +command -v claude +command -v codex +command -v copilot +command -v gh +nightshift doctor ``` -Report issues: https://github.com/marcus/nightshift/issues +Then authenticate the provider directly: + +```bash +claude # Complete Claude Code login +codex --login +copilot login +gh auth status # Legacy gh copilot fallback +gh extension list +``` + +Nightshift prefers standalone `copilot`. It falls back to `gh` only when the Copilot extension +appears in `gh extension list`. A provider `data_path` is not an executable path; changing it will +not fix a missing CLI. + +For a service-only PATH problem, compare the interactive executable path with the PATH captured +by launchd, systemd, or cron. Nightshift supplements service PATH with common local bin +directories, but a custom installation directory must still be available. Reinstall the service +after correcting PATH: + +```bash +nightshift uninstall +nightshift install +``` + +## Daemon lifecycle problems + +```bash +nightshift daemon status +nightshift logs --component daemon --level warn --tail 100 +nightshift daemon start --foreground +``` + +The PID file is `~/.local/share/nightshift/nightshift.pid`. A foreground start is the fastest way +to expose config, database, provider, and scheduler errors. `nightshift uninstall` removes +OS-managed scheduled services; it does not replace `nightshift daemon stop` for a detached daemon. + +## Inspect logs and reports + +```bash +nightshift logs --since "2026-07-25 22:00" --level warn +nightshift logs --match "no provider" --summary +nightshift report --period last-run --format plain --paths +nightshift status --today +``` + +Set `logging.level: debug` or `NIGHTSHIFT_LOG_LEVEL=debug` for more detail. + +Report reproducible problems at +[github.com/marcus/nightshift/issues](https://github.com/marcus/nightshift/issues) with the +Nightshift version, `doctor` output, relevant config with secrets removed, and filtered logs. From 3a68bc7af278198cf5e49f6fe30253c9b06c87d5 Mon Sep 17 00:00:00 2001 From: Greg Gardner Date: Sun, 26 Jul 2026 06:07:24 -0700 Subject: [PATCH 2/3] docs: correct backfilled CLI behavior Nightshift-Task: docs-backfill Nightshift-Ref: https://github.com/marcus/nightshift --- README.md | 37 ++++++++++++------- website/docs/cli-reference.md | 55 ++++++++++++++++++++++++---- website/docs/configuration.md | 60 +++++++++++++++++++++---------- website/docs/installation.md | 31 ++++++++++------ website/docs/integrations.md | 58 +++++++++++++++++++++--------- website/docs/scheduling.md | 64 ++++++++++++++++++++++++--------- website/docs/troubleshooting.md | 59 ++++++++++++++++++++++++------ 7 files changed, 272 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 85da0fa..577028d 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,8 @@ After installing, run the guided setup: nightshift setup ``` -This walks you through provider configuration, project selection, budget calibration, and daemon setup. Once complete you can preview what nightshift will do: +This walks you through provider configuration, project selection, budget calibration, and +scheduled-service setup. Once complete you can preview what nightshift will do: ```bash nightshift preview @@ -66,8 +67,10 @@ nightshift config get budget.max_percent nightshift config set budget.max_percent 60 --global ``` -Configuration precedence is built-in defaults, global config, project `nightshift.yaml`, -environment overrides, then command flags. +Configuration precedence is built-in defaults, global config, one project `nightshift.yaml`, +then supported environment overrides. `run --project`, `preview --project`, and +`task run --project` load the project file from the selected directory; otherwise Nightshift uses the +current directory. Command flags then override the behavior of that invocation. ## Common CLI Usage @@ -137,7 +140,7 @@ daemon, CI) confirmation is auto-skipped. | Flag | Default | Description | |------|---------|-------------| | `--dry-run` | `false` | Show preflight summary and exit without executing | -| `--project`, `-p` | _(all configured)_ | Target a single project directory | +| `--project`, `-p` | configured paths, or current directory | Target one project and load its `nightshift.yaml` | | `--task`, `-t` | _(auto-select)_ | Run a specific task by name | | `--max-projects` | `1` | Max projects to process (ignored when `--project` is set) | | `--max-tasks` | `1` | Max tasks per project (ignored when `--task` is set) | @@ -175,6 +178,7 @@ nightshift run --branch develop --timeout 45m ``` Other useful flags: + - `nightshift status --today` to see today's activity summary - `nightshift daemon start --foreground` for debug - `--category` — filter tasks by category (pr, analysis, options, safe, map, emergency) @@ -189,7 +193,7 @@ Other useful flags: Nightshift supports three AI providers: - **Claude Code** - Anthropic's Claude via local CLI - **Codex** - OpenAI's GPT via local CLI -- **GitHub Copilot** - GitHub's Copilot via GitHub CLI +- **GitHub Copilot** - GitHub's standalone Copilot CLI, with a retired `gh` extension fallback ### Claude Code @@ -203,10 +207,10 @@ Supports Claude.ai subscriptions or Anthropic Console credentials. ### Codex ```bash -codex --login +codex ``` -Supports signing in with ChatGPT or an API key. +Choose ChatGPT sign-in, or configure API-key authentication. ### GitHub Copilot @@ -215,14 +219,15 @@ Supports signing in with ChatGPT or an API key. npm install -g @github/copilot copilot login -# Also supported: legacy gh copilot extension +# Compatibility only: retired gh copilot extension gh auth login --web gh extension install github/gh-copilot --force ``` -Nightshift prefers the standalone `copilot` executable, then falls back to `gh` when the -`github/gh-copilot` extension appears in `gh extension list`. The upstream extension is -deprecated, so prefer standalone Copilot for new installations. A Copilot plan and any required +Nightshift prefers the standalone `copilot` executable. It retains a `gh copilot` compatibility +path, but GitHub has retired that extension. Automatic `nightshift run` checks only that `gh` +exists before selecting this fallback; `nightshift task run` also checks the extension list. +Install standalone Copilot for reliable unattended runs. A Copilot plan and any required organization policy are prerequisites. If you prefer API-based usage, you can authenticate Claude and Codex CLIs with API keys instead. @@ -240,6 +245,10 @@ Nightshift uses YAML config files to define: Run `nightshift setup` or `nightshift init --global` to create the global config at `~/.config/nightshift/config.yaml`. A project config is named exactly `nightshift.yaml`. +`init` writes an opinionated starter rather than the built-in defaults: the current global +template prefers Claude and Codex and explicitly enables their unattended permission-bypass +flags. Review those values and replace the template's task names with slugs reported by +`nightshift task list`. See the [full configuration docs](https://nightshift.haplab.com/docs/configuration) for detailed options. @@ -304,8 +313,10 @@ Each task has a default cooldown interval to prevent the same task from running `skill-groom` is enabled by default. Add it to `tasks.disabled` if you want to opt out. It updates project-local skills under `.claude/skills` and `.codex/skills` using `README.md` as project context and starts Agent Skills docs lookup from `https://agentskills.io/llms.txt`. Provider executables are discovered through `PATH`; `providers.*.data_path` points to usage and -session data, not to the executable. Automatic selection uses `providers.preference` and skips -disabled, unavailable, or budget-exhausted providers. +session data, not to the executable. Automatic `run` selection uses `providers.preference` and +skips disabled, missing, or budget-exhausted providers. It does not verify authentication before +execution. `preview` uses the first enabled provider in the fixed Claude, Codex, Copilot order +and does not check executable availability. ## Development diff --git a/website/docs/cli-reference.md b/website/docs/cli-reference.md index 00bb40f..b397f04 100644 --- a/website/docs/cli-reference.md +++ b/website/docs/cli-reference.md @@ -46,7 +46,19 @@ nightshift config validate `init` creates `nightshift.yaml` in the current directory. `init --global` creates `~/.config/nightshift/config.yaml`. Without `--global`, `config set` writes to the current -project config when it exists and otherwise writes to the global config. +project config when it exists and otherwise writes to the global config. `init --force` skips the +overwrite prompt. + +The generated global file is an opinionated starter, not a dump of built-in defaults. In the +current template it limits provider preference to Claude and Codex, enables their unattended +permission-bypass options, and includes legacy task aliases. Review the file after creation and +use `nightshift task list` for accepted task slugs. + +`config validate` validates each existing file and the merged configuration. It catches schema +rules such as mutually exclusive `schedule.cron` and `schedule.interval`, budget ranges, provider +preference names, task durations, and custom-task fields. It does not parse cron syntax, +`schedule.interval`, or execution-window values. Use `nightshift doctor`, `nightshift preview`, +or `nightshift daemon start --foreground` for scheduler parsing. ## `nightshift run` @@ -57,9 +69,9 @@ cron and system services, skip the prompt automatically. | Flag | Default | Behavior | |------|---------|----------| | `--dry-run` | `false` | Show the preflight plan and exit without execution | -| `--project`, `-p` | configured projects or current directory | Target one existing directory; ignores `--max-projects` | -| `--task`, `-t` | automatic selection | Run one named task; ignores `--max-tasks` and bypasses the processed-today skip | -| `--max-projects` | `1` | Maximum eligible projects; a positive `schedule.max_projects` supplies the default when the flag is omitted | +| `--project`, `-p` | configured paths or current directory | Target one existing directory, load its `nightshift.yaml`, and ignore `--max-projects` | +| `--task`, `-t` | automatic selection | Run one built-in task; ignores `--max-tasks`, task enablement, cooldown, estimated-cost filtering, and the processed-today skip | +| `--max-projects` | `1` | Maximum eligible projects; a positive `schedule.max_projects` supplies the default when the flag is omitted; explicit `0` is unlimited | | `--max-tasks` | `1` | Maximum selected tasks per project; a positive `schedule.max_tasks` supplies the default when the flag is omitted | | `--random-task` | `false` | Pick exactly one random eligible task; cannot be combined with `--task` | | `--ignore-budget` | `false` | Permit selection even when a provider budget is exhausted | @@ -78,7 +90,8 @@ nightshift run --branch develop --timeout 45m ## `nightshift preview` -Preview never executes tasks or modifies run state. +Preview requires a valid schedule. It never executes tasks or records project/task runs, although +it opens the configured database and `--write` deliberately creates prompt files. | Flag | Default | Behavior | |------|---------|----------| @@ -98,6 +111,10 @@ nightshift preview --json nightshift preview --write ./nightshift-prompts ``` +Preview chooses the first enabled provider in the fixed order Claude, Codex, Copilot. It does not +use `providers.preference` or test the provider executable. Its task plan contains one task per +project per previewed run. + ## `nightshift task` ```bash @@ -115,6 +132,12 @@ Its cost filter accepts `low`, `medium`, `high`, and `veryhigh`. `task run` requ `claude`, `codex`, or `copilot`; its default project is the current directory and its default timeout is `30m`. +The `task` subcommands currently expose built-in tasks only; they do not register `tasks.custom` +from configuration. `task run` is a direct execution path: it does not consult provider +enablement, provider preference, budgets, task enablement, cooldowns, or run history. Even +`--dry-run` checks that the requested provider executable is available (and, for the `gh` +Copilot fallback, that the extension is listed). + ## `nightshift budget` All budget commands accept `--provider`/`-p` with `claude`, `codex`, or `copilot`. @@ -130,7 +153,7 @@ nightshift budget calibrate --provider copilot `budget history` defaults to 20 snapshots. `snapshot --local-only` records provider data without starting a tmux scraping session. `calibrate` reports inferred budget status; it does not consume -an agent run. +an agent run. Claude and Codex support tmux percentage scraping; Copilot snapshots are local-only. ## Daemon and installed services @@ -143,6 +166,11 @@ nightshift daemon status nightshift daemon stop ``` +It loads global plus current-directory configuration once at startup and does not reload changed +files. At each scheduled time it walks every existing explicit `projects[].path`, skips projects +already processed that day, and selects up to five tasks per project. The daemon does not use +`schedule.max_projects` or `schedule.max_tasks`; those fields affect `nightshift run` only. + An installed service is OS-managed and invokes `nightshift run` at scheduled times: ```bash @@ -155,7 +183,15 @@ nightshift uninstall With no argument, `install` chooses launchd on macOS, systemd on Linux when `systemctl` is available, and cron otherwise. `uninstall` looks for and removes all three Nightshift service -types. See [Scheduling](/docs/scheduling) for lifecycle details. +types. + +For predictable installed-service timing, configure a simple five-field cron schedule before +installation. Cron preserves that expression; launchd uses only its numeric minute and hour; +systemd converts only its minute, hour, day-of-month, and month fields. Installed services ignore +execution windows. Interval configuration is fully supported by `daemon start`, but the service +generators do not translate it consistently: launchd and cron fall back to 02:00, while systemd +performs only a simple minute-style conversion. See [Scheduling](/docs/scheduling) for lifecycle +details. ## History, reports, logs, and diagnostics @@ -186,6 +222,11 @@ local date/time, or RFC3339 timestamp. `logs --level` accepts `debug`, `info`, `warn`, or `error`. Statistics periods are `all`, `last-7d`, `last-30d`, and `last-night`. +`doctor` parses the scheduler and checks enabled Claude/Codex executables, provider data paths, +database state, budget readiness, snapshots, tmux, daemon state, and the detected service files. +It does not test provider authentication, and it does not check whether a Copilot executable or +the retired `gh copilot` extension is installed. + ## Bus factor analysis ```bash diff --git a/website/docs/configuration.md b/website/docs/configuration.md index b56506b..223e246 100644 --- a/website/docs/configuration.md +++ b/website/docs/configuration.md @@ -37,16 +37,21 @@ nightshift config set logging.level debug --global otherwise it writes to the global file. It parses `true`/`false`, integers, and decimal numbers, and treats other values as strings. +The `init` templates are opinionated examples rather than serialized built-in defaults. In +particular, the current global template prefers only Claude and Codex, explicitly enables their +unattended permission-bypass flags, and contains legacy task aliases such as `lint` and `docs`. +Review the generated file and use `nightshift task list` for current task slugs. + ## Source precedence From lowest to highest precedence: 1. Built-in defaults. 2. `~/.config/nightshift/config.yaml`. -3. `nightshift.yaml` in the current directory, or in the directory supplied by - `run --project`. +3. One project `nightshift.yaml`: normally from the current directory, or from the directory + supplied to `run --project`, `preview --project`, or `task run --project`. 4. `NIGHTSHIFT_` environment overrides. -5. Command-line flags for the command being run. +5. Command-line flags that override behavior for the command being run. The project filename is exactly `nightshift.yaml`; `.nightshift.yaml` is not loaded automatically. The explicitly bound environment variables are: @@ -151,7 +156,12 @@ Choose exactly one scheduler: | `schedule.max_tasks` | `0` | Positive value supplies the default for `run --max-tasks`; otherwise the CLI default is 1 | `cron` and `interval` are mutually exclusive. A missing schedule is valid for manual commands, -but `daemon start` requires one. Windows may stay within one day or cross midnight. +but `preview` and `daemon start` require one. Windows may stay within one day or cross midnight. + +`config validate` checks mutual exclusion, but it does not parse the cron expression, interval, +window times, or timezone. Scheduler construction in `doctor`, `preview`, and `daemon start` +performs those checks. A five-field cron expression and a positive Go duration are required at +that point. ## Budget @@ -183,8 +193,9 @@ providers: ``` At run time, Nightshift walks that order and chooses the first enabled provider whose executable -is available and whose calculated allowance is positive. Preference names are case-insensitive -when used and must be unique values from `claude`, `codex`, and `copilot` during validation. +is available and whose calculated allowance is positive. This selection checks executable +presence, not authentication. Preference names are case-insensitive when used and must be unique +values from `claude`, `codex`, and `copilot` during validation. `data_path` points to a provider's local usage/session data. It does not select an executable; executables must be discoverable through `PATH`. The effective data-path defaults are @@ -195,9 +206,13 @@ configuration defaults are `false`. Codex execution itself preserves its headles when the setting is not enabled, so disable the Codex provider if you do not want it selected for autonomous execution. +`preview` is an exception to provider preference: it uses the first enabled provider in the fixed +Claude, Codex, Copilot order and does not check executable availability. `task run` is another +exception: its required `--provider` is used even when that provider is disabled in configuration. + ## Projects -Explicit paths are the reliable execution configuration: +Top-level commands currently resolve explicit `path` entries: ```yaml projects: @@ -207,7 +222,7 @@ projects: priority: 1 ``` -The configuration schema also accepts discovery patterns: +The schema also accepts `priority`, `tasks`, `config`, `pattern`, and `exclude` fields: ```yaml projects: @@ -217,13 +232,15 @@ projects: - ~/code/open-source/archived ``` -Patterns expand `~`, match directories with filepath glob syntax, and exclude exact paths and -their descendants. The current top-level `run` path enumeration uses explicit `path` entries, -so list concrete paths for unattended execution. +The project resolver package implements pattern expansion, exclusions, priority ordering, and a +limited per-project merge, but `run`, `preview`, and the daemon do not call that resolver. Their +current path enumeration uses only existing `projects[].path` values and preserves configuration +order. List concrete paths for unattended execution; the other project fields are accepted by +the schema but do not affect those commands. -When a configured project contains `nightshift.yaml`, project resolution can override -`schedule.cron`, `schedule.interval`, budget max/reserve percentages, task enabled/disabled/ -priorities, Claude/Codex enabled state, and log level. +Nightshift also does not automatically merge a `nightshift.yaml` found inside each configured +project. To use a project's file, invoke `run --project PATH`, `preview --project PATH`, or +`task run --project PATH`, or start Nightshift with that project as the current directory. ## Task customization @@ -249,14 +266,19 @@ Custom `type` values use lowercase letters, numbers, and hyphens. `type`, `name` `emergency`; cost tiers are `low`, `medium`, `high`, or `very-high`; risk levels are `low`, `medium`, or `high`. +`run` and `preview` register configured custom tasks. The `task list`, `task show`, and `task run` +commands currently expose only built-in task definitions. + ## Integrations, logging, and reporting -`integrations.claude_md` and `integrations.agents_md` default to `true`. They read supported -case variants of `CLAUDE.md` and `AGENTS.md` from each project. `task_sources` can enable td and -open GitHub issues carrying the `nightshift` label. See [Integrations](/docs/integrations). +`integrations.claude_md` and `integrations.agents_md` default to `true`. The schema also accepts +td, GitHub issue, and file task-source entries. Reader implementations exist for Claude/agent +instruction files, td, and GitHub issues, but no current CLI command invokes the integration +manager, so these settings do not yet add prompt context or tasks. See +[Integrations](/docs/integrations). Logging defaults to level `info`, JSON format, and `~/.local/share/nightshift/logs`. Valid levels are `debug`, `info`, `warn`, and `error`; valid formats are `json` and `text`. `reporting.morning_summary` defaults to `true`. Email and Slack -webhook fields exist in the configuration schema but are not currently dispatched by the run -implementation. +webhook fields exist in the configuration schema. Notification implementations also exist, but +the run finalizer currently saves the local summary without calling notification dispatch. diff --git a/website/docs/installation.md b/website/docs/installation.md index f10a21e..046c3ed 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -56,17 +56,22 @@ and supported enterprise providers can authenticate the CLI. See ### Codex ```bash +# macOS or Linux installer +curl -fsSL https://chatgpt.com/codex/install.sh | sh + +# Alternatives npm install -g @openai/codex -codex --login +brew install --cask codex + +codex ``` -Choose ChatGPT sign-in, or supply `OPENAI_API_KEY` for API-billed use. See -[OpenAI's Codex CLI setup](https://help.openai.com/en/articles/11381614-api-codex-cli-and-sign-in-with-chatgpt). +Choose ChatGPT sign-in on first launch, or configure API-key authentication. See the +[official Codex CLI README](https://github.com/openai/codex#readme). ### GitHub Copilot CLI -The standalone `copilot` executable is Nightshift's preferred Copilot mode. The npm package -requires Node.js 22 or later: +The standalone `copilot` executable is Nightshift's preferred Copilot mode: ```bash npm install -g @github/copilot @@ -93,15 +98,17 @@ gh extension install github/gh-copilot --force gh extension list ``` -GitHub has deprecated that extension in favor of the standalone CLI, so prefer `copilot` for new -installations. The fallback remains documented because the current Nightshift implementation -detects `github/gh-copilot` in `gh extension list`. +GitHub has retired that extension in favor of the standalone CLI, so prefer `copilot` for new +installations. The fallback remains documented only because Nightshift retains a compatibility +execution path. ## Provider discovery Nightshift looks for `claude`, `codex`, and `copilot` on `PATH`. For Copilot it prefers -standalone `copilot`, then falls back to `gh` plus the installed extension. Provider -`data_path` settings point to usage data and do not override executable paths. +standalone `copilot`, then falls back to `gh`. `task run` verifies the retired extension through +`gh extension list`, but automatic `run` selection only verifies that `gh` exists; without the +extension, execution fails later. Provider `data_path` settings point to usage data and do not +override executable paths. When launched by a daemon or service, Nightshift also searches existing directories at: @@ -123,4 +130,6 @@ nightshift preview --explain The wizard creates or updates the global config, checks provider availability, adds projects, configures budget and safety options, captures a snapshot, previews a run, and can install a -scheduled service. +scheduled service. Its environment screen treats any `gh` executable as Copilot availability and +does not test authentication, so verify standalone `copilot` and its login directly before +unattended use. diff --git a/website/docs/integrations.md b/website/docs/integrations.md index f97da02..955a42a 100644 --- a/website/docs/integrations.md +++ b/website/docs/integrations.md @@ -7,8 +7,7 @@ title: Integrations ## Execution providers -Nightshift supports Claude Code, Codex, and GitHub Copilot. They are enabled by default and tried -in configured preference order: +Nightshift supports Claude Code, Codex, and GitHub Copilot. They are enabled by built-in defaults: ```yaml providers: @@ -27,8 +26,14 @@ providers: dangerously_skip_permissions: false ``` -Nightshift skips a provider when it is disabled, its executable is unavailable, or its allowance -is exhausted. `run --ignore-budget` changes only the exhausted-budget decision. +Automatic `nightshift run` walks `providers.preference` and skips a provider when it is disabled, +its executable is unavailable, or its calculated allowance is exhausted. It does not test +authentication before selection. `run --ignore-budget` changes only the exhausted-budget +decision. + +The generated `nightshift init --global` starter differs from these built-in defaults: it +explicitly prefers Claude and Codex, omits Copilot from the preference list, and enables the +Claude/Codex unattended permission-bypass settings. ### Claude Code @@ -47,7 +52,7 @@ Nightshift invokes `claude --print`. When ```bash npm install -g @openai/codex -codex --login +codex ``` Nightshift invokes `codex exec` for headless work. Codex may use ChatGPT sign-in or @@ -77,7 +82,20 @@ gh extension install github/gh-copilot --force gh extension list ``` -The upstream extension is deprecated, so the standalone CLI is recommended. +GitHub has retired the extension, so standalone Copilot is recommended. `task run` confirms that +the extension is listed before using the fallback. Automatic `run` only checks for `gh` on +`PATH`; if the extension is absent, it can select Copilot and then fail during execution. + +## Provider selection exceptions + +- `preview` ignores `providers.preference`, chooses the first enabled provider in fixed Claude, + Codex, Copilot order, and does not check executable availability. +- `task run --provider NAME` uses the requested provider even when it is disabled in + configuration. It checks executable availability but bypasses budgets and automatic + eligibility. +- Copilot usage is modeled as local premium-request counts under `providers.copilot.data_path`. + The current agent execution path does not increment that counter, so budget output cannot be + treated as authoritative Copilot account usage. ## Project instruction files @@ -96,9 +114,11 @@ Nightshift looks in the project root, in order: | Claude context | `claude.md`, `CLAUDE.md`, `.claude.md` | | Agent instructions | `AGENTS.md`, `agents.md`, `.agents.md` | -The full file becomes prompt context. Nightshift also extracts task suggestions, conventions, -constraints, safety guidance, and action/tool restrictions as hints. Task types mentioned in -these files receive a selection score bonus. +The readers can return the full file as context and extract task suggestions, conventions, +constraints, safety guidance, and action/tool restrictions as hints. However, the current CLI +does not construct or call the integration manager, so these files do not currently change +prompts or task selection through these configuration keys. Provider CLIs may still discover +their own instruction files independently. ## td task source @@ -110,9 +130,9 @@ integrations: teach_agent: true ``` -When `td` is on `PATH`, Nightshift runs `td list --format json` from each project. A missing or -unconfigured td CLI is non-fatal. `teach_agent: true` adds the core assign, inspect, comment, and -complete workflow to the agent context. +The implemented reader runs `td list --format json` from each project and can add td usage +context. A missing or unconfigured td CLI is non-fatal. The current Nightshift commands do not +invoke this reader, so configuring it does not yet import td work. ## GitHub issue source @@ -128,12 +148,18 @@ This reader requires: - A GitHub `origin` remote in the project. - Open issues labeled `nightshift`. -Nightshift reads issue number, title, body, labels, and state with `gh issue list`. Priority labels -such as `critical`, `high`, `medium`, `low`, or `p0` through `p3` affect the imported task -priority. Authentication or repository failures are non-fatal and leave the source empty. +The implemented reader uses `gh issue list` to read number, title, body, labels, and state. +Priority labels such as `critical`, `high`, `medium`, `low`, or `p0` through `p3` affect the +imported task priority. Authentication or repository failures are non-fatal. The current +Nightshift commands do not invoke this reader, so configuring it does not yet add GitHub issues +to task selection. + +`task_sources[].file` is accepted by the configuration schema, but there is no file-source reader +in the current implementation. ## Generated reports `reporting.morning_summary` defaults to `true` and writes local summaries after runs. The `reporting.email` and `reporting.slack_webhook` keys are accepted by the configuration schema, -but the current run implementation does not send those notifications. +and notification helper implementations exist, but the current run finalizer does not call +notification dispatch. diff --git a/website/docs/scheduling.md b/website/docs/scheduling.md index 084a6c6..4817f71 100644 --- a/website/docs/scheduling.md +++ b/website/docs/scheduling.md @@ -24,12 +24,14 @@ schedule: interval: 8h ``` -Do not set both. `nightshift config validate` rejects a config containing both values. The cron -parser accepts minute, hour, day of month, month, and day of week fields; it does not accept a -seconds field. Interval examples include `30m`, `8h`, and `24h`. +Do not set both. `nightshift config validate` rejects a config containing both values, but it does +not parse either value. `nightshift doctor`, `nightshift preview`, and `nightshift daemon start` +construct the scheduler and catch malformed values. The cron parser accepts minute, hour, day of +month, month, and day of week fields; it does not accept a seconds field. Interval examples +include `30m`, `8h`, and `24h`, and the duration must be positive. A schedule is optional for manual `run`, `task run`, and configuration commands. It is required -for `daemon start`. +for `preview` and `daemon start`. ## Execution windows @@ -48,8 +50,10 @@ Times use `HH:MM`. The start is inclusive and the end is exclusive. When start i the window crosses midnight. If `timezone` is omitted, Nightshift uses the machine's local timezone. Invalid times and unknown IANA timezone names prevent scheduler creation. -The scheduler moves an out-of-window next-run preview to the next window start. At execution -time it also checks the window before running jobs. +The scheduler moves an out-of-window next-run preview to the next window start. For an interval +daemon that becomes the next timer firing. Cron jobs are different: the cron engine still fires +only on matching cron times, and an out-of-window firing is skipped rather than deferred to the +displayed window start. ## Project and task limits @@ -65,6 +69,9 @@ matching CLI flags are omitted. With no positive config value, `run` defaults to project and one task per project. `--project` ignores the project limit; `--task` ignores the task limit. `--random-task` always selects exactly one task. +The persistent daemon does not use these two fields. It visits every existing explicit +`projects[].path` in configuration order and selects up to five tasks per project. + Task cooldowns and budget filters can reduce the actual count. Projects already processed today are skipped during automatic selection; specifying `--task` bypasses that processed-today skip. @@ -76,13 +83,16 @@ nightshift daemon status nightshift daemon stop ``` -`daemon start` detaches a child process. It waits for the next cron or interval time; it does not -run a task immediately. The daemon: +`daemon start` loads global plus current-directory configuration, detaches a child process, and +waits for the next cron or interval time; it does not run a task immediately. Configuration is +not reloaded while the process is running. The daemon: - Writes `~/.local/share/nightshift/nightshift.pid`. - Runs scheduled work only inside the configured window. - Selects providers by preference and remaining budget. -- Captures and prunes calibration snapshots in the background. +- Processes only existing explicit `projects[].path` entries (or the current directory when none + are configured); project patterns and per-project config merging are not used. +- Captures Claude and Codex snapshots and prunes old snapshots in the background. - Handles SIGINT and SIGTERM for graceful shutdown. Use foreground mode to see failures directly: @@ -97,7 +107,9 @@ waits up to ten seconds, and sends SIGKILL if the process does not exit. ## OS-managed service `install` creates an OS scheduler entry that invokes `nightshift run`; it does not start the -persistent daemon. +persistent daemon. Installed jobs therefore load the global config plus any `nightshift.yaml` +visible from the service's working directory, and they bypass execution windows because manual +`run` does not enforce the scheduler window. ```bash nightshift install # auto-detect @@ -108,9 +120,9 @@ nightshift install cron | Type | Installed artifact | Lifecycle | |------|--------------------|-----------| -| launchd | `~/Library/LaunchAgents/com.nightshift.agent.plist` | Unloads any previous plist, writes it, then loads it | -| systemd | `~/.config/systemd/user/nightshift.service` and `nightshift.timer` | Reloads user units, then enables and starts the timer | -| cron | Managed `# nightshift managed cron entry` in the user's crontab | Replaces an older Nightshift entry | +| launchd | `~/Library/LaunchAgents/com.nightshift.agent.plist` | Uses numeric hour/minute from `schedule.cron`, unloads an old plist, writes, and loads | +| systemd | `~/.config/systemd/user/nightshift.service` and `nightshift.timer` | Converts part of the schedule to `OnCalendar`, reloads user units, enables, and starts | +| cron | Managed `# nightshift managed cron entry` in the user's crontab | Preserves `schedule.cron` and replaces an older Nightshift entry | With no type, macOS selects launchd. Linux selects systemd when `systemctl` exists and cron otherwise; other systems select cron. @@ -119,6 +131,21 @@ The service captures the resolved path of the Nightshift executable. Reinstall a upgrading a manually placed binary. It also runs non-interactively, so `run` confirmation is automatically skipped. +The three generators do not implement identical schedule semantics: + +- Use a simple five-field cron schedule for predictable installed-service behavior. +- launchd reads only numeric minute and hour. It ignores day, month, weekday, interval, and + execution-window constraints; without cron it uses 02:00. +- systemd maps interval text with a simple minute-oriented conversion and drops cron weekday. + Complex cron or non-minute intervals may produce an invalid or unintended timer. +- cron preserves a configured cron expression, ignores interval and execution-window settings, + and uses `0 2 * * *` when cron is empty. +- If loading configuration fails, the standalone `install` command silently installs the 02:00 + fallback instead of returning the configuration error. Run `config validate` and `doctor` + first. + +Use the persistent daemon when interval or execution-window semantics matter. + Remove installed services with: ```bash @@ -140,6 +167,11 @@ nightshift run --max-projects 3 --max-tasks 2 nightshift run --ignore-budget ``` -They still honor provider availability, task eligibility, cooldowns, and budget unless the -relevant explicit override applies. `--ignore-budget` does not enable a disabled provider or make -a missing executable available. +Automatic `run` still honors provider enablement, executable availability, task enablement, +cooldowns, and budget. `--task` bypasses task enablement, cooldown, cost filtering, and the +processed-today check. `--ignore-budget` bypasses budget exhaustion but does not enable a +disabled provider or make a missing executable available. + +`task run` is more direct: its explicit provider and task bypass provider enablement, preference, +budgets, task enablement, cooldowns, and run history. It still requires the executable and a +non-sensitive project path. diff --git a/website/docs/troubleshooting.md b/website/docs/troubleshooting.md index 5da7e51..c7b9d60 100644 --- a/website/docs/troubleshooting.md +++ b/website/docs/troubleshooting.md @@ -13,9 +13,10 @@ nightshift config nightshift config validate ``` -`doctor` checks configuration, scheduling, provider data, database health, snapshots, and budget -readiness. `config` shows which global and current-project files exist before printing the merged -configuration. +`doctor` checks configuration, scheduler parsing, enabled Claude/Codex executables, provider +data, database health, snapshots, and budget readiness. It does not test authentication or check +the Copilot executable. `config` shows which global and current-project files exist before +printing the merged configuration. ## Configuration is missing or loaded from the wrong place @@ -30,6 +31,11 @@ Only `nightshift.yaml` is recognized as a project config. A file named `.nightsh loaded. Run commands from the project root or use `run --project PATH` so Nightshift can load that project's file. +Configured `projects[].path` entries select directories to work on, but Nightshift does not +automatically load a separate `nightshift.yaml` from each of those directories. Project +`pattern`, `exclude`, `priority`, `tasks`, and `config` fields are also not used by the current +`run`, `preview`, or daemon path resolver. + `config set` writes to the project file only when it already exists in the current directory. Use `--global` when you intend to change the global file: @@ -60,11 +66,14 @@ schedule: ```bash nightshift config validate +nightshift doctor nightshift preview --explain ``` -If `daemon start` says no schedule is configured, add `cron` or `interval`. Manual runs do not -require a schedule. +`config validate` catches the case where both schedule types are set, but it does not parse cron, +interval, window time, or timezone values. `doctor`, `preview`, and `daemon start` perform that +runtime validation. If `daemon start` says no schedule is configured, add `cron` or `interval`. +Manual runs do not require a schedule. ## Nothing ran @@ -83,6 +92,9 @@ Common skip reasons include: - All preferred providers are disabled, unavailable, or out of budget. - A configured project path does not exist. +If configuration contains only project patterns, add explicit `path` entries; current execution +commands do not invoke pattern discovery. + To inspect a task independently of automatic selection: ```bash @@ -110,7 +122,8 @@ discovery, or task validation. ## Calibration is missing or low-confidence -Subscription calibration needs local usage data plus provider usage percentages: +Subscription calibration for Claude and Codex needs local usage data plus provider usage +percentages: ```bash nightshift budget snapshot --provider claude @@ -121,6 +134,7 @@ nightshift budget calibrate --provider claude Install `tmux`, enable `budget.calibrate_enabled`, and collect several snapshots over time. `snapshot --local-only` records token counts but cannot by itself infer a budget from a provider percentage. Verify the provider `data_path` when Nightshift cannot find local session data. +Copilot does not support tmux percentage scraping; its snapshots are local-only. If you are billed by API token rather than a subscription, avoid scraping and set explicit limits: @@ -151,15 +165,16 @@ Then authenticate the provider directly: ```bash claude # Complete Claude Code login -codex --login +codex # Choose ChatGPT sign-in or API-key setup copilot login gh auth status # Legacy gh copilot fallback gh extension list ``` -Nightshift prefers standalone `copilot`. It falls back to `gh` only when the Copilot extension -appears in `gh extension list`. A provider `data_path` is not an executable path; changing it will -not fix a missing CLI. +Nightshift prefers standalone `copilot`. The direct `task run` path checks `gh extension list` +before using the retired fallback, but automatic `run` selection checks only whether `gh` exists +and can fail later when the extension is missing. Install standalone Copilot for unattended use. +A provider `data_path` is not an executable path; changing it will not fix a missing CLI. For a service-only PATH problem, compare the interactive executable path with the PATH captured by launchd, systemd, or cron. Nightshift supplements service PATH with common local bin @@ -171,6 +186,30 @@ nightshift uninstall nightshift install ``` +## An installed service runs at the wrong time + +Installed launchd, systemd, and cron jobs do not share all persistent-daemon scheduling +semantics. Use a simple five-field cron expression before `nightshift install`: + +```yaml +schedule: + cron: "0 2 * * *" +``` + +launchd reads only numeric minute/hour, systemd performs a limited conversion, and cron preserves +the expression. All three ignore execution windows, and launchd/cron fall back to 02:00 for an +interval-only config. Use `nightshift daemon start` when intervals or windows matter. + +The standalone installer also falls back to 02:00 if configuration loading fails. Run these +before reinstalling: + +```bash +nightshift config validate +nightshift doctor +nightshift uninstall +nightshift install +``` + ## Daemon lifecycle problems ```bash From 4d3d2c8e63e0e36dadb1b140464a0f6022adb83e Mon Sep 17 00:00:00 2001 From: Greg Gardner Date: Sun, 26 Jul 2026 06:29:42 -0700 Subject: [PATCH 3/3] docs: reconcile CLI behavior Nightshift-Task: docs-backfill Nightshift-Ref: https://github.com/marcus/nightshift --- README.md | 26 +++++------ website/docs/cli-reference.md | 76 +++++++++++++++++++++++++++------ website/docs/configuration.md | 35 ++++++++++----- website/docs/installation.md | 25 +++++------ website/docs/integrations.md | 20 +++++---- website/docs/scheduling.md | 18 +++++--- website/docs/task-reference.md | 4 +- website/docs/tasks.md | 10 ++++- website/docs/troubleshooting.md | 16 ++++--- website/sidebars.js | 2 +- 10 files changed, 157 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 577028d..2db2cbb 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,7 @@ Other useful flags: Nightshift supports three AI providers: - **Claude Code** - Anthropic's Claude via local CLI - **Codex** - OpenAI's GPT via local CLI -- **GitHub Copilot** - GitHub's standalone Copilot CLI, with a retired `gh` extension fallback +- **GitHub Copilot** - GitHub's standalone Copilot CLI, directly or through current `gh copilot` ### Claude Code @@ -219,16 +219,18 @@ Choose ChatGPT sign-in, or configure API-key authentication. npm install -g @github/copilot copilot login -# Compatibility only: retired gh copilot extension +# Alternative: current GitHub CLI downloads/runs Copilot CLI gh auth login --web -gh extension install github/gh-copilot --force +gh copilot ``` -Nightshift prefers the standalone `copilot` executable. It retains a `gh copilot` compatibility -path, but GitHub has retired that extension. Automatic `nightshift run` checks only that `gh` -exists before selecting this fallback; `nightshift task run` also checks the extension list. -Install standalone Copilot for reliable unattended runs. A Copilot plan and any required -organization policy are prerequisites. +Nightshift prefers the standalone `copilot` executable. Recent GitHub CLI releases also expose a +built-in `gh copilot` command; the older `github/gh-copilot` extension is retired and should not +be installed. Automatic `nightshift run` can use the built-in command, but +`nightshift task run --provider copilot` still applies a stale extension-list check when +standalone Copilot is absent. Install standalone Copilot for direct task execution. The npm +package requires Node.js 22 or later, and a Copilot plan plus any required organization policy +are prerequisites. If you prefer API-based usage, you can authenticate Claude and Codex CLIs with API keys instead. @@ -245,10 +247,10 @@ Nightshift uses YAML config files to define: Run `nightshift setup` or `nightshift init --global` to create the global config at `~/.config/nightshift/config.yaml`. A project config is named exactly `nightshift.yaml`. -`init` writes an opinionated starter rather than the built-in defaults: the current global -template prefers Claude and Codex and explicitly enables their unattended permission-bypass -flags. Review those values and replace the template's task names with slugs reported by -`nightshift task list`. +`init` writes opinionated starters rather than the built-in defaults: both templates contain +legacy task aliases, and the current global template prefers Claude and Codex and explicitly +enables their unattended permission-bypass flags. Review those values and replace the template's +task names with slugs reported by `nightshift task list`. See the [full configuration docs](https://nightshift.haplab.com/docs/configuration) for detailed options. diff --git a/website/docs/cli-reference.md b/website/docs/cli-reference.md index b397f04..7b3e3c9 100644 --- a/website/docs/cli-reference.md +++ b/website/docs/cli-reference.md @@ -49,10 +49,15 @@ nightshift config validate project config when it exists and otherwise writes to the global config. `init --force` skips the overwrite prompt. -The generated global file is an opinionated starter, not a dump of built-in defaults. In the -current template it limits provider preference to Claude and Codex, enables their unattended -permission-bypass options, and includes legacy task aliases. Review the file after creation and -use `nightshift task list` for accepted task slugs. +`config` displays the effective configuration with built-in defaults. `config get` reads the +merged file/environment value for a key but returns `key not found` for a value supplied only by +a built-in default. `config set` accepts scalar values only and saves the change before printing +a validation warning, so run `config validate` after edits. + +The generated files are opinionated starters, not dumps of built-in defaults. Both templates +include legacy task aliases. The global template also limits provider preference to Claude and +Codex and enables their unattended permission-bypass options. Review either file after creation +and use `nightshift task list` for accepted task slugs. `config validate` validates each existing file and the merged configuration. It catches schema rules such as mutually exclusive `schedule.cron` and `schedule.interval`, budget ranges, provider @@ -70,7 +75,7 @@ cron and system services, skip the prompt automatically. |------|---------|----------| | `--dry-run` | `false` | Show the preflight plan and exit without execution | | `--project`, `-p` | configured paths or current directory | Target one existing directory, load its `nightshift.yaml`, and ignore `--max-projects` | -| `--task`, `-t` | automatic selection | Run one built-in task; ignores `--max-tasks`, task enablement, cooldown, estimated-cost filtering, and the processed-today skip | +| `--task`, `-t` | automatic selection | Run one built-in or configured custom task; ignores `--max-tasks`, task enablement, cooldown, estimated-cost filtering, and the processed-today skip | | `--max-projects` | `1` | Maximum eligible projects; a positive `schedule.max_projects` supplies the default when the flag is omitted; explicit `0` is unlimited | | `--max-tasks` | `1` | Maximum selected tasks per project; a positive `schedule.max_tasks` supplies the default when the flag is omitted | | `--random-task` | `false` | Pick exactly one random eligible task; cannot be combined with `--task` | @@ -133,10 +138,12 @@ Its cost filter accepts `low`, `medium`, `high`, and `veryhigh`. `task run` requ timeout is `30m`. The `task` subcommands currently expose built-in tasks only; they do not register `tasks.custom` -from configuration. `task run` is a direct execution path: it does not consult provider +from configuration. Use `nightshift run --task CUSTOM_TYPE --project PATH` for a configured +custom task. `task run` is a direct execution path: it does not consult provider enablement, provider preference, budgets, task enablement, cooldowns, or run history. Even -`--dry-run` checks that the requested provider executable is available (and, for the `gh` -Copilot fallback, that the extension is listed). +`--dry-run` checks that the requested provider executable is available. When standalone +`copilot` is absent, this direct path still uses a legacy `gh extension list` gate and can reject +the current built-in `gh copilot` command; install standalone Copilot for `task run`. ## `nightshift budget` @@ -168,8 +175,9 @@ nightshift daemon stop It loads global plus current-directory configuration once at startup and does not reload changed files. At each scheduled time it walks every existing explicit `projects[].path`, skips projects -already processed that day, and selects up to five tasks per project. The daemon does not use -`schedule.max_projects` or `schedule.max_tasks`; those fields affect `nightshift run` only. +already processed that day, and selects up to five built-in tasks per project. The daemon does +not register `tasks.custom` and does not use `schedule.max_projects` or `schedule.max_tasks`; +those fields affect `nightshift run` only. An installed service is OS-managed and invokes `nightshift run` at scheduled times: @@ -214,6 +222,33 @@ nightshift stats --json nightshift doctor ``` +### `status`, `report`, `logs`, and `stats` flags + +| Command | Flag | Default | Behavior | +|---------|------|---------|----------| +| `status` | `--last`, `-n` | `5` | Show the last N database run records | +| `status` | `--today` | `false` | Show today's activity summary instead | +| `report` | `--report`, `-r` | `overview` | Select `overview`, `tasks`, `projects`, `budget`, or `raw` | +| `report` | `--period`, `-p` | `last-night` | Select `last-night`, `last-run`, `last-24h`, `last-7d`, `today`, `yesterday`, or `all` | +| `report` | `--runs`, `-n` | `3` | Limit included runs; `0` means all matching runs | +| `report` | `--since`, `--until` | unset | Use explicit date, local date/time, or RFC3339 boundaries instead of `--period` | +| `report` | `--format` | `fancy` | Select `fancy`, `plain`, `markdown`, or `json` | +| `report` | `--no-color` | `false` | Disable ANSI color | +| `report` | `--paths` | `false` | Include report and log paths | +| `report` | `--max-items` | `5` | Limit highlights shown per run | +| `logs` | `--tail`, `-n` | `50` | Limit output to the last N matching lines; non-positive means unlimited | +| `logs` | `--follow`, `-f` | `false` | Stream appended entries; incompatible with `--summary` and `--until` | +| `logs` | `--export`, `-e` | unset | Write matching logs to a file | +| `logs` | `--since`, `--until` | unset | Apply date, local date/time, or RFC3339 boundaries | +| `logs` | `--level` | unset | Minimum `debug`, `info`, `warn`, or `error` level | +| `logs` | `--component`, `--match` | unset | Filter component or message by substring | +| `logs` | `--summary` | `false` | Show counts and range without entries | +| `logs` | `--raw` | `false` | Print raw stored log lines | +| `logs` | `--no-color` | `false` | Disable ANSI color | +| `logs` | `--path` | configured log path | Read a different log directory | +| `stats` | `--period`, `-p` | `all` | Select `all`, `last-7d`, `last-30d`, or `last-night` | +| `stats` | `--json` | `false` | Emit machine-readable JSON | + Report types are `overview`, `tasks`, `projects`, `budget`, and `raw`. Report formats are `fancy`, `plain`, `markdown`, and `json`. `--period` accepts `last-night`, `last-run`, `last-24h`, `last-7d`, `today`, `yesterday`, or `all`; `--since` and `--until` accept a date, @@ -224,8 +259,8 @@ local date/time, or RFC3339 timestamp. `doctor` parses the scheduler and checks enabled Claude/Codex executables, provider data paths, database state, budget readiness, snapshots, tmux, daemon state, and the detected service files. -It does not test provider authentication, and it does not check whether a Copilot executable or -the retired `gh copilot` extension is installed. +It does not test provider authentication or check whether standalone `copilot` or the current +built-in `gh copilot` command is available. ## Bus factor analysis @@ -236,8 +271,21 @@ nightshift busfactor . --file "internal/*.go" --save nightshift busfactor . --db ~/.local/share/nightshift/nightshift.db ``` -The optional positional path and `--path`/`-p` select the repository. Date boundaries accept -`YYYY-MM-DD` or RFC3339. +The optional positional path and `--path`/`-p` select the repository; the current directory is +the default. `--since` and `--until` accept `YYYY-MM-DD` or RFC3339 boundaries. `--file`/`-f` +limits analysis to a file or pattern, `--json` changes the output, `--save` stores the result, +and `--db` overrides the configured database path used by `--save`. + +## Shell completion + +Generate a completion script using Cobra's built-in subcommands: + +```bash +nightshift completion bash +nightshift completion zsh +nightshift completion fish +nightshift completion powershell +``` ## Global flags diff --git a/website/docs/configuration.md b/website/docs/configuration.md index 223e246..a0f2ead 100644 --- a/website/docs/configuration.md +++ b/website/docs/configuration.md @@ -33,14 +33,16 @@ nightshift config set budget.max_percent 60 nightshift config set logging.level debug --global ``` -`config set` writes to `nightshift.yaml` when that file exists in the current directory; -otherwise it writes to the global file. It parses `true`/`false`, integers, and decimal numbers, -and treats other values as strings. +`config` prints the effective configuration after built-in defaults are applied. `config get` +reads a key from the merged files and environment layer, but does not inject built-in defaults +for keys absent from both files. `config set` writes to `nightshift.yaml` when that file exists +in the current directory; otherwise it writes to the global file. It parses `true`/`false`, +integers, and decimal numbers, and treats other values as strings. -The `init` templates are opinionated examples rather than serialized built-in defaults. In -particular, the current global template prefers only Claude and Codex, explicitly enables their -unattended permission-bypass flags, and contains legacy task aliases such as `lint` and `docs`. -Review the generated file and use `nightshift task list` for current task slugs. +The `init` templates are opinionated examples rather than serialized built-in defaults. Both +templates contain legacy task aliases such as `lint` and `docs`. The global template also +prefers only Claude and Codex and explicitly enables their unattended permission-bypass flags. +Review either generated file and use `nightshift task list` for current task slugs. ## Source precedence @@ -53,6 +55,10 @@ From lowest to highest precedence: 4. `NIGHTSHIFT_` environment overrides. 5. Command-line flags that override behavior for the command being run. +Nested maps from global and project files are merged. Project scalars and lists replace their +global counterparts; for example, a project `tasks.enabled` list replaces the global list while +entries in `tasks.priorities` are merged by key. + The project filename is exactly `nightshift.yaml`; `.nightshift.yaml` is not loaded automatically. The explicitly bound environment variables are: @@ -63,6 +69,10 @@ The explicitly bound environment variables are: | `NIGHTSHIFT_LOG_LEVEL` | `logging.level` | | `NIGHTSHIFT_LOG_PATH` | `logging.path` | +Viper also checks `NIGHTSHIFT_` names for keys already present through a built-in default or a +loaded file. The four bindings above are the stable overrides that do not depend on a key first +appearing in a file; use YAML for schedules, lists, and maps. + ## Complete example ```yaml @@ -244,8 +254,10 @@ project. To use a project's file, invoke `run --project PATH`, `preview --projec ## Task customization -An empty `tasks.enabled` list means all built-in tasks are eligible. `tasks.disabled` always wins. -Higher priority numbers increase selection score. Interval values must be valid Go durations. +For automatic selection, an empty `tasks.enabled` list makes every registered task eligible +except a built-in marked disabled by default (`td-review`). A non-empty list acts as an +allowlist, and `tasks.disabled` wins over that list. Higher priority numbers increase selection +score. Interval values must be valid Go durations. ```yaml tasks: @@ -266,8 +278,9 @@ Custom `type` values use lowercase letters, numbers, and hyphens. `type`, `name` `emergency`; cost tiers are `low`, `medium`, `high`, or `very-high`; risk levels are `low`, `medium`, or `high`. -`run` and `preview` register configured custom tasks. The `task list`, `task show`, and `task run` -commands currently expose only built-in task definitions. +`run` and `preview` register configured custom tasks, so automatic selection and +`run --task dependency-review` can use them. The persistent daemon and the `task list`, +`task show`, and `task run` commands currently expose only built-in task definitions. ## Integrations, logging, and reporting diff --git a/website/docs/installation.md b/website/docs/installation.md index 046c3ed..f9e8ba3 100644 --- a/website/docs/installation.md +++ b/website/docs/installation.md @@ -78,7 +78,8 @@ npm install -g @github/copilot copilot login ``` -Homebrew and GitHub's install script are also supported: +The npm package requires Node.js 22 or later. Homebrew and GitHub's install script are also +supported: ```bash brew install copilot-cli @@ -89,26 +90,26 @@ An eligible Copilot plan and any required organization policy are prerequisites. reuse an authenticated GitHub CLI token. See [GitHub's Copilot CLI installation guide](https://docs.github.com/en/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli). -Nightshift also recognizes the legacy `gh copilot` extension when standalone `copilot` is not -installed: +Recent GitHub CLI releases also provide a built-in `gh copilot` command that downloads and runs +the current standalone Copilot CLI when needed: ```bash gh auth login --web -gh extension install github/gh-copilot --force -gh extension list +gh copilot ``` -GitHub has retired that extension in favor of the standalone CLI, so prefer `copilot` for new -installations. The fallback remains documented only because Nightshift retains a compatibility -execution path. +Do not install the retired `github/gh-copilot` extension; it stopped working in October 2025. +Nightshift's automatic `run` path can invoke the new built-in `gh copilot` command. The direct +`task run --provider copilot` availability check still looks for the retired extension when no +standalone `copilot` executable exists, so install standalone Copilot for that command. ## Provider discovery Nightshift looks for `claude`, `codex`, and `copilot` on `PATH`. For Copilot it prefers -standalone `copilot`, then falls back to `gh`. `task run` verifies the retired extension through -`gh extension list`, but automatic `run` selection only verifies that `gh` exists; without the -extension, execution fails later. Provider `data_path` settings point to usage data and do not -override executable paths. +standalone `copilot`, then falls back to `gh`. Automatic `run` verifies only that `gh` exists +before invoking `gh copilot`, so an old GitHub CLI without the built-in command fails at +execution. `task run` additionally applies the stale extension-list check described above. +Provider `data_path` settings point to usage data and do not override executable paths. When launched by a daemon or service, Nightshift also searches existing directories at: diff --git a/website/docs/integrations.md b/website/docs/integrations.md index 955a42a..a87d4f5 100644 --- a/website/docs/integrations.md +++ b/website/docs/integrations.md @@ -69,22 +69,24 @@ npm install -g @github/copilot copilot login ``` -Copilot can also authenticate with `COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN`, or reuse -an authenticated `gh` session. Nightshift invokes non-interactive prompt mode and, when +The npm install requires Node.js 22 or later. Copilot can also authenticate with +`COPILOT_GITHUB_TOKEN`, `GH_TOKEN`, or `GITHUB_TOKEN`, or reuse an authenticated `gh` session. +Nightshift invokes non-interactive prompt mode and, when `providers.copilot.dangerously_skip_permissions` is true, allows all tools and URLs. -If `copilot` is absent, Nightshift falls back to `gh` and requires the legacy Copilot extension -to appear in `gh extension list`: +If `copilot` is absent, automatic Nightshift runs fall back to `gh copilot`. Recent GitHub CLI +releases provide that command directly and download the current Copilot CLI when needed: ```bash gh auth login --web -gh extension install github/gh-copilot --force -gh extension list +gh copilot ``` -GitHub has retired the extension, so standalone Copilot is recommended. `task run` confirms that -the extension is listed before using the fallback. Automatic `run` only checks for `gh` on -`PATH`; if the extension is absent, it can select Copilot and then fail during execution. +The old `github/gh-copilot` extension is retired and should not be installed. A Nightshift +compatibility bug remains in `task run --provider copilot`: when standalone `copilot` is absent, +that command still checks `gh extension list` and can reject the new built-in `gh copilot`. +Install standalone Copilot for direct task execution. Automatic `run` only checks for `gh` on +`PATH`, so it requires a recent GitHub CLI with the built-in command. ## Provider selection exceptions diff --git a/website/docs/scheduling.md b/website/docs/scheduling.md index 4817f71..190d9de 100644 --- a/website/docs/scheduling.md +++ b/website/docs/scheduling.md @@ -48,7 +48,8 @@ schedule: Times use `HH:MM`. The start is inclusive and the end is exclusive. When start is later than end, the window crosses midnight. If `timezone` is omitted, Nightshift uses the machine's local -timezone. Invalid times and unknown IANA timezone names prevent scheduler creation. +timezone. Invalid times and unknown IANA timezone names prevent scheduler creation. Equal start +and end values pass parsing but create an empty window, so use different values. The scheduler moves an out-of-window next-run preview to the next window start. For an interval daemon that becomes the next timer firing. Cron jobs are different: the cron engine still fires @@ -70,7 +71,8 @@ project and one task per project. `--project` ignores the project limit; `--task task limit. `--random-task` always selects exactly one task. The persistent daemon does not use these two fields. It visits every existing explicit -`projects[].path` in configuration order and selects up to five tasks per project. +`projects[].path` in configuration order and selects up to five built-in tasks per project. +It does not register configured custom tasks. Task cooldowns and budget filters can reduce the actual count. Projects already processed today are skipped during automatic selection; specifying `--task` bypasses that processed-today skip. @@ -101,8 +103,10 @@ Use foreground mode to see failures directly: nightshift daemon start --foreground --timeout 45m ``` -`daemon status` reports the PID, schedule, window, and PID-file path. `daemon stop` sends SIGTERM, -waits up to ten seconds, and sends SIGKILL if the process does not exit. +`daemon status` reports the PID and PID-file path. It also displays the schedule and window from +the configuration visible to the status command, which can differ from the configuration cached +by an already-running daemon. `daemon stop` sends SIGTERM, waits up to ten seconds, and sends +SIGKILL if the process does not exit. ## OS-managed service @@ -127,9 +131,9 @@ nightshift install cron With no type, macOS selects launchd. Linux selects systemd when `systemctl` exists and cron otherwise; other systems select cron. -The service captures the resolved path of the Nightshift executable. Reinstall after moving or -upgrading a manually placed binary. It also runs non-interactively, so `run` confirmation is -automatically skipped. +The service captures the resolved path of the Nightshift executable. Reinstall after moving the +binary or when an upgrade changes that resolved path. It also runs non-interactively, so `run` +confirmation is automatically skipped. The three generators do not implement identical schedule semantics: diff --git a/website/docs/task-reference.md b/website/docs/task-reference.md index cb241df..7b2436e 100644 --- a/website/docs/task-reference.md +++ b/website/docs/task-reference.md @@ -30,7 +30,9 @@ Fully formed, review-ready artifacts. These tasks create branches and open pull | `td-review` | TD Review Session | Review open td reviews, fix obvious bugs, create tasks for bigger issues | High | Medium | 72h | :::note -`td-review` is **disabled by default** and must be explicitly opted in via `tasks.enabled`. It requires the td integration to be enabled (see [Integrations](/docs/integrations)). +`td-review` is **disabled by default** and must be explicitly opted in via `tasks.enabled`. Its +prompt expects the `td` executable and a td-enabled project; the currently unwired +`integrations.task_sources` settings are not required. ::: ## Analysis Tasks — "Here's what I found" diff --git a/website/docs/tasks.md b/website/docs/tasks.md index fead41d..ed04ee9 100644 --- a/website/docs/tasks.md +++ b/website/docs/tasks.md @@ -98,7 +98,11 @@ tasks: interval: "72h" ``` -Custom tasks use the same scoring, cooldowns, and budget controls as built-in tasks. The `description` field becomes the agent prompt. Only `type`, `name`, and `description` are required — other fields have sensible defaults. +When registered by `run` or `preview`, custom tasks use the same scoring, cooldowns, and budget +controls as built-in tasks. The `description` field becomes the agent prompt. Only `type`, `name`, +and `description` are required; other fields have defaults. The persistent daemon and the +`task list`, `task show`, and `task run` subcommands do not currently register custom tasks. +Execute one directly with `nightshift run --task CUSTOM_TYPE --project PATH`. ## Task Cooldowns @@ -136,4 +140,6 @@ tasks: - td-review ``` -Requires the td integration to be enabled (see [Integrations](/docs/integrations)). +The task prompt expects the `td` executable and a td-enabled project. The +`integrations.task_sources` settings are not required for this built-in task and are not wired +into current command execution. diff --git a/website/docs/troubleshooting.md b/website/docs/troubleshooting.md index c7b9d60..6b083ca 100644 --- a/website/docs/troubleshooting.md +++ b/website/docs/troubleshooting.md @@ -91,6 +91,7 @@ Common skip reasons include: - No task fits the remaining token allowance. - All preferred providers are disabled, unavailable, or out of budget. - A configured project path does not exist. +- Window start and end are equal, so the scheduler's execution window is empty. If configuration contains only project patterns, add explicit `path` entries; current execution commands do not invoke pattern discovery. @@ -167,14 +168,17 @@ Then authenticate the provider directly: claude # Complete Claude Code login codex # Choose ChatGPT sign-in or API-key setup copilot login -gh auth status # Legacy gh copilot fallback -gh extension list +gh auth status +gh copilot # Current GitHub CLI fallback ``` -Nightshift prefers standalone `copilot`. The direct `task run` path checks `gh extension list` -before using the retired fallback, but automatic `run` selection checks only whether `gh` exists -and can fail later when the extension is missing. Install standalone Copilot for unattended use. -A provider `data_path` is not an executable path; changing it will not fix a missing CLI. +Nightshift prefers standalone `copilot`. Recent GitHub CLI releases include `gh copilot`, which +downloads and runs the current Copilot CLI; the older `github/gh-copilot` extension is retired +and should not be installed. The direct `task run` path still applies a stale extension-list +check when standalone Copilot is absent, so use standalone `copilot` for that command. Automatic +`run` checks only whether `gh` exists and can fail later when GitHub CLI is too old to provide +the built-in command. A provider `data_path` is not an executable path; changing it will not fix +a missing CLI. For a service-only PATH problem, compare the interactive executable path with the PATH captured by launchd, systemd, or cron. Nightshift supplements service PATH with common local bin diff --git a/website/sidebars.js b/website/sidebars.js index e516e2c..ddb5931 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -15,7 +15,7 @@ const sidebars = { { type: 'category', label: 'Reference', - items: ['cli-reference', 'integrations'], + items: ['cli-reference', 'integrations', 'troubleshooting'], }, ], };