|
| 1 | +# Developer Data Portal |
| 2 | + |
| 3 | +A data portal that serves Marimo notebooks through a Next.js interface. Built on [OSO](https://www.oso.xyz). |
| 4 | + |
| 5 | +## Quickstart |
| 6 | + |
| 7 | +```bash |
| 8 | +# 1. Get an OSO API key at https://www.oso.xyz/start |
| 9 | +cp .env.example .env |
| 10 | +# Add your key: OSO_API_KEY=your_key_here |
| 11 | + |
| 12 | +# 2. Install dependencies |
| 13 | +uv sync |
| 14 | +cd app && pnpm install && cd .. |
| 15 | + |
| 16 | +# 3. Start |
| 17 | +cd app && pnpm dev:all |
| 18 | +``` |
| 19 | + |
| 20 | +Open http://localhost:3000. |
| 21 | + |
| 22 | +## Prerequisites |
| 23 | + |
| 24 | +- OSO API key ([get one here](https://www.oso.xyz/start)) |
| 25 | +- [uv](https://docs.astral.sh/uv/) — Python package manager |
| 26 | +- Node.js 20+ and [pnpm](https://pnpm.io/) |
| 27 | + |
| 28 | +## Structure |
| 29 | + |
| 30 | +``` |
| 31 | +ddp/ |
| 32 | +├── notebooks/ # Marimo notebooks (.py) |
| 33 | +│ ├── home.py |
| 34 | +│ ├── quick-start.py |
| 35 | +│ ├── publications.py |
| 36 | +│ ├── agent-guide.py |
| 37 | +│ ├── data/ |
| 38 | +│ │ ├── sources/ # Open Dev Data, GitHub Archive, OSS Directory |
| 39 | +│ │ ├── models/ # Ecosystems, Repositories, Developers, Commits, Events, Timeseries Metrics |
| 40 | +│ │ └── metric-definitions/ # Activity, Alignment, Lifecycle, Retention |
| 41 | +│ └── insights/ # 2025 Developer Trends, Lifecycle, Speedrun Ethereum, DeFi Journeys, Retention |
| 42 | +├── app/ # Next.js app (UI shell) |
| 43 | +│ ├── app/ # Pages (App Router) |
| 44 | +│ └── components/ # Sidebar, MarimoIframe |
| 45 | +├── serve_notebooks.py # Marimo ASGI server (port 8000) |
| 46 | +└── pyproject.toml |
| 47 | +``` |
| 48 | + |
| 49 | +## How it works |
| 50 | + |
| 51 | +- **Marimo server** (`localhost:8000`) — runs notebook kernels via `serve_notebooks.py` |
| 52 | +- **Next.js app** (`localhost:3000`) — navigation shell that embeds notebooks in iframes |
| 53 | + |
| 54 | +Each page in the Next.js app is a thin wrapper around a `MarimoIframe` component: |
| 55 | + |
| 56 | +```tsx |
| 57 | +<MarimoIframe notebookName="notebooks/insights/developer-lifecycle" /> |
| 58 | +``` |
| 59 | + |
| 60 | +## Adding a notebook |
| 61 | + |
| 62 | +1. Create `notebooks/<category>/<name>.py` using the standard template below |
| 63 | +2. Add a page at `app/app/<category>/<name>/page.tsx` |
| 64 | +3. Add a nav entry to `app/components/Sidebar.tsx` |
| 65 | + |
| 66 | +### Notebook template |
| 67 | + |
| 68 | +```python |
| 69 | +import marimo |
| 70 | + |
| 71 | +__generated_with = "unknown" |
| 72 | +app = marimo.App(width="full") |
| 73 | + |
| 74 | +@app.cell(hide_code=True) |
| 75 | +def setup_pyoso(): |
| 76 | + # This code sets up pyoso to be used as a database provider for this notebook |
| 77 | + # This code is autogenerated. Modification could lead to unexpected results :) |
| 78 | + import pyoso |
| 79 | + import marimo as mo |
| 80 | + pyoso_db_conn = pyoso.Client().dbapi_connection() |
| 81 | + return mo, pyoso_db_conn |
| 82 | + |
| 83 | +# Add cells here |
| 84 | + |
| 85 | +if __name__ == "__main__": |
| 86 | + app.run() |
| 87 | +``` |
| 88 | + |
| 89 | +For detailed notebook conventions, see [`notebooks/claude.md`](notebooks/claude.md). |
| 90 | + |
| 91 | +## Running servers separately |
| 92 | + |
| 93 | +```bash |
| 94 | +# Terminal 1 — Marimo |
| 95 | +uv run python serve_notebooks.py |
| 96 | + |
| 97 | +# Terminal 2 — Next.js |
| 98 | +cd app && pnpm dev |
| 99 | +``` |
| 100 | + |
| 101 | +Notebooks are served at `http://localhost:8000/notebooks/<name>` — Marimo must be running for iframes to render. |
| 102 | + |
| 103 | +## Configuration |
| 104 | + |
| 105 | +| Variable | Description | |
| 106 | +|----------|-------------| |
| 107 | +| `OSO_API_KEY` | Required. OSO data warehouse access key. | |
| 108 | + |
| 109 | +The Marimo port defaults to `8000`. To change it, update `serve_notebooks.py` and the `marimoPort` prop on `MarimoIframe` in any relevant pages. |
0 commit comments