Skip to content

Commit f219ca7

Browse files
authored
Merge pull request #24 from 3xcaffeine/docs
2 parents 10f8583 + 24c7f0a commit f219ca7

8 files changed

Lines changed: 1145 additions & 25 deletions

File tree

README.md

Lines changed: 278 additions & 0 deletions
Large diffs are not rendered by default.

assets/blog.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Building long-horizon SWE environments on Hugging Face: Frontier SWE × OpenEnv
2+
3+
**By the-thing**: we packaged and adapted 4 [FrontierSWE](https://www.frontierswe.com/) tasks as [OpenEnv](https://github.com/rycerzes/OpenEnv)-shaped services, pushed them to **Hugging Face Spaces**, and ran an **offline RL-style** training loop with public **datasets**, **Trackio** metrics, and a trainer Space.
4+
5+
---
6+
7+
## TL;DR
8+
9+
- **Four Dockerized environments** (notebook compression, Postgres wire adapter on SQLite, dependent type checker, libexpat → x86-64 asm) with a **shared Gym-style API** and **MCP** tools for planning and submission.
10+
- **Custom harness adapter** built on top of OpenEnv harness work ([meta-pytorch/OpenEnv PR #389](https://github.com/meta-pytorch/OpenEnv/pull/389) and RFC005), then forked and extended in [`rycerzes/OpenEnv` on `feature/pi-harness-adapter`](https://github.com/rycerzes/OpenEnv/commits/feature/pi-harness-adapter/).
11+
- **Composite rubric**: gates → L1 (tests / `reward.json` / regex ratios) → optional LLM layers → **episode reward** you can log and filter on for training.
12+
- **Offline pipeline**: trajectories on the Hub → hindsight scoring (SGLang) → HCAPO-style dataset → **LoRA fine-tune** on a GPU Space, with **Trackio** curves for loss, LR, and gradient norms.
13+
14+
**Try it:** [frontier-swe-postgres](https://huggingface.co/spaces/rycerzes/frontier-swe-postgres) · [frontier-swe-notebook](https://huggingface.co/spaces/rycerzes/frontier-swe-notebook) · [frontier-swe-type-checker](https://huggingface.co/spaces/rycerzes/frontier-swe-type-checker) · [frontier-swe-libexpat-to-x86asm](https://huggingface.co/spaces/rycerzes/frontier-swe-libexpat-to-x86asm) · [source on GitHub](https://github.com/3xcaffeine/frontier-swe-openenv)
15+
16+
---
17+
18+
## 1. Environment innovation - why this setup is hard (and worth it)
19+
20+
Classic coding benchmarks often score a single patch. **Long-horizon software engineering** is different: the agent has to **plan**, **edit a real workspace**, **call tools**, and **submit** work over many steps-closer to how people ship systems than to a one-shot fix.
21+
22+
**What we built on top of that idea**
23+
24+
We did not reinvent the underlying FrontierSWE task specs; we **re-homed** them inside a **uniform environment contract**:
25+
26+
That includes a **custom harness adapter** layer we built on top of [meta-pytorch/OpenEnv PR #389](https://github.com/meta-pytorch/OpenEnv/pull/389) and RFC005, then maintained and updated in our fork: [`rycerzes/OpenEnv` `feature/pi-harness-adapter`](https://github.com/rycerzes/OpenEnv/tree/feature/pi-harness-adapter/).
27+
28+
| Piece | What it does for the agent |
29+
| --- | --- |
30+
| **HTTP control** | `reset` / `step` / `state` / `health` - same shape every task, so harnesses and demos do not fork per domain. Maintaining the `openenv` specs |
31+
| **MCP tools** | `submit_plan`, `submit_subtask`, `get_status`, `advance` - forces **explicit decomposition** and **scored subtasks**, not a single anonymous blob of edits. |
32+
| **Multi-layer rubric** | **Gates** catch broken builds or missing artifacts early; **L1** is task-native (wire compat tests, notebook round-trips, type-checker scores, assembly benchmarks); **L2/L3** optionally add LLM code and plan review when grader env vars are set; **episode reward** blends plan quality, frozen subtask scores, completion, and tool usage. |
33+
34+
That combination is deliberately **stressful** in a good way: the agent must **coordinate** (plan → execute → advance), **respect verifier reality** (hidden tests, anti-cheat), and **earn** a dense scalar at the end of an episode that can run on the order of **45–90+ minutes** per run-so the environment is **challenging**, **creative** in how it composes rubrics, and **meaningful** for measuring behavior beyond single-turn chat.
35+
36+
---
37+
38+
## 2. The problem, the box, and what the agent actually does
39+
40+
**Problem.** Training or evaluating agents on real long-horizon SWE needs a **repeatable service**: same ports, same instructions, same scoring, same tool surface-whether you run locally, in CI, or on the Hub.
41+
42+
**Our box.** **frontier-swe-openenv** is a small monorepo: `tasks/<task-id>/` holds instructions and verifiers (what “correct” means operationally); `frontier_swe_env/` holds the **FastAPI** server, shared rubrics, and **TaskConfig** (how to invoke those verifiers inside the image); `spaces/` holds thin **Space** definitions synced from `main` after images build.
43+
44+
**Agent behavior (easy to follow for a demo).**
45+
46+
1. Connect (WebSocket client or baseline script).
47+
2. `reset` → read observation / phase.
48+
3. Loop: natural language or tool use → `step` → optional MCP calls to **submit a plan**, run **L1+L2** on a **subtask**, **advance** when satisfied.
49+
4. Episode ends with a **terminal episode reward** and subtask history you can log.
50+
51+
For a **concrete walkthrough without writing your own client**, the repo ships [`scripts/run_baseline.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/run_baseline.py): point it at `http://localhost:8000` with a task container running, and you get a full **reset → step** episode over the wire-good for recordings and “here is one turn of the loop” explanations.
52+
53+
---
54+
55+
## 3. Observable training progress - rewards, curves
56+
57+
Long episodes make **online** RL on the live env impractical at scale, so we invested in **offline** learning: **collect once**, **score offline**, **fine-tune**, **log everything**.
58+
59+
**Public artifacts (HF-native story)**
60+
61+
| Artifact | Link | Role in the demo |
62+
| --- | --- | --- |
63+
| Raw trajectories (pg-01, Qwen 3.6 27B) | [`rycerzes/fswe-pg-01-traj-q36-27b`](https://huggingface.co/datasets/rycerzes/fswe-pg-01-traj-q36-27b) | Shows **what** we logged per episode (`result.json`, sessions, logs, hindsight when present). |
64+
| HCAPO training JSONL | [`rycerzes/fswe-hcapo-pg-01-trajectories`](https://huggingface.co/datasets/rycerzes/fswe-hcapo-pg-01-trajectories) | **Step-level advantages** paired with messages for supervised fine-tuning. |
65+
| Trackio dashboard | [`rycerzes/trackio`](https://huggingface.co/spaces/rycerzes/trackio) | **Observable** loss, epoch, learning rate, gradient norm, global step. |
66+
67+
On a **3 epoch / ~18 optimizer step** reference run (Space-backed trainer), the root README documents what we see in Trackio: **loss** trending down on the order of **~25%** over the plotted window (smoothed), **epoch** progressing toward **~2.7**, **LR** warmup-then-decay, **gradient norms** staying in a moderate band-i.e. a **sanity fine-tune** where optimization looks stable, not a mystery box.
68+
69+
We also ship a **static dashboard figure** in-repo for slides and blog embeds: [`assets/training-trackio-dashboard.png`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/assets/training-trackio-dashboard.png).
70+
71+
**Before / after.** The cleanest **before/after** we surface in tooling today is **training loss and optimization metrics** on the HCAPO dataset, plus **episode-level rewards inside collected trajectories** for analysis. A live **A/B rollout score** on the full Docker env after LoRA is the natural next chapter for the demo-and the pipeline is set up so you can **regenerate trajectories** with the adapted policy and compare distributions. For hackathon judging, the **curves + public datasets + reproducible launch script** are the evidence chain we stand behind *right now*.
72+
73+
---
74+
75+
## 4. Reward logic and training pipeline - coherent signal end to end
76+
77+
**Episode reward (macro).** The scalar \(R\) matches [`EpisodeRubric`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/frontier_swe_env/rubrics/episode_rubric.py): weighted **plan score**, mean **frozen subtask** scores, **completion**, and **tool density**-clipped into **[0, 1]** for filtering (e.g. `--min-reward 0.05` in the dataset builder).
78+
79+
**L1 (micro, task-specific).** Each task implements its own verifier output: **regex ratio** on test totals (Postgres), **`reward_json`** fields (notebook), or **`reward_json_score`** with anchors (type checker, libexpat). Same server code paths; different physics.
80+
81+
**Training path (why it should move policy behavior).**
82+
83+
1. [`collect_trajectories.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/collect_trajectories.py) - rollouts into `trajectories/episode_NNN/`.
84+
2. [`backfill_rewards.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/backfill_rewards.py) - repair missing `episode_reward` when needed.
85+
3. [`compute_hindsight_scores.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/compute_hindsight_scores.py) - SGLang `/generate` with bounded logprob windows (memory-safe), MCP-aware **step → subtask** mapping, hindsight \(Q^H\) and smoothing.
86+
4. [`build_hcapo_dataset.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/build_hcapo_dataset.py) - GRPO-style macro advantages + normalized hindsight micro advantages → **JSONL** with **per-step weights**.
87+
5. [`train_hcapo.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/training/train_hcapo.py) + [`launch_hf_space.sh`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/scripts/launch_hf_space.sh) - **weighted CE on assistant tokens** (chunked forward for large models), Trackio reporting.
88+
89+
Coherent design is means that environment reward defines **which episodes matter**; hindsight defines **which tokens inside those episodes** get gradient; the trainer respects **assistant masks** and **step weights** so the update is not “one scalar smeared across the whole transcript.” Details and equations live in [`training/README.md`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/training/README.md)
90+
91+
---
92+
93+
## Where to go next
94+
95+
- **Run a Space** from the TL;DR links and narrate **one** subtask submission end to end.
96+
- **Open Trackio** to the named run and zoom the **loss / LR** panel while you talk through the pipeline slide.
97+
- **Clone the repo**, `uv sync`, and use **`./scripts/launch_hf_space.sh`** when you want the full HF training path on your own account.
98+
353 KB
Loading

spaces/libexpat-to-x86asm/README.md

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,82 @@ pinned: false
1010

1111
# Frontier SWE — libexpat to x86-64 Assembly
1212

13-
OpenEnv-shaped FastAPI service hosting the libexpat-to-x86asm task.
13+
OpenEnv-shaped **FastAPI** service for the **libexpat-to-x86asm** task: reimplement **libexpat 2.6.4** in **x86-64 assembly**, producing `/app/asm-port/libexpat.so` with the **expat C ABI**. The verifier compares against reference C libexpat, runs upstream tests and benchmarks, and writes `/logs/verifier/reward.json` (correctness and performance blend; hard fail to `0.0` on anti-cheat or missing `.so`).
1414

15-
- Source repo: <https://github.com/3xcaffeine/frontier-swe-openenv>
16-
- Container image: `ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-libexpat-to-x86asm:latest`
17-
- Health: `/health`
18-
- MCP JSON-RPC: `/mcp`
15+
## The task in depth
1916

20-
Deployed automatically from `main` via the `sync-hf-spaces` workflow.
17+
The agent’s deliverable is a **shared library** built from **`.s` / `.asm`** sources under **`/app/asm-port/`**, exporting symbols such as **`XML_ParserCreate`** so the upstream **expat** test suite can link against it. There is **no C compiler** in the agent environment; the verifier may compile reference C code for comparison. Scoring combines **weighted test pass rates** with **benchmark timing ratios** (reference time vs agent time) into a single **`score`** in **`reward.json`**, with explicit anti-cheat checks (no `dlopen` of system libexpat, no smuggled C core files, etc.). The server treats that file in **`reward_json_score`** mode with anchors **`(0.0, 1.0)`**.
18+
19+
## How this maps to the monorepo
20+
21+
- **`tasks/libexpat-to-x86asm/`** — Instructions, encrypted or staged toolchain bundles as designed, **`tests/`** with **`test.sh`**, **`compute_reward.py`**, and benchmark XML generators.
22+
- **`frontier_swe_env/tasks/libexpat_to_x86asm.py`****`TaskConfig`**: workspace **`/app/asm-port`**, gate script, verifier command, JSON path and anchors, CPU/memory hints, and judge context strings.
23+
- **`spaces/libexpat-to-x86asm/`** — This Space and manifest.
24+
25+
See [**Task assets and runtime configuration**](https://github.com/3xcaffeine/frontier-swe-openenv#task-assets-and-runtime-configuration) in the root README.
26+
27+
## Features
28+
29+
- **Assembly port workspace**: `/app/asm-port` with staged toolchain and bundles (see gate checks in manifest).
30+
- **Structured L1**: Normalised score from `reward.json`; gates for writable workspace, headers, `nasm` / `as` / `ld`, and staged artifacts.
31+
- **LLM rubric layers**: L2 code review and L3 plan review when grader env vars are set.
32+
- **MCP tools**: `submit_plan`, `submit_subtask`, `get_status`, `advance`.
33+
34+
## HTTP API
35+
36+
| Endpoint | Notes |
37+
| --- | --- |
38+
| `GET /health` | Liveness. |
39+
| `POST /reset`, `POST /step`, `GET /state` | OpenEnv Gym-style control. |
40+
| `POST /mcp` | OpenEnv JSON-RPC MCP. |
41+
| `/tools/mcp` | FastMCP Streamable HTTP. |
42+
43+
## Quick start (Docker)
44+
45+
```bash
46+
docker run --rm -p 8000:8000 \
47+
ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-libexpat-to-x86asm:latest
48+
```
49+
50+
This task is CPU- and memory-sensitive; the manifest requests **4 CPUs** and **8192 MiB** where the platform allows.
51+
52+
```bash
53+
docker run --rm -p 8000:8000 \
54+
-e FSWE_GRADER_MODEL=... \
55+
-e FSWE_GRADER_API_URL=... \
56+
-e FSWE_GRADER_API_KEY=... \
57+
ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-libexpat-to-x86asm:latest
58+
```
59+
60+
## Python client (host)
61+
62+
```python
63+
import asyncio
64+
from frontier_swe_env.client import FrontierSweEnv
65+
from frontier_swe_env.models import FrontierSweAction
66+
67+
68+
async def main():
69+
client = FrontierSweEnv(base_url="http://localhost:8000")
70+
await client.connect()
71+
try:
72+
await client.reset()
73+
await client.step(FrontierSweAction(message="Continue the assembly port."))
74+
finally:
75+
await client.close()
76+
77+
78+
asyncio.run(main())
79+
```
80+
81+
## Task manifest
82+
83+
[`openenv.yaml`](openenv.yaml) — episode timeout, L1 timeout, reward field anchors, rubric layers, metrics. Task sources: `tasks/libexpat-to-x86asm/`.
84+
85+
## Deployment
86+
87+
- **Image**: `ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-libexpat-to-x86asm:latest`
88+
- **Source**: [3xcaffeine/frontier-swe-openenv](https://github.com/3xcaffeine/frontier-swe-openenv)
89+
- **Sync**: HF Space updated from `main` after successful GHCR build.
90+
91+
Benchmark context: [FrontierSWE — libexpat to x86-64 assembly](https://www.frontierswe.com/libexpat-to-x86asm).

spaces/notebook/README.md

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,84 @@ pinned: false
1010

1111
# Frontier SWE — Notebook Compression
1212

13-
OpenEnv-shaped FastAPI service hosting the notebook-compression task.
13+
OpenEnv-shaped **FastAPI** service for the **notebook-compression** task: build a fit / compress / decompress pipeline for Jupyter notebooks inside a Linux workspace, with multi-layer rubric scoring and a structured `reward.json` written by the verifier.
1414

15-
- Source repo: <https://github.com/3xcaffeine/frontier-swe-openenv>
16-
- Container image: `ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-notebook:latest`
17-
- Health: `/health`
18-
- MCP JSON-RPC: `/mcp`
15+
## The task in depth
1916

20-
Deployed automatically from `main` via the `sync-hf-spaces` workflow.
17+
The agent needs to ship an executable **`/app/run`** with three subcommands: **`fit`** (train or build artifacts from a **visible** corpus only), **`compress`**, and **`decompress`**. At scoring time the agent does not see the hidden corpus: the verifier checks **byte-for-byte** recovery of every notebook file. Compression quality is summarised as a geometric mean of size ratios; hard failures (round-trip mismatch, crashes, invalid `reward.json` status) collapse the L1 signal to zero. That logic lives in the repo under [`tasks/notebook-compression/tests/`](https://github.com/3xcaffeine/frontier-swe-openenv/tree/main/tasks/notebook-compression/tests) (shell driver plus [`compute_reward.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/tasks/notebook-compression/tests/compute_reward.py)), which writes **`/logs/verifier/reward.json`** for the server to read.
2118

19+
## How this maps to the monorepo
20+
21+
- **`tasks/notebook-compression/`** — Authoritative instructions, verifier, and reward computation; copied into the image (for example **`/opt/verifier/test.sh`** and data mounts).
22+
- **`frontier_swe_env/tasks/notebook_compression.py`** — Registers **`TaskConfig`** with `l1_score_mode="reward_json"`, the container test command, long L1 timeouts, gate path, and prose for L2/L3 judges. The running server selects it when `FSWE_TASK_NAME` is `notebook` or `notebook-compression` (see [`__init__.py`](https://github.com/3xcaffeine/frontier-swe-openenv/blob/main/frontier_swe_env/tasks/__init__.py)).
23+
- **`spaces/notebook/`** — This Space: thin Dockerfile, this README, and **`openenv.yaml`** describing the same episode for Hugging Face and external tooling.
24+
25+
For the full picture of how task directories and Python configs interact, see the root README section [**Task assets and runtime configuration**](https://github.com/3xcaffeine/frontier-swe-openenv#task-assets-and-runtime-configuration).
26+
27+
## Features
28+
29+
- **Long-horizon SWE**: Plan subtasks, edit code under the configured workspace, submit for scoring.
30+
- **Composite rubric**: Shell gate checks → structured L1 from `/logs/verifier/reward.json` → optional LLM code review (L2) and plan review (L3) → weighted episode reward.
31+
- **MCP tools**: `submit_plan`, `submit_subtask`, `get_status`, `advance` (same contract as other Frontier SWE Spaces).
32+
- **Dual MCP transports**: OpenEnv `POST /mcp` and Streamable HTTP `/tools/mcp` for adapters.
33+
34+
## HTTP API
35+
36+
| Endpoint | Notes |
37+
| --- | --- |
38+
| `GET /health` | Liveness for orchestration and HF health checks. |
39+
| `POST /reset`, `POST /step`, `GET /state` | OpenEnv Gym-style control. |
40+
| `POST /mcp` | OpenEnv JSON-RPC MCP. |
41+
| `/tools/mcp` | FastMCP Streamable HTTP (POST + GET/SSE). |
42+
43+
## Quick start (Docker)
44+
45+
```bash
46+
docker run --rm -p 8000:8000 \
47+
ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-notebook:latest
48+
```
49+
50+
Optional grader configuration for LLM rubric layers:
51+
52+
```bash
53+
docker run --rm -p 8000:8000 \
54+
-e FSWE_GRADER_MODEL=... \
55+
-e FSWE_GRADER_API_URL=... \
56+
-e FSWE_GRADER_API_KEY=... \
57+
ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-notebook:latest
58+
```
59+
60+
## Python client (host)
61+
62+
From the [source repository](https://github.com/3xcaffeine/frontier-swe-openenv), with dependencies installed:
63+
64+
```python
65+
import asyncio
66+
from frontier_swe_env.client import FrontierSweEnv
67+
from frontier_swe_env.models import FrontierSweAction
68+
69+
70+
async def main():
71+
client = FrontierSweEnv(base_url="http://localhost:8000")
72+
await client.connect()
73+
try:
74+
await client.reset()
75+
await client.step(FrontierSweAction(message="Continue the task."))
76+
finally:
77+
await client.close()
78+
79+
80+
asyncio.run(main())
81+
```
82+
83+
## Task manifest
84+
85+
OpenEnv metadata for judges and tooling: [`openenv.yaml`](openenv.yaml) in this Space (mirrors `spaces/notebook/openenv.yaml` in the GitHub repo). Task sources: `tasks/notebook-compression/`.
86+
87+
## Deployment
88+
89+
- **Image**: `ghcr.io/3xcaffeine/frontier-swe-openenv/frontier-swe-notebook:latest`
90+
- **Source**: [3xcaffeine/frontier-swe-openenv](https://github.com/3xcaffeine/frontier-swe-openenv)
91+
- **Sync**: Pushed from `main` by the repository’s HF Spaces sync workflow after GHCR builds succeed.
92+
93+
Benchmark context: [FrontierSWE — Notebook compression](https://www.frontierswe.com/notebook-compression).

0 commit comments

Comments
 (0)