Get Started
Stark-Kit is a lightweight, strictly typed, and provider-agnostic TypeScript framework for building AI agents. Write your agentic loops once and run them on OpenAI, Claude, Gemini, or Mistral — without touching your core application logic.
Why Stark-Kit?
Most agent frameworks tightly couple your business logic to a specific provider's SDK. When you need to switch models — for cost, capability, or compliance reasons — you end up rewriting large portions of your code. Stark-Kit addresses this by introducing a provider-agnostic execution model centered around a unified CanonicalMessage interface. Every LLM adapter speaks the same internal language, so your agent code never needs to know which provider it's running on.
Beyond provider portability, Stark-Kit ships with everything you need to build production-grade agentic systems out of the box:
- •Strictly Typed Tools — Runtime schema validation via Zod — the model can't call a tool with wrong arguments.
- •Real-Time Streaming — Stream text chunks, tool call events, and lifecycle states as they occur.
- •Lifecycle Hooks — Intercept calls before they reach the LLM or before/after tool execution.
- •Human-in-the-Loop (HITL) — Pause execution mid-run to get human approval before running sensitive tools.
- •Agent Handoffs — Route conversations between specialized agents at runtime.
- •Structured Outputs — Bind an agent to a Zod schema and force structured JSON responses.
Architecture
Stark-Kit has three main components that work together to keep vendor logic separate from your agent code:
1. The Agent
An Agent encapsulates everything that defines an agent's behaviour: its system instructions, the tools it can call, the provider it runs on, runtime parameters like temperature and max steps, lifecycle hooks, and an optional output schema. An agent is a pure configuration object — it doesn't do anything on its own. It tells the run loop how to behave.
2. The Provider
A Provider is a standard interface implemented by each LLM adapter:OpenAIProvider, ClaudeProvider, GeminiProvider, and MistralProvider. Each adapter translates Stark-Kit's internal message structure into the native format that provider expects, and maps the response back to a unified shape. You can also implement the Provider interface yourself to add any LLM backend.
3. The Run Loop
run() and runStream() are the orchestrators. They manage the message history, call the provider, execute tools when requested, apply lifecycle hooks, handle HITL pauses, and transition control between agents during handoffs. The loop repeats until the model stops calling tools, a HITL pause is triggered, or maxSteps is exceeded.
import "dotenv/config";import { Agent, run, defineTool, OpenAIProvider } from "@mehularora/stark-kit";import z from "zod";
// 1. Create a provider — reads OPENAI_API_KEY from environmentconst provider = new OpenAIProvider({ model: "gpt-4o" });
// 2. Define a typed toolconst lookupTool = defineTool({ name: "lookupUser", description: "Look up a user by email.", parameters: z.object({ email: z.string().email() }), execute: async ({ email }) => { return { id: 1, name: "Alice", email }; },});
// 3. Configure the agentconst agent = new Agent({ name: "SupportBot", provider, instructions: "You are a support assistant. Look up user data when needed.", tools: [lookupTool], maxSteps: 10,});
// 4. Run the loopconst result = await run({ agent, messages: "Who is user@example.com?" });
if (result.status === "complete") { console.log(result.content);}