Add event-driven tasks via Gitea webhooks
Some checks failed
Deploy Production / deploy (push) Failing after 35s
CI / lint-and-test (push) Successful in 33s
CI / build (push) Has been cancelled

Webhook endpoint at /api/webhooks/gitea receives Gitea status events,
matches them against configurable event triggers with conditions
(event type, repo glob, state, context), renders task templates with
{{variable}} substitution, and creates harness tasks automatically.

Includes circuit breaker: after N consecutive task failures from the
same trigger (default 3), the trigger auto-disables. Re-enable
manually via PATCH /api/event-triggers/:id.

New tables: harness_event_triggers (rules + circuit breaker state),
harness_event_log (audit trail + dedup via X-Gitea-Delivery).
This commit is contained in:
Julia McGhee
2026-03-21 21:15:15 +00:00
parent ccebbc4015
commit eeb87018d7
19 changed files with 2368 additions and 35 deletions

View File

@@ -0,0 +1,43 @@
CREATE TABLE IF NOT EXISTS "harness_event_log" (
"id" serial PRIMARY KEY NOT NULL,
"trigger_id" text NOT NULL,
"delivery_id" text NOT NULL,
"event_type" text NOT NULL,
"repo" text NOT NULL,
"commit_sha" text,
"branch" text,
"status" text DEFAULT 'received' NOT NULL,
"task_id" text,
"skip_reason" text,
"error" text,
"payload" jsonb NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
CONSTRAINT "harness_event_log_delivery_id_unique" UNIQUE("delivery_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "harness_event_triggers" (
"id" text PRIMARY KEY NOT NULL,
"name" text NOT NULL,
"enabled" boolean DEFAULT true NOT NULL,
"event_type" text NOT NULL,
"repo_filter" text,
"state_filter" text,
"context_filter" text,
"task_template" jsonb NOT NULL,
"consecutive_failures" integer DEFAULT 0 NOT NULL,
"max_consecutive_failures" integer DEFAULT 3 NOT NULL,
"disabled_reason" text,
"webhook_secret" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "harness_orchestrator" (
"id" text PRIMARY KEY DEFAULT 'singleton' NOT NULL,
"running" boolean DEFAULT false NOT NULL,
"current_task_id" text,
"heartbeat" bigint,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
ALTER TABLE "harness_tasks" ADD COLUMN "cancel_requested" boolean DEFAULT false NOT NULL;

View File

@@ -0,0 +1,775 @@
{
"id": "e84e33a6-8185-4839-ad18-37149f19eb32",
"prevId": "629b632c-cf1f-46ff-bb2f-e47d2343ddbd",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.harness_agent_configs": {
"name": "harness_agent_configs",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"runtime": {
"name": "runtime",
"type": "text",
"primaryKey": false,
"notNull": true
},
"model_id": {
"name": "model_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"max_tokens": {
"name": "max_tokens",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"env": {
"name": "env",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_credentials": {
"name": "harness_credentials",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"label": {
"name": "label",
"type": "text",
"primaryKey": false,
"notNull": true
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true
},
"base_url": {
"name": "base_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_curated_models": {
"name": "harness_curated_models",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"context_window": {
"name": "context_window",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"cost_per_1k_input": {
"name": "cost_per_1k_input",
"type": "real",
"primaryKey": false,
"notNull": false
},
"cost_per_1k_output": {
"name": "cost_per_1k_output",
"type": "real",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_event_log": {
"name": "harness_event_log",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"trigger_id": {
"name": "trigger_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"delivery_id": {
"name": "delivery_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"event_type": {
"name": "event_type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"repo": {
"name": "repo",
"type": "text",
"primaryKey": false,
"notNull": true
},
"commit_sha": {
"name": "commit_sha",
"type": "text",
"primaryKey": false,
"notNull": false
},
"branch": {
"name": "branch",
"type": "text",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'received'"
},
"task_id": {
"name": "task_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"skip_reason": {
"name": "skip_reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"error": {
"name": "error",
"type": "text",
"primaryKey": false,
"notNull": false
},
"payload": {
"name": "payload",
"type": "jsonb",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"harness_event_log_delivery_id_unique": {
"name": "harness_event_log_delivery_id_unique",
"nullsNotDistinct": false,
"columns": [
"delivery_id"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_event_triggers": {
"name": "harness_event_triggers",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": true
},
"event_type": {
"name": "event_type",
"type": "text",
"primaryKey": false,
"notNull": true
},
"repo_filter": {
"name": "repo_filter",
"type": "text",
"primaryKey": false,
"notNull": false
},
"state_filter": {
"name": "state_filter",
"type": "text",
"primaryKey": false,
"notNull": false
},
"context_filter": {
"name": "context_filter",
"type": "text",
"primaryKey": false,
"notNull": false
},
"task_template": {
"name": "task_template",
"type": "jsonb",
"primaryKey": false,
"notNull": true
},
"consecutive_failures": {
"name": "consecutive_failures",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"max_consecutive_failures": {
"name": "max_consecutive_failures",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 3
},
"disabled_reason": {
"name": "disabled_reason",
"type": "text",
"primaryKey": false,
"notNull": false
},
"webhook_secret": {
"name": "webhook_secret",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_iterations": {
"name": "harness_iterations",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"task_id": {
"name": "task_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"n": {
"name": "n",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'pending'"
},
"diagnosis": {
"name": "diagnosis",
"type": "text",
"primaryKey": false,
"notNull": false
},
"agent_output": {
"name": "agent_output",
"type": "text",
"primaryKey": false,
"notNull": false
},
"evals": {
"name": "evals",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"diff_stats": {
"name": "diff_stats",
"type": "text",
"primaryKey": false,
"notNull": false
},
"started_at": {
"name": "started_at",
"type": "bigint",
"primaryKey": false,
"notNull": false
},
"completed_at": {
"name": "completed_at",
"type": "bigint",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_model_usage": {
"name": "harness_model_usage",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"model_id": {
"name": "model_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true
},
"task_id": {
"name": "task_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"task_slug": {
"name": "task_slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"iteration": {
"name": "iteration",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"input_tokens": {
"name": "input_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"output_tokens": {
"name": "output_tokens",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"duration_ms": {
"name": "duration_ms",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"timestamp": {
"name": "timestamp",
"type": "bigint",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_orchestrator": {
"name": "harness_orchestrator",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "'singleton'"
},
"running": {
"name": "running",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"current_task_id": {
"name": "current_task_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"heartbeat": {
"name": "heartbeat",
"type": "bigint",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.harness_tasks": {
"name": "harness_tasks",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": true
},
"goal": {
"name": "goal",
"type": "text",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'pending'"
},
"iteration": {
"name": "iteration",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 0
},
"max_iterations": {
"name": "max_iterations",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 6
},
"started_at": {
"name": "started_at",
"type": "bigint",
"primaryKey": false,
"notNull": false
},
"completed_at": {
"name": "completed_at",
"type": "bigint",
"primaryKey": false,
"notNull": false
},
"project": {
"name": "project",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'—'"
},
"evals": {
"name": "evals",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"pr": {
"name": "pr",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"cancel_requested": {
"name": "cancel_requested",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"spec": {
"name": "spec",
"type": "jsonb",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.users": {
"name": "users",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "serial",
"primaryKey": true,
"notNull": true
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"users_email_unique": {
"name": "users_email_unique",
"nullsNotDistinct": false,
"columns": [
"email"
]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -8,6 +8,13 @@
"when": 1774124029586,
"tag": "0000_sparkling_gressill",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1774127485727,
"tag": "0001_stale_pride",
"breakpoints": true
}
]
}

View File

@@ -75,6 +75,16 @@ export const agentConfigs = pgTable("harness_agent_configs", {
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// ─── HARNESS: ORCHESTRATOR STATE ──────────────────────────
export const orchestratorState = pgTable("harness_orchestrator", {
id: text("id").primaryKey().default("singleton"),
running: boolean("running").default(false).notNull(),
currentTaskId: text("current_task_id"),
heartbeat: bigint("heartbeat", { mode: "number" }),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// ─── HARNESS: TASKS ────────────────────────────────────────
export const tasks = pgTable("harness_tasks", {
@@ -89,6 +99,7 @@ export const tasks = pgTable("harness_tasks", {
project: text("project").notNull().default("—"),
evals: jsonb("evals").$type<Record<string, unknown>>().default({}).notNull(),
pr: jsonb("pr").$type<{ number: number; title: string; status: string }>(),
cancelRequested: boolean("cancel_requested").default(false).notNull(),
spec: jsonb("spec").$type<{
slug: string;
goal: string;
@@ -117,3 +128,60 @@ export const iterations = pgTable("harness_iterations", {
startedAt: bigint("started_at", { mode: "number" }),
completedAt: bigint("completed_at", { mode: "number" }),
});
// ─── HARNESS: EVENT TRIGGERS ───────────────────────────────
export const eventTriggers = pgTable("harness_event_triggers", {
id: text("id").primaryKey(),
name: text("name").notNull(),
enabled: boolean("enabled").default(true).notNull(),
// Matching conditions (all AND'd, null = any)
eventType: text("event_type").notNull(), // "status" | "*"
repoFilter: text("repo_filter"), // glob: "lazorgurl/*" or exact "lazorgurl/homelab"
stateFilter: text("state_filter"), // "failure" | "error" | null
contextFilter: text("context_filter"), // substring match on CI context, null = any
// Task template with {{variable}} placeholders
taskTemplate: jsonb("task_template").$type<{
slug: string;
goal: string;
project: string;
gitProvider?: string;
gitBaseUrl?: string;
agentId: string;
maxIterations: number;
criteria: { label: string; target: string }[];
constraints: string[];
knowledgeRefs: string[];
}>().notNull(),
// Circuit breaker
consecutiveFailures: integer("consecutive_failures").default(0).notNull(),
maxConsecutiveFailures: integer("max_consecutive_failures").default(3).notNull(),
disabledReason: text("disabled_reason"),
// Webhook auth (per-trigger override, falls back to GITEA_WEBHOOK_SECRET env)
webhookSecret: text("webhook_secret"),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
// ─── HARNESS: EVENT LOG ────────────────────────────────────
export const eventLog = pgTable("harness_event_log", {
id: serial("id").primaryKey(),
triggerId: text("trigger_id").notNull(),
deliveryId: text("delivery_id").notNull().unique(), // X-Gitea-Delivery header (dedup)
eventType: text("event_type").notNull(),
repo: text("repo").notNull(),
commitSha: text("commit_sha"),
branch: text("branch"),
status: text("status").notNull().default("received"), // received | task_created | skipped | error
taskId: text("task_id"),
skipReason: text("skip_reason"),
error: text("error"),
payload: jsonb("payload").$type<Record<string, unknown>>().notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});