diff --git a/README.md b/README.md index 71c6090..3543b63 100644 --- a/README.md +++ b/README.md @@ -1,150 +1,97 @@ # GoSentry -GoSentry is a cross-platform desktop scheduler inspired by cron. It provides a native GUI for creating, grouping, pausing, running, and monitoring scheduled shell commands. - -GoSentry is being designed and implemented with assistance from OpenAI Codex. - -Project notes: - -- [Changelog](docs/CHANGELOG.md) -- [Roadmap](docs/ROADMAP.md) -- [Architecture](docs/ARCHITECTURE.md) -- [Development](docs/DEVELOPMENT.md) +GoSentry is a cross-platform desktop scheduler. It provides a native GUI for +creating, grouping, pausing, running, and monitoring scheduled shell commands. ## Features - Native desktop GUI built with [Fyne](https://fyne.io/). -- Job storage in one clean YAML file. -- App settings in a separate YAML file. -- `@every` schedules and standard 5-field cron expressions. +- Job definitions stored in a clean, hand-editable `jobs.json`. +- `@every` intervals and standard 5-field cron expressions. - Manual and scheduled command runs. -- Per-run `.log` files with stdout/stderr. +- Parallel or sequential execution mode; configurable overlap policy (skip or queue). +- Per-run `.log` files with stdout/stderr capture. - Log cleanup by maximum file count and maximum age. - Global pause/resume for all job execution. -- Windows tray support. -- Version shown in the window title, Settings, and build artifact names. +- Desktop notifications on job failure. +- Windows tray icon: left-click to show the window, right-click for the menu. +- Autostart on login (Windows shortcut; Linux XDG desktop entry). -## Troubleshooting +## Documentation -### Windows, VirtualBox, RDP, And OpenGL - -GoSentry uses [Fyne](https://fyne.io/), and Fyne uses GLFW/OpenGL to create the -desktop window. In a Windows virtual machine, especially when the session is -opened through RDP inside VirtualBox, the available video driver can fail OpenGL -initialization. - -Typical error: - -```text -Fyne error: window creation error -Cause: APIUnavailable: WGL: The driver does not appear to support OpenGL -At: fyne.io/fyne/v2@v2.5.3/internal/driver/glfw/driver.go:149 -``` - -Known workaround: - -1. Download a Windows Mesa build from - [mesa-dist-win](https://github.com/pal1000/mesa-dist-win/releases). For a - regular Windows x64 GoSentry build, use the archive named like - `mesa3d--release-mingw.7z`, for example - `mesa3d-26.1.1-release-mingw.7z`. This matches the MSYS2 GCC toolchain used - to build GoSentry. The `devel`, `debug-info`, `tests`, and checksum files - are not needed for this workaround. -2. Open the downloaded archive and use the `x64` build from it. -3. Copy the Mesa OpenGL DLL files from `x64` into the same directory as the - GoSentry `.exe`, for example: - -```text -dist\windows\ - gosentry-0.3.0-windows-amd64.exe - opengl32.dll - ... -``` - -This makes Windows load Mesa's software OpenGL implementation next to the -application binary, which lets the Fyne window start even when the VirtualBox/RDP -driver does not provide usable OpenGL. +- [Changelog](docs/CHANGELOG.md) +- [Roadmap](docs/ROADMAP.md) +- [Architecture](docs/ARCHITECTURE.md) +- [Development](docs/DEVELOPMENT.md) — build instructions, project layout, dependencies ## Storage -GoSentry creates its runtime files next to the executable by default. +GoSentry stores its files next to the executable by default, making it a +portable application: moving the program folder also moves its configuration. -`gosentry.yaml` stores application settings: +`gosentry.json` stores application settings: -```yaml -# Directory containing jobs.yaml. "." means "the folder where the GoSentry -# executable lives"; an absolute path can be used when jobs should live elsewhere. -jobs_dir: . - -# Directory for per-run command output logs. Relative paths are resolved against -# the program folder, just like jobs_dir. -logs_dir: logs - -# Keep at most this many .log files after cleanup. Newest logs are preserved. -max_log_files: 100 - -# Delete .log files older than this many days during cleanup. -max_log_age_days: 30 - -# Start GoSentry automatically when the current desktop user signs in. -start_on_login: false - -# Closing the window hides it to the tray instead of stopping the scheduler. -keep_running_in_tray: true - -# Reserved for desktop failure notifications; the setting is stored now so the -# UI and config format do not need to change when notifications are wired fully. -notify_on_failure: true +```json +{ + "jobs_dir": ".", + "logs_dir": "logs", + "max_log_files": 100, + "max_log_age_days": 30, + "keep_running_in_tray": true, + "notify_on_failure": true, + "execution_mode": "parallel", + "overlap_policy": "skip" +} ``` -`jobs.yaml` stores only job definitions: +`jobs.json` stores job definitions: -```yaml -jobs: - # A harmless sample job created on first run so the scheduler can be tested - # immediately. Runtime fields such as last run time, next run time, and command - # output are intentionally not stored here; they are displayed in the GUI and - # written to separate log files. - - id: 1 - # Human-readable name shown in the jobs list and used in log file names. - name: Hello scheduler - - # Optional grouping label. Omit it or leave it empty to put the job under - # the "No folder" filter. - folder: Examples - - # Either @every with a Go duration, or a standard five-field cron expression. - schedule: '@every 1m' - - # Command passed to the platform shell: cmd.exe /C on Windows, sh -c on Linux. - command: echo GoSentry test job: scheduler is alive - - # Disabled jobs remain in jobs.yaml but are skipped by the scheduler. - enabled: true +```json +{ + "jobs": [ + { + "id": 1, + "name": "Hello scheduler", + "folder": "Examples", + "schedule": "@every 1m", + "command": "echo GoSentry test job: scheduler is alive", + "enabled": true + } + ] +} ``` -Command output is written to separate files under `logs_dir`. File names include the run timestamp and job name, for example: +`jobs_dir` is the directory GoSentry reads `jobs.json` from. The default `"."` +means the same folder as the executable. An absolute path can be used when jobs +should live elsewhere, such as a shared network drive. + +`logs_dir` is relative to the program folder when it does not start with a +drive letter or `/`. + +Command output is written to separate files under `logs_dir`. File names +include the run timestamp and job name: ```text -# Format: YYYYMMDD-HHMMSS_.log 20260614-224306_Hello_scheduler.log ``` +**Upgrading from an earlier build:** if `gosentry.yaml` / `jobs.yaml` exist +next to the executable, GoSentry imports them once and rewrites the data as +JSON. The old `.yaml` files are left untouched. + ## Schedules -Fast interval schedules: +Interval schedules using Go duration syntax: ```text -# Go duration syntax after @every; useful for tests and simple intervals. @every 10s @every 5m @every 1h30m ``` -Standard 5-field cron schedules: +Standard 5-field cron expressions: ```text -# Standard five-field cron: minute hour day-of-month month day-of-week. */5 * * * * every five minutes 0 2 * * * every day at 02:00 30 9 * * 1-5 weekdays at 09:30 @@ -153,48 +100,106 @@ Standard 5-field cron schedules: ## Using The App 1. Start GoSentry. -2. Use `New job` to create a command. -3. Set `Schedule`, `Command`, optional `Folder`, and `Enabled`. -4. Use `Run now` for a manual test run. -5. Use `Pause` to disable one job. -6. Use `Pause all` as a global stop switch. -7. Open `History` to see whether a run was `Manual`, `Schedule`, or `UI`. -8. Open `Settings` to change `jobs_dir`, `logs_dir`, and log cleanup limits. Use `Browse` to choose directories. +2. Use **New job** to create a scheduled command. +3. Set **Schedule**, **Command**, optional **Arguments**, **Folder**, and **Enabled**. +4. Use **Run now** for a one-off manual run without waiting for the schedule. +5. Use **Pause** on a single job to suspend it without deleting it. +6. Use **Pause all** as a global stop switch for all scheduled runs. +7. Open **History** to see past runs, their trigger (`Manual`, `Schedule`, or `UI`), state, and log file. +8. Open **Settings** to change storage directories, log cleanup limits, queue behavior, and notifications. -Changing `jobs_dir` saves the current job list to the new directory. +Changing `jobs_dir` in Settings saves the current job list to the new directory. -The `Start on login` setting shows an `OK` or `Problem` status next to the checkbox. Saving settings with the checkbox enabled rewrites the autostart entry using the current executable path. -Autostart entries add `--start-in-tray`, so scheduled jobs begin running after sign-in without opening the main window. +The **Start on login** checkbox shows an `OK` or `Problem` status. Saving with +it enabled writes an autostart entry using the current executable path. +Autostart entries include `--start-in-tray` so scheduled jobs run after sign-in +without opening the main window. + +## Queue Settings + +Two settings in the **Queue** group of the Settings tab control how simultaneous +and overlapping runs are handled. + +**Execution mode** — applies when multiple jobs become due at the same tick: + +| Value | Behaviour | +|-------|-----------| +| `parallel` (default) | All due jobs start at the same time. | +| `sequential` | Due jobs are started one after another, in the order they appear in the list. | + +**Overlap policy** — applies when a job's next scheduled run fires while its +previous run is still active: + +| Value | Behaviour | +|-------|-----------| +| `skip` (default) | The new run is discarded; the running instance continues. | +| `queue` | The new run is held and starts immediately after the current run finishes. | + +## Notifications + +When **Notify on failure** is enabled in Settings, GoSentry sends a desktop +notification whenever a scheduled or manual run exits with a non-zero exit code. +The notification shows the job name and the exit code. ## Autostart -GoSentry is a user desktop application, not a system daemon, so autostart should be configured per user. +GoSentry is a user desktop application, not a system daemon, so autostart is +configured per user. Linux: ```ini # GoSentry writes an XDG Autostart desktop entry when Start on login is enabled. -# This is better for a GUI/tray application than a systemd user service because -# the desktop environment starts it inside the graphical user session. -# Saving the setting also removes the old ~/.config/systemd/user/pysentry.service -# unit if it was created by an earlier GoSentry build. ~/.config/autostart/gosentry.desktop [Desktop Entry] Type=Application Name=GoSentry -Exec=/opt/gosentry/gosentry-0.3.0-linux-amd64 --start-in-tray +Exec=/opt/gosentry/gosentry-0.9.0-linux-amd64 --start-in-tray Terminal=false ``` Windows: ```text -# GoSentry writes a shortcut to the current user's Startup folder when Start on -# login is enabled. A .lnk stores the executable path as a structured TargetPath, -# and stores --start-in-tray as Arguments, so paths with spaces do not need -# fragile command-line quoting. Saving settings rewrites the shortcut and removes -# old HKCU Run entries from earlier builds. +# GoSentry writes a shortcut to the current user's Startup folder. +# A .lnk stores the executable path as TargetPath and --start-in-tray as +# Arguments, so paths with spaces do not need fragile command-line quoting. %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\GoSentry.lnk ``` +## Troubleshooting + +### Windows, VirtualBox, RDP, And OpenGL + +GoSentry uses [Fyne](https://fyne.io/), and Fyne uses GLFW/OpenGL to create the +desktop window. In a Windows virtual machine, especially when accessed through +RDP inside VirtualBox, the available video driver can fail OpenGL initialization. + +Typical error: + +```text +Fyne error: window creation error +Cause: APIUnavailable: WGL: The driver does not appear to support OpenGL +``` + +Known workaround: + +1. Download a Windows Mesa build from + [mesa-dist-win](https://github.com/pal1000/mesa-dist-win/releases). Use the + archive named like `mesa3d--release-mingw.7z` — this matches the + MSYS2 GCC toolchain used to build GoSentry. The `devel`, `debug-info`, + `tests`, and checksum files are not needed. +2. Open the archive and use the `x64` build. +3. Copy the Mesa OpenGL DLL files from `x64` into the same directory as the + GoSentry `.exe`: + +```text +dist\windows\ + gosentry-0.9.0-windows-amd64.exe + opengl32.dll + ... +``` + +Mesa's software OpenGL implementation lets the Fyne window start even when the +VirtualBox/RDP driver does not provide usable OpenGL. diff --git a/docs/PRE-RELEASE-TASKS.md b/docs/PRE-RELEASE-TASKS.md index 5d7fba9..b264b0f 100644 --- a/docs/PRE-RELEASE-TASKS.md +++ b/docs/PRE-RELEASE-TASKS.md @@ -118,7 +118,7 @@ These land together because both edit `domain/job.go` and `storage/store.go`. ### Phase 8 — Docs + version - [x] P8.1 — `docs/DEVELOPMENT.md` -- [ ] P8.2 — End-user README rewrite +- [x] P8.2 — End-user README rewrite - [ ] P8.3 — CHANGELOG + ROADMAP updates ## Definition of done