The Workbench, documented.
Everything the code environment does, in one page: the engines, the syntax, working examples, and the path from raw dataset to published work. Every snippet below runs as-is in a Workbench block.
๐งช The environment
What actually runs when you press Run.
The Workbench is a notebook of blocks โ note, SQL, and Python โ and the whole engine runs inside your browser tab. Nothing is installed on your machine and no code or data is sent to a server to execute:
| Block type | Engine | What that means |
|---|---|---|
| SQL | DuckDB (WebAssembly) | A real analytical database in the tab. Loads with the page; queries run instantly on the attached datasets. |
| Python | Pyodide โ CPython in WebAssembly | Real Python with pandas, numpy, and matplotlib. Downloads ~15 MB the first time you run a Python block, then it is cached. |
| Note | โ | Prose. Notes become the README of your published work. |
Deliberate limits (they are features, not bugs): Python has no network access, no pip install, no input(), and no threads; memory is what the browser tab allows. Everything a project needs ships with the runtime.
๐๏ธ Getting data in
Upload โ attach โ alias. The alias is the table name.
Data enters the platform once, at the top, and flows down to every member:
- Upload (curators): an admin uploads a CSV in the dataset manager. Rows and columns are scanned automatically and the dataset appears in the public library.
- Attach (brief authors): a project brief attaches one or more datasets, each under an alias. Aliases are validated because they become SQL table names โ budget works, Budget Data! is rejected.
- Use (you): open the Workbench on a claimed brief and every attached dataset is already loaded as a table under its alias. The left rail lists each one with a โ and its row count.
-- The aliases in the left rail ARE your tables. First look:
SELECT * FROM budget LIMIT 5;
Members do not upload their own files in the current version โ every project runs on curated data, which is what makes review and auto-checks possible. Have a dataset worth adding? Mail it to the address in the dataset library sidebar.
๐ค SQL guide
The dialect is DuckDB. If you learned MySQL or Postgres, 95% carries over โ the differences are listed at the end.
Selecting and filtering
SELECT category, budgeted_amount, actual_amount
FROM budget
WHERE actual_amount > budgeted_amount -- conditions can compare columns
ORDER BY actual_amount - budgeted_amount DESC
LIMIT 5;
Aggregating and grouping
SELECT category,
COUNT(*) AS line_items,
SUM(actual_amount) AS spent,
SUM(actual_amount) - SUM(budgeted_amount) AS variance
FROM budget
GROUP BY category
HAVING SUM(actual_amount) > 1000000 -- HAVING filters groups; WHERE filters rows
ORDER BY variance;
Dates
SELECT strftime(due_date, '%Y') AS year,
date_diff('day', due_date, DATE '2027-01-01') AS days_overdue
FROM receivables
WHERE due_date BETWEEN DATE '2022-01-01' AND DATE '2022-12-31';
Write date literals as DATE 'YYYY-MM-DD'. date_diff('day', a, b) counts from a to b; strftime(date, format) formats it.
Banding with CASE
SELECT CASE WHEN receivable_amount >= 30000 THEN 'large'
WHEN receivable_amount >= 10000 THEN 'medium'
ELSE 'small'
END AS size_band,
COUNT(*) AS invoices
FROM receivables
GROUP BY size_band; -- grouping by the alias works
Joins
SELECT b.category, d.dept_head, SUM(b.actual_amount) AS spent
FROM budget b
JOIN departments d ON b.category = d.category
GROUP BY b.category, d.dept_head
ORDER BY spent DESC;
-- LEFT JOIN keeps rows with no match (departments that spent nothing)
Subqueries and CTEs
WITH dept AS (
SELECT category, SUM(actual_amount) AS spent
FROM budget
GROUP BY category
)
SELECT category, spent,
ROUND(spent * 100.0 / (SELECT SUM(spent) FROM dept), 1) AS pct
FROM dept
ORDER BY spent DESC;
Views โ saving a query under a name
CREATE OR REPLACE VIEW clean_budget AS
SELECT * FROM budget WHERE actual_amount >= 0;
SELECT SUM(actual_amount) FROM clean_budget; -- reads through the view
Coming from MySQL? The differences that bite
| Habit | Here |
|---|---|
`backtick` quoting | Use "double quotes" for odd identifiers (rarely needed โ aliases are validated). |
LIMIT 10, 5 | LIMIT 5 OFFSET 10 |
DATE_SUB / DATE_ADD | date_diff(โฆ), d + INTERVAL 7 DAY |
IFNULL(x, y) | COALESCE(x, y) (works everywhere) |
Integer division 3/2 = 1 | 3/2 = 1.5 โ use // for integer division |
๐ Python guide
Real Python in the tab, with a tiny bridge to your data called lp.
| Call | Returns |
|---|---|
lp.datasets() | The list of attached dataset aliases. |
lp.table('budget') | That dataset as a pandas DataFrame. |
await lp.sql("SELECT โฆ") | Any SQL โ including your views โ run on DuckDB, back as a DataFrame. Note the await. |
# Cross-check a SQL number independently in pandas
df = await lp.sql("SELECT * FROM invoices")
overdue = df[df.is_overdue]
print("overdue invoices:", len(overdue))
print(f"overdue amount: {overdue.receivable_amount.sum():,}")
Output rules, in order: everything you print appears as stdout; a DataFrame that is the last expression of the block renders as a table (first 50 rows, with the true total shown); matplotlib figures appear as images โ up to two plots per run.
import matplotlib.pyplot as plt
cash = await lp.sql("""
SELECT cash_type, SUM(inflow) - SUM(outflow) AS net_cash
FROM cash_flow GROUP BY cash_type
""")
plt.bar(cash.cash_type, cash.net_cash)
plt.title("Net cash by activity")
plt.show()
Available out of the box: pandas, numpy, matplotlib, and the Python standard library. Not available, on purpose: network requests, pip installs, file system, input(), threads. If a script needs the internet, it belongs on your own machine โ the Workbench is for the analysis.
โถ๏ธ Running code & the pipeline
One block, the whole notebook, and the badge that proves it.
โถ Run โ executes one block (Ctrl/โ + Enter inside the editor does the same). The result is saved with the block, so your outputs are still there tomorrow.
โถโถ Run all โ executes every included SQL and Python block top to bottom and stops at the first error. If everything passes, the work earns a โ Reproducible stamp, shown on the published page โ proof the notebook runs clean start to finish, not just in the order you happened to click.
๐ฏ Checks โ tasks can carry an auto-check: run it and your current result is compared to the expected answer, pass or fail with the actual value shown. Reviewers see the same check summary.
Errors โ appear under the block, verbatim from the engine. Read them; they usually name the problem (an aggregate in WHERE, a missing table, a typo in a column). An error in a Run all halts the pipeline at that block so you always know where it broke.
๐ From Workbench to published work
The whole loop, end to end.
- Claim โ pick a brief; the Workbench opens with its datasets loaded and its tasks in the ๐ drawer.
- Work โ add note, SQL, and Python blocks; reorder freely; toggle any block out of the final piece. Included blocks become the README.
- Verify โ โถโถ Run all until green, run the ๐ฏ checks, cross-check a key number two ways.
- Submit โ your work enters the review queue. A human reviews it; changes may be requested with notes.
- Published โ the repo goes public on your portfolio, readable logged-out, with block-level comments โ and XP and coins land in your account.
๐ฌ Questions & answers
The ones every new member asks.