Operation Pipeline Interface
One operational path from every signal to the right human, agent, or system.
Quick start · Why op_pi · Interfaces · Security · Operations
CI failures, cloud alerts, GitHub activity, agent hooks, and live tmux sessions all speak different protocols. Teams usually connect them with one-off webhook scripts until nobody can explain why an alert reached one channel, missed another, or triggered an action.
op_pi gives those signals one typed, inspectable path.
intake -> normalize -> validate -> route -> render -> deliver
|
Provider-native intake GitHub, Git, AWS, Cloudflare, Discord, tmux, Codex, Claude, and custom events. |
Typed routing Match event families and payload metadata instead of parsing message text. |
Interface-aware delivery Render once, then deliver to Discord, Slack, local files, or an intentional drop. |
Operational control Explain decisions, inspect source health, bound logs, and keep cloud ingress closed by default. |
git clone https://github.com/IYENTeam/op_pi.git
cd op_pi
./install.sh --skip-star-promptThe installed command is op_pi.
# ~/.op_pi/config.toml
[providers.discord]
token = "DISCORD_BOT_TOKEN"
default_channel = "DISCORD_CHANNEL_ID"
[[routes]]
event = "github.*"
sink = "discord"
channel = "DISCORD_CHANNEL_ID"
format = "compact"op_pi start
op_pi status
op_pi explain github.pr-status-changed repo=my-app number=42The daemon listens locally at http://127.0.0.1:25294.
curl -fsS http://127.0.0.1:25294/health| Point integration | op_pi |
|---|---|
| Each provider owns its own delivery logic | Providers only produce normalized events |
| Message text becomes accidental routing state | Typed fields and explicit filters decide routes |
| One input maps to one hard-coded destination | One event resolves to zero, one, or many deliveries |
| Authentication varies by copied script | Intake security is centralized and testable |
| Failures repeat forever in unbounded logs | Health, backoff, deduplication, and rotation are built in |
| Nobody can preview a routing decision | op_pi explain shows the route without dispatching |
flowchart LR
subgraph Sources
GH[GitHub + Git]
AG[Agent hooks]
CL[Cloud events]
TM[tmux + Discord]
end
subgraph op_pi
IN[Intake]
EN[Typed envelope]
RT[Routes + policy]
RD[Renderer]
IN --> EN --> RT --> RD
end
subgraph Interfaces
DC[Discord]
SL[Slack]
LF[Local JSONL]
DR[Drop]
end
GH --> IN
AG --> IN
CL --> IN
TM --> IN
RD --> DC
RD --> SL
RD --> LF
RD --> DR
One event can fan out across interfaces. Rendering and transport stay separate, so the same operational fact can be compact in a routine channel, prominent in an escalation channel, and complete in an audit file.
| Source | Interface | Typical events |
|---|---|---|
| Git | local poller and CLI | commits, branch changes |
| GitHub | API poller, webhook, and CLI | issues, pull requests, CI |
| Codex and Claude | provider-native hook bridge | session and tool lifecycle |
| tmux | monitored sessions | keywords, stale sessions, recovery |
| Discord threads | Discord API monitor | thread creation and activity |
| AWS SNS | POST /aws/sns |
CloudWatch alarms, SNS notifications |
| AWS EventBridge | POST /aws/eventbridge |
GuardDuty, Health, EC2, custom events |
| Cloudflare Notifications | POST /cloudflare |
alert policies and health checks |
| Cloudflare Logpush | POST /cloudflare/logpush |
firewall and audit batches |
| Linear webhooks | POST /linear |
issues, labels, SLA, and other signed Linear events |
| Google Calendar | POST /google/calendar |
watch synchronization and resource changes |
| Custom systems | CLI and POST /api/event |
internal operational signals |
| Interface | Targets | Behavior |
|---|---|---|
| Discord | channels, threads, webhooks | explicit targets, rate-limit handling |
| Slack | channels and incoming webhooks | Block Kit rendering, 429 and 5xx retry |
| Local files | JSONL paths | rendered, bounded local capture; not an authoritative raw-event audit trail |
| Drop | explicit route | acknowledge noise without accidental delivery |
[providers.slack]
token = "xoxb-..."
default_channel = "C_OPERATIONS"
[aws]
topic_allowlist = [
"arn:aws:sns:us-east-1:123456789012:operations"
]
[[routes]]
event = "aws.cloudwatch-alarm"
sink = "slack"
channel = "C_OPERATIONS"
format = "alert"[aws]
webhook_secret = "EVENTBRIDGE_SHARED_SECRET"
[cloudflare]
webhook_secret = "CLOUDFLARE_NOTIFICATION_SECRET"
logpush_secret = "CLOUDFLARE_LOGPUSH_SECRET"
[[routes]]
event = "aws.eventbridge.guardduty-*"
sink = "discord"
channel = "SECURITY_CHANNEL_ID"
format = "alert"
[[routes]]
event = "cloudflare.health_check_status_notification"
sink = "slack"
channel = "C_EDGE_OPERATIONS"
format = "alert"
[[routes]]
event = "cloudflare.logpush.audit_logs_v2"
sink = "localfile"
local_path = "/var/log/op_pi/cloudflare-audit.jsonl"[linear]
webhook_secret = "LINEAR_WEBHOOK_SECRET"
[[routes]]
event = "linear.issue-label-update"
sink = "discord"
channel = "TRIAGE_CHANNEL_ID"
format = "compact"See the Linear intake guide for signature, acknowledgement, retry, and delivery caveats.
[providers.slack]
bot_token = "xoxb-your-slack-bot-token"
[google_calendar]
# At least 32 bytes when credentials_file/state_file enable durable sync.
channel_token = "replace-with-a-random-channel-token"
credentials_file = "/Users/you/.op_pi/google-calendar-oauth.json"
state_file = "/Users/you/.op_pi/google-calendar-state.json"
calendar_id = "primary"
callback_url = "https://ops.example.com/google/calendar"
renewal_margin_secs = 86400
[[routes]]
event = "calendar.*"
sink = "slack"
channel = "C_CALENDAR_OPERATIONS"
format = "compact"[[routes]]
event = "agent.approval-requested"
filter = { project = "production" }
sink = "discord"
channel = "APPROVAL_CHANNEL_ID"
format = "alert"op_pi routes and records the request. It does not treat message text as authorization to mutate infrastructure.
Codex and Claude own session launch and hook registration. op_pi owns the shared event contract, normalization, and routing layer.
op_pi hooks install --provider codex --scope global
op_pi hooks install --provider claude-code --scope global
op_pi native hook --provider codex --file payload.json
op_pi native hook --provider claude --file payload.json
cat payload.json | op_pi native hook --provider codexShared hook events include SessionStart, PreToolUse, PostToolUse,
UserPromptSubmit, and Stop.
Route with stable metadata such as provider, event, session_id,
repo_name, project, branch, and tool_name rather than rendered text.
Note
Cloud-facing endpoints are closed until their authentication settings are explicitly configured.
AWS SNS signature verification
- validates
TopicArnagainst an optional allowlist - restricts
SigningCertURLto HTTPS AWS SNS certificate endpoints - disables certificate-fetch redirects
- checks X.509 validity
- caps key caching at the shorter of cache TTL or certificate expiry
- verifies RSA/SHA-1 and RSA/SHA-256 SNS signatures
An allowlist is an additional filter, not a substitute for signature verification.
EventBridge and Cloudflare authentication
- return
503until a shared secret is configured - compare secrets in constant time
- reject missing or incorrect authentication
Cloudflare Logpush bounds
- limits raw request bodies to 10 MiB
- limits decompressed payloads to 5 MiB
- accepts NDJSON and gzip
- caps retained records per batch
- rejects malformed records and decompression bombs
Google Calendar channel authentication
- returns
503until[google_calendar].channel_tokenis configured - compares
X-Goog-Channel-Tokenin constant time - validates all required
X-Goog-*notification headers - binds accepted notifications to tracked channel/resource identities while
supporting Google's
primary/canonical-account URI alias - prevents general
/eventtraffic from triggering Calendar API synchronization - uses external mode-0600 OAuth credentials with the required Calendar events
read-only scope (
openid,email, anduserinfo.emailare also accepted) - requires a private mode-0600 config for an inline channel token; legacy webhook-only short tokens remain valid until durable sync is enabled
- performs retrying full/incremental sync with durable webhook triggers, sink-confirmed outbox delivery, and HTTP 410 recovery
- renews expiring watch channels, bounds pending activation, and durably retires old channels
- deduplicates notification message numbers across daemon restarts
- emits typed created, updated, cancelled, and failure events
- exposes separate public-safe sync/watch health without credential or token values
Linear webhook authentication
- returns
503until[linear].webhook_secretis configured - verifies
Linear-Signatureas a hex HMAC-SHA256 over the exact raw body - rejects signed bodies whose
webhookTimestampis more than 60 seconds from the daemon clock - without
OP_PI_DATABASE_URL, returns Linear's required200after volatile queue admission or replay-cache suppression - with
OP_PI_DATABASE_URL, commits and deduplicates in PostgreSQL before200; ledger or queue failure returns503. This is an AGI-vendored prototype, not owner-approved deployment evidence; see roadmap M2
Read the complete AWS and Cloudflare intake guide and Linear intake guide. For Calendar watch setup and event fields, see the Google Calendar intake guide.
Inspect a routing decision without sending anything:
op_pi explain github.pr-status-changed repo=my-app number=42
op_pi explain --json github.pr-status-changed repo=my-app number=42The explainer reports which routes match, which filters pass, and where each delivery would go.
op_pi status
op_pi config
op_pi config verify-gateway-allowlist
op_pi send --channel <id> --message "test"
op_pi plugin list
op_pi tmux list
op_pi gajae statusOperational behavior includes:
- bounded internal queues
- startup route validation
- source health in
/health - Slack rate-limit and server-failure retries
- degraded-source backoff
- repeated-error log deduplication
- bounded log rotation
scripts/rotate_op_pi_logs.shThe bundled utility rotates above 25 MiB, retains four gzip generations, and can restart the launchd service after rotating open log files.
- Keep secrets in provider configuration or environment variables.
- Match typed event fields, never rendered message text.
- Use explicit Discord channel or thread targets.
- Keep dynamic tokens disabled unless a route requires them.
- Route high-volume datasets to local files before chat.
- Use
droponly for intentionally acknowledged noise. - Treat approval events as requests, not authorization.
op_pi is the sole identifier for commands, configuration, automation,
deployments, and telemetry. The versioned telemetry schema is
op_pi.telemetry.v1.
src/source/ event producers and monitors
src/intake.rs AWS, Cloudflare, Linear, and Google Calendar intake authentication
src/router.rs route resolution
src/render/ destination-independent rendering
src/sink/ Discord, Slack, and local-file delivery
src/daemon.rs HTTP server, queue, source lifecycle, health
docs/ event contracts and operational runbooks
scripts/ verification and operations utilities
plugins/ tool-specific hook bridges
op_pi is an independent operations pipeline built around:
- explicit operational interfaces
- provider-native event intake
- deterministic, inspectable routing
- human-visible policy boundaries
- local-first operation
- secure cloud ingress
- bounded delivery behavior
Signals in. Decisions routed. Actions out.
op_pi is licensed under the MIT License.