Thanks for helping improve SFT OPD. This guide is written for contributors who want to get a local checkout running quickly, make a focused change, and submit something that can be reviewed without guesswork.
- Go 1.22 or newer.
- Git.
- Optional: Playwright CLI for refreshing README screenshots.
- Optional: Python and an open-r1 checkout when working on grading flows that invoke the math verification filter.
git clone https://github.com/Piping/sftopd.git
cd sftopd
go test ./...The project has no Node.js build step. Web templates and static assets are embedded by Go from internal/app/web.
Use explicit roots when running outside the production workspace:
mkdir -p /tmp/sftopd-demo/data /tmp/sftopd-demo/logs /tmp/sftopd-demo/work
printf '%s\n' \
'{"source_id":"demo-001","problem":"Find x if x+7=12.","answer":"5"}' \
> /tmp/sftopd-demo/data/demo.jsonl
go run ./cmd/sftopd \
--addr 127.0.0.1:6060 \
--data-root /tmp/sftopd-demo/data \
--log-root /tmp/sftopd-demo/logs \
--work-dir /tmp/sftopd-demo/workOpen http://127.0.0.1:6060.
If 6060 is already in use, choose another local port:
go run ./cmd/sftopd --addr 127.0.0.1:6071go test ./...
go run ./cmd/sftopd help
go run ./cmd/sftopd training help
go run ./cmd/sftopd training specs
go run ./cmd/sftopd training status --jsonBuild a local binary:
go build -o sftopd ./cmd/sftopd- Keep changes focused on the workflow being fixed or added.
- Prefer the Go standard library unless a dependency removes real complexity.
- Preserve the embedded web asset model; avoid adding a frontend build pipeline for small UI changes.
- Keep HTTP handlers small enough to read and move reusable logic into
internal/dataorinternal/trainingwhen it belongs there. - Return structured JSON errors through the existing server helpers for API routes.
- Do not delete user data or runtime artifacts unless the command or UI action clearly says it does so.
At minimum, run:
go test ./...Add or update tests when a change affects parsing, file discovery, merge behavior, grading reports, task discovery, or any logic that can be exercised without a live SFT workspace.
For UI changes, also run the server locally and inspect the affected route in a browser. Check both a populated data root and an empty data/log root when possible.
Screenshots live in docs/assets/ and are referenced by README.md.
mkdir -p /tmp/sftopd-readme-demo/data /tmp/sftopd-readme-demo/logs /tmp/sftopd-readme-demo/work docs/assets
printf '%s\n' \
'{"source_id":"geo-001","problem":"Find x if x+7=12.","answer":"5"}' \
'{"source_id":"geo-002","problem":"A triangle has sides 3,4,5. What is the area?","answer":"6"}' \
> /tmp/sftopd-readme-demo/data/geometry.jsonl
go run ./cmd/sftopd \
--addr 127.0.0.1:6071 \
--data-root /tmp/sftopd-readme-demo/data \
--log-root /tmp/sftopd-readme-demo/logs \
--work-dir /tmp/sftopd-readme-demo/workIn another terminal:
playwright screenshot --viewport-size=1440,1000 http://127.0.0.1:6071 docs/assets/sftopd-dashboard.png
playwright screenshot --viewport-size=1440,1000 http://127.0.0.1:6071/data docs/assets/sftopd-data.pngOnly refresh screenshots when the visible UI changed or the README needs a new visual.
Before opening a PR, make sure:
go test ./...passes.- The change has a short, concrete description.
- New flags, environment variables, routes, or workflows are documented in
README.mdwhen user-facing. - Screenshots are refreshed if the documented UI changed.
- The PR does not include unrelated generated files or local machine artifacts.
When filing a bug, include:
- The command or route that failed.
- Effective
--data-root,--log-root, and--work-dirvalues when relevant. - Expected behavior and actual behavior.
- A short log excerpt or JSON response if the failure came from the CLI or API.
Avoid attaching private dataset samples unless they have been scrubbed.