Install
$ agentstack add skill-tkellogg-open-strix-pollers ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ● Filesystem access Used
- ● Shell / process execution Used
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Pollers — Event-Driven Monitoring
Pollers are lightweight scripts that check external services on a schedule and report back when something needs attention. They live inside skills and are discovered automatically by the scheduler.
How It Works
- A skill includes a
pollers.jsonfile alongside itsSKILL.md - The scheduler discovers all
pollers.jsonfiles at startup and whenreload_pollersis called - On each cron tick, the scheduler runs the poller command as a subprocess
- Each line of stdout is parsed as JSON and delivered to the agent as an event
- If there's nothing to report, the poller outputs nothing — silence is the filter
Creating a Poller
1. Write the poller script
The script runs in the skill directory. It receives these environment variables automatically:
| Variable | Description | |----------|-------------| | STATE_DIR | The skill directory (writable, for cursors/state) | | POLLER_NAME | The poller's name from pollers.json |
Plus any custom env vars from the env field, plus the agent's existing environment.
Output contract:
- stdout: JSONL (one JSON object per line). Each line must have
poller(string) andprompt(string) fields. - stderr: Free-form logging. Not forwarded to the agent.
- Exit 0: Success. Non-zero: Error, this cycle is skipped.
Example poller script:
#!/usr/bin/env python3
"""Check for new items since last poll."""
import json, os, sys
from pathlib import Path
STATE_DIR = Path(os.environ.get("STATE_DIR", "."))
CURSOR_FILE = STATE_DIR / "cursor.json"
def load_cursor():
if CURSOR_FILE.exists():
return json.loads(CURSOR_FILE.read_text())
return {}
def save_cursor(cursor):
CURSOR_FILE.write_text(json.dumps(cursor, indent=2))
def main():
cursor = load_cursor()
# ... check your service, compare against cursor ...
new_items = [] # your logic here
for item in new_items:
event = {
"poller": os.environ.get("POLLER_NAME", "my-poller"),
"prompt": f"New item: {item['title']}"
}
print(json.dumps(event))
# Update cursor so next run skips these items
save_cursor(cursor)
if __name__ == "__main__":
main()
2. Create pollers.json in the skill directory
{
"pollers": [
{
"name": "my-service-check",
"command": "python poller.py",
"cron": "*/5 * * * *",
"env": {
"SERVICE_URL": "https://example.com/api"
}
}
]
}
Top-level must be a dict with a pollers key (not a bare array).
| Field | Required | Description | |-------|----------|-------------| | name | yes | Unique identifier. Used in logs and event routing. | | command | yes | Shell command, relative to the skill directory. | | cron | yes | Cron expression (5-field, UTC). | | env | no | Additional environment variables for the script. |
3. Register the pollers
After creating or updating pollers.json, call the reload_pollers tool. This re-scans all skill directories and registers any new pollers with the scheduler.
reload_pollers()
# → "Reloaded. 2 poller(s) registered: bluesky-mentions, github-issues"
Pollers are also loaded automatically at startup.
File Layout
skills/my-monitor/
├── SKILL.md
├── pollers.json ← declares pollers
├── poller.py ← the script
├── cursor.json ← poller state (managed by script)
└── events.jsonl ← optional local event log
Design Patterns
See [design-patterns.md](design-patterns.md) for detailed guidance on:
- State management — cursor pattern, timestamp vs URI cursors, external service state, recovery on first run
- Filtering — selecting actionable notification types, avoiding shared
is_readtraps - Prompt quality — including URIs/CIDs so the agent can act, not just observe
- Error handling — fail silently (exit non-zero), never emit on error
- Anti-patterns — common mistakes and how to avoid them
Security & Privacy
See [security.md](security.md) for guidance on:
- Trust tiers — the follow-gate pattern for sorting trusted vs unknown sources
- Operator in the loop — keeping the human informed without locking everything down
- Credential handling — env vars, per-agent accounts, what not to log
- Prompt injection — honest reporting with context, not sanitization
Key Constraints
- 60-second timeout. If a poller doesn't finish in 60s, it's killed and the cycle is skipped.
- Silence means nothing to report. Only output lines when there's something actionable.
- One JSON object per line. Each line must parse independently.
pollerandpromptare required fields. Lines missing either are dropped.- Pollers are dumb. No LLM calls. Check a service, output what changed, exit. Keep them fast and pure.
- State management is the poller's job. Use
STATE_DIRto store cursors, history, or any persistent state. The scheduler doesn't track state for you.
Debugging
If a poller isn't working:
- Check it was discovered:
reload_pollersreports the count and names - Run it manually:
cd skills/my-monitor && STATE_DIR=. POLLER_NAME=test python poller.py - Check stderr: Poller stderr is logged as
poller_stderrevents - Check exit code: Non-zero exits are logged as
poller_nonzero_exit - Check JSON format: Each stdout line must be valid JSON with
pollerandpromptkeys
Available Tool
| Tool | Description | |------|-------------| | reload_pollers | Re-scan all skills/*/pollers.json and register pollers. Call after installing/updating skills. |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: tkellogg
- Source: tkellogg/open-strix
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.