Skip to content

feat: add workspace automations with scheduled daemon sessions - #98

Open
CompN3rd wants to merge 5 commits into
jmfederico:mainfrom
CompN3rd:feat/workspace-automations
Open

feat: add workspace automations with scheduled daemon sessions#98
CompN3rd wants to merge 5 commits into
jmfederico:mainfrom
CompN3rd:feat/workspace-automations

Conversation

@CompN3rd

@CompN3rd CompN3rd commented Jul 25, 2026

Copy link
Copy Markdown

Summary

This PR adds a machine-owned Automations tab for running prompts in fresh Pi sessions—on demand or on durable schedules—without requiring the browser or autoreloading web/API process to remain connected.

It includes the complete workflow: authoring and testing jobs, schedule validation, durable dispatch, cancellation and timeout handling, session inspection, usage/cost reporting, remote-machine routing, and an operations dashboard.

Workspace Automations dashboard

What users can do

Create and schedule automations

  • Create workspace-scoped jobs with a name and Pi prompt.
  • Run jobs manually, once at a future time, at a fixed interval, or using a six-field cron expression with an explicit IANA timezone.
  • Choose the machine's default model or pin an exact provider/model.
  • Select only thinking levels supported by the chosen model; unsupported pinned values remain visible when editing existing data, but cannot be newly selected accidentally.
  • Configure execution timeouts from 1 minute to 24 hours.
  • Run a job immediately, enable/pause scheduling, edit it, cancel an active run, or delete it.

Operate and inspect jobs

The Automations tab is also an operations dashboard with:

  • total, active, and attention-needed run counts;
  • median and p95 execution duration;
  • root-session token totals and estimated spend;
  • a timeline showing run activity;
  • per-automation usage and cost summaries;
  • job cards showing revision/test state, next run, last result, model, thinking level, timeout, and cumulative usage;
  • a run inbox with status, queued/started/completed timestamps, duration, actual model/thinking configuration, usage, errors, and links to the resulting Pi session.

The panel refreshes more aggressively while runs are active and backs off while idle, pauses refreshes while hidden, and rejects stale responses after switching machine or workspace.

Core design decisions

Sessiond owns execution

Scheduling, persistence, and automation-created Pi sessions live in pi-web-sessiond, not the browser or web/API process. This follows PI WEB's split-runtime model: browser disconnects and UI/API autoreloads do not interrupt active automation runs.

The API remains thin and machine-aware. Local and federated requests are forwarded to the selected machine's daemon, where definitions and execution remain machine-local.

Durable state with immutable run snapshots

Definitions, revisions, scheduled occurrences, attempts, cancellation intent, deadlines, actual model/thinking settings, errors, and terminal usage are stored in a WAL-enabled SQLite database under $PI_WEB_DATA_DIR.

Each claimed run freezes the relevant automation name, prompt, workspace, and configuration. Editing a job therefore changes future runs without rewriting historical records. A single-owner fence prevents multiple daemons from concurrently scheduling against the same database.

Test before unattended execution

New jobs are created disabled. A successful manual run records the exact tested revision; enabling is permitted only for that revision. Editing a job increments its optimistic revision, pauses it, and invalidates the previous test result.

This is intentional friction: users must validate the current prompt and settings before allowing unattended execution, and concurrent/stale edits receive a conflict rather than silently overwriting newer changes.

Prefer avoiding duplicate side effects

  • Only one run per automation may be active at a time; overlapping occurrences are durably recorded as skipped.
  • The daemon currently runs at most two automation sessions concurrently, queueing additional work.
  • Missed recurring schedules are coalesced into one due occurrence plus the next future occurrence instead of replaying a potentially dangerous backlog.
  • After a daemon restart, ambiguous starting, running, or cancelling attempts become unknown; they are not blindly replayed.

These choices favor avoiding duplicate filesystem, network, or tool side effects over guaranteed at-least-once execution.

Fresh sessions, not an OS sandbox

Every run starts a fresh Pi session and reapplies the resolved model and thinking policy at dispatch. The daemon reauthorizes the stable projectId/workspaceId immediately before execution; callers cannot provide an arbitrary cwd. Fixed models are validated when saved and again when dispatched, with no silent fallback.

A fresh conversation is intentionally not presented as a security sandbox. Automations still inherit the selected machine user's filesystem, network, credentials, processes, and available Pi tools. The UI/docs make unattended execution and its external side effects explicit.

Bounded cancellation and honest recovery states

Cancellation intent is persisted before contacting the running session. PI WEB first requests a soft abort, then uses a bounded force-stop path after a grace period. Confirmed aborts become cancelled or timed_out; if termination cannot be proven, the run becomes unknown rather than falsely claiming success.

Completed sessions remain available for inspection. While an automation owns an active session, normal interactive mutations are rejected so user actions, idle cleanup, and automation lifecycle management cannot race each other.

Telemetry reports what is actually known

Terminal runs freeze root-session input/output/cache token counts and estimated cost in integer micros, together with the actual model and thinking level used. Partial or unavailable accounting is represented as unknown and excluded from numeric totals instead of being displayed as zero.

This intentionally reports the root automation session only. Untracked subagents, detached children, and external paid tools are not claimed as part of the estimate until explicit lineage/accounting exists.

Capability-gated federation

The tab appears only when both the web/API runtime and target session daemon advertise the automations capability. All definition, model, run, and cancellation routes participate in the existing federation layer, so the same UI works against local and registered remote machines without replicating automation state between them.

Implementation outline

  • AutomationsPanel provides the editor, dashboard, polling lifecycle, controls, and session links.
  • Machine-aware client APIs and federated routes carry automation requests to the target daemon.
  • AutomationService coordinates revision policy, scheduling, concurrency, lifecycle, recovery, realtime events, and telemetry.
  • AutomationStore owns durable SQLite state, claiming, immutable snapshots, ownership fencing, and restart recovery.
  • AutomationSessionRunner creates fresh sessions and applies exact model/thinking/timeout settings.
  • PiSessionService tracks automation ownership and provides awaitable prompt, abort, and force-stop lifecycle operations.

Validation

  • npx tsc --noEmit — passed
  • npm run build — passed
  • Full Vitest run: 1768 passed, 34 skipped
  • One existing sessionController.tree.test.ts assertion fails identically with the relevant files replaced by their exact jmfederico/main versions; it is unrelated to this feature.
  • The screenshot follow-up commit passed the repository's staged typecheck, Knip, and related Vitest checks.

Coverage includes schedule/timezone/rate and timeout validation, missed-run coalescing, revision/test-before-enable behavior, optimistic edit conflicts, workspace authorization, ownership fencing, immutable run snapshots, overlap and cancellation races, usage freezing, restart recovery, force-stop behavior, model-specific thinking choices, API parsing/URL encoding, federated forwarding, capability negotiation, and Automation panel behavior.

Operational note

This PR changes src/server/sessiond.ts and daemon-only session lifecycle paths. Testing or deployment requires a manual restart of pi-web-sessiond.service (or the environment-specific sessiond service), not only a web/API reload.

Marc Kassubeck added 3 commits July 25, 2026 12:09
…ssions

Manual, one-shot, interval, and timezone-aware cron triggers per workspace
on local and federated machines. Each machine stores and runs its own
schedules in fresh daemon-owned Pi sessions with fixed model/thinking
settings, configurable timeouts, durable cancellation, immutable run
history, and duration/token/cost reporting.

Thinking-level selection in the automations editor is scoped to the levels
the selected model actually supports.
@CompN3rd
CompN3rd marked this pull request as ready for review July 25, 2026 10:40
Marc Kassubeck added 2 commits July 26, 2026 20:47
…tomations

# Conflicts:
#	src/server/sessiond.ts
#	src/shared/apiTypes.ts
…tomations

# Conflicts:
#	src/client/src/api.ts
#	src/server/sessiond.ts
#	src/server/sessions/piSessionService.ts
#	src/shared/capabilities.test.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant