Skip to content

Repository files navigation

Agentic Unattended (Service)

License: MIT CI .NET 10

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.

States

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

Prerequisites

Quick Start

cd AgenticUnattended-Service
dotnet run

The server starts on http://127.0.0.1:17321. Verify with:

curl http://127.0.0.1:17321/health

Setup: Agent Hooks

The 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).

VS Code Copilot

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.json

Copilot automatically discovers JSON files in .github/hooks/.

Claude Code

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.json

If you already have a .claude/settings.json, manually merge the "hooks" section into your existing file.

Automated Install Script

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/project

PowerShell (Windows / pwsh):

.\scripts\install-hooks.ps1 -TargetDir C:\path\to\your\project

Both 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.

Per-Project vs Global

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.json in your global .github/hooks/ directory
  • Claude Code: Add the hooks section to ~/.claude/settings.json (user-level settings)

API

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

SSE Event Format

{
  "eventType": "Done",
  "sessionId": "4439e1a4-7230-4ec3-ad56-162c827e7495",
  "source": "Copilot",
  "hookEvent": "Stop",
  "reason": "Agent finished responding",
  "timestamp": "2026-02-21T12:00:00Z"
}

Configuration

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

Default Event Mappings

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.

Fake Mode

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 } }

Architecture

View architecture diagram

Multi-Session / Multi-Window

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

Components

  • Hooks use inline curl commands — 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 Support

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.

Contributing

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.

License

MIT © 2026 Coopski101

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages