P8.2: rewrite README.md for end users
- Update Features to reflect JSON storage, queue execution mode/overlap policy, failure notifications, and tray left-click-to-show. - Replace Documentation project-notes list with a proper Documentation section. - Rewrite Storage section: JSON file examples with all current fields (execution_mode, overlap_policy); add YAML upgrade note. - Add Queue Settings section documenting parallel/sequential and skip/queue. - Add Notifications section. - Fix all 0.3.0 version strings to 0.9.0. - Remove Codex attribution line. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,150 +1,97 @@
|
|||||||
# GoSentry
|
# 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 a cross-platform desktop scheduler. 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)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Native desktop GUI built with [Fyne](https://fyne.io/).
|
- Native desktop GUI built with [Fyne](https://fyne.io/).
|
||||||
- Job storage in one clean YAML file.
|
- Job definitions stored in a clean, hand-editable `jobs.json`.
|
||||||
- App settings in a separate YAML file.
|
- `@every` intervals and standard 5-field cron expressions.
|
||||||
- `@every` schedules and standard 5-field cron expressions.
|
|
||||||
- Manual and scheduled command runs.
|
- 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.
|
- Log cleanup by maximum file count and maximum age.
|
||||||
- Global pause/resume for all job execution.
|
- Global pause/resume for all job execution.
|
||||||
- Windows tray support.
|
- Desktop notifications on job failure.
|
||||||
- Version shown in the window title, Settings, and build artifact names.
|
- 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
|
- [Changelog](docs/CHANGELOG.md)
|
||||||
|
- [Roadmap](docs/ROADMAP.md)
|
||||||
GoSentry uses [Fyne](https://fyne.io/), and Fyne uses GLFW/OpenGL to create the
|
- [Architecture](docs/ARCHITECTURE.md)
|
||||||
desktop window. In a Windows virtual machine, especially when the session is
|
- [Development](docs/DEVELOPMENT.md) — build instructions, project layout, dependencies
|
||||||
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-<version>-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.
|
|
||||||
|
|
||||||
## Storage
|
## 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
|
```json
|
||||||
# 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": ".",
|
||||||
jobs_dir: .
|
"logs_dir": "logs",
|
||||||
|
"max_log_files": 100,
|
||||||
# Directory for per-run command output logs. Relative paths are resolved against
|
"max_log_age_days": 30,
|
||||||
# the program folder, just like jobs_dir.
|
"keep_running_in_tray": true,
|
||||||
logs_dir: logs
|
"notify_on_failure": true,
|
||||||
|
"execution_mode": "parallel",
|
||||||
# Keep at most this many .log files after cleanup. Newest logs are preserved.
|
"overlap_policy": "skip"
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`jobs.yaml` stores only job definitions:
|
`jobs.json` stores job definitions:
|
||||||
|
|
||||||
```yaml
|
```json
|
||||||
jobs:
|
{
|
||||||
# A harmless sample job created on first run so the scheduler can be tested
|
"jobs": [
|
||||||
# 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
|
"id": 1,
|
||||||
# written to separate log files.
|
"name": "Hello scheduler",
|
||||||
- id: 1
|
"folder": "Examples",
|
||||||
# Human-readable name shown in the jobs list and used in log file names.
|
"schedule": "@every 1m",
|
||||||
name: Hello scheduler
|
"command": "echo GoSentry test job: scheduler is alive",
|
||||||
|
"enabled": true
|
||||||
# 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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
```text
|
||||||
# Format: YYYYMMDD-HHMMSS_<sanitized job name>.log
|
|
||||||
20260614-224306_Hello_scheduler.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
|
## Schedules
|
||||||
|
|
||||||
Fast interval schedules:
|
Interval schedules using Go duration syntax:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
# Go duration syntax after @every; useful for tests and simple intervals.
|
|
||||||
@every 10s
|
@every 10s
|
||||||
@every 5m
|
@every 5m
|
||||||
@every 1h30m
|
@every 1h30m
|
||||||
```
|
```
|
||||||
|
|
||||||
Standard 5-field cron schedules:
|
Standard 5-field cron expressions:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
# Standard five-field cron: minute hour day-of-month month day-of-week.
|
|
||||||
*/5 * * * * every five minutes
|
*/5 * * * * every five minutes
|
||||||
0 2 * * * every day at 02:00
|
0 2 * * * every day at 02:00
|
||||||
30 9 * * 1-5 weekdays at 09:30
|
30 9 * * 1-5 weekdays at 09:30
|
||||||
@@ -153,48 +100,106 @@ Standard 5-field cron schedules:
|
|||||||
## Using The App
|
## Using The App
|
||||||
|
|
||||||
1. Start GoSentry.
|
1. Start GoSentry.
|
||||||
2. Use `New job` to create a command.
|
2. Use **New job** to create a scheduled command.
|
||||||
3. Set `Schedule`, `Command`, optional `Folder`, and `Enabled`.
|
3. Set **Schedule**, **Command**, optional **Arguments**, **Folder**, and **Enabled**.
|
||||||
4. Use `Run now` for a manual test run.
|
4. Use **Run now** for a one-off manual run without waiting for the schedule.
|
||||||
5. Use `Pause` to disable one job.
|
5. Use **Pause** on a single job to suspend it without deleting it.
|
||||||
6. Use `Pause all` as a global stop switch.
|
6. Use **Pause all** as a global stop switch for all scheduled runs.
|
||||||
7. Open `History` to see whether a run was `Manual`, `Schedule`, or `UI`.
|
7. Open **History** to see past runs, their trigger (`Manual`, `Schedule`, or `UI`), state, and log file.
|
||||||
8. Open `Settings` to change `jobs_dir`, `logs_dir`, and log cleanup limits. Use `Browse` to choose directories.
|
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.
|
The **Start on login** checkbox shows an `OK` or `Problem` status. Saving with
|
||||||
Autostart entries add `--start-in-tray`, so scheduled jobs begin running after sign-in without opening the main window.
|
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
|
## 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:
|
Linux:
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
# GoSentry writes an XDG Autostart desktop entry when Start on login is enabled.
|
# 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
|
~/.config/autostart/gosentry.desktop
|
||||||
|
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=GoSentry
|
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
|
Terminal=false
|
||||||
```
|
```
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
# GoSentry writes a shortcut to the current user's Startup folder when Start on
|
# GoSentry writes a shortcut to the current user's Startup folder.
|
||||||
# login is enabled. A .lnk stores the executable path as a structured TargetPath,
|
# A .lnk stores the executable path as TargetPath and --start-in-tray as
|
||||||
# and stores --start-in-tray as Arguments, so paths with spaces do not need
|
# Arguments, so paths with spaces do not need fragile command-line quoting.
|
||||||
# fragile command-line quoting. Saving settings rewrites the shortcut and removes
|
|
||||||
# old HKCU Run entries from earlier builds.
|
|
||||||
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\GoSentry.lnk
|
%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-<version>-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.
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ These land together because both edit `domain/job.go` and `storage/store.go`.
|
|||||||
|
|
||||||
### Phase 8 — Docs + version
|
### Phase 8 — Docs + version
|
||||||
- [x] P8.1 — `docs/DEVELOPMENT.md`
|
- [x] P8.1 — `docs/DEVELOPMENT.md`
|
||||||
- [ ] P8.2 — End-user README rewrite
|
- [x] P8.2 — End-user README rewrite
|
||||||
- [ ] P8.3 — CHANGELOG + ROADMAP updates
|
- [ ] P8.3 — CHANGELOG + ROADMAP updates
|
||||||
|
|
||||||
## Definition of done
|
## Definition of done
|
||||||
|
|||||||
Reference in New Issue
Block a user