Before any code, a project that runs. This lesson gets your machine ready: the toolchain (Node + pnpm), the exact dependency set the whole course pins, the two workspace settings that make installs work, and the TypeScript config that lets us run .ts directly. Five minutes here means every later lesson just runs.
The whole course lives on GitHub at knpkv/effect-course-agentcore — the runnable project is in course/. Clone it and work from there:
git clone https://github.com/knpkv/effect-course-agentcore.git
cd effect-course-agentcore/course
You need Node 22+ (we rely on import.meta.main to guard the server entrypoint in lesson 02) and pnpm as the package manager. The cleanest way to get the exact pnpm the project expects is corepack, which ships with Node:
node --version # v22.x or newer
corepack enable # makes pnpm available, pinned by the project
pnpm --version # 11.5.0 (from packageManager in package.json)
The version is pinned by a "packageManager": "pnpm@11.5.0" field, so corepack hands everyone the same pnpm — no "works on my machine" drift. We use pnpm (not npm) because the course is a small workspace, and pnpm's workspace settings are where two install-time policies live (section 03).
The whole course is one effect@4 program, so the dependency set is small and deliberately pinned. From inside course/:
# runtime
pnpm add effect@4.0.0-beta.74 \
@effect/platform-node@4.0.0-beta.74 \
alchemy@2.0.0-beta.44 \
@distilled.cloud/aws@0.22.0
# dev
pnpm add -D @effect/vitest@4.0.0-beta.74 vitest tsx typescript @types/node
The result is the project's package.json — note the scripts you'll use every lesson:
{
"name": "effect-agentcore",
"type": "module",
"scripts": {
"dev": "tsx watch src/agent.ts", // agent on :8080 (lesson 02)
"deploy": "alchemy deploy", // provision the stack (lesson 05+)
"destroy": "alchemy destroy",
"test": "vitest run" // drive the lesson tests green
},
"dependencies": {
"alchemy": "2.0.0-beta.44",
"effect": "4.0.0-beta.74",
"@effect/platform-node": "4.0.0-beta.74",
"@distilled.cloud/aws": "0.22.0"
},
"devDependencies": {
"@effect/vitest": "4.0.0-beta.74",
"@types/node": "^25.6.0",
"tsx": "^4.21.0",
"typescript": "^6.0.3",
"vitest": "^4.1.5"
}
}
effect brings the agent server (effect/unstable/httpapi) and the AI module (effect/unstable/ai — LanguageModel, Tool, Toolkit, Prompt, Response); @effect/platform-node runs it on Node; alchemy is Infrastructure-as-Effects; @distilled.cloud/aws is Alchemy's native-Effect AWS SDK (it gives us Bedrock Converse and the AgentCore control plane). Notably absent: the standalone @effect/ai — it's effect-3-only, but core's effect/unstable/ai covers it; we hand-write only the Bedrock provider in lesson 03. No raw @aws-sdk/* either.
src/effect-agentcore/package.json
pnpm reads a pnpm-workspace.yaml. A few dependencies ship native post-install build scripts (esbuild, workerd, msgpackr-extract) that pnpm won't run until they're listed:
# pnpm-workspace.yaml
allowBuilds:
esbuild: true
msgpackr-extract: true
workerd: true
After the first install, approve the builds once:
pnpm install
pnpm approve-builds # one-time: confirms the allowBuilds list
pnpm test errors before any test runs
That's almost always an un-approved build: pnpm's pre-run dependency check fails on an ignored build script. The fix is the sequence above — corepack enable → pnpm install → pnpm approve-builds → pnpm test. This bit us during scaffolding; getting the workspace settings right is what made the suite go green.
src/effect-agentcore/pnpm-workspace.yaml
We never compile to JavaScript — tsx runs .ts directly and tsc is only a type checker (--noEmit). A few flags follow from that:
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "nodenext",
"moduleResolution": "nodenext",
"strict": true,
"exactOptionalPropertyTypes": true,
"noEmit": true,
"allowImportingTsExtensions": true, // we import "./model.ts" with the extension
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noUncheckedIndexedAccess": true,
"types": ["node"]
},
"include": ["src", "given", "alchemy.run.ts"]
}
| Flag | Why it's here |
|---|---|
allowImportingTsExtensions + noEmit | We import "../given/ai/StubModel.ts" with the .ts suffix and run it via tsx — no build step, so emitting is off. |
exactOptionalPropertyTypes | Distinguishes "absent" from "undefined". It's why lesson 03 builds the Converse request by omitting toolConfig rather than setting it to undefined. |
verbatimModuleSyntax | Forces explicit import type — Effect codebases lean on it heavily. |
noUncheckedIndexedAccess | Array access is T | undefined; you'll see hits[0]! in tests where we've already checked length. |
src/effect-agentcore/tsconfig.json
Two commands prove the project is ready. First, the test suite — it runs against the deterministic StubModel, so it needs no AWS credentials:
$ pnpm test
Test Files 3 passed (3)
Tests 9 passed (9)
Then the agent itself:
$ pnpm dev
[INFO] Listening on http://0.0.0.0:8080
$ curl -s localhost:8080/ping
{"status":"Healthy"}
If both of those work, your environment is correct and the rest of the course is additive — every lesson adds a few lines to a project that already compiles, tests, and runs. You won't touch setup again; you'll just keep this loop (pnpm test / pnpm dev) running.
One last orientation before lesson 01. The project splits in two: code you grow, and a shipped library you consume.
The given test/ suites define "done" for each lesson; you drive them green. Each lesson also has a full end-state checkpoint under solutions/<NN> — compare against it or copy from it if you get stuck. Now you're ready — Lesson 01 explains what AgentCore actually is and why we treat it as one Effect program.
course/README.md