Skip to content

Latest commit

 

History

35 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Park Bench Task Images

Docker task images for Park Bench.

This repo contains composable layers and Dockerfiles for the curated Park Bench task catalog. Each task image is assembled from reusable layers -- base content, extensions, harness configs, and skills -- combined via a Dockerfile under tasks/.

Layout

park-bench-task-images/
├── layers/
│   ├── base/                        # core task content
│   │   ├── make-me-a-playlist/
│   │   ├── oas-generation/
│   │   └── trellette/
│   ├── extensions/                  # pi agent extensions
│   │   ├── lint-guard-both-languages/
│   │   ├── lint-guard-only-python/
│   │   └── pied-pi/
│   ├── harness/                     # phase config + phase skills
│   │   ├── exercise-2phase/
│   │   └── fullstack-4phase/
│   └── skills/                      # domain knowledge libraries
│       ├── litestar/
│       ├── pi-extension-lint-guard-python-only/
│       ├── pi-extension-pied-pi-4-phase/
│       ├── playwright-bdd/
│       ├── react-frontend/
│       └── recommender/
├── tasks/
│   ├── oas-generation/
│   │   ├── Dockerfile
│   │   └── task-manifest.json
│   ├── make-me-a-playlist/
│   │   ├── Dockerfile
│   │   └── task-manifest.json
│   ├── trellette/
│   │   ├── Dockerfile
│   │   └── task-manifest.json
│   └── trellette-bare/
│       ├── Dockerfile
│       └── task-manifest.json
├── scripts/
├── .github/workflows/build-task-images.yml
└── Makefile

Layers

Layers live under layers/ and are organized into four categories:

base/ -- core task content

Source code, tests, docs, schemas, and prompts that define a task. Each subdirectory is a self-contained project (e.g. backend + UI + feature specs). Copied into /task/ in the final image. The runtime task-manifest.json lives next to each task's Dockerfile under tasks/<name>/, not inside the base layer, so variants can share a base while specifying their own manifest (different prompt, resources, scoring, etc.) without duplicating base content.

extensions/ -- pi agent extensions

Runtime extensions for the pi agent. Currently includes:

  • pied-pi -- the pied-pi runtime extension
  • lint-guard-both-languages -- linting enforcement for Python and TypeScript
  • lint-guard-only-python -- linting enforcement for Python only

Copied into /task/.pi/extensions/<name>/.

harness/ -- phase config and phase skills

Phase configuration (harness.json) and per-phase skill definitions that control how the harness orchestrates work. Examples:

  • exercise-2phase -- planning + implementation phases
  • fullstack-4phase -- planning, test-creation, implementation, documentation

Copied into /task/.pied-pi/.

skills/ -- domain knowledge libraries

Reference documentation that the agent can consult during execution. Each skill directory contains a SKILL.md entry point and supporting docs. Examples:

  • litestar -- Litestar framework patterns (DI, ORM, testing, OpenAPI)
  • react-frontend -- React component patterns, TanStack, Zustand
  • playwright-bdd -- Playwright BDD testing
  • recommender -- recommender system patterns
  • pi-extension-lint-guard-python-only -- lint-guard extension documentation
  • pi-extension-pied-pi-4-phase -- pied-pi harness documentation

Copied into /task/.pi/skills/<name>/.

Image contract

Every published task image must:

  • inherit from the unified Park Bench iteration base image
  • contain a /task directory
  • contain /task/task-manifest.json -- a valid JSON file matching the TaskManifest schema with manifest_version: 1
  • keep task contents self-contained
  • contain no symlinks under task/
  • define the label io.parkbench.task-name

The manifest is the authoritative runtime contract. Park Bench resolves the catalog image_ref, validates the manifest, extracts /task into the metadata cache, and executes the resolved image digest.

Publishing to GHCR

Task images are published by GitHub Actions from tags shaped like:

task/<task-name>/<version>

Examples:

git tag task/oas-generation/v1
git push origin task/oas-generation/v1

git tag task/make-me-a-playlist/v1
git push origin task/make-me-a-playlist/v1

git tag task/trellette/v1
git push origin task/trellette/v1

git tag task/trellette-bare/v1
git push origin task/trellette-bare/v1

The workflow publishes images named:

  • ghcr.io/<owner>/park-bench-task-oas-generation:<version>
  • ghcr.io/<owner>/park-bench-task-make-me-a-playlist:<version>
  • ghcr.io/<owner>/park-bench-task-trellette:<version>
  • ghcr.io/<owner>/park-bench-task-trellette-bare:<version>

Local development flow

Park Bench resolves task images by pulling them through Docker and then using a repo digest, so the end-to-end local flow should push to a local registry, not just build an unpushed local image.

1. Start a local registry

make registry-up
make registry-check

This uses 127.0.0.1:5000 so Docker can pull from the local registry without a custom TLS setup.

2. Build and push a task image locally

make build-oas TAG=dev
make smoke-oas TAG=dev
make push-oas TAG=dev

Or for the other tasks:

make build-playlist TAG=dev
make smoke-playlist TAG=dev
make push-playlist TAG=dev

make build-trellette TAG=dev
make smoke-trellette TAG=dev
make push-trellette TAG=dev

make build-trellette-bare TAG=dev
make smoke-trellette-bare TAG=dev
make push-trellette-bare TAG=dev

Builds use docker build -f tasks/<name>/Dockerfile with the repo root as the build context, so layer paths in COPY directives resolve correctly.

3. Point Park Bench at the local image

In the Park Bench repo, update the seeded catalog row to the local-registry ref. For example:

docker compose exec server python - <<'PY'
import sqlite3

conn = sqlite3.connect('/data/results.db')
conn.execute(
    """
    UPDATE task_images
    SET image_ref = ?, updated_at = datetime('now')
    WHERE name = ?
    """,
    ('127.0.0.1:5000/park-bench-task-oas-generation:dev', 'oas-generation'),
)
conn.commit()
conn.close()
PY

Then trigger a benchmark or suite run through Park Bench normally.

Creating task variants

To create a new task variant, add a directory under tasks/<name>/ with:

  • Dockerfile that composes the layers you need. The build context is always the repo root, so COPY paths start with layers/ or tasks/.
  • task-manifest.json describing the runtime execution contract (prompt, container resources, workspace rules, scoring paths, and persistence mode). The Dockerfile must copy it to /task/task-manifest.json.

For example, a stripped-down playlist variant without skills or lint-guard:

# tasks/make-me-a-playlist-no-skills/Dockerfile
FROM ghcr.io/danballance/park-bench-iteration:0.13.0

LABEL io.parkbench.task-name="make-me-a-playlist-no-skills"

COPY layers/base/make-me-a-playlist/     /task/
COPY layers/extensions/pied-pi/          /task/.pi/extensions/pied-pi/
COPY layers/harness/fullstack-4phase/    /task/.pied-pi/
COPY tasks/make-me-a-playlist-no-skills/task-manifest.json /task/task-manifest.json

Then add corresponding build-*, smoke-*, and push-* targets to the Makefile following the same pattern as the existing tasks.

Base image

All task Dockerfiles use the unified Park Bench iteration base image:

  • ghcr.io/danballance/park-bench-iteration:0.13.0

If you need to test against local, unreleased Park Bench base-image changes, build that base image locally with the same tag before building task images.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages