Repository navigation
Releases: eyelock/ynf
Release list
v0.4.0
ynf v0.4.0
Each run's telemetry budget now reaches ynr, and ynf moves to the current ynh, ynr and ynm releases. Nothing has been removed, and no existing lane changes behaviour.
The spool manifest carries the run's budget: run_quota_bytes
ynf holds each run's spool folder to telemetry.run_quota (64 MiB by default). Until now that budget was never handed to ynr. The manifest ynf writes for each run (manifests/<run id>.json) now carries it as run_quota_bytes, in bytes, beside the run, lane, harness, focus, item, step and uid.
From ynr 0.3.1, ynr serve reads it: it stops reading a run folder that exceeds its budget, and stamps what it shipped from that run with ynr.provenance.warning=over-budget. A ynr that predates the field ignores it, and a manifest without it is read with the 64 MiB default.
Pins
The factory image and CI are tested against:
- ynh 0.14.0 (was 0.12.0)
- ynm 0.4.2 (was 0.4.1)
- ynr 0.3.2 (was 0.2.2)
ghcr.io/eyelock/ynf-factory:0.4.0 carries ynh 0.14.0 and ynm 0.4.2. What the new ynh brings to a factory run includes: sensors from an included harness run against that harness (and an include can opt out with "sensors": false), a harness's includes baked into its image, and the harness's own repository refreshed on every run. ynh 0.14.0 still lists the agent-run-harness-path and agent-run-fetches-includes features, so folder harnesses run as before.
ynf's CI now also runs ynr's conformance rule 13 (never into memory), with ynm on the PATH, and it passes.
Upgrading from 0.3.0
Nothing to change. run_quota_bytes is written for you from telemetry.run_quota. To have ynr enforce it, run ynr 0.3.1 or later.
Install
brew install eyelock/tap/ynfghcr.io/eyelock/ynf-factory:0.4.0
v0.3.0
ynf v0.3.0
Two new lane settings let you say more about which paths a run may touch, and lanes validate now catches a harness pinned to a branch. Everything is optional and nothing has been removed.
Append-only paths: pr.append_only_paths
A lane can list paths that a run may add to but not change. The diff gate reads how each path changed (added, modified, deleted, type changed; a rename counts as a deletion plus an addition) and allows additions only. A refused run escalates, and the refusal names each path and how it changed:
diff gate refused: <path> (append-only: modified|deleted)
For example: diff gate refused: internal/x/x_test.go (append-only: modified), internal/y/y_test.go (append-only: deleted).
The built-in protected paths and protected_paths are judged first, then allowed_paths. Shadow mode asks the same question, so its gate_accepted agrees with the live gate.
The limit: append-only does not stop a new file from changing how existing tests run. A Go TestMain or init() in a new _test.go, or a new conftest.py, passes the gate. The companion on the harness side is the ynh "test trust" sensors, which check that no tests were lost, that a new test fails before the change, and run mutation testing on the diff.
Review paths: pr.review_paths
Routing only. When a run touches a path matching pr.review_paths, the pull request opens as usual, labelled ynf:review-paths, with a ### Touches review paths section in its body listing the paths. It requests no reviewers and changes no decision. The enforced version is a CODEOWNERS file plus a ruleset that requires code-owner review.
lanes validate refuses a harness pinned to a branch
ynf lanes validate now applies the same check as a run and ynf harness: a harness pinned to a branch is refused, because a branch moves. Use a tag or a commit. To tell a branch from a tag or commit, validate reads the pin repository's refs, so it needs the network for a lane with a pinned harness.
Run record: added and deleted
The run record gains added and deleted lists beside changed. changed is unchanged. A path in changed that is in neither list was modified, and a record without the new lists reads every change as a modification.
Pins
The factory image and CI are tested against:
- ynh 0.12.0
- ynm 0.4.1
- ynr 0.2.2
Upgrading from 0.2.0
Nothing was removed and no existing lane changes behaviour. pr.append_only_paths and pr.review_paths are new, optional lane settings. The one change you may notice is that ynf lanes validate now fails a lane whose pinned harness is a branch (a run already refused it), and it needs the network for pinned lanes.
Install
brew install eyelock/tap/ynfghcr.io/eyelock/ynf-factory:0.3.0
v0.2.0
ynf v0.2.0
Shadow mode
ynf shadow run --auto-approvelets a shadow run grant edits on the host.- Shadow mode measures a lane's yield against closed tickets: it replays the lane on the commit before a human fix, grades the attempt, and changes nothing outward.
Runner detection, and finding tools only on PATH
- A lane with no runner uses ynh when it is detected, and otherwise runs its command.
- ynf finds ynh and ynr only on PATH, like any other command.
Sensor scope
sensor_scopemay only narrow a declared sensor. It can no longer replace one, but it may keep the declared environment prefix verbatim.
Memory
- Memory writes queue while ynm is down and are sent when it is back.
- Failure memories carry what the run reported, so memory can explain a failure. Failure records end with a full stop.
- ynm's store is found as ynm finds it: the git root, then
YNM_HOMEor~/.ynm, with no walk up.
OpenTelemetry on ynr's contract
- Steps are traced as
ynf.stepspans on ynr's OpenTelemetry contract. - Intake events are mirrored as CloudEvents.
- Each run gets its own spool folder, which can be its own volume, and a run's manifest names its user.
ynr servecollects a factory job.- Quotas apply to what a run spools.
- A job cleans up run volumes left behind by a ynf that was killed.
- ynr conformance and the full-chain trace check run in CI.
Harnesses
- A lane whose harness is a folder runs on the process and inline executors, as well as the others.
- A harness pin's host/path form is normalised to https.
- On the host, a harness pinned from git runs without a copy, and an unreadable harness folder is an error.
- A folder harness goes straight to ynh when ynh reports
agent-run-harness-path, and it supports git includes.
PR checks
- ynf reads every required check, including those set by rulesets, by App, and across pages.
- A PR whose required checks are never reported stays proposed.
- No-CI escalation: a PR with no CI is warned about, and can be escalated after a delay.
Item references and reasons
- Short references find adopted PRs, and items show the latest reason.
--versionis supported.- A sweep that finds nothing now says so, with a hint.
- Calibration runs after e2e, and skips a fixture with no fixed state, saying why.
The public repository
- ynf is now public. The private plumbing is gone, Terraform keeps the repository public, and security and conduct concerns go to support@eyelock.net.
Pinned: ynh 0.12.0, ynm 0.4.1, ynr 0.2.2.
Upgrading from 0.1.0
YNF_YNH_BINandYNF_YNR_BINare removed. Put ynh and ynr on PATH.- Lanes have an
idfield. - There is a new
telemetryconfig. calibrate.skipis new.no_ci_afterandwhen.no_ciare new.- ynm is detected only when a store is configured.
ynf shadow run --auto-approveis new, for granting edits to a shadow run on the host.- Replaying retry decisions recorded before 0.2.0 shows a wording difference in the reason.
Install
brew install eyelock/tap/ynf, or ghcr.io/eyelock/ynf-factory:0.2.0.
v0.1.0
ynf 0.1.0
The first release of ynf, your named factory: the outer loop around agent runs. ynf watches tickets and pull requests, decides what to do with each one, runs an agent (through ynh) or a command in containment on a fresh checkout, proposes the change as a draft pull request, and follows it through CI and review. A human always merges. What keeps going wrong is remembered in ynm.
Docs: https://eyelock.github.io/ynf/, with two tutorial tracks: ynf on its own, and the factory with ynh, ynm and ynf together.
What's in it
The loop
- Work items with a durable state machine, and a pure decider: every decision is recorded and
ynf replayrecomputes it, under the recorded lanes or a changed lanes file. - Lanes in versioned YAML with CEL guards. A configuration repository's lanes lie under each repository's own, merged key by key.
ynf lanes validate --repochecks a repository's lanes merged as ynf would. - One claim at a time: leases with heartbeats and fencing, over SQLite or S3. A crashed run is restarted, not resumed.
- Stop conditions: yield floors, pausing a lane with a reason, and
ynf statsper lane.
Starting work
- From a search (
sweep,serve), a GitHub webhook (serve --listen), a CI event (handle, with--lane), or by instruction:ynf start <ticket>orynf start --prompt … --label …. - Trackers besides GitHub, through their MCP server, such as JIRA. ynf calls the tools itself, with no model.
- GitHub.com and GitHub Enterprise Server as forges, with host-qualified item keys.
Running it
- Runners: ynh, for an agent with its harness, sensors and budgets, or any command.
- A lane may pin the agent's model (
run.ynh.model) and effort (run.ynh.effort), tighten its budgets and scope its sensors. It never loosens or redefines them. - Executors: docker, with an egress proxy and an allow list; process, attended only; and inline, inside the factory image under the job runner's containment.
- Each run gets a self-contained checkout, so git works inside the container.
--auto-approveonly inside containment.
Seeing what happened
- Every run records the model, effort, turns, tokens (input, output and cache reads), cost, the cap that bound it, and the harness version.
ynf statsbreaks every lane down by model and effort.- Failure signatures name what failed: the sensor, the budget cap, the CI check that diverged from the loop's sensors. Each occurrence is written to ynm, tagged
occurrence, locally or over HTTP to a hosted ynm with a machine token. ynf doctor,forges,trackers,ticketandharnesscheck a factory before it's relied on.
The factory image
ghcr.io/eyelock/ynf-factory:0.1.0, for amd64 and arm64: ynh 0.10.0's image with ynf and ynm 0.3.0. Build your harness on it with ynh image … --base, and run it as a job (Run the factory image).
Install
brew install eyelock/tap/ynfynf pairs with ynh 0.10.0 and ynm 0.3.0. Both are optional: ynf detects them, and runs commands without them.