Quickstart
Get up and running with Tavora in five minutes. This guide walks you through initializing the SDK, creating an index, uploading a document, searching it, and running an agent. Code samples are shown in Go and TypeScript; the REST equivalent is one tab over.
Prerequisites
Section titled “Prerequisites”- A Tavora app with an API key (mint one in the admin web UI — covered in the platform’s internal docs).
- Optional: the
tavoraCLI installed, withtavora initrun to save your credentials. - Go 1.25+ or Node ≥ 20.
Install the SDK
Section titled “Install the SDK”go get github.com/tavora-ai/tavora-sdk-gonpm install @tavora/sdk# or: pnpm add @tavora/sdkInitialize the client
Section titled “Initialize the client”package main
import ( "context" "fmt" "log"
tavora "github.com/tavora-ai/tavora-sdk-go")
func main() { client := tavora.NewClient( "https://api.tavora.ai", // or http://localhost:8080 in dev "tvr_your-api-key", ) ctx := context.Background()
app, err := client.GetApp(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Connected to app: %s\n", app.Name)}import { Client } from '@tavora/sdk';
const client = new Client('https://api.tavora.ai', 'tvr_your-api-key');
const app = await client.getApp();console.log('Connected to', app.name);Every SDK method is a direct call on the client — no nested service namespaces. The Go variant is context-aware on every method so callers can cancel, deadline, or trace any request.
Create an index and upload a document
Section titled “Create an index and upload a document”An index is an app-scoped RAG container — what other ecosystems call a “vector store.” Documents inside an index get chunked, embedded, and become searchable by meaning. (Customer file blobs and structured records belong in your backend — Tavora is the agent layer, not a storage layer.)
index, err := client.CreateIndex(ctx, tavora.CreateIndexInput{ Name: "Support docs", Description: "FAQ and product manuals",})if err != nil { log.Fatal(err)}
doc, err := client.UploadDocument(ctx, tavora.UploadDocumentInput{ IndexID: index.ID, FilePath: "./faq.md",})if err != nil { log.Fatal(err)}fmt.Printf("Uploaded %s (status: %s)\n", doc.ID, doc.Status)import { openAsBlob } from 'node:fs';
const index = await client.createIndex({ name: 'Support docs', description: 'FAQ and product manuals',});
const file = await openAsBlob('./faq.md');const doc = await client.uploadDocument({ indexId: index.id, file, filename: 'faq.md',});console.log(`Uploaded ${doc.id} (status: ${doc.status})`);curl -X POST https://api.tavora.ai/api/sdk/indexes \ -H "X-API-Key: tvr_..." \ -H "Content-Type: application/json" \ -d '{"name":"Support docs","description":"FAQ and product manuals"}'
curl -X POST https://api.tavora.ai/api/sdk/indexes/INDEX_ID/documents \ -H "X-API-Key: tvr_..." \ -F "file=@./faq.md"Embedding runs in the background. Poll getDocument until
status === "ready" before searching — or just upload and search a
moment later in dev.
Search semantically
Section titled “Search semantically”results, err := client.Search(ctx, tavora.SearchInput{ Query: "what document formats are supported?", IndexID: index.ID, Limit: 5,})if err != nil { log.Fatal(err)}for _, r := range results { fmt.Printf("%.2f — %s\n", r.Score, r.Snippet)}const results = await client.search({ query: 'what document formats are supported?', indexId: index.id, limit: 5,});for (const r of results) { console.log(`${r.score.toFixed(2)} — ${r.snippet}`);}curl -X POST https://api.tavora.ai/api/sdk/search \ -H "X-API-Key: tvr_..." \ -H "Content-Type: application/json" \ -d '{"query":"what document formats are supported?","index_id":"INDEX_ID","limit":5}'Default search returns one row per matched chunk. Use
searchDocuments when the agent’s question is “what artifacts are
about X” rather than “what passages are about X” — same call, server-
deduped to one row per document with the best chunk inlined.
Run an agent
Section titled “Run an agent”Agent sessions are the canonical path for anything that needs
reasoning, tool use, or multi-step work. One session = one ongoing
conversation; each turn runs the LLM, which writes JS that executes in
the Goja sandbox where it can search, fetch, ai, remember,
require('<mcp-server>'), and more.
session, err := client.CreateAgentSession(ctx, tavora.CreateAgentSessionInput{ Title: "First agent chat", SystemPrompt: "You are a helpful assistant. Use think for " + "computation or multi-step work.",})if err != nil { log.Fatal(err)}
err = client.RunAgent(ctx, session.ID, "Summarise my FAQ in 3 bullets.", func(evt tavora.AgentEvent) { switch evt.Type { case tavora.EventTypeExecuteJS: fmt.Printf("[js] %s\n", evt.Content) case tavora.EventTypeResponse: fmt.Printf("\n%s\n", evt.Content) case tavora.EventTypeDone: if evt.Summary != nil && evt.Summary.Tokens != nil { fmt.Printf("[%d steps, %d+%d tokens]\n", evt.Summary.Steps, evt.Summary.Tokens.Prompt, evt.Summary.Tokens.Completion) } } })if err != nil { log.Fatal(err)}const session = await client.createAgentSession({ title: 'First agent chat', system_prompt: 'You are a helpful assistant. Use think for computation or multi-step work.',});
for await (const evt of client.runAgent( session.id, 'Summarise my FAQ in 3 bullets.',)) { if (evt.type === 'execute_js') console.log(`[js] ${evt.content}`); else if (evt.type === 'response') console.log(`\n${evt.content}\n`); else if (evt.type === 'done' && evt.summary?.tokens) { const { prompt, completion } = evt.summary.tokens; console.log(`[${evt.summary.steps} steps, ${prompt}+${completion} tokens]`); }}runAgent streams SSE events: execute_js, execute_js_result,
tool_call, tool_result, sandbox_event, response, input_request,
done. Reuse the same session.id across turns to keep conversation
history.
Author the agent code-first
Section titled “Author the agent code-first”The session above ran an ad-hoc agent (inline Title +
SystemPrompt). For production, author the agent under a local
tavora/ folder and ship with tavora deploy; your runtime then
just passes AgentID to CreateAgentSession. See the tavora
CLI for the init / dev / deploy loop.
Next steps
Section titled “Next steps”- Go & TS SDKs overview — full method catalogue.
- MCP servers — declare your domain API in
agent.jsonc → mcpso the agent can call your tools. - Browser-based chat — let a browser call the SDK directly via session-minted keys.
- Skills —
require()-able JS modules and prompt skills authored as files under your agent’s folder. - REST API — when the SDK isn’t an option.