Skip to content

seangeng/agentblip

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agentblip

Your Slack status, synced with your local AI agents. Every session is a blip on your team's radar.

npm CI MIT

agentblip.com · npm · GitHub

Your team can't see your agents. You kick off three Claude Code sessions, go heads-down reviewing what they produce, and on Slack you look… idle. Meanwhile someone pings you mid-run, an agent sits blocked on a permission prompt for twenty minutes, and nobody — including you — knows. Presence used to mean "at the keyboard." Now half the work is delegated, and the green dot has nothing to say about it.

agentblip turns local agent sessions into your Slack status — the little green light for the AI era:

Your status reads When
🤖 claude agent working one session busy
🤖 3 agents working three sessions busy
🤖 claude: finalizing CI/CD activity granularity — what it's actually doing
1 agent(s) waiting on me an agent is blocked on you

Quick start

npm i -g agentblip
agentblip setup           # walks through Slack connect + hook install
agentblip start --detach  # daemon runs in the background

That's it. Claude Code sessions appear automatically via hooks; Codex via its notify hook plus a session watcher. Anything else can report itself with one HTTP request (see Integrations). When every agent finishes, your status clears.

How it works

Claude Code hooks ─┐
Codex watcher ─────┤   POST /event      ┌────────────────────┐  POST /api/status   ┌──────────────┐
Any tool (curl) ───┼──────────────────▶ │ agentblip daemon   │ ───────────────────▶│ relay Worker │──▶ Slack API
                   │  localhost:4519    │ SessionStore →     │  pre-formatted      │ (or direct   │   users.profile.set
                   └                    │ formatStatus →sink │  SlackStatus only   │  Slack sink) │
                                        └────────────────────┘                     └──────────────┘

The daemon is the only thing that sees raw session data. Hooks and adapters report events to 127.0.0.1:4519; the daemon aggregates your sessions and formats the status text locally, applying your granularity, templates, and redaction patterns before anything touches the network. The relay receives exactly three fields — text, emoji, expiration — and passes them to Slack's users.profile.set. It cannot see your prompts, tool calls, file paths, or projects, because they never leave your machine unless you chose a granularity that puts them in the status text itself. (At "presence" the relay sees the same fixed string all day.)

Every push carries a rolling expiration (5 minutes by default). If your laptop sleeps, the daemon crashes, or wifi drops, Slack clears the status on its own — no stale "working" lies. Server-side, the relay stores nothing about you beyond your Slack user/team ids and an AES-GCM-encrypted Slack token keyed to your device, and you can revoke that any time with agentblip unlink.

Granularity & customization

One knob controls how much your status reveals:

granularity Your status reads
off never set
presence 🤖 heads down with agents
count (default) 🤖 claude agent working · 🤖 3 agents working
activity 🤖 claude: finalizing CI/CD · 🤖 3 agents · finalizing CI/CD

At count and activity, agents blocked on you append · 1 waiting on me; when nothing is working and agents are only waiting, the status flips to ✋ 1 agent(s) waiting on me.

Everything lives in ~/.config/agentblip/config.json (XDG_CONFIG_HOME respected), created by agentblip setup. The comments below are documentation — the real file is plain JSON:

{
  // How much your status reveals: "off" | "presence" | "count" | "activity".
  "granularity": "count",

  // Append the project name: "claude agent working (agentblip)".
  // Project is usually the basename of the session's cwd.
  "showProject": false,

  // What to do when a status agentblip didn't set is already up:
  // "respect" (default) — never overwrite it; stand down until it clears.
  // "overwrite" — displace it once, remember it, restore it when sessions end.
  "statusPolicy": "respect",

  // Rolling expiration in seconds — Slack auto-clears the status if the daemon
  // stops refreshing it (sleep, crash, dead wifi). 0 = never expire.
  "statusTtlSec": 300,

  // Minimum ms between Slack pushes (users.profile.set allows ~50/min).
  "debounceMs": 10000,

  // Local daemon port (loopback only).
  "port": 4519,

  // Relay the daemon pushes through in relay mode. `agentblip setup` asks for
  // it at the "Relay URL" prompt (default https://agentblip.com), or takes it
  // via --relay-url. The AGENTBLIP_RELAY_URL env var overrides it at runtime.
  "relayUrl": "https://agentblip.com",

  // Strings or regexes scrubbed from activity/project text before it can reach
  // your status. Case-insensitive; strings that don't compile as regexes match
  // literally. Matches become "…".
  "redactPatterns": ["secret-project", "client-\\w+"],

  // Project names to suppress entirely — sessions in these projects still count
  // toward "N agents working" but never contribute activity/project text.
  "hideProjects": ["acme-confidential"],

  // Status emoji, Slack ":name:" form.
  "emoji": { "working": ":robot_face:", "waiting": ":raised_hand:" },

  // Status text templates. Placeholders in {braces}; unknown ones are left as-is.
  "templates": {
    "presence": "heads down with agents",              // fixed text for "presence"
    "workingOne": "{agent} agent working",             // {agent} {activity} {project}
    "workingMany": "{working} agents working",         // {working} {total}
    "waitingSuffix": " · {waiting} waiting on me",     // {waiting} — appended while agents wait
    "activityOne": "{agent}: {activity}",              // {agent} {activity} {project}
    "activityMany": "{working} agents · {activity}",   // {working} {activity}
    "waitingOnly": "{waiting} agent(s) waiting on me"  // {waiting} — nothing working, agents blocked
  },

  // Auto-start the daemon from a hook when it isn't already running (a failed
  // start is cooled down for 60s so a broken config can't respawn on every hook).
  "autoStartDaemon": true,

  // Which source adapters the daemon activates. Codex also takes an optional
  // sessionsDir override (defaults to ~/.codex/sessions).
  "adapters": {
    "claudeCode": { "enabled": true },
    "codex": { "enabled": true }
  }
}

The config block above must stay in sync with configSchema in packages/cli/src/lib/config.ts — that schema is the source of truth.

Status text is truncated to Slack's 100-character cap. {agent} is a friendly display name (claude-codeclaude, codexcodex, gemini-cligemini); unknown sources display as-is.

Plays nice with your status

Your status field isn't only agentblip's. Before every push the daemon reads your current Slack status (via the relay in relay mode, or straight from Slack in direct mode — that's the users.profile:read scope) and decides what it's allowed to do:

  • statusPolicy: "respect" (default). A status agentblip didn't set — one you typed yourself, or another app's — is never overwritten. The daemon stands down (agentblip status shows it backing off) and resumes automatically the moment that status clears or expires.
  • statusPolicy: "overwrite". agentblip displaces the existing status, remembers it, and puts it back when your sessions end.
  • A manual change mid-session always wins, under either policy. If your status changes out from under agentblip while it's active, that's you (or another app) speaking deliberately: the daemon backs off, treats the new status as the truth, and drops anything it had saved.

Honest edge cases: if the daemon dies mid-session, your status simply expires blank after the rolling TTL (no stale "working" lies) — and a status agentblip had displaced under "overwrite" is restored the next time the daemon starts, unless it carried its own expiration that has since passed. If your Slack token predates the read scope, agentblip can't see the current status and falls back to its old blind-push behavior; re-authorize to get the new one:

agentblip unlink && agentblip setup

Integrations

Claude Code — automatic

agentblip setup installs hooks into your Claude Code settings. Seven hook events map onto the session lifecycle:

Claude Code hook Event sent
SessionStart start
UserPromptSubmit working
PreToolUse working (tool as activity)
PostToolUse working (keeps liveness fresh)
Notification waiting (permission prompt, question)
Stop idle
SessionEnd end

Each hook pipes its JSON to agentblip hook claude-code, which forwards a normalized event to the daemon. Multiple concurrent sessions just work — each is tracked by its session id.

Codex — notify + watcher

agentblip setup adds a notify hook to your Codex config (agentblip hook codex is the entrypoint), which reports turn completions. Because notify alone can't see when a turn starts, the daemon also watches Codex session logs to mark sessions working in real time.

Anything else — one HTTP request

The daemon's localhost API is a stable public interface. Report any process as an agent session:

curl -X POST http://127.0.0.1:4519/event \
  -H "authorization: Bearer $(cat ~/.local/state/agentblip/daemon.secret)" \
  -H "content-type: application/json" \
  -d '{
    "source": "my-tool",
    "sessionId": "run-42",
    "kind": "working",
    "activity": "backfilling embeddings",
    "project": "acme-api"
  }'

The daemon auto-generates that bearer secret (0600, XDG_STATE_HOME respected); every endpoint except GET /health requires it.

Send {"kind": "end"} with the same source + sessionId when it finishes. Full schema, event semantics, staleness rules, and adapter-writing guide: docs/INTEGRATIONS.md.

CLI reference

Command Does
agentblip setup Interactive setup: pick a mode (relay / slack / console) + install agent hooks. Relay mode prompts for the Relay URL (default https://agentblip.com — enter your own domain to self-host); --relay-url <url> skips the prompt
agentblip start [--detach] Run the daemon, foreground or in the background
agentblip stop Stop the background daemon
agentblip status [--json] Show daemon state, live sessions, and the current status
agentblip emit Send a session event by hand (testing, scripts)
agentblip hook <source> stdin→event adapter wired into agent hooks (e.g. agentblip hook claude-code)
agentblip pause Pause Slack updates without stopping the daemon
agentblip resume Resume Slack updates
agentblip unlink Revoke this device's token and clear the status
agentblip doctor [--json] Diagnose config, daemon, hooks, and connectivity

Menu bar app (macOS)

A tiny native SwiftUI menu bar app puts the blip on your own screen — a colored dot that shows idle / N working / waiting, with a dropdown to pause, change the detail level, and flip the overwrite-vs-respect policy live. It's a thin client of the daemon (holds no logic of its own), so nothing duplicates the core.

cd apps/menubar && ./scripts/make-app.sh && open dist/agentblip.app

Requires macOS 13+ and the daemon running. See apps/menubar/.

Self-hosting & direct mode

The relay is one Cloudflare Worker with one KV namespace — fork the repo, create the namespace and two secrets, deploy, and point the CLI at your own domain with agentblip setup --relay-url https://your.domain (or enter it at the Relay URL prompt). The full walkthrough is in docs/SELF_HOSTING.md. If you'd rather run no server at all, direct mode has the daemon call Slack's API straight from your machine with your own Slack app's user token — no relay in the loop.

Contributing

PRs welcome — see CONTRIBUTING.md for dev setup, the repo map, and what a good PR looks like. The one hard rule: the relay must never see anything beyond the final formatted status.

License

MIT © 2026 Sean Geng

About

Your Slack status, synced with your local AI agent sessions — claude agent working, 3 agents working, finalizing CI/CD

Topics

Resources

License

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages