Files
gosentry/README.md
T
mix 18da021526 chore: land the remaining low-severity items from the whole-project review
Phase 11 of PROJECT_REVIEW_PLAN.md: the themed cleanup pass over every
low-severity finding still open (2.2-2.3, 3.4-3.6, 4.3-4.7, 6.4-6.7,
7.1-7.3, 8.2-8.3, 9.1-9.4, and the under-documented decisions in §10/§11).

Behavioral fixes:
- Reassign duplicate job IDs in a hand-edited jobs.json instead of letting
  two jobs share one runtime, schedule entry, and SeedStats bucket.
- Disambiguate run-log file names that collide within the same second.
- Compute AvgDurationMS as DurationSumMS/TimedRunCount instead of an
  incremental integer mean, so it always matches the seeded-from-logs
  average instead of drifting from truncation error.
- Clean absolute paths in ResolveConfiguredPath so two spellings of the
  same jobs file do not trigger a spurious adoption.
- Report InstallDesktopIcon failures through ErrorOccurred instead of
  discarding them silently.
- Move settingsView's blocking AutostartStatus (PowerShell on Windows) off
  the UI thread.
- Give notify-timing.tsv its own extension so CleanupLogs no longer
  manages it as a run log.
- Replace the settingsView Save handler's second copy of validateConfig's
  rules with a bare parse, letting the Service's own error surface.

Cleanups:
- Delete collectActivity, the dead yaml tags on RunRecord, and the
  logArguments/LogArguments alias.
- Fold the two systemTrayRegistered/mainWindowHidden globals into one
  trayState instance Run owns and threads through Settings and the
  single-instance reveal path.
- Fix stale comments/docs: the frozen window-size restore claim, a
  reference to a renamed recordRun, README's "Pause all" and notification
  wording, the PowerShell quoting note for TESTS.md's coverage command,
  and scripts/test.bat's UTF-8 checkmarks under a non-UTF-8 code page.
- Document the single-instance fallback's consequence and the
  unauthenticated instance-channel port in STANDARDS.md; record the
  config-shim retirement plan in ROADMAP.md.

3.5, 7.3, and 9.4 turned out to already be fixed by earlier phases; no
change needed for those three.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-07 03:35:10 +03:00

12 KiB

GoSentry

GoSentry

GoSentry is a cross-platform desktop scheduler. It provides a native GUI for creating, grouping, pausing, running, and monitoring scheduled shell commands.

Screenshots

Jobs tab
Jobs tab — job list with details panel and run statistics.
Settings tab
Settings tab — application, queue, storage, and version info.

Features

  • Native desktop GUI built with Fyne.
  • Job definitions stored in a clean, hand-editable jobs.json.
  • @every intervals and standard 5-field cron expressions.
  • Manual and scheduled command runs.
  • Parallel or sequential execution mode; overlap policy (skip or queue) set globally or per job.
  • Run timeout, off by default, set globally or per job.
  • Per-run .log files with stdout/stderr capture.
  • Log cleanup by maximum file count and maximum age.
  • Global pause/resume for scheduled job execution (manual runs remain available).
  • 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).
  • Detailed or compact job list, and a system or branded theme; both are remembered.

Platforms

GoSentry is built and tested on Windows and Linux:

Platform Status Notes
Windows Supported Tray icon, autostart shortcut (.lnk), desktop integration.
Linux Supported Autostart via XDG desktop entry; desktop integration on X11/Wayland.
macOS Not supported The Fyne GUI may build, but autostart and desktop integration are not implemented.

Documentation

  • Changelog — record of notable changes by version
  • Roadmap — planned work larger than a single bug fix
  • Architecture — component interaction model
  • Standards — quality rules and intentional behavior
  • Development — build instructions, project layout, dependencies
  • Tests — test suite layout and how to run it
  • Performance — measured performance findings

Storage

GoSentry stores its files next to the executable by default, making it a portable application: moving the program folder also moves its configuration.

gosentry.json stores application settings:

{
  "jobs_file": "jobs.json",
  "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",
  "default_timeout_seconds": 0,
  "theme": "gosentry",
  "job_list_view": "detailed"
}

That is the file GoSentry writes on first run. default_timeout_seconds is the run timeout applied to jobs that do not set their own; 0 means no timeout, and it is written out even though it is zero, because a missing value and a deliberate "no timeout" have to stay distinguishable in a hand-edited file. theme is system or gosentry (the branded teal/amber look), and job_list_view is detailed or compact — both are remembered from the choices made in the app. Keys left at their off value (start_on_login, paused) are omitted until they are turned on.

jobs.json stores job definitions:

{
  "jobs": [
    {
      "id": 1,
      "name": "Hello scheduler",
      "folder": "Examples",
      "schedule": "@every 1m",
      "command": "echo GoSentry test job: scheduler is alive",
      "enabled": true
    }
  ]
}

jobs_file is the file GoSentry reads job definitions from, file name included, so the file can be named anything. The default "jobs.json" is relative and resolves to the executable's folder. An absolute path can be used when jobs should live elsewhere, such as a shared network drive.

A gosentry.json from an earlier version that carries jobs_dir instead keeps working: the directory is combined with jobs.json on load, and the file is rewritten with jobs_file.

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:

20260614-224306_Hello_scheduler.log

Schedules

GoSentry accepts two schedule forms: fixed @every intervals and standard 5-field cron expressions.

@every intervals

Write @every followed by a Go duration — a positive number with a unit suffix. Units can be combined in one value:

@every 10s          every 10 seconds
@every 5m           every 5 minutes
@every 1h           every hour
@every 1h30m        every hour and a half (same as @every 90m)
@every 2h45m10s     hours, minutes, and seconds combined

Supported units:

Unit Meaning
ns nanoseconds
us, µs microseconds
ms milliseconds
s seconds
m minutes
h hours

@every does not support days, weeks, months, or years — those follow a calendar, not a fixed interval. For “every day at 02:00”, “on the 1st of each month”, or “once a year”, use a cron expression (below).

The scheduler checks due jobs once per second, so values shorter than 1s are accepted but will not fire faster than once a second.

Cron expressions

Five fields: 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
0 0 1 * *        first day of every month at midnight
0 0 1 1 *        every year on 1 January at midnight

Named descriptors are also accepted: @hourly, @daily, @weekly, @monthly, @yearly (and @annually, @midnight).

Using The App

  1. Start GoSentry.
  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 Disable auto 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 the storage paths, log cleanup limits, queue behavior, and notifications.

The Jobs file row picks the file itself: Browse lists .json files, and a path can also be typed to name a file that does not exist yet. What Save does depends on whether that file is already there:

  • The file exists — its jobs are loaded and replace the current list, so selecting a jobs file switches to it (another machine's file, a shared one on a network drive). History records how many jobs were loaded and from where.
  • The file does not exist — the current jobs are written to it, which is how the jobs file is renamed or moved somewhere else.

Switching to a different jobs file is refused while a job is running, because loading a new list discards the run state of the old one.

The Start on login checkbox shows an OK or Problem status. Saving with it enabled writes an autostart entry using the current executable path. When Keep running in the system tray is also enabled, the entry includes --start-in-tray so scheduled jobs run after sign-in without opening the main window. With the tray option off, autostart still works but opens the main window normally. Changing the tray setting updates close behaviour and the autostart entry immediately; the tray icon itself updates only after you restart GoSentry (a Fyne limitation — see docs/ROADMAP.md).

Queue Settings

Three settings in the Queue group of the Settings tab control how simultaneous, overlapping, and over-long 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.

Default 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.

Default timeout (s) — how long a run may take before it is killed. 0 (the default) means no limit.

The last two are defaults: a job's own dialog has an Overlap policy and a Timeout (s) field that override them. A job that overrides nothing follows whatever the Settings tab says, so changing a default moves every such job with it. In jobs.json an override is an overlap_policy or timeout_seconds key on the job; absent means inherit. A "timeout_seconds": 0 on a job is an override too — it means that job has no timeout even when the global default sets one.

Notifications

When Notify on failure is enabled in Settings, GoSentry sends a desktop notification whenever a scheduled or manual run ends in the Failed state — a non-zero exit code, a timeout, or a process that failed to start. The notification shows the job name and the failure detail.

Autostart

GoSentry is a user desktop application, not a system daemon, so autostart is configured per user.

Linux:

# GoSentry writes an XDG Autostart desktop entry when Start on login is enabled.
~/.config/autostart/gosentry.desktop

[Desktop Entry]
Type=Application
Name=GoSentry
Exec=/opt/gosentry/gosentry-<version>-linux-amd64 --start-in-tray
Terminal=false

Windows:

# 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, 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:

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. 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:
dist\windows\
  gosentry-<version>-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.

Development assistance

Parts of this project were developed with assistance from Cursor AI (Composer agent) and Claude Code.