Quickstart: TypeScript

Wire @wytness/ai into your AGT-instrumented Node app in about five minutes. Install, set four env values (plus the optional endpoint), call init(). Every audit entry AGT-TS chains is auto-forwarded to Wytness with PII pseudonymisation and a per-event Ed25519 envelope signed with your customer-held key.

@wytness/ai 1.12.0ChangelogBuilt on AGT

1. Install the wrapper

Microsoft's @microsoft/agent-governance-sdk@5.0.0 is a hard dependency of wytness-ai — installed automatically. Targets Node 18+ (uses the global fetch).

terminal
npm install @wytness/ai
Note
Need just AGT-TS, no Wytness on your runtime? See the direct-ingest pathnpm install @microsoft/agent-governance-sdk and point its native CloudEvents sink at api.wytness.ai/ingest. You get the dashboard but not customer-held PII keys or Evidence Packs.

2. Generate keys

Wytness adds two customer-held primitives on top of AGT — per-event Ed25519 non-repudiation and zero-knowledge PII pseudonymisation. Both rely on keys you generate in your browser; the private halves never reach Wytness.

Open the Keys page. Click Generate on each of the three key cards (signing, PII encryption, PII HMAC), then download each private half. The public halves auto-register against your org. The four env values you need are then shown as a copy-block on the Onboarding "Instrument" step:

  • WYTNESS_API_KEY — transport credential (server-issued, prefix wyt_api_live_…)
  • WYTNESS_SIGNING_KEY — base64 Ed25519 private key, 32 bytes decoded (always required — non-repudiation is the product promise)
  • WYTNESS_PII_PUBKEY — base64 X25519 public key, 32 bytes (optional; required together with the secret to enable PII pseudonymisation)
  • WYTNESS_PII_SECRET — base64 HMAC secret, ≥16 bytes (optional; required together with the pubkey)
Important
The signing private key and the PII HMAC secret are the roots of trust for the Wytness guarantees. Treat them like database passwords. If either leaks, an attacker can forge events that look like they came from your agent (signing key) or correlate pseudonymised events back to identities (HMAC secret). Wytness never sees either — store them in your secrets manager and load them as env vars at process start.

3. Set the environment

Set the four values as environment variables. In production use your secrets manager (Azure Key Vault, AWS Secrets Manager, Vercel env, k8s secrets, etc.); in local dev a .env file loaded by Node’s built-in --env-file flag is fine. init() reads them directly — no constructor boilerplate. If you use a .env file locally, add it to .gitignore before the first git add.

.env
WYTNESS_API_KEY=wyt_api_live_...
WYTNESS_ENDPOINT=https://api.wytness.ai
WYTNESS_SIGNING_KEY=<base64 Ed25519 private key>
WYTNESS_PII_PUBKEY=<base64 X25519 public key>
WYTNESS_PII_SECRET=<base64 HMAC secret>

4. Wire it in

Call init() once at process start, before AGT-TS's AuditLogger is first instantiated. The wrapper hooks AGT's audit logger cleanly so every entry it chains flows through the Wytness path — your existing AGT code stays unchanged.

agent.ts
import { init, shutdown, AuditLogger } from "@wytness/ai";
// Reads WYTNESS_* env vars by default. piiFields lists dotted paths
// whose values should be pseudonymised (emails, customer names, etc.).
await init({ piiFields: ["customer.email", "customer.name"] });
// Use AGT-TS exactly as you would without the wrapper.
const audit = new AuditLogger();
audit.log({
agentId: "billing-agent",
action: "tool_invocation:send_invoice",
decision: "allow",
});
// Drain the in-flight batch on exit.
await shutdown();
Note
Auto-wire is on by default. Pass init({ autoWire: false }) if you'd rather attach the audit sink yourself — see the SDK API reference.
Tip
AGT-TS's AuditLogger.log() takes a small camelCase entry shape. Extra Wytness fields (data, outcome, resource) can be stashed on the next entry with setNextEntryExtras(...). See the SDK API reference.

5. Run it

Run your agent normally. The wrapper batches events (default 100 or 5 seconds, whichever first), pseudonymises declared PII fields, signs each event with your Ed25519 key, and POSTs the canonical-shape envelope to api.wytness.ai/ingest. Failed POSTs are written to a local dead-letter file for replay once connectivity returns.

terminal
npx tsx agent.ts

Open your app.wytness.ai dashboard within ~5 seconds of the first event to confirm it arrived. Events show the AGT identity, the AGT-supplied hash chain, and the Wytness envelope signature side-by-side.

What you'll see in the dashboard

  • Each AGT-TS AuditEntry as a row in the Events page
  • Three-layer verdict: AGT identity (Ed25519 DID), AGT-supplied hash chain, Wytness envelope (Ed25519)
  • PII fields rendered as typed tokens (EMAIL_3c866e6f, etc.); reveal in-browser with your X25519 private key
  • Source format chip showing wytness_agt_ts (TypeScript wrapper) on every event
  • Per-agent Identity Badge pulled from AGT-TS's DID + trust score

Full working example

Save as test-audit.ts, then run with npx tsx test-audit.ts.

test-audit.ts
import { init, shutdown, setNextEntryExtras, AuditLogger } from "@wytness/ai";
await init({ piiFields: ["customer.email"] });
const audit = new AuditLogger();
setNextEntryExtras({
data: { customer: { email: "alice@example.com" }, message: "Hi" },
outcome: "success",
});
audit.log({
agentId: "test-agent",
action: "tool_invocation:hello_world",
decision: "allow",
});
setNextEntryExtras({
data: { a: 40, b: 2, result: 42 },
outcome: "success",
});
audit.log({
agentId: "test-agent",
action: "tool_invocation:add_numbers",
decision: "allow",
});
await shutdown();
console.log("Done — check your dashboard.");

What happens under the hood

  1. AGT-TS runs unchanged — identity check, policy evaluation, hash-chain entry
  2. The wrapper's WytnessAuditSink receives the entry, transforms camelCase to canonical snake_case, applies your piiFields pseudonymisation
  3. The canonical-shape data payload is signed with your Ed25519 key, wrapped in a CloudEvents 1.0 envelope
  4. The batch is POSTed to api.wytness.ai/ingest as application/vnd.wytness.agt+json
  5. Failed POSTs are written to a local dead-letter file for replay once connectivity returns

Automatic LLM capture

Prefer not to write AuditLogger().log(...) by hand? Wrap your model client after init() and every Anthropic Messages API call (including the beta namespace) and every OpenAI Chat Completions and Responses call — streaming included — is recorded automatically — prompt, reply, reasoning (Anthropic extended thinking), latency, and token usage. Token usage needs no opt-in: on OpenAI streams the SDK requests it and hides the resulting usage-only chunk, so your loop is unchanged. Other providers are not captured. Captured calls ride the same signed, PII-pseudonymised path as manual entries.

agent.ts
import Anthropic from "@anthropic-ai/sdk";
import { init, shutdown, wrapAnthropic } from "@wytness/ai";
await init({ agentDid: "did:web:acme.example:support-bot", piiFields: ["customer.email"] });
const client = wrapAnthropic(new Anthropic());
await client.messages.create({ // recorded automatically — no audit.log() needed
model: "claude-haiku-4-5",
max_tokens: 512,
messages: [{ role: "user", content: "Summarise ticket #4821" }],
});
await shutdown();
Note
OpenAI is identical — wrapOpenAI(new OpenAI()). Streaming calls (stream: true and messages.stream(...)) are captured too — one event per call when the stream ends; helper streams are captured on completion via the SDK's own events, even if your code never reads them. OpenAI streamed usage needs no opt-in — the SDK requests it and hides the resulting usage-only chunk, so your loop is unchanged.

Using a TypeScript agent framework?

AGT-TS 5.0.0 ships GenericFrameworkAdapter only — no framework-specific adapters for LangChain.js / AutoGen / OpenAI Agents / Semantic Kernel today. Implement one adapter method against your framework's tool-call lifecycle, and every entry AGT-TS chains flows into Wytness via wytness-ai. See the framework integrations guide for the adapter pattern.

Next steps

  • PII Protection — declare custom pseudonymisation fields, generate keys, reveal tokens in the dashboard
  • SDK API reference — full init() / shutdown() options, manual wiring, batch tuning
  • Event schema — canonical-shape data payload + Wytness envelope layout
  • Quickstart (Python) — same shape for wytness-ai (PyPI)

Ready to audit your AI agents?

Start recording

We set no cookies. Sign-in and preferences use essential first-party browser storage only — no tracking, advertising, or third-party analytics. Privacy Policy

Quickstart: TypeScript
TABLE OF CONTENTS