@forwardimpact/libwatchdog
v0.1.0
Published
Guardrail engine for agent teams — count repository activity over a window, compare it against thresholds, and engage an operator latch when the activity breaches them.
Downloads
333
Maintainers
Readme
libwatchdog
Guardrail engine for agent teams — count repository activity over a window, compare it against thresholds, and engage an operator latch when the activity breaches them.
A guardrail engine. It counts activity signals over a window, compares each count against a threshold, and engages an operator latch when any count breaches. Doubt stops the line: a signal the engine cannot read, and a response that cannot cover the window, both breach.
The library names no tenant. The latch variable's name, the threshold, and the window all arrive as arguments.
Seams
| Seam | Contract |
| ---- | -------- |
| Rule | { id, threshold, probe }. createRule builds one. activityRules builds the four repository-activity rules. |
| Probe | async ({ request, repo, defaultBranch, cutoff }) => { count, covered }. It throws when it cannot read. |
| Latch | { read, write }. createActionsVariableLatch reads both variable scopes and writes the repository scope. |
| Policy | decide(state, { windowMs, now }) => "engage" \| "skip". It yields to a stop already in place and to a human who cleared the latch inside the window. |
The next guardrail adds a rule set and a probe. It adds no second script.
Compose
import {
activityRules,
createActionsVariableLatch,
createRequest,
decide,
encodeReason,
evaluate,
} from "@forwardimpact/libwatchdog";
import { isoTimestamp } from "@forwardimpact/libutil";
const request = createRequest({ token, clock });
const windowMs = 2 * 3600000;
const verdict = await evaluate(activityRules(32), {
request,
repo: "owner/repo",
defaultBranch: "main",
clock,
windowMs,
});
if (verdict.engage) {
const latch = createActionsVariableLatch({
request,
repo: "owner/repo",
name: "MY_KILLSWITCH",
});
const state = await latch.read();
if (decide(state, { windowMs, now: clock.now() }) === "engage") {
await latch.write(
encodeReason({
name: "watchdog",
breaches: verdict.breaches,
// The reason records the run, not the moment the window opened.
at: isoTimestamp(clock.now()),
}),
);
}
}Guide
Guard an Agent Team's Activity covers the counters, the threshold and the window, the latch contract, the clearing rule, the CI wiring, and the exit codes.
