Liners: Governance as Code
Composable control layers that wrap event handlers to enforce safety, observability, and governance without touching agent code
Overview
In Happen, we believe that control should be composable. Most frameworks force developers into a false dichotomy between:
Safety: Rigid, restrictive platforms that limit what agents can do
Power: Raw, dangerous runtime access with no guardrails
Happen transcends this trade-off through a pattern we call Liners—giving you both safety and power simultaneously.
What is a Liner?
A Liner is a thin, protective layer that wraps an event handler. It allows you to:
Inspect events before they reach your logic
Transform or modify data flowing through the system
Block dangerous operations before execution
Observe results after completion
At its core, a Liner is simply a Higher-Order Function. It takes a next function (the original handler) and returns a new, enhanced handler function.
Anatomy of a Liner
// The Anatomy of a Liner
const myLiner = (next) => {
return (event, context) => {
// 1. Pre-Process: Inspect the event before execution
console.log(`Processing ${event.type}...`);
// 2. Execute: Call the original handler
const result = next(event, context);
// 3. Post-Process: Inspect the result
console.log(`Finished with status: ${result.status}`);
return result;
};
}; Composing Liners
The true power of Liners emerges when you stack them. You can layer multiple behaviors—logging, budgeting, safety checks—onto a single node, creating a composable security architecture.
We provide a utility called line() to compose Liners elegantly.
import { createNode } from "happen";
import { line } from "./utils";
const fsNode = createNode("file-system");
// The raw, dangerous capability
const deleteHandler = (event) => {
Bun.file(event.payload.path).delete();
return { deleted: true };
};
// The protected, observable handler
fsNode.on(
"file.delete",
line(
deleteHandler, // The core logic
withLogging, // Liner 1: Log the attempt
withShadowMode, // Liner 2: Intercept writes (Safety)
),
);In this stack, the event flows through withShadowMode → withLogging → deleteHandler. If withShadowMode determines the action is unsafe, it returns early, and deleteHandler never executes.
Practical Examples
Let's explore real-world Liners that solve critical problems in agentic systems:
Shadow Mode Liner (Safety)
Transform dangerous tools into safe ones by intercepting destructive actions and virtualizing them for human review.
export const withShadowMode = (next) => (event, context) => {
const isDestructive = event.type.includes("delete") ||
event.type.includes("overwrite");
if (isDestructive && !event.context.approved) {
// INTERCEPT: Don't call next(). Stage for review instead.
ShadowSystem.stageChange({
type: event.type,
payload: event.payload,
risk: "high",
});
return {
status: "paused",
message: "Operation halted for human review.",
};
}
};Last updated