# Teaching Script — DD-14: Mastra (Observability Primitives)

**Instructor notes**: ~2000 words. 11 slide cues. Pace: ~3 minutes per slide. Two load-bearing ideas: (1) the wrapper-vs-native observability distinction (Module 10 reference), and (2) the explicit read/write memory split that makes write-gating interface-level (Module 4.3 reference). The NemoClaw parallel (slide 5) is the cross-module connection that lands both — two interface-level defenses at different layers. Watch for students assuming native observability covers bring-your-own components (slide 3) — catch that.

---

[SLIDE 1 — Title]

This is Mastra, the TypeScript-first SDK. Two contributions define it, and both are references the course points at: native observability as a first-class primitive — the Module 10 reference, 5 out of 5 — and explicit read/write memory tiers — the Module 4.3 reference, also 5 out of 5. Mastra is the only harness in the roster where the memory-poisoning defense is structural rather than advisory. The cost: no sandbox, smaller community, and you must build against its primitives to get the observability benefit. 34 out of 60 — the observability-and-memory shape.

[SLIDE 2 — The thesis: observability in the component, not around it]

Here is the distinction Module 1.4 and Module 10 teach, and that Mastra exists to embody. Most SDKs use the wrapper pattern. You write `withObservability(agent, { tracer })`. Observability is applied externally. The component itself knows nothing about tracing. The wrapper intercepts calls, records spans, emits telemetry. This works. It is how most production instrumentation is retrofitted. Its weakness: the wrapper only sees what crosses the boundary. Internal decisions the component makes without calling out are invisible. And the wrapper can drift out of sync with the component's behavior as the component evolves.

Mastra uses the native pattern. `component.run(input)` returns `{ result, events[] }`. The component owns its event emission. Every internal decision — why it picked this tool, why it stopped, what it pruned from context — is an event the component emits because that is what the component does. Not because a wrapper is watching. The events are the contract.

And notice the convergence with Tau, DD-21. Tau makes its typed event union the observability layer for a teaching harness. Mastra makes native emission the primitive for a production SDK. They converge on the same conclusion: observability belongs in the component, not around it. Events ARE the cross-layer contract.

[SLIDE 3 — What "native" buys you: three properties]

Three properties make the native pattern worth its cost. First, internal decisions are visible. A wrapper sees tool calls; a native emitter sees why the tool was chosen, what alternatives were rejected, what the component decided to prune. For debugging a long agent run, this is the difference between a span tree and a reasoning trace.

Second, the contract cannot drift. Because emission is part of the interface, the events track the component as it evolves. A wrapper can silently stop recording when the component changes shape; a native emitter changes with the component or fails to compile.

Third, every consumer gets the same stream. A logger, a dashboard, an alerting rule, a replay system — they all read the same events. There is no "the telemetry says X but the logs say Y" gap.

And here is the cost, and I want you to catch this because it is where teams go wrong. Native only pays off when components are native. If you bring your own components — an off-the-shelf LLM wrapper, a custom tool — and slot them into Mastra, those components do not emit Mastra's events. You inherit their observability gap. The event stream shows a hole wherever your non-native component runs. So the value of Mastra is contingent on building against its primitives. If your team is unwilling to do that, the native pattern does not apply and you should use a wrapper-based SDK.

[SLIDE 4 — The explicit read/write memory boundary]

Mastra's second contribution. Most harnesses conflate read and write. There is a memory store, and agents read from and write to it through the same handle. Mastra splits them. `readMemory(query)` returns results. `writeMemory(entry)` returns an ack. Two separate interfaces, separately permissionable.

This is architecturally cleaner than a conflated store, and it has a direct security implication that Module 4.3 is built around. The memory-poisoning defense is fundamentally a write-path control. If reads and writes share a handle, restricting writes means intercepting calls and checking intent — a policy layer bolted onto a unified interface. If reads and writes are separate interfaces, restricting writes is an interface-level decision. You give an agent the read-memory interface and you withhold the write-memory interface. The defense is structural, not advisory.

Compare to CrewAI, DD-12. Crew-scoped shared memory means every agent in the crew can write to the store every other agent later reads. The write-gating defense is unavailable by default because there is no separate write interface to withhold. Mastra's split is the cleaner abstraction precisely because it makes the security-relevant decision a type-level one.

[SLIDE 5 — The NemoClaw parallel: two interface-level defenses]

This is the cross-module connection that lands both ideas. Mastra's read/write split is structurally identical to NemoClaw's argument about credentials.

NemoClaw's load-bearing claim is that credentials live outside the sandbox's reach. The sandboxed agent never has a handle to the credentials at all, so the question of leaking them cannot arise inside the sandbox. The defense is architectural — no handle exists — not advisory, a policy that says "do not leak."

Mastra makes the same move at the memory layer. An agent that never receives the write-memory interface cannot poison memory — not because a policy forbids it, but because there is no handle to call. Two different layers — sandbox credentials versus memory writes — one structural principle. The strongest defense is to remove the handle, not to write a policy that says "do not misuse it."

This is why Module 4.3 points at Mastra and why NemoClaw is load-bearing for Module 2. The interface-level defense is the architectural move the course keeps returning to: when the handle does not exist, misuse is not possible.

[SLIDE 6 — Score: 34/60, the observability-and-memory shape]

Now the score. Mastra is 34 out of 60. Two 5 out of 5 peaks. Module 10 Observability: 5 out of 5 — the best built-in observability primitives in the roster, native event emission. Module 4.3 Write-gating: 5 out of 5 — interface-level, not policy-level, the reference.

Strong on Module 4 Memory, 4 out of 5 — explicit read/write separation. And Module 2 Tools, 3 out of 5 — SDK-defined surface, not a fixed tool set.

But then the production gaps. Module 5 Sandbox: 1 out of 5 — none, bring your own. Module 9 Verification: 1 out of 5 — none. Module 11 Security: 2 out of 5 — the read/write split is an asset, but there is no sandbox and no SECURITY model. The split and the observability deserve an explicit security framing to match.

The interpretation: Mastra is the observability-and-memory reference, not the production-readiness reference. Two 5 out of 5 peaks. Pair it with a harness that has the security modules implemented — NemoClaw for governance, the Agents SDK for sandboxing. Mastra gives you the observability and the memory safety; you bring the containment.

[SLIDE 7 — The OpenHarness-vs-Mastra observability axis]

The previous lecture was OpenHarness, DD-13. Both are observability-first, but they optimize for different objective functions.

OpenHarness: inspectability-as-product, human-readable logs, the cleanest mechanism reference for research. Module 10: 4 out of 5 — below 5 only because human-readable over machine-readable.

Mastra: native event emission, machine-readable structured events, the production observability reference. Module 10: 5 out of 5.

Same goal — see what the agent did. Different objective functions. Research reproducibility versus production operability. And notice: OpenHarness approaches the Mastra standard but does not meet it. The gap that keeps OpenHarness at 4 out of 5 on Module 10 while Mastra is 5 out of 5 is exactly the machine-readable-logs gap — the third thing OpenHarness would need to fix if misused as production. OpenHarness is the lab harness where you study compaction; Mastra is the production harness where you ship observability.

[SLIDE 8 — MLSecOps relevance: the two hardest substrates to retrofit]

For MLSecOps, Mastra gives you the two substrates that are hardest to retrofit into other harnesses. First, a structural write boundary. The read/write split makes memory-poisoning defense interface-level. An MLSecOps team gets a write boundary that is in the type system, not in a policy layer that can be bypassed or misconfigured.

Second, an intrinsic observability stream. Native event emission means every internal decision is an event a SIEM or alerting layer can consume. There is no "the agent did something but we cannot see what" gap.

The gap: no sandbox, no threat model. The memory and observability assets deserve an explicit security framing to match. Pair Mastra with a harness that has the sandbox and verification modules. Mastra gives you visibility and memory safety; you still need containment.

[SLIDE 9 — Three better, three to fix]

Three things Mastra does better. Observability as a first-class primitive — built in, not a wrapper. The Module 10 reference. Explicit read/write memory tiers — the cleanest abstraction, the Module 4.3 reference, the only roster harness where memory-poisoning defense is structural. And TypeScript-first DX — the best TypeScript experience in the SDK category.

Three things to fix. Add a sandbox — none present; for a production SDK this is a gap the user must fill. Compare the Agents SDK's 7-provider sandbox abstraction. Broaden integrations — fewer than OpenCode and Aider; the observability story deserves more consumers to justify building native. Add a SECURITY.md and a documented threat model — the read/write split and native observability are security assets that deserve explicit framing, not just architectural description.

The verdict: build on Mastra when TypeScript plus observability plus memory safety are your priorities and you are willing to build against its primitives. The observability reference for Module 10. The cleanest memory abstraction for Module 4. The only roster harness where memory-poisoning defense is structural rather than advisory.

[SLIDE 10 — Takeaways]

Five takeaways.

One: observability belongs in the component, not around it. The wrapper pattern sees boundary crossings; the native pattern sees internal decisions. Mastra is the native-pattern reference for Module 10.

Two: native buys you three properties — internal decisions visible, contract cannot drift, every consumer gets the same stream. The cost: you must build native to get the benefit. Bring your own components and you bring your own observability gap.

Three: the read/write memory split makes write-gating interface-level. Give the read interface, withhold the write interface. The defense is in the type system, not in a policy layer.

Four: Mastra's split is structurally identical to NemoClaw's credential isolation. Both remove the handle rather than writing a policy. Different layers — memory versus sandbox — one principle: when the handle does not exist, misuse is not possible.

Five: 34 out of 60 is the observability-and-memory shape, not the production-readiness shape. Two 5 out of 5 peaks. Pair Mastra with a harness that has the security modules.

This is the final deep-dive of Course 1. All 14 deep-dives complete. The harness roster is now in your hands — the reference set you take into the rest of the course and into your own work. Use the score table, not the score number. Use the pole pairs, not the averages. And use the architectural patterns — the interface-level defense, the non-destructive record, the native event emission — when you design your own harness.

---

**End of teaching script.** Lab: see `07-lab-spec.md` — implement both the wrapper and the native observability pattern in TypeScript-style pseudocode, implement the read/write split with an interface-level write gate, and verify the structural defense (an agent without the write interface cannot write).
