Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Open Routines

Schedule, run, and verify OpenCode tasks in the background — driven by natural language through MCP, managed from a web UI, and kept alive by your OS as a native service.

CI Release License: GPL v3 Go Platforms

Website: 4nkitd.github.io/open-routines

Open Routines is a single Go binary that exposes a Model Context Protocol (MCP) server. It lets an OpenCode agent create routines — one-time or recurring tasks — that are executed later by a fresh OpenCode instance, then independently verified by a second one.

Tell your agent:

"Every day at 8 AM, check my emails and send me a summary to ntfy."

…and it will gather the details, register a routine, and the scheduler takes care of the rest — even after reboots.


Table of contents


Features

  • MCP-native — 7 tools (routines_create/list/get/update/delete/trigger/runs) over a Streamable-HTTP endpoint, ready to drop into any MCP client.
  • One-time & recurring — standard 5-field cron, @hourly/@daily/@every 30m descriptors, or a single RFC3339 timestamp.
  • Execute → Verify — each run executes your prompt with OpenCode, then a separate OpenCode instance judges whether it actually succeeded and records a verdict.
  • Runs as a native service — installs into systemd (Linux), launchd (macOS), or the Windows Service Manager, so routines keep firing in the background and across reboots.
  • Web UI — a clean dashboard on a non-standard port (47600) to create, edit, trigger, enable/disable routines and browse run history, with a live "next fire times" preview while you type a schedule.
  • Webhook notifications — get a JSON POST when a run fails (or on every run), globally or per routine.
  • File logging with monthly rotation — daemon logs go to logs/routines-YYYY-MM.log; the last 6 months are kept.
  • Cross-platform, pure Go — no CGO, builds and runs identically on macOS, Linux, and Windows.
  • Embedded storage — routines and run history live in a single bbolt file. No external database.

How it works

flowchart LR
    A[OpenCode agent] -- routines_create --> B(MCP server)
    U[You / Web UI] -- REST --> B
    B --> S[(bbolt store)]
    B --> SCH{Internal scheduler}
    SCH -- at scheduled time --> E[Executor:\nopencode run]
    E --> V[Verifier:\nsecond opencode\nJSON verdict]
    V --> S
    OS[systemd / launchd / SCM] -. keeps daemon alive .-> B
Loading
  1. Plan — the agent calls routines_create with a self-contained prompt, a working directory, and a schedule.
  2. Store — the routine is saved to bbolt and its next run time is computed.
  3. Execute — at the scheduled moment the daemon runs opencode run "<prompt>" --dir <dir> in the target directory.
  4. Verify — a second OpenCode instance inspects the output and returns {"success": …, "reason": …}. The result is stored, and recurring routines are rescheduled (one-time routines disable themselves).

Design note: the daemon uses the OS service manager to guarantee it survives reboots, and runs a precise internal cron scheduler inside that always-on process. This is more reliable and portable than writing individual crontab / Task Scheduler entries per routine.


Requirements

  • OpenCode installed and authenticated (opencode auth login). The routine runner shells out to the opencode CLI, so whichever models/providers you've configured are what routines will use.
  • Go 1.25+ — only required to install/build from source.

Installation

Option A — prebuilt binaries (recommended)

Download the archive for your OS/arch from the latest release, extract it, and put routines somewhere on your PATH:

# example: macOS Apple Silicon
tar -xzf routines_*_darwin_arm64.tar.gz
sudo mv routines /usr/local/bin/

Option B — go install

go install github.com/4nkitd/open-routines/cmd/routines@latest

This puts a routines binary in $(go env GOPATH)/bin (make sure that's on your PATH).

Option C — build from source

git clone https://github.com/4nkitd/open-routines.git
cd open-routines
go build -o routines ./cmd/routines

Register the background service

routines install

This registers and starts routines as a per-user service (launchd LaunchAgent / systemd user service / Windows service) and prints the Web UI + MCP URLs and a ready-to-paste OpenCode config snippet.

Other lifecycle commands:

routines status      # running / stopped
routines stop
routines start
routines restart
routines uninstall    # stop + remove the service
routines info         # show config paths and the MCP URL

Connect it to OpenCode

Add the server to your OpenCode config (~/.config/opencode/opencode.json):

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "routines": {
      "type": "remote",
      "url": "http://127.0.0.1:47600/mcp",
      "enabled": true
    }
  }
}

Restart OpenCode and the routines_* tools become available to the agent.


Usage

Via the agent (MCP)

Just ask in natural language. The agent maps your request onto the tools:

"Create a routine that runs every weekday at 9am in ~/work/reports, generates the daily standup notes from git log, and posts them to my ntfy topic standup."

"List my routines and show the last run of the email one."

"Disable the blinkit routine."

Via the web UI

Open http://127.0.0.1:47600:

  • Active routines — create, edit, Run now, enable/disable, delete.
  • Run history — filter by routine, see every run, click a row to expand execution + verification output.

Via the CLI

The CLI manages the service itself; routines are managed via the agent, the web UI, or the REST API.


Scheduling reference

Type once schedule example Meaning
Cron false 0 8 * * * every day at 08:00
Cron false */5 * * * * every 5 minutes
Descriptor false @hourly, @daily shorthand intervals
Descriptor false @every 30m, @every 1h30m fixed interval
One-time true 2026-01-02T08:00:00+05:30 run once at an absolute time (RFC3339)
One-time true 2026-01-02 08:00 run once (local time, friendly format)

Cron fields are the standard five: minute hour day-of-month month day-of-week.


Configuration

Config lives at <config-dir>/routines/config.json:

OS Path
macOS ~/Library/Application Support/routines/
Linux ~/.config/routines/
Windows %AppData%\routines\
{
  "host": "127.0.0.1",
  "port": 47600,
  "opencode_path": "/path/to/opencode",
  "default_model": "",
  "db_path": ".../routines/routines.db",
  "timeout_seconds": 900,
  "webhook_url": "",
  "webhook_events": "failure"
}
  • port — non-standard by default to avoid collisions; change it and re-run routines restart (update your OpenCode config URL too).
  • opencode_path — auto-resolved at install time; set explicitly if opencode isn't on the service's PATH.
  • default_model — used when a routine doesn't specify its own model. Leave empty to use OpenCode's own default.
  • timeout_seconds — default per-run timeout; overridable per routine.
  • webhook_url — global webhook that receives a JSON POST after runs finish; overridable per routine.
  • webhook_eventsfailure (default, notify only on failed / verify-failed runs) or all (also on success).

Webhook notifications

Set webhook_url globally in config.json, or per routine (web UI field, webhook_url in the MCP/REST create/update payloads). The per-routine URL wins when both are set.

After a run finishes, the daemon POSTs:

{
  "event": "run.failed",
  "routine_id": "",
  "routine_name": "Daily email check",
  "run_id": "",
  "status": "verify_failed",
  "error": "",
  "started_at": "2026-07-02T08:00:01+05:30",
  "ended_at": "2026-07-02T08:03:12+05:30",
  "duration_seconds": 191.2
}
  • event is run.failed or run.succeeded (run.succeeded is only sent when webhook_events is "all").
  • Delivery is retried up to 3 times with backoff; a 2xx response counts as delivered.
  • Works out of the box with ntfy, Slack incoming webhooks (via a bridge), Discord (via /slack proxies), or your own endpoint.

Logs

The daemon writes logs to <config-dir>/routines/logs/routines-YYYY-MM.log, rotating to a new file each month and keeping the last 6 months. routines info prints the log directory.


MCP tools

Tool Description
routines_create Create a routine (name, prompt, schedule, once, directory, model, verify_prompt, timeout_seconds, webhook_url).
routines_list List all routines with status and next run time.
routines_get Fetch one routine by id.
routines_update Patch any field of a routine (only provided fields change).
routines_delete Delete a routine and its run history.
routines_trigger Run a routine immediately, regardless of schedule.
routines_runs List run history, optionally filtered by routine_id.

REST API

The web UI is built on a small JSON API (same port):

Method & path Purpose
GET /api/routines list routines
POST /api/routines create routine
GET /api/routines/{id} get routine
PUT /api/routines/{id} update routine
DELETE /api/routines/{id} delete routine
POST /api/routines/{id}/trigger run now
POST /api/routines/{id}/toggle enable/disable
GET /api/runs?routine={id}&limit={n} run history (limit=0 = all)
GET /api/schedule/preview?schedule={expr}&once={bool} next 5 fire times for a schedule expression
GET /api/info port, opencode path, MCP URL

Security

Warning

Routines execute opencode run with --dangerously-skip-permissions so they can run unattended. A routine prompt can do anything your user account can do (run commands, edit files, make network calls). Only create routines you trust, and keep the server bound to 127.0.0.1 (the default). Do not expose port 47600 to untrusted networks.


Troubleshooting

Symptom Likely cause / fix
Runs fail instantly with a model error The routine/default_model/OpenCode default points at an unavailable model. Set a valid model on the routine.
opencode: executable file not found Set opencode_path in config.json, then routines restart.
Web UI/MCP unreachable routines status; check the port isn't taken; confirm the URL in your OpenCode config.
Routine never fires Make sure it's enabled and the cron/once time is in the future; check routines status.
Browser/login tasks fail Tasks needing a logged-in browser session require that session to already exist; verification will report the failure reason.

Inspect run output and the verifier's verdict in the Run history panel or via GET /api/runs.


Contributing

Issues and PRs welcome. Please keep changes cross-platform (no CGO) and run go build ./..., go vet ./... and go test ./... before submitting — CI runs the same checks. Releases are cut automatically by GoReleaser when a v* tag is pushed. See the Wiki for architecture details.


License

Released under the GNU General Public License v3.0. See LICENSE.

About

Open Routines is a single Go binary that exposes a Model Context Protocol (MCP) server. It lets an OpenCode agent create routines — one-time or recurring tasks — that are executed later by a fresh OpenCode instance, then independently verified by a second one.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages