Skip to content

Commit d610cac

Browse files
committed
Add a team-card Lab 0 to the Cloud course
The hackathon environments are now created for each team and handed over as a team card, so participants need a Lab 0 that creates nothing and needs no snctl. This adds one beside the existing Lab 0, which is unchanged. - labs/cloud/00-set-up-team-card.md: fill in .env from the card, load the login stream once for the team, run the doctor. It keeps the step numbers of 00-set-up.md, so every "Lab 0, step 2/3" reference holds for both pages. - The READMEs, .env.cloud.example and docs/before-you-arrive.md point at it. Before-you-arrive tells card holders to skip creating resources. - The tutor asks whether the learner has a team card before Lab 0 of the Cloud course, and uses the matching page. - check-labs.sh accepts a lab page the tutor names with its course folder, and checks that it exists there. - What was run: the new page against a test instance on StreamNative Cloud, on the Python path, plus the doctor and the seeder on the TypeScript path and with the CLI commands.
1 parent aef76ed commit d610cac

10 files changed

Lines changed: 344 additions & 10 deletions

File tree

‎.env.cloud.example‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# cp .env.cloud.example .env
55
#
66
# labs/cloud/00-set-up.md, step 2, has the snctl command for each address.
7+
# With a team card, every value comes from the card instead:
8+
# labs/cloud/00-set-up-team-card.md, step 2.
79
# (The Local course writes its own .env: see labs/local/00-set-up.md.)
810

911
# -------------------------------------------------- from the organizers --

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ The same five labs, on two stacks.
2626
| | [Cloud course](labs/cloud/README.md) | [Local course](labs/local/README.md) |
2727
|---|---|---|
2828
| Runs on | StreamNative Cloud: your own instance, with a Kafka cluster, a SQL workspace, and an agent workspace | Your laptop: [Ursa for Kafka](https://openlakestream.org/docs/ursa-for-kafka), [RisingWave](https://risingwave.com), and the Orca Agent Engine (`ork local`) |
29-
| You need | A StreamNative Cloud login with your own instance, from the hackathon organizers | Docker and an Anthropic API key |
29+
| You need | A StreamNative Cloud login from the hackathon organizers, with a team card or an instance of your own | Docker and an Anthropic API key |
3030
| Time | About 40 minutes | About 45 minutes, plus image downloads |
31-
| Start | [Lab 0: Set up](labs/cloud/00-set-up.md) | [Lab 0: Set up](labs/local/00-set-up.md) |
31+
| Start | [Lab 0: Set up](labs/cloud/00-set-up.md), or [from a team card](labs/cloud/00-set-up-team-card.md) | [Lab 0: Set up](labs/local/00-set-up.md) |
3232

3333
At the hackathon, take the Cloud course: see
3434
[Before you arrive](docs/before-you-arrive.md). Without a StreamNative Cloud

‎docs/before-you-arrive.md‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ Everyone also needs:
3030
- [`jq`](https://jqlang.org/download/), for the checks in every lab.
3131
- [`snctl`](https://docs.streamnative.io/tools/cli/snctl/snctl-overview) (the
3232
StreamNative Cloud CLI): `brew install streamnative/streamnative/snctl`. Lab 0
33-
uses it to read your instance's addresses and to create your topic.
33+
uses it to read your instance's addresses and to create your topic. With a
34+
team card (step 4) you do not need it.
3435

3536
## 1. Get the code
3637

@@ -73,6 +74,13 @@ Every line should say `PASS`.
7374

7475
## 4. Set up your instance
7576

77+
**Getting a team card?** If the organizers told you that your team's
78+
environment is created for you, skip this step and create nothing in the
79+
console: your Kafka cluster, SQL workspace, and agent workspace already exist.
80+
Your team card has their addresses and an API key, and
81+
[Lab 0: Set up from a team card](../labs/cloud/00-set-up-team-card.md) starts
82+
from it.
83+
7684
The organizers add you to the hackathon organization on StreamNative Cloud, give
7785
you an **instance** of your own, and make a **service account** in it. They give
7886
you its name and its **API key**: keep the key to yourself.

‎docs/tutor.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ last row works in any agent that can read a file.
4949
Started with no request, the tutor asks three things:
5050

5151
```text
52-
1. Course: Cloud (your own instance on StreamNative Cloud) or Local (everything on your laptop)?
52+
1. Course: Cloud (on StreamNative Cloud, with a team card from the organizers or with your own instance: say which) or Local (everything on your laptop)?
5353
2. Path: CLI, Python, or TypeScript?
5454
3. What now: start at Lab 0, resume at a lab, quiz me on a lab, or check my setup?
5555
```
@@ -59,6 +59,7 @@ Started with no request, the tutor asks three things:
5959
| You want to | Say |
6060
|---|---|
6161
| Take a course from the start | `Start the Cloud course on the Python path.` |
62+
| Start from a team card | `Start the Cloud course on the Python path. I have a team card.` |
6263
| Pick up where you stopped | `Resume the Local course at Lab 3. I'm on TypeScript.` |
6364
| Be quizzed | `Quiz me on Lab 2.` |
6465
| Find out why something fails | `Check my setup.` Or paste the error. |

‎labs/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Two courses teach the same five labs on two stacks. Pick one.
55
| | [Cloud course](cloud/README.md) | [Local course](local/README.md) |
66
|---|---|---|
77
| Runs on | StreamNative Cloud: your own instance, with a Kafka cluster, a SQL workspace, and an agent workspace | Your laptop: Ursa for Kafka, RisingWave, and the Orca Agent Engine |
8-
| You need | A StreamNative Cloud login with your own instance, from the hackathon organizers | Docker and an Anthropic API key |
8+
| You need | A StreamNative Cloud login from the hackathon organizers, with a team card or an instance of your own | Docker and an Anthropic API key |
99
| Time | About 40 minutes | About 45 minutes, plus the image downloads |
1010
| Take it when | You are at the event | You have no StreamNative Cloud instance, or you want to see every part run |
1111

‎labs/cloud/00-set-up-team-card.md‎

Lines changed: 275 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
# Lab 0: Set up from a team card
2+
3+
**Cloud course** · 5 minutes, plus 5 on your own · CLI, Python, or TypeScript
4+
5+
You put your team card in `.env`, load the login stream into your team's Kafka
6+
cluster, and run the doctor. When this lab is done, the Agent Engine, Kafka,
7+
and Schema Registry on your card all answer, and your topic holds 246 logins.
8+
9+
No team card? [Lab 0: Set up](00-set-up.md) starts from an instance of your own
10+
instead. Both end in the same place, and Lab 1 is the same after either.
11+
12+
## Before you start
13+
14+
- You have your **team card** from the organizers: an **API key**, and the
15+
addresses of the environment they created for your team on StreamNative
16+
Cloud. That environment is a Kafka cluster, a SQL workspace that imports it,
17+
an agent workspace, and the service account the key belongs to. Everything on
18+
the card already exists: you create nothing, and you do not need `snctl`.
19+
- You can log in to StreamNative Cloud, and the organizers added your login to
20+
your team's environment. This lab does not use that login; Labs 2 and 3 do.
21+
- You cloned this repository and opened a terminal in it. The terminal runs
22+
`bash`: on Windows that is WSL or Git Bash, on every path, because the checks
23+
are `bash` commands.
24+
- You have `git`, [`ork`](https://github.com/orca-ae/orca-cli) v0.6.0 or newer,
25+
and [`jq`](https://jqlang.org/download/). `ork` does the first MCP login in
26+
Lab 3 for all three paths, and `ork` with `jq` runs the checks in every lab.
27+
28+
## Step 1: Install your path
29+
30+
Pick **one** path. Your teammate can pick a different one.
31+
32+
**Python** (3.11 or newer)
33+
34+
```bash
35+
cd python
36+
python3 -m venv .venv
37+
source .venv/bin/activate # Git Bash on Windows: source .venv/Scripts/activate
38+
pip install -r requirements.txt
39+
```
40+
41+
**TypeScript** (Node.js 20 or newer)
42+
43+
```bash
44+
cd typescript
45+
npm install
46+
```
47+
48+
**CLI**: `ork` and `jq` are all the labs need. Set up Python or TypeScript as
49+
above too: the doctor, the seeder, and the data injector come from one of them.
50+
51+
### Check
52+
53+
Run the doctor without the network. Every line says `PASS`.
54+
55+
| Python or CLI | TypeScript |
56+
|---|---|
57+
| `python doctor.py --offline` | `npm run doctor -- --offline` |
58+
59+
```text
60+
PASS Python 3.11+ 3.13
61+
PASS package runorca
62+
PASS package confluent-kafka[avro]
63+
PASS package python-dotenv
64+
PASS ork found
65+
PASS jq found
66+
67+
All good: you're ready.
68+
```
69+
70+
## Step 2: Fill in `.env` from your team card
71+
72+
Open a second terminal at the repository root and copy the template:
73+
74+
```bash
75+
cp .env.cloud.example .env
76+
```
77+
78+
`.env` is git-ignored. It will hold your team's key: do not commit it or paste
79+
it anywhere. Give each of these lines its value from the card:
80+
81+
| `.env` line | On your card | Write it as |
82+
|---|---|---|
83+
| `SN_API_KEY` | API key | the raw key, with no `token:` in front |
84+
| `SN_SERVICE_ACCOUNT` | Service account | `<name>@<org>.auth.streamnative.cloud`. If the card has only the name, add the rest, with the organization id from the card (`o-...`) |
85+
| `ORCA_BASE_URL` | Agent workspace endpoint | `https://` and the host, with no `/v1` |
86+
| `KAFKA_BOOTSTRAP_SERVERS` | Broker URL | the host and its port, `:9093` |
87+
| `SCHEMA_REGISTRY_URL` | Schema registry URL | `https://` and the host |
88+
| `SN_MCP_URL` | SQL workspace MCP endpoint | `https://mcp.streamnative.cloud/mcp/x/<org>/sqlworkspace.compute.streamnative.io/<SQL workspace>` |
89+
| `SN_SQL_DATABASE` | SQL database | as given. It is the name of your SQL catalog, not of your SQL workspace |
90+
91+
If your card already is a list of `NAME=value` lines, paste each one over the
92+
empty line with the same name.
93+
94+
`SN_SQL_DATABASE` is the database you use in Lab 2 and the agent targets in
95+
Labs 3 and 4. Leave the other lines as they are: the MCP server uses a separate
96+
browser login in Lab 3, so `SN_MCP_AUTH=oauth` stays, and `SN_MCP_OAUTH_ISSUER`
97+
stays empty.
98+
99+
**Two people share one team card.** Your teammate fills in the same values, and
100+
you both work in the same Kafka cluster and the same SQL database. Your agents
101+
stay apart: each is named after its owner's OS user name, like
102+
`hello-agent-ana`. If the two of you have the same user name, each set
103+
`PARTICIPANT` in `.env` to a name of your own. In Lab 2 the view and the table
104+
are created once for the team: if your teammate got there first, the `CREATE`
105+
statement says they already exist, and you go on to the step's check. The reset
106+
script that Lab 4 mentions drops them for both of you, so agree before one of
107+
you runs it.
108+
109+
### Check
110+
111+
One authenticated read of your Agent Engine. It prints `true` when the endpoint
112+
and the key on your card are accepted.
113+
114+
```bash
115+
./lab-ork agent list -o json | jq -e 'has("data")'
116+
```
117+
118+
Before you filled in `.env`, the same command says
119+
`Missing ORCA_BASE_URL, SN_API_KEY` instead: the two values it needs.
120+
121+
## Step 3: Load the login stream
122+
123+
The course reads one topic in your team's Kafka cluster,
124+
`security.login_events`. It needs the login stream once, for the whole team.
125+
**One of you** runs the seeder, in your path's folder:
126+
127+
| Python | TypeScript | CLI |
128+
|---|---|---|
129+
| `python seed.py` | `npm run seed` | `(cd ../python && .venv/bin/python seed.py)` or `(cd ../typescript && npm run seed)` |
130+
131+
It prints one of two lines, and both are fine. A topic that was empty is now
132+
loaded:
133+
134+
```text
135+
Loaded 246 logins for 91 accounts into security.login_events.
136+
```
137+
138+
A topic that the organizers or your teammate loaded before you is left as it is:
139+
140+
```text
141+
security.login_events already holds 246 events, so it is seeded. To load another copy anyway: python seed.py --force
142+
```
143+
144+
Do not use `--force`: a second copy would double every count in Lab 2. The
145+
number is higher than 246 once someone on your team has run Lab 3, and the
146+
TypeScript seeder ends the line with `npm run seed -- --force`.
147+
148+
The seeder replays [`data/login_events.jsonl`](../../data/login_events.jsonl):
149+
synthetic logins at a fictional bank, with their timestamps moved to now. It
150+
also registers the topic's Avro schema, which SQL Workspace needs in Lab 2.
151+
152+
If it says `The topic security.login_events does not exist yet`, the topic was
153+
not created with your environment. Raise your hand, or create it yourself with
154+
`snctl`: [Lab 0: Set up](00-set-up.md), step 3.
155+
156+
### Check
157+
158+
Run the doctor. It checks your laptop, then each service on your card, and a
159+
failed check prints its fix on the next line.
160+
161+
| Python | TypeScript | CLI |
162+
|---|---|---|
163+
| `python doctor.py` | `npm run doctor` | `(cd ../python && .venv/bin/python doctor.py)` or `(cd ../typescript && npm run doctor)` |
164+
165+
After the lines from step 1, it prints:
166+
167+
```text
168+
PASS .env cloud stack, participant: ana
169+
PASS ORCA_BASE_URL https://...
170+
PASS Agent Engine API key accepted
171+
PASS Kafka security.login_events has 1 partition(s)
172+
PASS Schema Registry security.login_events-value v1
173+
PASS login topic schema has account_id, event_time, ip_address, result, failure_reason
174+
WAIT MCP OAuth no tutorial vault yet
175+
next: Nothing to do now: Lab 3 opens your browser to authorize the MCP server. Run doctor again after it.
176+
177+
You're ready. 1 check(s) wait for a later lab.
178+
```
179+
180+
`WAIT` is not a failure. The MCP server needs a login that only Lab 3 can do.
181+
On a topic that nobody has loaded yet, the `Schema Registry` line fails before
182+
this step: the seeder is what registers the schema.
183+
184+
Still failing after two tries? Raise your hand, or see
185+
[Troubleshooting](troubleshooting.md).
186+
187+
## Check your understanding
188+
189+
**1. The doctor prints `WAIT MCP OAuth`. What should you do?**
190+
191+
- A. Fix it now: the doctor has to print only `PASS`.
192+
- B. Nothing yet: Lab 3 does the browser login this check waits for.
193+
- C. Ask for a new team card.
194+
195+
<details>
196+
<summary>Answer</summary>
197+
198+
**B.** The MCP server wants an OAuth login, and the lab script does it the first
199+
time the agent needs the server. `WAIT` means "not ready, and not your mistake".
200+
A real problem prints `FAIL` and its fix.
201+
202+
</details>
203+
204+
**2. The seeder says `security.login_events already holds 246 events, so it is seeded`. What should you do?**
205+
206+
- A. Run it again with `--force`, so that your copy is loaded too.
207+
- B. Nothing: the stream is there already, loaded by the organizers or by your teammate.
208+
- C. Ask for a new Kafka cluster.
209+
210+
<details>
211+
<summary>Answer</summary>
212+
213+
**B.** Your team shares one topic, and it needs the 246 logins once. A second
214+
copy would double every count in Lab 2.
215+
216+
</details>
217+
218+
**3. What does `./lab-ork` add to `ork`?**
219+
220+
- A. It is a different CLI with its own commands.
221+
- B. It points `ork` at your Agent Engine with the key from `.env`, and fills in the ids your scripts saved.
222+
- C. It runs the lab's steps for you.
223+
224+
<details>
225+
<summary>Answer</summary>
226+
227+
**B.** Everything after `./lab-ork` goes to `ork` as you typed it. The wrapper
228+
only supplies the endpoint, the credential, and the four `@..._id` words.
229+
230+
</details>
231+
232+
## Try it yourself
233+
234+
Make the doctor fail on purpose, so you know what a failure looks like before a
235+
real one. Change one value in `.env` so that a check fails, read the fix the
236+
doctor prints, then put the value back.
237+
238+
### Check
239+
240+
The doctor ends on the "ready" line again.
241+
242+
```bash
243+
(cd python && .venv/bin/python doctor.py) | tail -n 1
244+
```
245+
246+
On the TypeScript path, use `npm --prefix typescript run doctor | tail -n 1`.
247+
248+
<details>
249+
<summary>Solution</summary>
250+
251+
Add `/v1` to the end of `ORCA_BASE_URL` and run the doctor:
252+
253+
```text
254+
FAIL ORCA_BASE_URL https://<your-host>/v1
255+
fix: Use the host root only: ORCA_BASE_URL=https://<your-host>
256+
```
257+
258+
The doctor does not call an endpoint it can see is wrong. It skips the Agent
259+
Engine check, tells you the exact value to use, and ends with
260+
`1 check(s) failed`. Remove the `/v1` and run it again.
261+
262+
</details>
263+
264+
## Recap
265+
266+
- `.env` holds your team card: the addresses of your team's environment and its
267+
key. It is git-ignored.
268+
- Your team shares that environment. The login stream is loaded once, and the
269+
seeder refuses a second copy.
270+
- The doctor checks each service on the card and prints the fix for a failure.
271+
- `./lab-ork` is how you look at your Agent Engine from the terminal.
272+
273+
## What's next
274+
275+
[Lab 1: Hello, agent](01-hello-agent.md)

‎labs/cloud/README.md‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ flowchart LR
2525
| Lab | Time | Where | You | The idea |
2626
|---|---|---|---|---|
2727
| [0. Set up](00-set-up.md) | 10 min | terminal | Fill in `.env` from your instance, load the topic, run the doctor | Check service access before you build on it |
28+
| or [0. Set up from a team card](00-set-up-team-card.md) | 5 min | terminal | Fill in `.env` from your team card, load the topic, run the doctor | The same, when the organizers created your environment |
2829
| [1. Hello, agent](01-hello-agent.md) | 5 min | CLI / Python / TS | Create an agent and chat | Agent, environment, session, events |
2930
| [2. Hello, streaming SQL](02-streaming-sql.md) | 8 min | SQL Workspace | Build a materialized view over the topic | Context that keeps itself fresh |
3031
| [3. Agent + live context](03-live-context.md) | 9 min | CLI / Python / TS | Give the agent SQL tools, inject new data | The answer changes with the data |
@@ -43,8 +44,13 @@ your own.
4344
- One path installed, plus `ork`, `jq`, and `snctl`. All of this is in
4445
[Before you arrive](../../docs/before-you-arrive.md).
4546

46-
Start with [Lab 0: Set up](00-set-up.md). If something goes wrong, see
47-
[Troubleshooting](troubleshooting.md). How labs and checks work is in
47+
**Have a team card?** Then the organizers created all of this for your team,
48+
and the card has its addresses and an API key. You need only your login, one
49+
path, `ork`, and `jq`, and you start with
50+
[Lab 0: Set up from a team card](00-set-up-team-card.md).
51+
52+
Otherwise, start with [Lab 0: Set up](00-set-up.md). If something goes wrong,
53+
see [Troubleshooting](troubleshooting.md). How labs and checks work is in
4854
[The labs](../README.md), and a coding agent can
4955
[tutor you through the course](../../docs/tutor.md).
5056

@@ -60,6 +66,15 @@ cluster was Serverless; the SQL workspace ran RisingWave 3.1.0-alpha.
6066
- **Lab 0**: every `snctl` lookup, the topic, the seeder, and the doctor, on the
6167
Python path. On the TypeScript path, the doctor, and the seeder against the
6268
topic once it was loaded.
69+
- **Lab 0 from a team card**: added on 6 October 2026 and run that day against
70+
the same test instance, from a card of ready-made `NAME=value` lines. On the
71+
Python path: every step and check, and the failing doctor run its solution
72+
shows. On the TypeScript path, and with the CLI column's commands: the doctor
73+
and the seeder. The topic was loaded already (274 events, after earlier Lab 3
74+
runs), so the seeder printed its "already holds" line each time. The card had
75+
no `SN_SQL_DATABASE` line; nothing in Lab 0 reads that value. Not run from
76+
this page: the seeder on an empty topic, a card of labeled values, and an
77+
environment the organizers created.
6378
- **Lab 2**: every statement and check, through `psql`. The console was not
6479
used.
6580
- **Labs 1, 3 and 4**: every step and check, on all three paths, with the model

0 commit comments

Comments
 (0)