Skip to main content

Event system for AI CLI agents

Project description

trigr

Make any AI coding agent autonomous.

AI coding agents like Claude Code are reactive — they only work when a human types a message. Frameworks like OpenClaw solve this with a full platform, but sometimes you just want to add events to the agent you already use.

trigr is a lightweight event system that delivers events into a running agent session. The agent calls trigr watch, goes to sleep, and wakes up when something happens.

Agent runs trigr watch (background task or blocking)
    → blocks until event
    → event arrives → prints JSON → exits
    → agent wakes up, processes event
    → agent runs trigr watch again
    → "asleep" until next event

One tool. One pattern. Works with Claude Code, Codex, and Gemini CLI.

Install

uv tool install trigr

Quick Start

# Initialize trigr in your project
trigr init

# Terminal 1: watch for events (auto-starts server)
trigr watch

# Terminal 2: send an event
trigr emit hello --data '{"msg": "world"}'
# → Terminal 1 prints the event JSON and exits

Agent Integration

Claude Code

trigr watch runs as a background task — the agent can chat with the user while waiting for events. When an event arrives, the background task exits and the agent gets notified.

# In a Claude Code skill or agent instruction:
# "Run trigr watch as a background task. When it completes, process the event and restart."
trigr watch --timeout 3600

Codex CLI / Gemini CLI

trigr watch runs as a blocking call. The agent waits for the next event, processes it, and restarts the loop.

Agent How trigr watch runs Background chatting?
Claude Code Background task Yes
Codex CLI Blocking call No (not needed)
Gemini CLI Blocking call No

Event Sources

trigr supports three ways to produce events:

1. Manual / Programmatic

Anything can POST events — other terminals, scripts, webhooks, other agents:

trigr emit code_review --data '{"pr": 42, "repo": "myapp"}'

2. Pollers

Shell commands that run on an interval. If stdout is non-empty, it becomes an event:

[pollers.check-inbox]
interval = 60
command = "python check_mail.py"

3. Cron Jobs

Shell commands on a cron schedule:

[crons.daily-summary]
cron = "0 9 * * *"
command = "python daily_report.py"

Pollers and cron commands are language-agnostic. Write a script in any language that prints JSON to stdout. trigr runs it on schedule.

Delayed Events

The agent can schedule its own future events — perfect for follow-ups:

# "Follow up in 48 hours if no response"
trigr emit followup --data '{"candidate": "C-4821"}' --delay 48h

# Supported units: s (seconds), m (minutes), h (hours), d (days)

trigr.toml

Project-local configuration. Created by trigr init.

[server]
host = "127.0.0.1"
port = 9374

[pollers.check-inbox]
interval = 60
command = "python check_mail.py"

[crons.morning-sync]
cron = "0 9 * * *"
command = "echo '{\"type\": \"morning\"}'"

Add jobs from the CLI:

trigr add inbox-check --interval 60 --command "python check_mail.py"
trigr add daily-report --cron "0 9 * * *" --command "python report.py"

Commands

Command Description
trigr init Create trigr.toml in the current directory
trigr serve [-f] Start server (detached by default, -f foreground)
trigr watch [--timeout 300] Block until event, print JSON, exit
trigr emit <type> [--data '{}'] [--delay 10s] Push event to queue
trigr add <name> -c "cmd" (--interval N | --cron "...") Add poller/cron to config
trigr status Show server state

How It Works

trigr serve → FastAPI server + APScheduler
                ├── POST /emit    (push events to priority queue)
                ├── GET  /next    (long-poll, blocks until event ready)
                └── GET  /status  (queue depth, registered jobs)

Events sit in an in-memory priority queue sorted by delivery time. GET /next blocks until an event whose fire_at has passed, then returns it as JSON.

The server auto-starts when you run trigr watch or trigr emit. A .trigr.pid file lives next to trigr.toml, so multiple projects can run independent servers on different ports.

Poller Output Format

Poller commands should print JSON to stdout. If the JSON has a type field, it's used as the event type. Otherwise it defaults to poller.<name>.

# Poller script example
echo '{"type": "new_email", "data": {"from": "jane@example.com", "subject": "Re: Role"}}'

If stdout is empty, no event is created. This lets pollers silently skip cycles when nothing is new.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

trigr-1.0.2.tar.gz (28.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

trigr-1.0.2-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file trigr-1.0.2.tar.gz.

File metadata

  • Download URL: trigr-1.0.2.tar.gz
  • Upload date:
  • Size: 28.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for trigr-1.0.2.tar.gz
Algorithm Hash digest
SHA256 2781c7452d9b01cedecbd144e93d4f65a52504f5578034a0bf97c287bd940023
MD5 62327c3fbedfc75ac249b15b5a4253e7
BLAKE2b-256 1562b272e86d2918ffd9892cc60e516f6f4b3d4e931dccc31d9ee73feb498e3c

See more details on using hashes here.

File details

Details for the file trigr-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: trigr-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for trigr-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 314d65a004faefd10e8477bc889bea9ff542f2329c76853fcf23fa36dfa11b9c
MD5 8a4dfc304f52ee4124e39ae90db1ddde
BLAKE2b-256 ecabac2bd9f17a738e64d9a05ca3963cbde81f4317d5fa6a0792b49e04c027ef

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page