Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# ClassBuild — API Keys
# Keys are entered through the app's Setup page (not read from environment variables).
# In the app, keys are entered on the Setup page. The CLI scripts read them from environment variables.
# This file documents what you'll need.

# Required — Anthropic Claude API key
ANTHROPIC_API_KEY=sk-ant-...

# Optional — Google Gemini API key for infographics and voice narration (TTS)
# Optional — Google Gemini API key, used as a course-content provider (alternative to Claude)
# and by `npm run smoke:gemini` and `scripts/canvas-course.ts --provider gemini`.
GEMINI_API_KEY=
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,10 @@ public/voices/

# Pitch scratch — not part of the app
pitch/

# Secrets — keys are entered in the app / passed via env vars, never committed
.env
.env.*
!.env.example
*.pem
*.key
4 changes: 2 additions & 2 deletions tools/canvas-test/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ anything under `src/services/export/` or `src/services/template/`.
tools/canvas-test/build-demo-cartridge.sh

# 2. import into Canvas and inspect what it built (Canvas on another box → set CCT_SSH)
export CCT_SSH=canvas@192.168.1.139 CCT_SSH_KEY=~/.ssh/canvas_vm_ed25519
export CCT_SSH=canvas@<canvas-host> CCT_SSH_KEY=~/.ssh/<your-key>
tools/canvas-test/cct.sh import output/demo-course-native.imscc "native demo"
tools/canvas-test/cct.sh import output/demo-template-export.imscc "template demo"

Expand All @@ -51,7 +51,7 @@ instance details** (LAN address, account UUID/ids in `course_settings/context.xm
## Building the Canvas instance

```bash
CCT_LAN_HOST=192.168.1.139 tools/canvas-test/setup-canvas.sh # 30–90 min the first time
CCT_LAN_HOST=<canvas-host> tools/canvas-test/setup-canvas.sh # 30–90 min the first time
```

Run on Ubuntu 22.04/24.04 with Docker + compose plugin, git, python3, openssl, curl; ~8 GB RAM (add
Expand Down
8 changes: 4 additions & 4 deletions tools/canvas-test/setup-canvas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
# Reproducible and resumable. Run it on an Ubuntu 22.04/24.04 box (a VM is ideal) that has
# Docker + the compose plugin, git, python3, openssl and curl, and ~8 GB RAM (+ swap), ~60 GB disk.
#
# CCT_LAN_HOST=192.168.1.139 ./setup-canvas.sh # full build (30–90 min the first time)
# CCT_LAN_HOST=192.168.1.139 ./setup-canvas.sh fixes # only (re)apply the config/dependency fixes
# CCT_LAN_HOST=192.168.1.139 ./setup-canvas.sh smoke # only check that it is up and QTI is enabled
# CCT_LAN_HOST=<canvas-host> ./setup-canvas.sh # full build (30–90 min the first time)
# CCT_LAN_HOST=<canvas-host> ./setup-canvas.sh fixes # only (re)apply the config/dependency fixes
# CCT_LAN_HOST=<canvas-host> ./setup-canvas.sh smoke # only check that it is up and QTI is enabled
#
# Phases that finished are recorded in $CANVAS_DIR/.cct/state/; a re-run skips them
# (SETUP_FORCE=1 redoes everything). Progress lines start with "PHASE".
Expand Down Expand Up @@ -35,7 +35,7 @@ QTI_REF="aab28af7a05142140c6fd2f45ed67a4c925a7d1b" # 2026-03-23
PLATFORM_ALERTS_VERSION="1.0.1"

CANVAS_DIR="${CANVAS_DIR:-$HOME/canvas-lms}"
LAN_HOST="${CCT_LAN_HOST:?set CCT_LAN_HOST to the address you will browse to, e.g. 192.168.1.139}"
LAN_HOST="${CCT_LAN_HOST:?set CCT_LAN_HOST to the address you will browse to, e.g. 192.168.1.50}"
PORT="${CCT_PORT:-3000}"
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@canvas-test.local}"
ADMIN_FILE="$HOME/canvas-admin.txt"
Expand Down
2 changes: 1 addition & 1 deletion tools/smoke-gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ await check('unknown model id → a clear "model not found" message', true, asyn
// Needs no real key: Google must reject it, and we must explain that well.
await check('bad key → "API key rejected" (against Google\'s real error text)', false, async () => {
try {
await streamMessageGemini({ apiKey: 'AIzaThisIsNotARealKey000000000000000000', model: MODEL, messages: [{ role: 'user', content: 'hi' }] }, {});
await streamMessageGemini({ apiKey: 'not-a-real-key', model: MODEL, messages: [{ role: 'user', content: 'hi' }] }, {});
} catch (e) {
const raw = (e as Error).message;
const friendly = friendlyError(e);
Expand Down
Loading