hello world
A goal is an observable condition and an action to try.
This plan checks if GET / returns 200. If it doesn't, the agent runs curl. That's it.
import { Effect } from "effect";
import {
Act,
Assert,
Gate,
Plan,
createHttpObserveResource,
} from "gateproof";
const plan = Plan.define({
goals: [{
id: "hello-world",
title: "GET / returns hello world",
gate: Gate.define({
observe: createHttpObserveResource({ url: "https://example.com" }),
act: [Act.exec("curl -sf https://example.com")],
assert: [
Assert.httpResponse({ status: 200 }),
Assert.responseBodyIncludes("hello world"),
Assert.noErrors(),
],
}),
}],
});
if (import.meta.main) {
const result = await Effect.runPromise(Plan.run(plan));
console.log(JSON.stringify(result, null, 2));
if (result.status !== "pass") process.exitCode = 1;
}You write the condition
A gate is an HTTP check, a shell command, or any observable assertion. No magic — just a function that returns pass or fail.
The agent runs the loop
Observe, act, assert, repeat. The agent keeps trying the action until every assertion passes or the loop times out.
One file is the whole spec
Your plan.ts is readable by humans and executable by agents. No config layer, no dashboard — just TypeScript.
Case Studies
See it run against real systems.
Cinder is the first case study — a real system validated by a single plan file, start to finish.