A local HTTP+SSE service that tracks AI agent activity across multiple VS Code windows simultaneously and publishes concise updates when something actually needs attended to (waiting for input, or done). Each window's Copilot/Claude session is tracked independently using their provided hooks and correlated to its window. The server applies filters as not to publish redundant events - signaling "waiting" or "done" only when it assumes the user isn't actively looking at that window, deferring via an AFK timer when the window is focused, and auto-clearing when the user returns focus or comes back from idle — so downstream clients (LED strips, desktop widgets, etc.) only light up when there's genuinely unattended work. Multiple clients can be connected as well.
| Mode | Meaning |
|---|---|
| Idle | No active signal — agent is not doing anything noteworthy |
| Waiting | Agent needs your attention (permission prompt, idle prompt) |
| Done | Agent finished responding |
cd AgenticUnattended-Service
dotnet runThe server starts on http://127.0.0.1:17321. Verify with:
curl http://127.0.0.1:17321/healthThe beacon relies on agent hooks — each agent runs a curl command at lifecycle moments, which POSTs JSON to the beacon server. You just need to drop a config file into your project (or globally).
Copy the hook config into your project's .github/hooks/ directory:
mkdir -p /path/to/your/project/.github/hooks
cp hook-configs/copilot/CopilotHookSettings.json /path/to/your/project/.github/hooks/CopilotHookSettings.jsonCopilot automatically discovers JSON files in .github/hooks/.
Merge the hook entries from hook-configs/claude-code/settings.json into your project's .claude/settings.json:
# If you don't have a settings file yet, just copy it:
mkdir -p /path/to/your/project/.claude
cp hook-configs/claude-code/settings.json /path/to/your/project/.claude/settings.jsonIf you already have a .claude/settings.json, manually merge the "hooks" section into your existing file.
Use the provided scripts to copy hook configs into any target project:
Bash (macOS / Linux / Git Bash on Windows):
./scripts/install-hooks.sh /path/to/your/projectPowerShell (Windows / pwsh):
.\scripts\install-hooks.ps1 -TargetDir C:\path\to\your\projectBoth scripts copy the Copilot config into .github/hooks/ and the Claude Code config into .claude/. If a .claude/settings.json already exists, the script warns you to merge manually instead of overwriting.
The steps above are per-project — hooks only fire in repos that have the config. If you want hooks in every project:
- Copilot: Place
CopilotHookSettings.jsonin your global.github/hooks/directory - Claude Code: Add the hooks section to
~/.claude/settings.json(user-level settings)
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Returns { "ok": true, "version": "2.0.0" } |
/state |
GET | Per-session state (all sessions, or ?sessionId=... for one) |
/events |
GET | SSE stream of BeaconEvent objects |
/hook |
POST | Receives hook payloads from agent scripts |
{
"eventType": "Done",
"sessionId": "4439e1a4-7230-4ec3-ad56-162c827e7495",
"source": "Copilot",
"hookEvent": "Stop",
"reason": "Agent finished responding",
"timestamp": "2026-02-21T12:00:00Z"
}Edit AgenticUnattended-Service/appsettings.json or override via environment variables using the ASP.NET Core convention (Beacon__PropertyName):
| Setting | Default | Description |
|---|---|---|
Port |
17321 | HTTP listen port |
VscodeProcessName |
"Code" | Process name for focus detection |
AfkThresholdSeconds |
30 | Seconds idle before AFK return triggers Clear |
PollIntervalMs |
250 | Focus/idle polling interval |
IdleTimeoutSeconds |
300 | Seconds with no events before auto-clear |
FakeMode |
false | Cycle through states for testing |
CopilotEventMappings |
(see below) | Copilot hook event → beacon state mapping |
ClaudeEventMappings |
(see below) | Claude Code hook event → beacon state mapping |
Mappings are split per agent since each has different hook events:
Copilot:
{
"Stop": "Done",
"UserPromptSubmit": "Clear",
"SessionStart": "Clear"
}Claude Code:
{
"Stop": "Done",
"SubagentStop": "Done",
"Notification:permission_prompt": "Waiting",
"Notification:idle_prompt": "Waiting",
"UserPromptSubmit": "Clear",
"SessionStart": "Clear"
}To add a new mapping (e.g., treat Copilot's PreToolUse as Waiting), just add it to the appropriate section — no code changes required.
For testing without a real agent, enable fake mode to cycle through states every 10 seconds:
# Via environment variable
Beacon__FakeMode=true dotnet run
# Or in appsettings.json
{ "Beacon": { "FakeMode": true } }Each VS Code window is tracked as a separate session, identified by its Win32 window handle (HWND). This works even though all VS Code windows share a single process PID. Publishing rules are per-session:
- Window not focused → publish immediately (Waiting/Done)
- Window focused → start AFK timer; publish only if user goes idle
- Window gains focus while Waiting/Done → publish Clear
- User returns from AFK with session window focused → publish Clear
- Window closed → end session
- Hooks use inline
curlcommands — agents pipe JSON to stdin, curl POSTs it to the server. No script files needed. - HookNormalizer translates agent-specific events into unified types using configurable per-agent mappings
- SessionOrchestrator manages per-session state, applies publishing rules, handles focus/AFK logic
- SessionRegistry maps session IDs ↔ window handles, tracks lifecycle
- EventBus pure broadcast pub/sub to SSE clients (no global state)
- IPlatformMonitor (Windows:
SetWinEventHook+GetLastInputInfo+IsWindow; other platforms: no-op stub) detects window focus changes, idle duration, and window liveness
| Platform | Hook Pipeline | Focus/Idle Detection |
|---|---|---|
| Windows | Full | Full (Win32 P/Invoke) |
| macOS/Linux | Full | Stub (no-op) |
The hook-based detection (the core feature) is fully cross-platform. Only the presence clearing (focus + AFK) is Windows-specific, and it degrades gracefully — on other platforms, clearing happens via UserPromptSubmit and SessionStart hooks instead.
Contributions are welcome! See CONTRIBUTING.md for build instructions, project layout, and PR guidelines. By participating you agree to abide by the Code of Conduct.
For security issues, please follow SECURITY.md instead of filing a public issue.
MIT © 2026 Coopski101