Skip to content

Commit d5b4c9c

Browse files
authored
Add a team-card Lab 0 to the Cloud course (#7)
* 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. * Document building the team card from the environment sheet Teams are given access to the environment sheet that the organizers keep and build their team card themselves, so the team-card Lab 0 now says how. - Step 2 maps six columns of a team row to .env lines, gives the console steps for creating an API key for the team service account, and shows a finished card with placeholders. - The READMEs, .env.cloud.example and docs/before-you-arrive.md describe a team environment and its sheet instead of a card that is handed over. - Troubleshooting: with a team card, a rejected key is replaced by creating a new one. - The tutor asks whether the team has a row in the environment sheet. - What was run: steps 2 and 3 against a test instance with the seven lines filled in. The API key steps follow the labels of the console and were not clicked through.
1 parent aef76ed commit d5b4c9c

11 files changed

Lines changed: 392 additions & 11 deletions

File tree

‎.env.cloud.example‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
# cp .env.cloud.example .env
55
#
66
# labs/cloud/00-set-up.md, step 2, has the snctl command for each address.
7+
# In an environment the organizers created for your team, the values come from
8+
# your row in their environment sheet, and you create the API key yourself:
9+
# labs/cloud/00-set-up-team-card.md, step 2.
710
# (The Local course writes its own .env: see labs/local/00-set-up.md.)
811

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

0 commit comments

Comments
 (0)