# Configuration
URGithub stores its configuration in `\urgithub\.urgithub\config.json`. Every setting is also exposed through the CLI — you never need to hand-edit JSON.
> **Deep merge:** any omitted key falls back to the built-in default. You only need to store the values you change.
## Reading and setting values
```bash
python urgithub.py --config # show full configuration
python urgithub.py --config triggers.every_hours # read one value (dot path)
python urgithub.py --config triggers.every_hours 6 # set one value
```
After changing scheduling-related settings, reapply the scheduler and verify:
```bash
python urgithub.py --schedule install
python urgithub.py --schedule status
```
You can also edit `config.json` with any JSON editor, then re-run `--schedule install`.
## Settings reference
### Repository behavior
| Key | Default | Purpose |
|---|---|---|
| `github_owner` | `auto` | GitHub owner to reconcile against (`auto` = logged-in user) |
| `clone_missing_repos` | `true` | Clone local repos that exist remotely but not locally |
| `skip_forks` | `false` | Skip forked repositories |
### Commit policy
| Key | Default | Purpose |
|---|---|---|
| `commit_policy.auto_commit` | `false` | Automatically commit local changes |
| `commit_policy.message_prefix` | `sync:` | Prefix prepended to auto-commit messages |
### Push
| Key | Default | Purpose |
|---|---|---|
| `push.push_all_branches` | `false` | Push every branch instead of the current branch |
| `push.timeout_seconds` | `60` | Timeout per push operation |
### Shutdown (Windows)
| Key | Default | Purpose |
|---|---|---|
| `shutdown.enabled` | `true` | Enable quick-push before shutdown |
| `shutdown.quick_push` | `true` | Push pending changes during shutdown |
| `shutdown.timeout_seconds` | `30` | Time budget for the shutdown push |
| `shutdown.open_report` | `false` | Open the report during shutdown |
### Report
| Key | Default | Purpose |
|---|---|---|
| `report.auto_open` | `true` | Open `report.html` in the browser after a run |
| `report.archive` | `true` | Archive old reports |
| `report.archive_keep_days` | `90` | How long archived reports are kept |
| `report.show_files` | `true` | Show file lists in the report |
| `report.files_max` | `500` | Maximum files listed per repository |
### Security
| Key | Default | Purpose |
|---|---|---|
| `security.block_on_secrets` | `true` | Block sync when secrets are detected |
| `security.patterns` | see below | Filename patterns treated as secrets |
| `security.content_patterns` | see below | Content regexes for secret detection |
| `security.allow_files` | `[]` | Explicit file allow-list exceptions |
| `security.max_scan_bytes` | `1048576` | Maximum bytes scanned per file |
### Limits
| Key | Default | Purpose |
|---|---|---|
| `limits.max_file_mb` | `100` | Hard size limit per file |
| `limits.warn_file_mb` | `50` | Warning threshold per file |
| `limits.block_on_oversize` | `true` | Block sync for files over the hard limit |
### Deleted / renamed repos
| Key | Default | Purpose |
|---|---|---|
| `deleted_repo_policy.confirm_scans` | `3` | Consecutive scans before a deletion is flagged |
| `deleted_repo_policy.confirm_days` | `7` | Days before a deletion is confirmed |
| `deleted_repo_policy.require_remote_confirmation` | `true` | Require the remote to confirm deletion |
| `deleted_repo_policy.require_user_confirmation` | `true` | Require explicit user confirmation |
### Notifications
| Key | Default | Purpose |
|---|---|---|
| `notify.toast_on_failure` | `true` | Show a desktop toast on failed runs |
| `notify.email.enabled` | `false` | Email notifications (off by default) |
| `notify.email.smtp` / `recipients` | — | SMTP host and recipient list |
| `notify.webhook.discord` / `slack` | `""` | Webhook URLs (empty = disabled) |
| `notify.webhook.github_actions` | `false` | Send GitHub Actions-compatible events |
### Triggers
| Key | Default | Purpose |
|---|---|---|
| `triggers.startup` | `true` | Run at login |
| `triggers.shutdown` | `true` | Quick-push at shutdown (Windows) |
| `triggers.every_hours` | `3` | Repeat interval in hours (`0` = off) |
| `triggers.every_minutes` | `0` | Repeat interval in minutes (`0` = off) |
| `triggers.at_time` | `null` | Single daily time, e.g. `18:00` |
| `triggers.file_change` | `true` | Run when watched files change |
| `triggers.manual` | `true` | Allow manual runs |
Notes:
- `every_minutes` **wins over** `every_hours` when it is greater than 0.
- `every_hours` boundaries are epoch-aligned (runs land on the hour).
- `at_time` runs daily at the given time and **rolls to tomorrow** if the time has already passed.
- `0` on `every_hours` / `every_minutes` disables that interval.
- Run any trigger by name with `python urgithub.py --run `.
Next: [Automation](automation.md) — how triggers become real scheduled runs on each OS.