61. Harness CEL triggers and fullsend dispatch drivers
Date: 2026-06-23
Status
Accepted (partially supersedes static stage routing from ADR 0041; preserves its synchronous workflow_call execution model)
Only the event-only CEL context is superseded by ADR 0098, which retains one harness predicate but evaluates it against a resolved entity and optional event. The remaining decisions in this ADR remain accepted.
Context
Custom agents should be easy to author and portable across forges. Today, adding one means editing shared dispatch bash in GitHub Actions, adding per-stage workflow files, and re-implementing routing per install mode — work that is GitHub-specific and not co-located with the harness (gitlab-implementation.md, ADR 0045, ADR 0026).
A second constraint is security allow-listing: token mint and inference APIs trust only explicit job_workflow_ref values (ADR 0029). Each new agent workflow file requires operational updates in both surfaces, which discourages org-specific agents.
Colocating CEL trigger rules on harness files and routing through fullsend dispatch lets orgs drop in harness YAML without new allow-listed workflows. Routing nuance (slash commands, labels, actor ACLs, fork gates) lives in portable expressions over a forge-neutral NormalizedEvent (normative v1 spec).
CEL evaluation requires knowing which harness files exist. ADR 0058 defines config-level agent registration — an agents list in org/per-repo config — that fullsend run and dispatch use to resolve harness paths at runtime (scaffold discovery removed — PR #5425; resolution is now config entries with agents-repo fallback for known first-party agents).
Options
Option A: Keep routing in workflow bash (status quo)
- Proven behavior; remains forge-coupled and hard to test.
Option B: Central config.yaml routing table
- One audit file; rules drift from harness definitions.
Option C: CEL trigger on harness files
- Self-describing agents; requires
fullsend dispatchand input/output drivers.
Decision
Adopt Option C.
NormalizedEvent: routing input with forge-neutral field names (docs/normative/normalized-event/v1/, ADR 0015). v1 normative scope is GitHub Actions (gha-eventdriver); other forges are documented as future illustrations only. (Scope extended to GitLab cron-poll input by ADR 0067 and to Jira poll input by ADR 0063.) Examples and projection rules live in the normative tree — not duplicated here.- Authorization:
fullsend dispatchenforces ADR 0054 as a platform-level gate after the input driver normalizes the event and before CEL trigger evaluation. Authorization is not delegated to per-harness CEL expressions. - Harness enumeration: before evaluating CEL
triggerexpressions,fullsend dispatchloads the harness set from agent registration per ADR 0058 (configagentsentries with agents-repo fallback for known first-party agents (scaffold discovery removed — PR #5425)). Each registered harness path is a candidate for CEL matching. - Harness
trigger: optional CEL boolean with root variableevent. Notrigger→ manualfullsend runonly. Multiple harnesses may match (parallel fan-out). fullsend dispatch: input driver → authorize → enumerate harnesses → evaluate harness CEL → project execution ref (unchangedfullsend runcontract) → output driver (gha-matrix,json, etc.). Drivers are flagged or auto-detected (GITHUB_EVENT_PATH→gha-event).- Workflow integration: installations may replace bash stage routing with
fullsend dispatch --output-driver gha-matrixand a dynamic job matrix. Reintroduces dynamic agent discovery via CEL (superseding ADR 0041's staticworkflow_callstage list) while keeping synchronous matrix-job execution. Deprecate# fullsend-stage:markers and duplicated bash routers where dynamic routing is adopted. - Coexistence with explicit workflows: implementing this ADR does not preclude hand-written workflows that invoke a particular harness file directly (today's per-agent or per-stage
workflow_callpattern). CEL-based dispatch and explicit harness invocation may run side by side in the same installation — for example, default agents routed byfullsend dispatchwhile org-specific agents remain on dedicated workflows that callfullsend runwith a fixed harness path.
Consequences
- Custom agents ship as harness files with
trigger; no per-agent workflow or dispatch bash edits. - Mint and inference allow-lists can trust a small set of generic runner workflows instead of every agent-specific workflow file.
- Authorization remains centralized per ADR 0054; CEL triggers express routing only, not permission policy.
- Routing is unit-testable via
NormalizedEventfixtures without GitHub Actions; input adapters own forge-specific mapping including commentcommand/instructionextraction (from downstream workflow steps such asreusable-fix.yml). - CEL linting, documentation, and eval fixtures are required (testing-agents.md); sequential multi-agent chaining remains out of scope (ADR 0018).
