WASM build tooling and monorepo developer guide. Describes the WebAssembly component architecture, build pipeline, WIT contracts, and cross-package development workflow.
The TypeScript SDK is compiled into a WebAssembly component (strands-agent.wasm). Python loads this component via wasmtime-py and drives it.
The WIT contract (wit/agent.wit) defines what crosses the WASM boundary:
- Exports (TS implements, Python calls): The
apiinterface — agent construction, streaming, conversation management. All model provider HTTP calls (Bedrock, Anthropic, OpenAI, Gemini) happen inside the WASM guest. - Imports (Python implements, TS calls back into):
tool-providerfor executing Python-defined tools, andhost-logfor routing log entries to Python's logging framework.
In WIT terminology, the WASM component is the "guest" and Python is the "host". When the TS agent loop decides a tool needs to run, it calls the tool-provider import which crosses the WASM boundary back to Python where the actual tool function lives.
- Node.js 20+
- Python 3.10+
git clone https://github.com/strands-agents/harness-sdk.git
cd harness-sdk
npm install
npm run dev -- bootstrapbootstrap installs toolchains, links strandly to your PATH, generates type bindings, builds all layers, installs strands-py-wasm, and runs all tests. If this command doesn't enable development out of the box, file an issue.
Changes flow through a pipeline. Each layer compiles into the next:
graph TD
WIT["wit/agent.wit"] -->|generate| TS_GEN["strands-ts/generated/"]
WIT -->|generate| WASM_GEN["strands-wasm/generated/"]
TS_GEN --> TS["strands-ts (npm build)"]
TS -->|esbuild bundle| WASM_BUNDLE["strands-wasm (ESM bundle)"]
WASM_GEN --> WASM_BUNDLE
WASM_BUNDLE -->|componentize-js| WASM["agent.wasm (WASM component)"]
WASM -->|wasmtime-py| PY["strands-py-wasm (Python package)"]
| Directory | Language | What it is |
|---|---|---|
wit/ |
WIT | Interface contract between the WASM guest and host |
strands-ts/ |
TypeScript | Agent runtime: event loop, model providers, tools, hooks, streaming |
strands-wasm/ |
TypeScript | Bridges the TS SDK to WIT exports, compiles to a WASM component |
strands-py-wasm/ |
Python | Python wrapper: Agent class, @tool decorator, direct WASM host |
strandly/ |
TypeScript | Dev CLI that orchestrates build, test, lint, and CI |
team/ |
Markdown | Governance and cross-SDK process docs (tenets, decisions, PR guidelines, designs/ proposals) |
strandly generate produces type bindings from wit/agent.wit into:
strands-ts/generated/(gitignored)strands-wasm/generated/(gitignored)strands-py-wasm/src/strands/_generated/(committed)
Generated files are created by running strandly generate (or bootstrap). Do not edit them by hand. CI runs strandly generate --check and fails if they are stale.
| Layer | Framework | Location |
|---|---|---|
| TypeScript SDK | vitest | strands-ts/src/**/__tests__/ (unit), strands-ts/test/ (integ) |
| Python wrapper | pytest | strands-py-wasm/tests/ |
Add tests alongside the code you change. Bug fixes should include a test that reproduces the original issue.
Each layer depends on the layers above it in the pipeline. The validate command rebuilds and tests exactly the layers your change affects.
| What you changed | Validate command |
|---|---|
WIT contract (wit/agent.wit) |
strandly validate wit |
| TS SDK internals | strandly validate ts |
| TS SDK public API | strandly validate ts-api |
WASM bridge (strands-wasm/entry.ts) |
strandly validate wasm |
Pure Python (strands-py-wasm/) |
strandly validate py |
TS internals vs. public API: The WASM bridge (strands-wasm/entry.ts) imports specific types and functions from strands-ts/. If your change modifies something the bridge imports, it is a public API change — use validate ts-api. If the bridge does not import it, use validate ts.
WIT contract changes cascade to every layer. After running validate wit, fix any compile errors in strands-wasm/entry.ts and the language wrappers. The build will not succeed until every layer matches the new contract.
strandly <command> [options]Most commands accept layer flags (--ts, --wasm, --py). No flags means all layers.
| Command | What it does |
|---|---|
bootstrap |
First-time setup: install, link, generate, build, install py-wasm, test |
setup |
Install toolchains (--node, --python) |
link |
Install strandly on PATH as a live symlink to this repo |
generate |
Regenerate type bindings from WIT (--check) |
build |
Compile layers (--ts, --wasm, --py) |
test |
Run tests (--py, --ts, or a specific [file]) |
check |
Lint and type-check (--ts, --wasm, --py) |
fmt |
Format all code (--check to verify without writing) |
validate <layer> |
Rebuild and test the layers affected by a change |
ci |
Full pipeline: generate, format, lint, build, test |
rebuild |
Clean rebuild: clean, generate, build |
clean |
Remove all build artifacts |
example <name> |
Run an example (--py, --ts) |
| Language | Formatter | Linter |
|---|---|---|
| TypeScript | prettier |
tsc --noEmit |
| Python | ruff format |
ruff check |
strandly fmt # format everything
strandly check # lint everythingComments are normative statements that describe what code does or why a decision was made. Avoid TODO's without associated issues, notes-to-self, and parenthetical asides.
- Run
strandly cibefore pushing. This is the same pipeline CI runs. - Keep PRs focused on a single change.
- Use conventional commit messages:
feat:,fix:,refactor:,docs:, etc.