Skip to content

Automation and scheduling

Responsibility

The scheduler executes configured recurring and one-shot tasks, records history, exposes operational state, and coordinates domain jobs such as synchronization, publishing, ingestion, maintenance, and planning refresh.

The automation feature owns the task-scheduler screen and interval conversion utilities. The control-center feature owns the operational dashboard, history, members, and directive dialogs. Each has a public lazy route entry; shared API adapters preserve task identity, interval units, permission checks, and payloads. Moving a screen never enables a task or starts a job.

Scheduler task metadata, persisted runtime state, and the optional notification boundary are strictly typed in dedicated modules. The manager remains below the source-size guardrail and validates legacy persisted task dictionaries before constructing runtime tasks.

Task model

A task definition has stable identity, enabled state, schedule, operation, configuration, and execution policy. Task history records start, completion, status, message, and duration. Definitions and connection settings are aligned before execution so a job cannot accidentally use a removed or different integration.

Execution flow

sequenceDiagram
    participant Clock as Scheduler clock
    participant Manager as Scheduler manager
    participant History as Execution history
    participant Job as Domain job or skill
    Clock->>Manager: Task is due
    Manager->>Manager: Validate enabled config and overlap policy
    Manager->>History: Record running attempt
    Manager->>Job: Execute with isolated context
    Job-->>Manager: Result or controlled error
    Manager->>History: Persist status, message, duration

Task functions must be idempotent where repetition is possible. The manager guards overlapping instances according to task policy and uses fresh database or provider contexts. A process restart reconciles schedules from persisted configuration instead of trusting only in-memory state.

Native startup enables the scheduler by default. Deterministic smoke tests and diagnostic sessions over real local data may set GNOSI_DISABLE_SCHEDULER=1 so the API and UI can be verified without firing overdue third-party integrations; this switch does not alter persisted task configuration.

The manager owns scheduling lifecycle, persistence, overlap control, and task history. task_handlers.py owns dispatch policy and the larger operational task bodies, including bounded maintenance. This keeps task execution reusable and strictly typed without coupling it back to the scheduler thread lifecycle.

Operational notifications are dispatched through a provider-neutral platform boundary. Database and per-device Markdown persistence remain available on every host; native macOS alerts are best effort. Markdown logs live below GNOSI_DATA_DIR, never inside a OneDrive-, Google Drive-, Nextcloud-, Dropbox- or other provider-specific Vault path, and one failed channel cannot block the others. The historical notification skill path is a compatibility facade only.

Academic synchronization and review updates

academic_repository_sync is a durable, resumable job for local OAI indexes. Its cursor, counts, error, cancellation state, and last successful synchronization are persisted outside the request process. An administrator explicitly starts the first harvest; after it completes, daily incremental scheduling resumes from the repository's last completed checkpoint and applies OAI tombstones.

Saved review strategies may also schedule academic_review_update jobs. A run replays the versioned strategy, records exact per-source activity and partial errors, and registers only candidates whose deterministic identity is new to that review. The next run is persisted with the review configuration rather than held only by the scheduler process.

The queue requires an explicit LOCAL_DATA root and fails before opening SQLite when configuration is incomplete. Worker adapters narrow opaque queue payloads to concrete mappings before dispatch, and legacy dispatcher registration rejects a missing callable before constructing its typed contract. Scheduled contact synchronization constructs each engine with explicit database, workspace, and integration arguments, preventing account payloads from being misbound to workspace identity as service signatures evolve.

Academic scheduler adapters resolve the active Vault before entering literature storage. A first-run process without a configured Vault records a successful, structured skip with zero queued jobs instead of constructing Path(None). Reader queue recovery likewise verifies that the provider-owned job document still exists before claiming work; orphaned queue records are rejected once and never create failing worker threads.

Vault automations

Vault automation rules combine triggers, conditions, and actions. Derived field formulas and rollups are deterministic evaluation, not arbitrary code execution. External or destructive actions use the same authorization and confirmation boundaries as interactive actions.

Autonomous quality work

Maintenance and quality loops are bounded operational tasks. They may diagnose, generate reports, or apply changes within their declared scope. They do not gain broader filesystem, secret, Git, or publishing authority because they are scheduled.

Per-device maintenance boundary

system_maintenance clears the in-memory application cache and truncates only the regular, singly linked logs/gnosi.log under the canonical GNOSI_DATA_DIR, only when selected by the active LOG_FILE configuration. It preserves the log inode for the running logger. Directory components and the file must not be symlinks; invalid paths or platforms without safe directory-relative operations skip disk cleanup instead of following them.

It does not clean source trees, Python bytecode, arbitrary configured logs, private workspace mailboxes, databases, secrets, Vault documents or synchronized folders. The legacy mailbox, temporary-file and bytecode counters remain in the response with zero values. Filesystem cleanup of old development checkouts is a separate, explicitly reviewed workspace operation, not an application schedule.

Daily audio generation

The Reader podcast service uses typed model and language selection, bounded sentence-level TTS workers, and atomic MP3 replacement. Background generation captures the selected Vault explicitly and refuses to start when no Vault is active, so output cannot fall through to an ambiguous local path.

Invariants

  • Disabled or invalid tasks do not execute.
  • A task run has one durable history outcome.
  • Retries do not duplicate external effects without an idempotency strategy.
  • Connection deletion or reassignment updates dependent schedules.
  • Scheduling uses explicit time zone semantics.
  • Job exceptions are isolated from the scheduler loop.
  • Background work does not reuse request-scoped database sessions.
  • A cancelled OAI harvest keeps its durable cursor and can be resumed.
  • Scheduled review refreshes are idempotent for the same deduplicated work.

Verification focus

Test config resilience, connection alignment, planning schedules, task history, overlap prevention, time zones, retry/idempotency, OAI resume and cancellation, tombstones, review new-result detection, and maintenance path confinement, plus the Playwright automation scout. A representative scheduled integration should run end to end against a safe fixture or test account.

Unified activity centre

The dashboard owns schedules, execution history and pending approvals. Schedules distinguish personal skill automations from system maintenance and integration tasks. Settings keeps models, agents, skills and tools; legacy operations tabs redirect to the dashboard. The standalone scheduler URL redirects to the system schedule view.

Personal schedules support intervals, daily local times and selected weekdays, with an explicit IANA timezone. A nonexistent spring-forward time moves forward by the DST gap; an ambiguous autumn time runs at its first occurrence only. Editing unrelated fields preserves the next occurrence. The additive automations_0002 migration preserves existing interval schedules and adds a bounded final response to execution history.

The history endpoint joins definitions and runs within the current Vault, workspace and user scope. Pagination and the loaded-page filter limitation are visible. System history, background jobs and personal runs have distinct origins. The internal automation dispatcher is hidden until technical activity is enabled. System run details translate generic completion messages without claiming that work was performed when the log does not record it. A schedule link opens the specific system service; run references and original diagnostic messages are collapsed, labelled and copyable for support. Failures are displayed separately from empty results. Deleting an automation retains the historical storage rows but removes them from the joined personal history; this endpoint is operational history, not a permanent audit archive.