Navigate docs

al-instrument-ts

Auto-instrument TypeScript AI agents with AgentLattice governance. One command adds identity, authorization, and audit trails to every tool your agent calls.

Works with Claude Agent SDK, Vercel AI SDK, and OpenAI SDK out of the box.

Install

npm install -g @agentlattice/instrument

Requires Node.js 18+. Dependencies: ts-morph, commander.

Quick Start

# See what al-instrument-ts would change (diff to stdout)
al-instrument-ts agent.ts

# Apply the changes
al-instrument-ts agent.ts --apply

# Apply + register the agent + verify governance wiring
al-instrument-ts agent.ts --apply --register --test

The diff is the tutorial. Review the generated code to understand exactly what governance means for your agent.

What It Does

al-instrument-ts runs a five-stage pipeline on your TypeScript file:

1. Analyze

Uses ts-morph (TypeScript AST) to find every AI agent tool definition in your code. Three SDK patterns are detected:

// Pattern 1: Claude Agent SDK — tool() call
import { tool } from "@anthropic-ai/claude-agent-sdk";

const searchTool = tool("search_database", "Search the customer database", {
  query: z.string(),
}, async ({ query }) => {
  return db.search(query);
});

// Pattern 2: Vercel AI SDK — tool({ description, parameters, execute })
import { tool } from "ai";

const emailTool = tool({
  description: "Send an email to a customer",
  parameters: z.object({ to: z.string(), subject: z.string(), body: z.string() }),
  execute: async ({ to, subject, body }) => {
    return emailClient.send(to, subject, body);
  },
});

// Pattern 3: OpenAI SDK — function tool definitions
const tools = [
  {
    type: "function" as const,
    function: {
      name: "delete_records",
      description: "Delete records from the database",
      parameters: {
        type: "object",
        properties: {
          ids: { type: "array", items: { type: "string" } },
        },
      },
    },
  },
];

Detection is deterministic. No LLM involved. Handles aliased imports (import { tool as myTool } from "ai").

2. Classify

Each detected tool is classified with an action type and risk level using the {domain}.{verb} taxonomy.

Domains: api, code, db, email, file, payment, system, user, web

Risk is determined by the verb, not the domain:

Verb Risk level Default policy
query read auto-approve
read read auto-approve
write write log
send write log
execute write log
create write log
update write log
delete delete require approval

So db.query is read risk, db.delete is delete risk, and system.execute is write risk. The domain provides context for audit trails and policy rules, but the verb drives the default risk level.

If ANTHROPIC_API_KEY or OPENAI_API_KEY is set, classification uses an LLM for intelligent action type assignment. Without an API key, it falls back to tool.{name} (e.g., tool.search_database) with a default risk level of write. The tool.* namespace is outside the standard taxonomy and won't match domain-specific policies until you reclassify.

3. Generate

Transforms your source code using ts-morph (preserving AST structure and indentation):

Claude Agent SDK and Vercel AI SDK get a gate() call injected at the top of the handler function:

// BEFORE
import { tool } from "@anthropic-ai/claude-agent-sdk";

const searchTool = tool("search_database", "Search the customer database", {
  query: z.string(),
}, async ({ query }) => {
  return db.search(query);
});
// AFTER
import { tool } from "@anthropic-ai/claude-agent-sdk";
import { AgentLattice } from "@agentlattice/sdk";

const al = new AgentLattice({ apiKey: process.env.AL_API_KEY ?? "" });

const searchTool = tool("search_database", "Search the customer database", {
  query: z.string(),
}, async ({ query }) => {
  await al.gate("db.query"); // AgentLattice: read-only database access, auto-approved by default policy
  return db.search(query);
});

OpenAI SDK tools are data-only definitions (JSON Schema, no handler function). al-instrument-ts emits TODO comments pointing you to where gate() calls should go in your dispatch handler:

// TODO(al-instrument): Add gate() calls in your tool dispatch handler:
//   case "delete_records": await al.gate("db.delete"); break; // destructive database operation, requires approval

4. Register (optional)

With --register, al-instrument-ts registers your agent with the AgentLattice API and writes the API key to your .env file. If AL_API_KEY is already present in .env, the file is not modified.

AL_SERVICE_KEY=sk-svc-... al-instrument-ts agent.ts --apply --register

You can also pass the key directly:

al-instrument-ts agent.ts --apply --register --service-key sk-svc-...

5. Verify (optional)

With --test, al-instrument-ts calls the AgentLattice API for each action type to verify that governance policies are correctly wired:

al-instrument-ts agent.ts --apply --register --test

The verifier checks that each action type gets a policy decision from AgentLattice, confirming that the governance pipeline is live end-to-end. In CI mode (--ci), any verification failure returns exit code 1.

CLI Reference

al-instrument-ts <file> [options]

Arguments:
  file                  TypeScript file containing AI agent tool definitions

Options:
  --apply               Write instrumented code back to the file (default: show diff)
  --register            Register the agent with AgentLattice (requires --apply)
  --test                Verify governance wiring (requires --register)
  --service-key <key>   AL_SERVICE_KEY for registration (default: $AL_SERVICE_KEY)
  --agent-name <name>   Agent name for registration (default: derived from filename)
  --base-url <url>      AgentLattice API base URL (default: https://www.agentlattice.io)
  --ci                  CI mode: non-interactive, exit codes only

Idempotency

Running al-instrument-ts on an already-instrumented file is safe. It detects the @agentlattice/sdk import and skips with a message:

File already has AgentLattice governance (@agentlattice/sdk imported). Skipping.

Report Output

After every run, al-instrument-ts prints a structured report:

════════════════════════════════════════════════════
  al-instrument-ts report
════════════════════════════════════════════════════

  TOOLS FOUND: 3
    search_database  → db.query     (read, auto-approved)    [claude-agent]
    send_email       → email.send   (write, requires approval) [vercel-ai]
    delete_records   → db.delete    (delete, requires approval) [openai]

  CLASSIFICATION: LLM-assisted (Claude)
  CHANGES: written to agent.ts

  ACTION REQUIRED (1 item):
    1. agent.ts:42 — TODO(al-instrument): Add gate() calls
       in your tool dispatch handler

  NEXT STEPS:
    1. Review the diff: git diff agent.ts
    2. Fix the TODO above (add gate() calls to OpenAI dispatch)
    3. Set AL_API_KEY in your environment
    4. Run your agent — governance is active
    5. Visit https://www.agentlattice.io/dashboard to configure policies

════════════════════════════════════════════════════

Supported SDKs

SDK Pattern Governance injection
Claude Agent SDK tool("name", "desc", schema, handler) gate() injected at top of handler
Vercel AI SDK tool({ description, parameters, execute }) gate() injected at top of execute
OpenAI SDK { type: "function", function: { name, ... } } TODO comments (data-only, no handler)

How It Fits Together

al-instrument-ts generates code that uses the @agentlattice/sdk TypeScript package:

  • @agentlattice/sdk provides the AgentLattice client and gate() method that communicates with the API

After instrumentation, every tool call flows through: Tool invoked → al.gate() checks authorization → AgentLattice evaluates policy → Approved/Denied → Tool executes or throws error.

Configure policies, approval flows, and audit rules in the AgentLattice dashboard.