# Bring an existing Agent to FluxBench Docker

This guide covers private Agents and open-source GitHub projects. FluxBench runs your image with the model API selected under your website account. Automatic source-to-image conversion is planned for later; adaptation and image building are currently manual.

## 1. Identify the task entrypoint

Locate the code that accepts a task, calls a model, executes tools and writes results. CLI programs, Python/Node applications and frameworks such as LangGraph can work. Projects that require interactive prompts, a browser or a permanent Web server need an entrypoint that runs one task unattended and exits.

Package your Agent and its dependencies. Do not package DC, Innovus, PrimeTime, licenses, technology libraries or API keys. The image and the user's model API configuration are submitted separately. Private repository credentials are build inputs, not image contents; keep them out of layers, build contexts and logs.

## 2. Transparent environment and prompt injection

FluxBench preserves your image's native ENTRYPOINT, CMD, WORKDIR and USER. You do not need to parse proprietary task JSON files. The platform automatically injects standard model credentials and writes the task instructions:

- **Model environment variables**:
  - `OPENAI_API_KEY`, `OPENAI_BASE_URL` (when OpenAI/chat_completions is selected)
  - `ANTHROPIC_API_KEY`, `ANTHROPIC_BASE_URL` (when Anthropic messages is selected)
  - `MODEL_NAME` (configured model ID)
- **Task paths and prompt**:
  - `TASK_WORK_DIR`: writable workspace directory for synthesis and PnR deliverables.
  - `TASK_PROMPT_PATH`: path to `prompt.md` containing benchmark requirements.
  - `$TASK_WORK_DIR/prompt.md`: automatically generated benchmark prompt.

Your agent can directly read standard environment variables or `$TASK_WORK_DIR/prompt.md`:

```python
import os
from pathlib import Path

api_key = os.environ.get("OPENAI_API_KEY") or os.environ.get("ANTHROPIC_API_KEY")
base_url = os.environ.get("OPENAI_BASE_URL") or os.environ.get("ANTHROPIC_BASE_URL")
model = os.environ.get("MODEL_NAME")

prompt_path = os.environ.get("TASK_PROMPT_PATH") or "prompt.md"
prompt = Path(prompt_path).read_text(encoding="utf-8")
```

If the framework accepts standard environment variables, no custom wrapper is required. Never write credentials into the image, prompt, Tcl, logs or artifacts. Shared Worker Claude/Codex account configuration is not injected.

## 3. Connect EDA tools

All benchmark inputs are mounted under `$FLUXBENCH_WORK_ROOT/picorv32_input` (RTL, SDC, technology files and checklists), read-only. Generated files live under the writable work tree. Container and host EDA see **the same absolute paths**: relative Tcl references, `source`, and output paths need no translation. Do not hard-code a particular task path.

The platform adds `dc_shell`, `innovus`, `pt_shell` to PATH, with their exact command paths in `task.tools`. These small command bridges call the corresponding Worker tool, stream logs and return its exit code. The image needs **Python 3 on PATH** for these commands; no pip dependency is required. Keep the injected PATH when launching a child shell (use `bash -c`, since a login shell may reset PATH).

```bash
cd "$FLUXBENCH_WORK_ROOT/01_dc/run"
dc_shell -f dc.tcl
# In an Innovus run* directory:
innovus -nowin -init route.tcl
# In a PrimeTime work directory:
pt_shell -multi -f eco.tcl
```

Supported arguments: `-f SCRIPT` or `-init SCRIPT`; `-multi` for PrimeTime; `-nowin` for Innovus. Scripts and cwd must exist within the task work tree. This is a batch command interface, not an interactive EDA terminal. Unsupported arguments return a readable error. A missing file or nonzero tool exit should be sent back to your Agent as a tool result so it can repair and retry.

File operations and stage checklists run inside the container. Actual EDA binaries use the Worker's unified environment (`/data/jydeng/eda-unified/v1/env.sh`), the same configuration used by Preset. Host installations and Docker sockets are not mounted into the image.

| Container command (path in `task.tools`) | Worker tool entry |
|---|---|
| `dc_shell` | `/data/jydeng/eda-unified/v1/bin/dc_shell` |
| `innovus` | `/data/jydeng/eda-unified/v1/bin/innovus` |
| `pt_shell` | `/data/jydeng/eda-unified/v1/bin/pt_shell` |

Frameworks can alternatively call the following HTTP interface directly, with no Python requirement.

`task.eda` supplies `socket`, `credential_file` and `operations_path`. Read the task token and use HTTP over the Unix socket:

```python
import httpx, uuid
endpoint = task["eda"]
token = json.loads(Path(endpoint["credential_file"]).read_text())["token"]
client = httpx.Client(
    transport=httpx.HTTPTransport(uds=endpoint["socket"]),
    base_url="http://localhost", trust_env=False,
    headers={"Authorization": "Bearer " + token},
)
response = client.post(endpoint["operations_path"],
    headers={"Idempotency-Key": uuid.uuid4().hex},
    json={"tool": "dc_shell", "script": "synth.tcl", "cwd": "01_dc"})
response.raise_for_status()
operation = response.json()
```

First write the script under `paths.work/01_dc/synth.tcl`. cwd is relative to paths.work; script is relative to cwd. Absolute task-local paths also work. Internal `..` and links are normalized; escaping the task is rejected. Older workspace-relative script requests remain compatible when no cwd-relative file exists. PATH_NOT_FOUND includes the resolved missing path.

- Tools: `dc_shell`, `innovus`, `pt_shell`.
- PrimeTime DMSA: add `"multi": true` to request `pt_shell -multi`. Other tools do not accept this mode.
- Status: `GET /v1/operations/{id}`.
- Logs: `GET /v1/operations/{id}/logs?after=0`; continue with the returned `next_cursor`.
- Cancel: `POST /v1/operations/{id}/cancel` with `{}`.

Wait for a terminal state and cleanup_complete=true before starting the next operation. Only one host EDA operation runs at a time. Exit code zero alone is not design success: inspect logs and artifacts, then repair failures. End tool Tcl with `exit`.

## 4. Preserve the task and artifact requirements

PicoRV32 runs DC → Innovus → PrimeTime/ECO. The platform prompt defines the frequency, die size, paths and deliverables.

Run each supplied stage checklist:

```bash
bash "$FLUXBENCH_INPUT_ROOT/checklist/check_dc_outputs.sh"
```

The platform injects the FLUXBENCH_*_ROOT variables into both the container and host EDA tools. In Tcl, use `$::env(FLUXBENCH_INPUT_ROOT)` for the input root. Use check_innovus_outputs.sh and check_pt_outputs.sh for subsequent stages. An exit-zero checklist may still print `MISSING:`. Repair missing outputs and rerun it.

Write progress to stdout/stderr. Exit zero on completion and nonzero on failure. Handle SIGTERM and cancel outstanding operations. Normal execution must finish one task and exit, rather than leave a permanent listener running.

On Workers with automatic evaluation enabled, the platform independently runs artifact acceptance and scoring after container and host operation cleanup. Passing stage checks, exiting zero or passing the compatibility check does not mean benchmark acceptance passed. Agents must not run platform scoring themselves. Internal artifact file links can be materialized during collection; escaping, broken and cyclic links are rejected.

### Stage indicators on the website

The platform reads stage progress from existing Agent stdout logs; no extra control endpoint is needed. The LangGraph example already emits `eda_submitted` and `stage_check`. Other frameworks can print a JSON line when work starts and an END event after the stage checks pass:

```json
{"kind":"stage_progress","stage":"dc","event":"START"}
{"kind":"stage_progress","stage":"dc","event":"END"}
```

Use stages `dc`, `innovus`, `pt`. A recoverable failure can emit FAILED followed by START when retrying. Put each record on its own line and flush promptly. An EDA exit code of zero does not complete a stage; emit END only after its checks pass. These indicators describe Agent progress; acceptance and scores are still calculated independently by the platform.

## 5. Build and export

Current requirements: linux/amd64, a default executable entrypoint, numeric UID/GID (or root), and no declared VOLUME. `USER 1000:1000` is recommended. Install and pin runtime dependencies at build time.

```dockerfile
FROM python:3.11-slim
WORKDIR /opt/agent
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
COPY fluxbench_entry.py .
USER 1000:1000
ENTRYPOINT ["python", "-u", "/opt/agent/fluxbench_entry.py"]
```

fluxbench_entry.py is your adapter from steps 2–4, not an automatically supplied universal converter. For Node or another runtime, change the base image and dependency installation accordingly.

Exclude .git, .env files, API configuration, SSH keys, caches and previous results through .dockerignore. Never copy your entire HOME into the image.

```bash
docker build --platform linux/amd64 -t my-agent:fluxbench .
docker save my-agent:fluxbench | gzip > my-agent.tar.gz
```

One image and platform per archive. `docker export` produces a container filesystem, not the required image archive. The current upload limit is 1 GiB; the outer archive expansion check defaults to 4 GiB. Execution is pinned to the loaded immutable image ID.

examples/langgraph-agent/ contains a runnable full-flow adapter supporting all three model protocols. Its earlier DC-only probe is preserved as dc_smoke_agent.py and is not the full-flow entrypoint.

The updated LangGraph example treats explicit EDA log errors as failures even when the exit code is zero. Three consecutive failures with identical script contents and errors terminate the Agent. Script or error changes start a new count, and success clears it. Rebuild and upload the image to enable this protection; a website update does not replace previously uploaded images.

## 6. Preflight compatibility testing (Sandbox Smoke Test)

External agent images do not need to implement custom SHA256 challenges or handshake files. Instead, the platform runs a transparent 4-point sandbox startup smoke test:

1. **Archive integrity**: Valid tar/tar.gz archive with a linux/amd64 manifest and defined ENTRYPOINT or CMD.
2. **Container startup**: Container starts up cleanly without missing shared libraries or architecture incompatibilities.
3. **EDA bridge execution**: Container can invoke mounted EDA CLI tools (`dc_shell --fluxbench-probe`) with exit code 0.
4. **Workspace write & exit**: Container has write access to the task workspace and terminates cleanly.

You can verify your image archive locally before submission using the CLI tool:

```bash
python -m fluxbench_backend.image_check /path/to/my-agent.tar.gz \
  --runtime --root /path/to/check-dir \
  --docker /path/to/docker
```

Results are saved to `report.json` with detailed diagnostics (`stderr_tail`) on failure.

## 7. Submit through the website

Sign in → Customer worker → select your `.tar` or `.tar.gz` image archive.

1. **Upload & Preflight**: The web console uploads the archive and runs the Sandbox Smoke Test asynchronously. Depending on image size and worker load, this may take a few minutes; the page shows progress while it runs.
2. **Verification feedback**:
   - On pass: displays `Verified: AMD64 / Entrypoint / EDA bridge ready` and enables the launch button.
   - On failure: displays `Verification Failed`, lists failed checks, and reveals container stderr logs to help identify missing libraries or entrypoint issues.
3. **Queue evaluation**: Select your model provider, frequency (350 or 700 MHz), and target worker, then start evaluation.

| Symptom | Action |
|---|---|
| UNSUPPORTED_IMAGE_USER | Use a numeric USER such as 1000:1000 |
| UNSUPPORTED_IMAGE_VOLUMES | Remove inherited VOLUME declarations; choose a different base if necessary |
| INCOMPATIBLE_PLATFORM | Rebuild for linux/amd64 |
| Missing EDA bridge execution | Ensure Python 3 is available in your container for running mounted EDA tool wrappers |
| 401 / model not found | Check the account's key, endpoint, protocol and actual model ID |
| INVALID_PATH / PATH_NOT_FOUND | Keep paths inside work; resolve script relative to cwd and create the file first |
| MISSING: | Complete the missing stage artifacts; this is not a passing check |
| Agent success without a score | Inspect evaluation enablement, acceptance errors and missing metrics |
