scheduled agents

Agents that run without you.

A routine is a real Claude- or Ollama-powered agent with tools, memory, and a budget, running on a systemd timer, on your machine, on your terms. Everyone else has agents you talk to. vinOS has agents that work while you sleep — briefing you at 6 am, reviewing your PRs at 1 pm, closing your day at 6 pm — and shut up when they have nothing to say. All output lands as human-readable markdown in ~/.vinos/routines/state/. Every run is metered in a SQLite ledger.

What is a routine, exactly?

One declarative TOML file. It names an agent, sets a cron-ish schedule, declares the tools the agent may call (read-globs and shell commands, both whitelist-enforced by the runtime — not by the model), points at an output destination, and caps the budget in tokens per run and dollars per day. vinos-routine enable <name> generates a systemd user timer. Every run executes shell tools inside a bwrap sandbox — no network unless you ask for it — and logs cost, duration, and exit status to ~/.vinos/routines/state/ledger.db.

Full spec: docs/v2/vinos-routine-spec.md.

Starter routines shipped in the ISO

All five live in /etc/vinos/routines/. All ship disabledvinos-welcome asks which you want active on first boot. Copy any to ~/.vinos/routines/ to customize; the user copy wins.

<div class="spec-block">
  <h3>day-brief</h3>
  <p><strong>06:00 daily</strong> · Morning brief: top 3 for today, tech/AI/OS signals, one reflection.</p>
  <p class="small-print"><code>vinos-routine enable day-brief</code></p>
[routine]
name = "day-brief"
enabled = false

[schedule]
oncalendar = "*-*-* 06:00:00"
jitter     = "5m"

[agent]
route  = "anthropic"
model  = "claude-sonnet-4-6"
tools  = [
  "read:~/Notes/today.md",
  "shell:gh api /notifications --paginate",
  "shell:gcalcli agenda today",
]

[output]
type = "brief"
open_on_login = true

[budget]
max_tokens_per_run  = 4000
max_dollars_per_day = 0.20
</div>

<div class="spec-block">
  <h3>github-review</h3>
  <p><strong>09:00 · 13:00 · 17:00</strong> · Summarizes new PRs across your repos and flags what needs your eyes.</p>
  <p class="small-print"><code>vinos-routine enable github-review</code></p>
[routine]
name = "github-review"

[schedule]
oncalendar = "*-*-* 09,13,17:00:00"

[agent]
route = "anthropic"
model = "claude-sonnet-4-6"
tools = [
  "shell:gh pr list --state=open --json url,title,author,updatedAt",
]
</div>

<div class="spec-block">
  <h3>evening-shutdown</h3>
  <p><strong>18:00 daily</strong> · What shipped today, what's stuck, tomorrow's top-3. Files a git note.</p>
  <p class="small-print"><code>vinos-routine enable evening-shutdown</code></p>
[routine]
name = "evening-shutdown"

[schedule]
oncalendar = "*-*-* 18:00:00"

[agent]
route = "anthropic"
model = "claude-sonnet-4-6"
# short prompt, three fixed sections

[budget]
max_tokens_per_run  = 3000
max_dollars_per_day = 0.20
</div>

<div class="spec-block">
  <h3>inbox-triage</h3>
  <p><strong>hourly</strong> · Reads unread mail, drafts responses, tags them — <strong>never sends</strong>. You approve and send yourself.</p>
  <p class="small-print"><code>vinos-routine enable inbox-triage</code></p>
[routine]
name = "inbox-triage"

[schedule]
oncalendar = "hourly"

[agent]
route = "auto"           # local first, escalate on complex threads
tools = [
  "read:~/inbox/*.eml",
  "shell:notmuch search tag:unread",
]

[output]
type = "notification"    # mako toast when N drafts ready
</div>

<div class="spec-block">
  <h3>research-recap</h3>
  <p><strong>22:00 nightly</strong> · Reads new saved articles/PDFs in <code>~/Reading</code>, generates cross-links and spaced-repetition cards.</p>
  <p class="small-print"><code>vinos-routine enable research-recap</code></p>
[routine]
name = "research-recap"

[schedule]
oncalendar = "*-*-* 22:00:00"

[agent]
route = "ollama"                # 80% case — pure summarization
model = "qwen2.5:7b"
tools = [
  "read:~/Reading/*.md",
  "read:~/Reading/*.pdf",
]
</div>

Three ways to install a routine

  1. 01

    Enable a shipped one

    Every starter above lives in /etc/vinos/routines/. Enable turns it on.

    vinos-routine enable day-brief
  2. 02

    Author your own

    Scaffold a routine, edit in your $EDITOR, enable when ready.

    vinos-routine create weekly-review && vinos-routine edit weekly-review
  3. 03

    Load from a project

    Drop a .vinos/routines.yaml in your repo — teammates run vinos-routine load . after clone and inherit the same agent set. The way .github/workflows/ did for CI.

    git clone git@github.com:acme/monorepo && cd monorepo && vinos-routine load .

The CLI

vinos-routine list All routines + next-run + last status
vinos-routine enable <name> Activate the systemd timer
vinos-routine run <name> Ad-hoc run, streams to stdout
vinos-routine logs <name> --tail Per-routine execution log
vinos-routine cost --today Ledger summary + top spenders
vinos-routine create <name> Scaffold a new routine from a template
vinos-routine load <path> Install all routines in a repo's .vinos/routines.yaml

Full CLI + waybar module + vinos-brief panel: vinos-routine-spec.md.

Build your own

The spec is short and reads in ten minutes. Two files cover everything:

The runtime is deliberately boring: whitelist-enforced tools, bwrap sandbox, atomic writes to the state store, hard budget caps in a SQLite ledger, auto-disable after 3 consecutive failures. If it fails, you get a mako notification — never a silent drop.

Community-contributed routines

Coming in v2.0.6. The submission flow — vinos-routine install <slug>, a public gallery, per-author sponsor profiles — lands with the next release. In the meantime, share your TOMLs in GitHub Discussions and we'll help you get them installed.