Buildml’s problem library grows through community contributions. If you have an AI/ML concept, algorithm, or paper implementation that would make a good challenge, you can add it by writing a TypeScript seed script, providing a Python starter template for users, and supplying a test file for the executor service that grades submissions. This guide walks through every step of that process.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Praashh/buildml/llms.txt
Use this file to discover all available pages before exploring further.
Data Model Overview
Before writing any code, it helps to understand how content is structured in the database. The Prisma schema (prisma/schema.prisma) defines two core models for problem content:
ProblemSet is a named, slug-identified collection of related problems — for example, "NumPy Fundamentals" or "Attention Is All You Need". It has a title, a globally unique slug, and an optional description.
Problem belongs to a ProblemSet and represents a single coding challenge. Each problem has:
| Field | Type | Purpose |
|---|---|---|
title | String | Display name shown in the UI |
slug | String (unique) | URL identifier — must be globally unique across all problems |
description | String (@db.Text) | Full problem statement; Markdown with KaTeX math supported |
difficulty | String | "Easy", "Medium", or "Hard" |
templateCode | String (@db.Text) | Python starter code shown to the user in the editor |
testCode | String (@db.Text) | Either a full Python test script or a reference comment pointing to the executor’s test file |
order | Int | Display order within the problem set (1-indexed) |
problemSetId | String? | Foreign key linking to the parent ProblemSet |
Submission stores a user’s code attempt alongside a status of PENDING, PASS, FAIL, or ERROR, with output from the executor written back to the output field.
testCode is not run directly by users. It is executed by the separate FastAPI executor service inside a Docker sandbox. Depending on the problem set pattern, testCode can either contain the full Python test script inline (as in the ML Fundamentals seed) or hold a reference comment pointing to a test file that lives in the executor service repository (as in the Attention and Neural Networks seeds). Either way, the executor — not the browser — runs the tests.Creating a New Problem Set
Create a seed file
Add a new file at The
prisma/seed-{topic}.ts. Model it after prisma/seed-numpy.ts, which seeds the “NumPy Fundamentals” problem set. Start by importing the Prisma client:finally block ensures the database connection is always closed, even if the seed throws.Define the ProblemSet
Use
prisma.problemSet.upsert so the script is safe to run repeatedly. The where clause matches on slug, and update keeps the description in sync if you re-run:Define each Problem
Build an array of problem objects and upsert them in a loop. Each problem must reference the parent set via
problemSetId:Run the seed script
Execute the seed file directly with Bun:The upsert logic means re-running the script is safe — it will update existing records rather than duplicating them.
Add the test file for the executor
The test script is what the FastAPI executor service runs when a user submits code. Place your test at the path the executor expects inside its Docker container:The test file imports the user’s solution module and runs assertions. See the Test Code Conventions section below for the expected format and a real example from the existing seed data.
Problem Description Format
Descriptions are rendered as full Markdown with LaTeX math via KaTeX. Use standard Markdown for headings, lists, code blocks, and bold/italic text. Use KaTeX delimiters for math:- Inline math — wrap in single dollar signs:
$f(x) = \sigma(x) = \frac{1}{1 + e^{-x}}$ - Block (display) math — wrap in double dollar signs:
- A brief prose introduction to the concept
- A Mathematical Formulation section with the defining equations
- An Instructions section listing the exact function signature and argument/return types
- A short Example showing expected inputs and outputs as a Python code block
- Any Constraints (e.g., “Use pure NumPy. PyTorch/JAX are not allowed.”)
prisma/seed-nn.ts, showing the sigmoid activation description. The description field would contain the following Markdown text:
Sigmoid Activation Function
The sigmoid function maps any real number to a value between 0 and 1.Mathematical Formulation
The derivative has an elegant form:Instructions
Implementsigmoid(x) and sigmoid_derivative(x).
Example
Template Code Conventions
templateCode is the Python starter shown to users in the code editor when they open a problem. It should:
- Import any standard libraries the solution will need (typically
numpy as np) - Define the exact function signature specified in the description
- Include a docstring documenting args and return type
- End with
raise NotImplementedError(preferred) orpassas the stub body — both patterns appear in the existing seeds
prisma/seed-numpy.ts:
prisma/seed-nn.ts (two-layer neural network):
Test Code Conventions
The test file is a standalone Python script run inside the executor’s Docker sandbox. It is not run by the user and does not appear in the editor — the executor service calls it when grading a submission. The file imports the user’s submitted code assolution and uses assert statements to verify correctness. When all assertions pass, it prints "SUCCESS" to stdout — that signal tells the executor the submission passed.
Here is a real test from prisma/seed.ts (Xavier initialization), where the full test is stored directly in the testCode field:
testCode field in the seed holds only a reference comment (e.g., # Tests are executed in the Docker sandbox. See executor test: nn1_sigmoid.py), and the actual test script lives inside the executor service repository at /app/tests/{problem-slug}.py. Both patterns are valid — choose the one that fits your workflow and coordinate with a maintainer if you need access to the executor repository.
Key conventions to follow regardless of which pattern you use:
- Always import from
solution(the executor names the user’s filesolution.py) - Provide 5–10 test cases covering edge cases (empty arrays, boundary values, dtype checks)
- Use descriptive assertion messages so users understand what failed
- Print
"SUCCESS"at the end of the test function — the executor reads this from stdout - Gate execution with
if __name__ == "__main__": test()
Difficulty Guidelines
Choose the difficulty level based on the cognitive complexity of the problem:| Difficulty | When to use | Example |
|---|---|---|
| Easy | Tests a single concept with a direct formula or one NumPy operation | sigmoid(x), reverse_array, layer_norm |
| Medium | Combines 2–3 concepts; requires knowing how to compose operations correctly | xavier_init, matrix_normalization, binary_cross_entropy |
| Hard | Implements a complex algorithm, requires careful understanding of shapes/broadcasting, or comes directly from a research paper | multi_head_attention, two_layer_nn (with backprop), moving_average (vectorized) |
Verifying Your Problems
After running your seed script, start the development server and navigate to/practice to confirm your new problem set appears in the list. Click through to individual problems and verify that:
- The description renders correctly (math, code blocks, headings)
- The template code appears in the editor pre-populated
- The difficulty badge shows the correct level
- The problems appear in the correct
orderwithin the set
Adding a problem to the database is only half the work. The executor service is a separate FastAPI application running in Docker. You must also deploy the corresponding test file to
/app/tests/{problem-slug}.py inside that container. Without the test file in place, all submissions to your new problem will return an ERROR status. Coordinate with a maintainer if you need access to the executor service repository.