Project Info
Give txt2crs a topic, pasted text, public URL, YouTube URL, PDF, DOCX, or PPTX. It turns that single bounded source into a source-grounded course, review pack, student assessment, and separate instructor answer key.
txt2crs combines a reusable Python generation engine, a durable FastAPI application, and a warm, focused React learner experience. Docker Compose is the complete reference deployment, and the same images can run on a hosted container platform that preserves the documented security and state contract.
What It Does
An authenticated learner can submit:
- a topic prompt or pasted text;
- a public URL or YouTube URL; or
- one bounded PDF, DOCX, or PPTX upload.
The application then:
- validates and durably accepts the exact request before returning
202; - ingests and policy-checks the source before provider work;
- performs bounded Tavily research through a package-owned loopback MCP boundary;
- runs the operator-selected exact Codex model with no silent fallback;
- validates and checkpoints the generated learning structure;
- renders four publications in HTML, Markdown, PDF, and DOCX; and
- exposes exactly sixteen owner-private, integrity-checked artifacts.
| Publication | What the learner gets |
|---|---|
| Course | A structured curriculum with objectives, modules, lessons, and cited sources |
| Review pack | Key ideas, examples, study guidance, and focused practice |
| Student assessment | A complete test aligned to what the course actually teaches |
| Instructor answer key | Correct responses, explanations, and grading guidance kept separate from the student copy |
Every publication ships in HTML, Markdown, PDF, and DOCX: four useful documents in four portable formats, for sixteen private artifacts in total.
Progress survives refreshes and process replacement. Results include bounded source summaries and conflict disclosures, while the learner-facing API never returns prompts, evidence excerpts, provider payloads, token data, checkpoint JSON, artifact paths, or unrestricted file links.
The persistent owner-scoped course library lists retained work newest first, uses opaque pagination, and reopens every active or completed request on its existing durable job URL. The intake page also reads authoritative rolling admission capacity before enabling another paid generation.
Origin Story
Two days after I joined OpenAI Build Week, my Zimbabwean wife asked me: "How can we bring AI to Africa?"
That question brought me back to an IBM AI Developer certification project: a Make.com workflow that expanded learning material, created study guides, and generated review questions. txt2crs turns that early experiment into a durable product boundary for learners and instructors who need structured, reviewable education material from almost any bounded source.
Try The Deterministic Sample
The stable deterministic sample uses this synthetic request:
| Field | Value |
|---|---|
| Topic | Teach Python variables. |
| Learning goal | Explain and use Python variables. |
| Audience | Adult learner |
| Depth | Introductory |
| Duration | 60 minutes |
| Assessment items | 1 |
This credential-free fast gate runs without network access or provider credentials through the public deterministic application factory. The scenario exercises real durable request, checkpoint, validation, rendering, and artifact stores, then proves four publications and sixteen private artifacts.
Run the engine lifecycle:
cd backend/packages/txt2crs
uv run --package txt2crs pytest \
tests/integration/test_application_lifecycle.py -q
Run the same journey through the real FastAPI and React boundary:
cd frontend
TXT2CRS_BROWSER_SCENARIO=complete npx playwright test \
--config=playwright.jobs.config.ts \
--project=chromium
See the complete deterministic sample contract and the separately identified live artifact inspection.
Quick Start
Prerequisites
- Docker Engine with Compose
- Git and Bash (Git Bash is sufficient on Windows)
- A ChatGPT subscription identity or OpenAI Platform API key for live Codex generation
- A Tavily API key for live research
Python, Node.js, uv, and npm are needed only for host-side development or focused validation.
1. Configure local secrets
cp .env.example .env
Replace SECRET_KEY, POSTGRES_PASSWORD, and
FIRST_SUPERUSER_PASSWORD with independent values. Add the Tavily secret to
TAVILY_API_KEY. The established model remains the default; you may replace
it with any safe exact identifier reported by your Codex account:
TXT2CRS_MODEL_ID=gpt-5.6-sol
Do not commit .env. Public signup is enabled by default; set
ENABLE_PUBLIC_SIGNUP=false for an invite-only installation.
2. Start the complete application
./scripts/start-local.sh
The startup assistant validates .env, Docker, Compose, and local port
availability, then starts PostgreSQL first and verifies the configured password
over the same authenticated network path used by the backend. If a preserved
local volume still has an older password, the assistant updates that role in
place without deleting records or printing the secret. It then runs the
authoritative docker compose up --detach --build --wait deployment, excluding
the explicit test-only Playwright profile. It waits for declared health checks,
prints bounded diagnostics on failure, and shows the exact application and
setup URLs on success. It is safe to run repeatedly and never deletes named
volumes or globally prunes Docker state.
Open:
- Learner application: http://localhost:5195
- Backend API: http://localhost:8016
- Superuser setup: http://localhost:5195/setup
3. Configure Codex authentication
The packaged Codex runtime accepts either a ChatGPT subscription identity or
Platform API-key authentication. For ChatGPT, sign in with FIRST_SUPERUSER
and FIRST_SUPERUSER_PASSWORD, open the superuser setup page, and start its
device login. For API-key mode, set OPENAI_API_KEY in the ignored .env
before starting the stack. The setup page must report authentication, exact
model, research, storage, and worker readiness before accepting a live course.
For host-only development, the short recovery helper runs the same packaged
device flow and stores credentials under the ignored
.txt2crs-system/ directory:
./scripts/auth-codex.sh --no-browser
That host directory is separate from Docker's txt2crs-state volume. Use the
setup page for the Docker Compose application.
Stop containers while preserving PostgreSQL and private engine-state volumes:
./scripts/start-local.sh --stop
The authoritative detailed paths are onboarding, configuration, and the deployment policy.
Architecture
The shell is intentionally thin: it owns HTTP, identity, lifecycle, and safe
errors, while every course-generation responsibility stays behind the public
txt2crs package facade.
%%{init: {"theme":"base","themeVariables":{"background":"#faf8f2","primaryColor":"#edf3ee","primaryTextColor":"#24231f","primaryBorderColor":"#235a46","lineColor":"#6f746e","secondaryColor":"#fbf4df","tertiaryColor":"#eef1f5","fontFamily":"system-ui, sans-serif"},"flowchart":{"curve":"basis","nodeSpacing":28,"rankSpacing":42}}}%%
flowchart TB
SOURCE["Topic · text · URL<br/>YouTube · PDF · DOCX · PPTX"]
subgraph PRODUCT["LEARNER APPLICATION"]
direction LR
UI["React 19 workspace<br/>create · follow · revisit"]
API["FastAPI shell<br/>HTTP · identity · safe errors"]
USERS[("PostgreSQL<br/>application users")]
UI -->|generated OpenAPI client| API
API <--> USERS
end
subgraph PACKAGE["REUSABLE TXT2CRS ENGINE"]
direction LR
ENGINE["Public engine facade<br/>ingest · policy · checkpoints<br/>validate · render · deliver"]
JOBS[("Tenant SQLite<br/>durable job truth")]
FILES[("Private filesystem<br/>immutable artifacts")]
ENGINE <--> JOBS
ENGINE --> FILES
end
PROVIDERS["Bounded providers<br/>Tavily loopback MCP<br/>Codex · exact configured model"]
OUTPUTS["Course · review pack<br/>student test · answer key<br/>HTML · Markdown · PDF · DOCX"]
SOURCE --> UI
API -->|public facade only| ENGINE
ENGINE <--> PROVIDERS
FILES -->|owner-scoped, integrity-checked| OUTPUTS
classDef input fill:#fbf4df,stroke:#c7922c,color:#24231f,stroke-width:2px;
classDef shell fill:#f7f5ef,stroke:#5f6b63,color:#24231f;
classDef focal fill:#edf3ee,stroke:#235a46,color:#183d30,stroke-width:2px;
classDef store fill:#eef1f5,stroke:#65728a,color:#24231f;
classDef external fill:#f8efe9,stroke:#a45c42,color:#24231f,stroke-dasharray:5 3;
classDef output fill:#fbf4df,stroke:#c7922c,color:#24231f,stroke-width:2px;
class SOURCE input;
class UI,API shell;
class ENGINE focal;
class USERS,JOBS,FILES store;
class PROVIDERS external;
class OUTPUTS output;
style PRODUCT fill:#faf8f2,stroke:#d8d3c7,stroke-width:1px,color:#235a46
style PACKAGE fill:#f7faf7,stroke:#9ab4a4,stroke-width:1px,color:#235a46
PostgreSQL owns application users. Tenant-scoped SQLite is the only generation-job source of truth, and the private filesystem owns immutable artifacts. One non-root FastAPI process owns one serial generation worker. This topology prevents duplicate runtime ownership until a real external queue exists.
The shell never reimplements generation, research, validation, persistence, or rendering. Routes call the public engine facade and translate typed engine errors into bounded RFC 9457 responses.
Read the full architecture guide and workspace boundary.
How Codex Is Used
Codex helped build and validate the project across the engine, FastAPI shell, React application, tests, release tooling, documentation, and production Docker path. Specification-driven sessions kept architectural decisions, tests-first implementation, code review, security checks, and validation evidence tied to exact repository changes.
The shipped application's package-owned runtime discovers the exact configured
model. The compatibility default is gpt-5.6-sol, but operators may configure
another safe exact identifier exposed by their Codex account. Readiness and
execution fail closed instead of silently choosing a different or first
available model.
Tavily supplies bounded web research through a two-tool MCP server on loopback. The engine owns both provider lifecycles, closes every listener and temporary resource, checkpoints accepted work, and requires explicit provider processing consent before transfer.
The 1.0.0 live proof used synthetic, nonpersonal input with exact
gpt-5.6-sol and real Tavily research. It completed with six sources, nine
durable checkpoints, four publications, and sixteen inspected artifacts. Its
historical source revision remains explicit in the
release evidence index.
Testing
The fast credential-free repository gate is:
./scripts/validate-changes.sh
Package-specific commands:
# Backend shell
cd backend
POSTGRES_DB=app_test uv run pytest tests/ -v # pre-provisioned test DB only
uv run ruff check app
uv run mypy app
# Reusable engine
cd backend/packages/txt2crs
uv run --package txt2crs pytest
uv run --package txt2crs ruff check .
uv run --package txt2crs mypy
# Frontend
cd frontend
npm run test:unit
npm run lint
npm run typecheck
npm run build
The validated release also covers migrated PostgreSQL acceptance tests, deterministic Playwright journeys, fixed engine evaluations, Python distributions, production images, non-root ownership, health checks, and persistent container replacement. The one live provider proof is explicit and separate from default credential-free validation.
See development and validation and the bounded release evidence.
Privacy And Current Limits
The public API uses owner-scoped allowlists. Wrong-owner and missing artifact reads are indistinguishable, downloads are integrity-checked and private, HTML preview is parsed inertly inside an empty sandbox, and normal logs exclude source content, prompts, provider payloads, artifact bytes, paths, tokens, and email addresses.
Before a public installation accepts personal data, its operator must define legal basis, provider-transfer terms, retention, log erasure, backup erasure, and provider-copy handling. The project makes no automatic GDPR-compliance claim.
Current product limits:
- Docker Compose is the reference topology; hosted deployments must preserve its single-replica persistence and security contract;
- exactly one backend process and one serial generation worker are supported;
- one upload is limited to 20 MiB and normalized input to 200,000 characters;
- PDF input is limited to 200 pages and a complete bundle to 100 MiB;
- public signup is operator-configurable in every environment;
- there is no bundled LMS export, collaborative editing, automatic grading, public artifact sharing, or concurrent worker pool.
See security, deployment scope, and configuration. The complete collision-free host listener inventory is in port allocations.
Repository Layout
txt2crs/
|-- backend/
| |-- app/ # FastAPI application shell
| |-- packages/txt2crs/ # Reusable education engine
| `-- tests/ # Shell and acceptance tests
|-- frontend/ # React learner and operator application
|-- scripts/ # Development and validation commands
|-- docs/
| |-- release/ # Bounded release proof
| `-- archive/ # Historical project records
|-- docker-compose.yml
|-- VERSION
`-- README.md
Package references:
License And Release
The repository has explicit scoped licensing in LICENSE. Original repository material outside the engine is MIT-0, identified boilerplate material retains its stated 0BSD or MIT provenance, and the independently installable engine retains its own scoped MIT-0 and Hermes-derived MIT terms.
The current synchronized release version is stored in VERSION.
Each release is preserved by an annotated v<version> tag after the engine,
shell, frontend, distribution, container, and security checks pass. Historical
Build Week evidence remains non-authoritative project history in
docs/archive/.
Analysis
View
Metric
- 95
- 1
Figures cover GitHub contributors during the hackathon window. A co-authored commit counts in full for each author, so per-member totals add up to more than the whole-team figures.
Technology
- CSSIn code
- HTMLIn code
- PythonIn code
- ReactIn code
- SQLIn code
- Tailwind CSSIn code
- TypeScriptIn code
- FastAPIClaimed
- OpenAIClaimed
7 of 9 appear in the indexed code. 2 claimed on Devpost could not be matched to code, which may simply mean the tool leaves no trace in the repository.
AI coding agents
- Claude CodeConfig
- CodexConfig
Detected from committed agent config files and commit authorship. Absence of a signal is not proof an agent was unused.
Codebase size
Source size
5.6 MB
Source files
763
Counts recognized source files only; vendored directories, binaries and lockfiles are excluded, so this is smaller than the repository on disk.
Repository
moshehbenavraham/txt2crs
1,188 files · 12.6 MB · @ 65c9e86
Structure
Interface
132 files · 11%Screens, components and styles rendered to the user.
API & routing
27 files · 2%Request entry points: routes, handlers and controllers.
Application logic
136 files · 11%Domain rules, services and shared utilities.
+4 moreBackground jobs
16 files · 1%Work run outside a request: tasks, workers and schedules.
Data & schema
14 files · 1%Schema definitions, migrations and data access.
Supporting
Layers are inferred from where files sit in the tree, not from reading the code. A project that names its directories unconventionally will read oddly here — open the file browser to check anything the diagram implies.
Languages
- Markdown43%
- Python39%
- TypeScript14%
- Shell2%
- YAML1%
- CSS0%
- Other (2)0%
Share of indexed source by file size. Binary and vendored files are excluded.
Dependencies
frontend/package.json
npm · 45- @hookform/resolvers
- @radix-ui/react-avatar
- @radix-ui/react-checkbox
- @radix-ui/react-collapsible
- @radix-ui/react-dialog
- @radix-ui/react-dropdown-menu
- @radix-ui/react-label
- @radix-ui/react-radio-group
- @radix-ui/react-scroll-area
- @radix-ui/react-select
- @radix-ui/react-separator
- @radix-ui/react-slot
- @radix-ui/react-tabs
- @radix-ui/react-tooltip
- @tailwindcss/vite
- @tanstack/react-query
- @tanstack/react-router
- @tanstack/react-table
- +27 more
backend/pyproject.toml
pypi · 25- alembic
- email-validator
- emails
- fastapi[standard]
- httpx
- jinja2
- mcp
- opentelemetry-api
- opentelemetry-exporter-otlp
- opentelemetry-instrumentation-fastapi
- opentelemetry-instrumentation-httpx
- opentelemetry-instrumentation-sqlalchemy
- opentelemetry-sdk
- psycopg[binary]
- pwdlib[argon2,bcrypt]
- pydantic
- pydantic-settings
- pyjwt
- +7 more
backend/packages/txt2crs/pyproject.toml
pypi · 13- httpx
- mcp
- openai-codex
- openai-codex-cli-bin
- pillow
- pydantic
- pymupdf
- pytesseract
- python-docx
- python-pptx
- uvicorn
- youtube-transcript-api
- +1 more
Declared in the repository’s manifests at the indexed commit. A declared package is not proof it is used, and runtime dependencies are listed first.
This project’s features have not been analysed yet.
Export this project's context (description, README, evidence, key source files) to chat with an AI agent elsewhere.