Skip to content

SantiagoBobrik/agent-pulse

Repository files navigation

agent-pulse

agent-pulse

A local event gateway for AI code agents.
Capture lifecycle events from Claude Code, Gemini CLI, and more — fan them out to any HTTP endpoint, webhook, or device.

InstallQuickstartAgent SetupConfigCommands


Why agent-pulse?

Every AI code agent has its own hook system — different formats, different configs, scattered across projects. Adding a new webhook means editing every project's settings for every agent you use.

agent-pulse solves this with a single global config:

  • One config, all agents — Define your clients once in ~/.config/agent-pulse/config.yaml. Every project, every agent, every event routed through one place.
  • Zero per-project setup — No more duplicating hook configs across repositories. Register your hooks once and you're done.
  • Fan-out to anything — HTTP endpoints, webhooks, IoT devices (ESP32, Raspberry Pi, etc.), scripts — if it speaks HTTP, agent-pulse can reach it.
  • Fully local — Everything runs on your machine. No cloud, no accounts, no data leaves your network.
  • Enrich with metadata — Attach custom data to every lifecycle hook via a project-level .agent-pulse.json — project name, team, or anything your clients need.
  • Filter what matters — Route specific events to specific clients. Send notification events to your desk light, session_start to your dashboard, everything to your logger.
  • Real-time streaming — Connect to the SSE endpoint and watch events flow in real-time. Perfect for dashboards, browser UIs, or a simple curl -N.

Diagram

Architecture diagram


Features

  • Event bridge — Local HTTP gateway that receives agent lifecycle events and dispatches them to registered clients
  • Multi-provider — Support for Claude Code and Gemini CLI (Codex CLI and OpenCode on the roadmap)
  • Client routing — Per-client filtering by event type and provider
  • Interactive wizardclient add walks you through registration step by step
  • Custom headers — Attach headers to client requests with environment variable interpolation (${API_TOKEN})
  • Auto-start — The gateway starts automatically when a hook fires — no need to manually run the server
  • Parallel dispatch — Events fan out to all matching clients concurrently
  • Config hot-reload — Add or remove clients without restarting the server
  • SSE streaming — Real-time event stream via GET /events/stream for browsers, dashboards, and curl
  • Project metadata — Attach project context (name, team) to every event via a local .agent-pulse.json file
  • Single binary — Zero runtime dependencies, just one Go binary

Installation

Homebrew

brew tap SantiagoBobrik/tap
brew install agent-pulse

From source

Requires Go 1.25+:

go install github.com/SantiagoBobrik/agent-pulse@latest

Make sure $GOPATH/bin (or $HOME/go/bin) is in your PATH:

# Add to your ~/.bashrc or ~/.zshrc
export PATH="$PATH:$(go env GOPATH)/bin"

Quickstart

# 1. Register a client
agent-pulse client add

# 2. Configure hooks in your agent (see Agent Setup below)

# 3. Work normally — the gateway auto-starts when the first event fires

Agent Setup

Claude Code

Add hooks to your Claude Code settings file at ~/.claude/settings.json. The pattern is the same for every event — here are two examples:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "command": "agent-pulse hook --provider claude --event stop",
            "type": "command"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "command": "agent-pulse hook --provider claude --event notification",
            "type": "command"
          }
        ]
      }
    ]
  }
}

Add as many events as you need by following the same structure. agent-pulse supports all hook events that Claude Code provides — check the Claude Code Hooks documentation for the full list of available hook points.

You can configure hooks at the user level (~/.claude/settings.json) to apply globally, or at the project level (.claude/settings.json) for per-repo hooks.

Gemini CLI

Note: Gemini CLI support is untested and under review. The hook interface may change.

Gemini CLI uses the same stdin/stdout JSON protocol as Claude Code. Add hooks to ~/.gemini/settings.json:

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "command": "agent-pulse hook --provider gemini --event session_start",
            "type": "command"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "command": "agent-pulse hook --provider gemini --event notification",
            "type": "command"
          }
        ]
      }
    ]
  }
}

Add as many events as you need following the same pattern. See the Gemini CLI Hooks documentation for all available hook events.

Other Providers

Support for Codex CLI and OpenCode is on the roadmap. Codex CLI hooks are currently under development by the Codex team.


Configuration

The global config at ~/.config/agent-pulse/config.yaml controls where events go — which clients receive them, how they're routed, and server settings. This is the only file you need to manage.

Config anatomy

# Server settings
port: 8789                    # Gateway listen port (1024-65535)
bind_address: "127.0.0.1"    # IP address to bind to
gateway_url: "http://localhost" # Base URL for the gateway

# Registered clients
clients:
  - name: "my-webhook"       # Unique client identifier
    url: "https://example.com/hook"  # Destination endpoint
    timeout: 5000             # Delivery timeout in milliseconds
    events:                   # Event filter (omit for all events)
      - stop
      - notification
    providers:                # Provider filter (omit for all providers)
      - claude
    headers:                  # Custom HTTP headers
      Authorization: "Bearer ${WEBHOOK_TOKEN}"
      X-Source: "agent-pulse"

Reference

Key Type Default Description
port int 8789 Server listen port. Must be between 1024 and 65535.
bind_address string "127.0.0.1" IP address the server binds to.
gateway_url string "http://localhost" Base URL used by the hook command to reach the gateway.
clients array [] List of registered event clients (see below).

Client object

Key Type Default Description
name string required Unique identifier for the client. Alphanumeric, hyphens, and underscores only.
url string required HTTP endpoint to deliver events to. Auto-prefixed with http:// if no scheme is provided.
timeout int 2000 Request timeout in milliseconds. Valid range: 0–30000.
events array [] Event types this client receives. Empty means all events.
providers array [] Providers this client receives events from. Empty means all providers.
headers map {} Custom HTTP headers sent with each request. Values support env var interpolation with ${VAR_NAME} syntax.

Providers

Provider Status
claude Supported
gemini Supported (hooks in testing)

Example: multi-client setup

port: 8789
bind_address: "127.0.0.1"
gateway_url: "http://localhost"

clients:
  # ESP32 on local network — lights up on agent activity
  - name: "desk-light"
    url: "http://192.168.1.42"
    timeout: 2000
    events:
      - notification
      - stop

  # Send all events to a logging service
  - name: "logger"
    url: "https://logs.example.com/ingest"
    timeout: 3000
    headers:
      Authorization: "Bearer ${LOG_API_KEY}"

  # Claude-only events to a dashboard
  - name: "claude-dashboard"
    url: "http://localhost:3000/api/events"
    timeout: 5000
    providers:
      - claude

Project Metadata

You can attach project-level context to every event by placing a .agent-pulse.json file in your project root (the directory where the agent runs):

{
  "metadata": {
    "project": "my-api",
    "team": "backend"
  }
}

When present, the metadata object is included in every event sent to your clients. The structure is freeform — put whatever key/value pairs are useful for your setup.

  • If the file doesn't exist, events are sent without metadata (no error).
  • If the file contains invalid JSON, a warning is logged and the event is sent without metadata.
  • Discovery is CWD-only — agent-pulse does not walk parent directories.

This is separate from the global config (~/.config/agent-pulse/config.yaml), which controls where events go. .agent-pulse.json controls what context travels with them.


SSE streaming

Connect to GET /events/stream to receive all events in real-time via Server-Sent Events. This is a firehose — every event the gateway receives is broadcast to all connected SSE clients.

The server binds to 127.0.0.1 (local-only), so SSE is only available from your machine.

curl

curl -N http://localhost:8789/events/stream

Each event arrives as an SSE data: line containing the full JSON payload:

data: {"provider":"claude","event":"stop","data":{"session_id":"abc"}}

data: {"provider":"claude","event":"notification","data":{"message":"done"}}

JavaScript (EventSource)

const source = new EventSource("http://localhost:8789/events/stream");

source.onmessage = (e) => {
  const event = JSON.parse(e.data);
  console.log(event.provider, event.event, event.data);
};

Event payload

Events are delivered to clients as JSON via HTTP POST:

{
  "provider": "claude",
  "event": "stop",
  "data": { ... },
  "metadata": { "project": "my-api", "team": "backend" }
}

The data field contains the raw payload from the agent, passed through without modification. The metadata field is included when a .agent-pulse.json file exists in the working directory (see Project Metadata).


Commands

agent-pulse server start

Start the event bridge gateway. You normally don't need to run this yourself — when an agent hook fires, agent-pulse hook checks whether the server is running and starts it automatically in the background if it isn't. The server stays alive to handle subsequent events until you explicitly stop it with agent-pulse server down.

agent-pulse server start          # Use port from config (default: 8789)
agent-pulse server start -p 9000  # Override port

The server writes its PID to ~/.config/agent-pulse/server.pid and logs to ~/.config/agent-pulse/server.log. It handles SIGINT/SIGTERM for graceful shutdown.


agent-pulse server down

Stop the running gateway server.

agent-pulse server down

Sends SIGTERM to the server process and removes the PID file.


agent-pulse server logs

View server logs.

agent-pulse server logs       # Show last 50 lines
agent-pulse server logs -f    # Follow log output in real time

agent-pulse client add

Register a new event client. Runs an interactive wizard if no flags are provided.

# Interactive wizard
agent-pulse client add

# Non-interactive
agent-pulse client add \
  --name my-webhook \
  --url https://example.com/hook \
  --port 443 \
  --timeout 5000 \
  --events stop,notification
Flag Description
--name Client name
--url Client URL or IP address
--port Port number (default: 80)
--timeout Delivery timeout in ms (default: 2000)
--events Comma-separated event types, or "all"

agent-pulse client list

List all registered clients and their configuration.

agent-pulse client list
NAME              URL                              TIMEOUT  EVENTS              PROVIDERS
logger            https://logs.example.com/ingest  3000     all                 all
desk-light        http://192.168.1.42:80           2000     notification, stop  all
claude-dashboard  http://localhost:3000/api/events  5000     all                 claude

agent-pulse client remove

Remove a registered client by name.

agent-pulse client remove desk-light

Name lookup is case-insensitive.


agent-pulse hook

Called by agent hooks to forward events to the gateway. You typically don't call this directly — it's invoked by the hook configuration in your agent's settings.

echo '{"message": "done"}' | agent-pulse hook --provider claude --event stop
Flag Required Description
--provider Yes Agent provider (claude, gemini)
--event Yes Lifecycle event name (session_start, session_end, stop, notification)

Reads the event payload from stdin as JSON. If the gateway is unreachable, it automatically starts the server in the background before dispatching.


License

MIT

About

A local event gateway for AI code agents. Capture lifecycle events from Claude Code, Gemini CLI, and more — fan them out to any HTTP endpoint, webhook, or device.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors