Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ dist-test/

# Test output
test-results/

# VitePress dev cache (build output goes to .vitepress/dist, covered by dist/)
docs/.vitepress/cache/
107 changes: 107 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { defineConfig } from 'vitepress'

export default defineConfig({
title: 'GemStack',
description: 'Framework-agnostic tools for building AI applications in Node.',
lang: 'en-US',
ignoreDeadLinks: 'localhostLinks',

head: [
['link', { rel: 'icon', type: 'image/svg+xml', href: '/logo.svg' }],
['meta', { name: 'theme-color', content: '#10b981' }],
],

themeConfig: {
logo: '/logo.svg',
siteTitle: 'GemStack',

nav: [
{ text: 'Guide', link: '/guide/', activeMatch: '/guide/' },
{ text: 'Packages', link: '/packages/', activeMatch: '/packages/' },
{
text: 'Reference',
items: [
{ text: 'Changelog', link: 'https://github.com/gemstack-land/gemstack/releases' },
{ text: 'npm — @gemstack', link: 'https://www.npmjs.com/org/gemstack' },
],
},
],

sidebar: {
'/guide/': [
{
text: 'Introduction',
items: [
{ text: 'What is GemStack?', link: '/guide/' },
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Your First Agent', link: '/guide/first-agent' },
],
},
{
text: 'Packages',
items: [
{ text: 'Overview', link: '/packages/' },
{ text: 'ai-sdk', link: '/packages/ai-sdk/' },
{ text: 'ai-skills', link: '/packages/ai-skills' },
{ text: 'ai-autopilot', link: '/packages/ai-autopilot' },
{ text: 'ai-mcp', link: '/packages/ai-mcp' },
{ text: 'mcp', link: '/packages/mcp' },
],
},
],

'/packages/': [
{
text: 'Overview',
items: [{ text: 'The GemStack family', link: '/packages/' }],
},
{
text: 'ai-sdk — the agent runtime',
items: [
{ text: 'Overview', link: '/packages/ai-sdk/' },
{ text: 'Agents', link: '/packages/ai-sdk/agents' },
{ text: 'Tools', link: '/packages/ai-sdk/tools' },
{ text: 'Streaming', link: '/packages/ai-sdk/streaming' },
{ text: 'Structured Output', link: '/packages/ai-sdk/structured-output' },
{ text: 'Memory & Persistence', link: '/packages/ai-sdk/memory' },
{ text: 'Vector Stores & RAG', link: '/packages/ai-sdk/rag' },
{ text: 'Providers', link: '/packages/ai-sdk/providers' },
{ text: 'Testing & Evals', link: '/packages/ai-sdk/testing' },
],
},
{
text: 'The family',
items: [
{ text: 'ai-skills', link: '/packages/ai-skills' },
{ text: 'ai-autopilot', link: '/packages/ai-autopilot' },
{ text: 'ai-mcp', link: '/packages/ai-mcp' },
{ text: 'mcp', link: '/packages/mcp' },
],
},
],
},

search: {
provider: 'local',
},

socialLinks: [
{ icon: 'github', link: 'https://github.com/gemstack-land/gemstack' },
],

footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2026-present GemStack contributors',
},

editLink: {
pattern: 'https://github.com/gemstack-land/gemstack/edit/main/docs/:path',
text: 'Edit this page on GitHub',
},
},

markdown: {
theme: { light: 'github-light', dark: 'github-dark' },
lineNumbers: true,
},
})
25 changes: 25 additions & 0 deletions docs/.vitepress/theme/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
:root {
/* GemStack brand — emerald gem */
--vp-c-brand-1: #0d9488;
--vp-c-brand-2: #10b981;
--vp-c-brand-3: #14b8a6;
--vp-c-brand-soft: rgba(16, 185, 129, 0.14);
}

.dark {
--vp-c-brand-1: #2dd4bf;
--vp-c-brand-2: #14b8a6;
--vp-c-brand-3: #5eead4;
--vp-c-brand-soft: rgba(16, 185, 129, 0.16);
}

.VPHero .name .clip {
background: linear-gradient(120deg, #10b981 10%, #06b6d4 90%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}

.vp-code-group .tabs {
border-bottom-color: var(--vp-c-brand-soft);
}
9 changes: 9 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import DefaultTheme from 'vitepress/theme'
import './custom.css'
import type { Theme } from 'vitepress'

const theme: Theme = {
extends: DefaultTheme,
}

export default theme
87 changes: 87 additions & 0 deletions docs/guide/first-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Your First Agent

This walkthrough assumes you have [installed](/guide/installation) `@gemstack/ai-sdk` and registered a provider.

## A one-line prompt

```ts
import { agent } from '@gemstack/ai-sdk'

const response = await agent('You are a helpful assistant.')
.prompt('Summarize the transformer architecture in one sentence.')

console.log(response.text)
```

`agent(instructions)` returns an agent; `.prompt(input)` runs it and resolves to an `AgentResponse` with `.text`, `.steps`, `.usage`, and more.

## Three agent shapes

Pick whichever reads best at the call site:

```ts
import { agent, AI, Agent, stepCountIs } from '@gemstack/ai-sdk'

// Inline, one-off
const r1 = await agent('You summarize text.').prompt('Summarize this...')

// Facade with the default model
const r2 = await AI.prompt('Hello world')

// Configured anonymous agent - tools + options together
const r3 = await agent({
instructions: 'You help find users.',
model: 'anthropic/claude-sonnet-4-6',
tools: [searchTool],
}).prompt('Find all admins')

// Reusable typed class
class SearchAgent extends Agent {
instructions() { return 'You help find users.' }
model() { return 'anthropic/claude-sonnet-4-6' }
tools() { return [searchTool] }
stopWhen() { return stepCountIs(5) }
}
const r4 = await new SearchAgent().prompt('Find all admins')
```

A class is the right shape once an agent has tools, a fixed model, middleware, or memory - everything lives in one place and the type is reusable.

## Giving the agent a tool

Tools let the agent call your code. Define one with `toolDefinition(...)`, declare its input with Zod, and attach a `.server()` handler:

```ts
import { agent, toolDefinition } from '@gemstack/ai-sdk'
import { z } from 'zod'

const searchTool = toolDefinition({
name: 'search_users',
description: 'Search users by name or email',
inputSchema: z.object({
query: z.string().describe('Name or email substring'),
limit: z.number().int().min(1).max(50).default(10),
}),
}).server(async ({ query, limit }) => {
return await db.users.search(query, limit)
})

const response = await agent({
instructions: 'You help find users.',
tools: [searchTool],
}).prompt('Find all admins')
```

The agent decides when to call the tool, validates the arguments against `inputSchema` before your handler runs, and feeds the result back to the model. Inspect `response.steps` for the full trace.

## Where to go next

| You want to… | Read |
|---|---|
| Understand the agent loop, sub-agents, multi-step runs | [Agents](/packages/ai-sdk/agents) |
| Go deeper on tools, scoped tools, client tools, approval gates | [Tools](/packages/ai-sdk/tools) |
| Stream tokens and tool progress to a UI | [Streaming](/packages/ai-sdk/streaming) |
| Get typed objects back instead of text | [Structured Output](/packages/ai-sdk/structured-output) |
| Persist conversations and give the agent memory | [Memory & Persistence](/packages/ai-sdk/memory) |
| Retrieval-augmented generation over your documents | [Vector Stores & RAG](/packages/ai-sdk/rag) |
| Test agents without hitting a real model | [Testing & Evals](/packages/ai-sdk/testing) |
46 changes: 46 additions & 0 deletions docs/guide/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# What is GemStack?

GemStack is a collection of high-quality, framework-agnostic tools for building AI applications in Node. Each tool is a standalone, well-tested package that works in any Node app and composes cleanly with the others.

It is shared, community-governed infrastructure built in the open with the [Vike](https://vike.dev) team. Packages join GemStack by *graduating* one at a time - when they prove framework-agnostic value - not by bulk-moving a framework's package set in.

## The family

All packages publish under the **`@gemstack/`** scope.

| Package | What it is |
|---|---|
| [`ai-sdk`](/packages/ai-sdk/) | The agent runtime: providers, the agent loop, tools, streaming, middleware, structured output, memory, and evals. The engine the rest of the family builds on. |
| [`ai-skills`](/packages/ai-skills) | Portable capability bundles: load `SKILL.md` skills (instructions + tools + resources) and compose them onto an agent on demand. |
| [`ai-autopilot`](/packages/ai-autopilot) | Orchestration: a Supervisor that plans, dispatches subagents (bounded concurrency + budget guardrails), and synthesizes the result. |
| [`ai-mcp`](/packages/ai-mcp) | The agent/MCP bridge: consume a remote MCP server's tools as agent tools, and expose an agent as an MCP server. |
| [`mcp`](/packages/mcp) | A standalone framework for *authoring* MCP servers: tools, resources, prompts, decorators, OAuth 2.1, a framework-neutral HTTP handler, and a test client. Agent-agnostic. |

## How they fit together

```
ai-sdk agent runtime (the "verbs")
ai-skills capability bundles (the composable "nouns") -> ai-sdk
ai-autopilot orchestration / autonomy (the "director") -> ai-sdk (+ skills)
ai-mcp agent <-> MCP bridge (the "adapter") -> ai-sdk
-----------------------------------------------------------------------------------
mcp standalone MCP server framework agent-agnostic, not ai-*
```

`ai-sdk` is the foundation: it owns the single-agent loop, tools, and streaming. `ai-skills` and `ai-autopilot` build on top of it. `ai-mcp` bridges an agent to the Model Context Protocol. `mcp` stands apart - it is for *authoring* MCP servers and knows nothing about agents.

## Design principles

- **Framework-agnostic core.** Every package runs in any `fetch`-capable JS runtime - Node, the browser, Electron, React Native. The agent runtime has zero static `node:*` imports in its main entry, and its only required runtime dependency is `zod`.
- **Neutral contracts, not bundled infrastructure.** Persistence (conversation history, user memory, budgets, suspended runs, generated-file storage) is defined as interfaces you implement against your own database, cache, or object store. In-memory defaults ship for getting started.
- **One way to do a thing.** A single `tool()` shape, a single `Agent` base, a single provider config object - shared across the whole family.
- **Graduated, not dumped.** GemStack grows by promoting packages that earn framework-agnostic standing, with the API settling toward `1.0` in the open.

## Where these came from

The AI engine was spun out of Rudder's `@rudderjs/ai` and re-versioned under the GemStack umbrella. The Rudder package now re-exports this engine and adds the Rudder-specific bindings on top (an ORM-backed store set, a `/server` provider, a `make:agent` scaffolder). Those bindings are documented in Rudder's own docs; everything here is the framework-agnostic engine.

## Next

- [Installation](/guide/installation) - install the runtime and a provider SDK.
- [Your First Agent](/guide/first-agent) - define and run an agent in a few lines.
62 changes: 62 additions & 0 deletions docs/guide/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Installation

The agent runtime lives in [`@gemstack/ai-sdk`](/packages/ai-sdk/). Install it plus the provider SDK(s) you actually use - provider SDKs are optional peers, and each adapter lazy-loads its SDK on first call.

```bash
pnpm add @gemstack/ai-sdk

pnpm add @anthropic-ai/sdk # Anthropic (Claude)
pnpm add openai # OpenAI (also OpenRouter / Mistral / DeepSeek / Groq / xAI / Ollama)
pnpm add @google/genai # Google (Gemini)
pnpm add cohere-ai # Cohere (reranking + embeddings)
pnpm add @aws-sdk/client-bedrock-runtime # AWS Bedrock
# ElevenLabs, Voyage, Jina - no extra package needed (direct HTTP)
```

The core stands alone: `@gemstack/ai-sdk`'s only required runtime dependency is `zod`.

## Configure a provider

Register the providers you want and set a default model. Each provider's `name` (e.g. `anthropic`) becomes the registry key, and model strings are always `provider/model`.

```ts
import { AiRegistry, AnthropicProvider, OpenAIProvider, OllamaProvider } from '@gemstack/ai-sdk'

AiRegistry.register(new AnthropicProvider({ apiKey: process.env.ANTHROPIC_API_KEY! }))
AiRegistry.register(new OpenAIProvider({ apiKey: process.env.OPENAI_API_KEY! }))
AiRegistry.register(new OllamaProvider({ baseUrl: 'http://localhost:11434' }))

AiRegistry.setDefault('anthropic/claude-sonnet-4-6')
```

Run this once at startup (an `ai.ts` module you import early, for example). Models are always `provider/model` - a bare model name throws. See [Providers](/packages/ai-sdk/providers) for every adapter and its config.

> Behind an LLM gateway or proxy? If it is OpenAI- or Anthropic-compatible, set `baseUrl` on the matching provider. If it speaks its own wire format, subclass the gateway adapter from the `@gemstack/ai-sdk/gateway` subpath.

## Runtime compatibility

`@gemstack/ai-sdk` works in any `fetch`-capable JS runtime - Node, browser, Electron (main and renderer), React Native. The main entry has zero static `node:*` imports.

| Import | Runtimes | What's inside |
|---|---|---|
| `@gemstack/ai-sdk` | Node, browser, RN, Electron | Agents, tools, streaming, providers, attachments, structured output |
| `@gemstack/ai-sdk/node` | Node only | `documentFromPath()`, `imageFromPath()`, `transcribeFromPath()` filesystem helpers |
| `@gemstack/ai-sdk/react` | Browser | React bindings (`useAgentRun`) |
| `@gemstack/ai-sdk/eval` | Node | Eval framework (`evalSuite`, metrics, reporters) |
| `@gemstack/ai-sdk/computer-use` | Node | Computer-use tool + executor |

In a client runtime, use byte-based factories instead of filesystem paths:

```ts
import { Image } from '@gemstack/ai-sdk'

const img = Image.fromBase64(cameraBase64, 'image/jpeg')
const url = await Image.fromUrl('https://example.com/photo.jpg')
```

> Calling LLM providers directly from a browser or React Native client leaks your API key - use a server-side proxy in production. The main client-side use case is BYOK desktop apps.

## Next

- [Your First Agent](/guide/first-agent) - define and run an agent.
- [Packages overview](/packages/) - the whole GemStack family.
41 changes: 41 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
layout: home

hero:
name: "GemStack"
text: "Framework-agnostic tools for building AI applications in Node."
tagline: "An agent runtime, portable skills, multi-agent orchestration, and an MCP toolkit - standalone packages that work in any Node app and compose cleanly with each other."
image:
src: /logo.svg
alt: GemStack
actions:
- theme: brand
text: Get Started
link: /guide/installation
- theme: alt
text: What is GemStack?
link: /guide/
- theme: alt
text: View on GitHub
link: https://github.com/gemstack-land/gemstack

features:
- icon: 🧠
title: Provider-agnostic agent runtime
details: "Define an agent once; swap Anthropic, OpenAI, Google, Ollama, Groq, DeepSeek, xAI, Mistral, and more by changing one config string. Tool calling, streaming, middleware, structured output, and memory included."
- icon: 🧩
title: Portable capability bundles
details: "Ship a skill as a folder - instructions + tools + resources - and compose it onto an agent on demand. The same SKILL.md shape Claude uses."
- icon: 🎛️
title: Multi-agent orchestration
details: "A Supervisor that plans, dispatches subagents under bounded concurrency and token budgets, and synthesizes the result. Pluggable plan / workers / synthesize stages."
- icon: 🔌
title: Model Context Protocol, both directions
details: "Bridge agents to MCP - consume a remote server's tools or expose an agent as a server - and author standalone MCP servers with tools, resources, prompts, and OAuth 2.1."
- icon: 🪶
title: Zero framework lock-in
details: "Each package works in any fetch-capable JS runtime. The agent runtime's only required dependency is zod; persistence is via neutral contracts you implement against your own infrastructure."
- icon: 💎
title: Graduated, not dumped
details: "Packages join GemStack one at a time, when they prove framework-agnostic value - built in the open with the Vike team."
---
Loading
Loading