Prepare a Reusable Coding Environment from a Tiny Repository

Drafted and reviewed using AI assistance.

On this page

Make preparation finish before starting a service. A useful environment packet contains the source inputs, commands that rebuild its assets, checks with meaningful failures, and a separate way to start, inspect and stop the runtime. A server printing that it is listening is only one step in that sequence.

This tutorial supplies a complete original project, label-lab. It turns a two-row CSV into a deterministic JSON catalog, then serves it on a loopback address. We ran the packet from its source archive in two newly created, empty local directories. The local results below are actual executions of authored teaching code. They are not Codex Cloud runs, customer records or a model benchmark.

Get the complete source and its small contract

Download label-lab.zip and extract it. The archive contains the entire project under label-lab/, including its README:

label-lab/
  .gitignore
  README.md
  data/labels.csv
  scripts/build_catalog.py
  scripts/check_catalog.py
  scripts/prepare.py
  scripts/serve_catalog.py
  scripts/lifecycle.py
  scripts/wrong_prepare.py
  tests/test_catalog.py

Nothing in this project needs a package download, account, secret or external service. Use Python 3.9 or later on a POSIX system for the supplied lifecycle helper. That helper uses selectors to wait on its child process's output pipe. Verify the runtime available on your machine; the local version used here is reported below, rather than assumed to exist everywhere. Local policy must also allow binding a loopback socket.

The complete input CSV is:

id,label
alpha,Alpha
beta,Beta

The output contract is exactly these two entries, ordered by ID. The canonical file has this one line followed by one LF:

[{"id":"alpha","label":"Alpha"},{"id":"beta","label":"Beta"}]

The build script validates the header and rows, rejects duplicate IDs, sorts by ID and writes the JSON. The checker verifies both the exact two-entry meaning and canonical bytes. These are deliberately narrow rules for this fixture, not a general-purpose catalog format.

Run finite preparation and let it return

Open a terminal in the extracted label-lab directory. First check which interpreter you will use, then run preparation:

python3 --version
python3 scripts/prepare.py

Continue only if preparation exits with code 0. Its complete command file uses the same interpreter to run three finite operations:

scripts/build_catalog.py
scripts/check_catalog.py
-m unittest discover -s tests -v

Each operation has a bounded subprocess wait. A failed operation stops preparation. No service is started by this command, and the final line on success is:

preparation complete; no service started

You now have build/catalog.json. The complete converter and checker are included, so this result does not depend on a file left behind in the author's workspace. The build directory is disposable and excluded by .gitignore; the original CSV and scripts are the material to keep.

The three CLI behavior tests do more than check whether a path exists. They build the valid two-row catalog and compare its contents, ask the real converter to reject a duplicate alpha, and ask the checker to reject a missing catalog. Their inputs and outputs live in disposable directories. A rejected input is a successful negative test, not a successful build.

Start separately, verify readiness, then close the child

After preparation succeeds, run:

python3 scripts/lifecycle.py

The lifecycle helper starts exactly one catalog server at 127.0.0.1. It passes port 0, letting the operating system choose an available port without taking one from another process. The standalone server defaults to 8765 if no port is supplied; that default was not used by this reproduction.

The helper waits for a bounded listening announcement, then checks two different responses:

Request Required response in this fixture
GET /health HTTP 200, body exactly ok
GET /catalog HTTP 200, bytes identical to the checked build/catalog.json

The local client disables proxy use and contacts only the announced loopback address. If the catalog is missing or fails its contract, the server returns HTTP 503 with catalog unavailable; it does not invent an empty catalog or announce successful readiness.

The helper's finally block terminates and waits for its own child. A bounded kill-and-wait fallback exists if that child does not stop. It never searches for or kills a process using a port. The result reports the child's exit and a closed-port probe. Both successful local runs observed server exit 0, childStopped: true and portClosedAfterStop: true.

This helper is a finite start/check/stop exercise. It deliberately leaves no running service after it returns. If you want to inspect the server interactively instead, use another terminal:

python3 scripts/serve_catalog.py --port 0

Use the port from that process's own announcement and stop it with Ctrl-C in the same terminal. For work that needs a service to remain running, retain a supervised service session and define its shutdown separately. Do not mistake the finite lifecycle exercise for a daemon launcher.

See why a foreground server belongs outside preparation

Here is the complete deliberately wrong ordering:

python3 scripts/serve_catalog.py --port 0
python3 scripts/build_catalog.py
python3 scripts/check_catalog.py

In a fresh directory, the first command stays in the foreground. While it keeps running, the build and check lines are not reached. The socket may be listening, but there is no catalog to serve successfully.

This is an author-constructed recipe error. To observe it without leaving a process behind, the project includes a bounded demonstration. Run it only in a fresh copy without build/catalog.json:

python3 scripts/wrong_prepare.py

It waits one second for its own server, records that the next step has not been reached, and stops/reaps the child in finally. In local copy A, the observed result was:

{"authoredCounterexample":true,"buildStepReached":false,"catalogExists":false,"childStopped":true,"foregroundServerBlockedNextStep":true,"serverExit":0}

The demonstration's exit 0 means it observed the intended counterexample and cleaned up. It does not mean preparation completed. In the same unprepared copy, python3 scripts/lifecycle.py --timeout 0.5 exited 1 after observing HTTP 503; it also stopped the child and observed the port closed.

The repair was the earlier finite sequence: run prepare.py, wait for exit 0, then run lifecycle.py. That sequence actually built, checked, tested and served the catalog in copy A. It also succeeded independently in copy B, which was extracted afresh rather than copied from A's generated files.

Read the two-copy result at its actual scope

The reproduction requested /usr/bin/python3. Its recorded interpreter installation is represented by <LOCAL_PYTHON_EXECUTABLE> in the public files, reporting Python 3.9.6 on macOS 26.5.2 arm64. Both workspaces were newly created temporary directories, empty before extracting the same archive. The directories were removed afterward; the public command record preserves runtime, command semantics, stdout/stderr and exits while rebasing machine-specific paths to declared placeholders. This is a public projection, not byte-identical raw output; no project rerun was performed to produce it.

Observation Local copy A Local copy B
Catalog absent before preparation Yes Yes
Finite build, check and three behavior tests Exit 0 Exit 0
Duplicate-ID CLI result inside tests Exit 2; duplicate id: alpha; no output created Same
Absent-catalog checker result inside tests Exit 1; missing-catalog error Same
Prepared service health/catalog HTTP 200 / HTTP 200 HTTP 200 / HTTP 200
Catalog bytes 62 62
Child stopped and loopback port closed Observed Observed

Both generated the same SHA-256:

b82daf83bcd381d0dc86acf390f89197677e4988441b487d0ab45f2ae3759b90

The observed catalog file preserves those actual 62 bytes. The public reproduction report identifies the commands and the initial failure: the default local sandbox denied loopback binding. The later successful local runs had separate authorization permitting loopback access. That permission failure is separate from CSV validation and from a cloud service outcome.

Two clean directories on one machine establish this packet's local reconstruction under that runtime. They do not establish portability to every operating system, a provider's available runtime, or the state of a published cloud environment.

Map the packet to the documented cloud roles

OpenAI's current Cloud environments guide separates an Install script for dependencies and development assets from a Start skill for starting services and checking readiness. For a separately authorized setup, describe this repository and its verified runtime; use the finite preparation command for the first role and the README's service instructions for the second. The lifecycle helper checks and stops a service; it does not leave one running.

The guide says publishing captures prepared files for new tasks. Existing tasks keep their own saved state. After updating reusable setup, republish and start a new task to use it; do not expect an existing task to acquire that update automatically. It also currently excludes computer/browser use. This example needs terminal commands and loopback HTTP, not browser automation. This is a documented mapping, not a tested cloud setup or a guessed configuration schema. No environment or cloud task was created here.

Keep real failure reports separate from the teaching error

A public setup question asks how installation and startup fit together. A separate individual report of hanging cloud work describes problems after earlier small successes. The saved research retained conflicting date information and did not verify a root cause or general reliability. Our bounded foreground-server example is not a diagnosis or cure for that report.

Keep the original project files and exact command results when adapting the packet. If preparation fails, fix and rerun the failed finite step before starting a service. If health is unavailable, inspect the catalog and service result rather than treating a listening port as completion. You can type or speak the request that describes your environment; inspect any transcription, and preserve paths, options and negation. The input method does not establish better results.

The finished local packet gives the next reader something concrete to rebuild: complete inputs and code, a finite preparation command, an independently controlled service and actual reconstruction evidence. Any later cloud setup needs its own observed results.