Important
Project status (October 2026): open source, community-driven. plugged.in, the hosted service, is moving to a new, separately developed platform. After that move, this repository will no longer run plugged.in. The code stays open source under its current license, and the community is welcome to carry it on: issues, pull requests, forks and new maintainers are welcome, and self-hosting remains supported. The cutover date will be announced here. At the cutover, the current service moves to v1.plugged.in and keeps running there until December 31, 2026. What this means
This client talks to the plugged.in API. Before the cutover we will release a version that points it to v1.plugged.in. After December 31, 2026, point it at your own pluggedin-app instance.
Official Go SDK for the Plugged.in Library API. Full support for document management, RAG queries, and file uploads.
go get github.com/veriteknik/pluggedinkit-gopackage main
import (
"context"
"fmt"
"log"
pluggedin "github.com/veriteknik/pluggedinkit-go"
)
func main() {
// Initialize client
client := pluggedin.NewClient("your-api-key")
// For local development:
// client := pluggedin.NewClientWithOptions("your-api-key", "http://localhost:12005", nil)
ctx := context.Background()
// List documents
docs, err := client.Documents.List(ctx, &pluggedin.DocumentFilters{
Source: pluggedin.SourceAll,
Limit: 10,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d documents\n", docs.Total)
// Search documents
results, err := client.Documents.Search(ctx, "machine learning", nil, 10, 0)
if err != nil {
log.Fatal(err)
}
for _, result := range results.Results {
fmt.Printf("%s - Relevance: %.2f\n", result.Title, result.RelevanceScore)
}
// Query RAG
answer, err := client.RAG.AskQuestion(ctx, "What are the main features?")
if err != nil {
log.Fatal(err)
}
fmt.Println(answer)
}- 📄 Document Management - Full CRUD operations for documents
- 🔍 Semantic Search - AI-powered document search
- 🤖 RAG Integration - Natural language queries to your knowledge base
- 📋 Clipboard/Memory - Persistent key-value storage for MCP tools and AI agents
- 📤 File Uploads - Upload files with progress tracking
- 🔄 Version Control - Document versioning and history
- ⚡ Type Safety - Full Go type definitions
- 🔐 Authentication - Secure API key authentication
- 🔁 Context Support - Context-aware operations for cancellation
- 📊 Rate Limiting - Built-in rate limit handling
Get your API key from your Plugged.in profile settings:
import (
"os"
pluggedin "github.com/veriteknik/pluggedinkit-go"
)
client := pluggedin.NewClient(os.Getenv("PLUGGEDIN_API_KEY"))filters := &pluggedin.DocumentFilters{
Source: pluggedin.SourceAIGenerated,
Tags: []string{"report", "analysis"},
Sort: pluggedin.SortDateDesc,
Limit: 20,
Offset: 0,
}
response, err := client.Documents.List(ctx, filters)
if err != nil {
log.Fatal(err)
}
for _, doc := range response.Documents {
fmt.Printf("%s (%d bytes)\n", doc.Title, doc.FileSize)
}// Get document metadata
doc, err := client.Documents.Get(ctx, "document-id", false, false)
if err != nil {
log.Fatal(err)
}
// Get document with content
docWithContent, err := client.Documents.Get(ctx, "document-id", true, true)
if err != nil {
log.Fatal(err)
}
fmt.Println(docWithContent.Content)filters := map[string]interface{}{
"modelProvider": "anthropic",
"dateFrom": "2024-01-01T00:00:00Z",
"tags": "finance,q4",
}
results, err := client.Documents.Search(ctx, "quarterly report", filters, 10, 0)
if err != nil {
log.Fatal(err)
}
for _, result := range results.Results {
fmt.Printf("%s\n", result.Title)
fmt.Printf(" Relevance: %.2f\n", result.RelevanceScore)
fmt.Printf(" Snippet: %s\n", result.Snippet)
}request := &pluggedin.UpdateDocumentRequest{
Operation: pluggedin.OpAppend,
Content: "\n\n## New Section\n\nAdditional content here.",
Metadata: map[string]interface{}{
"changeSummary": "Added implementation details",
"model": map[string]string{
"name": "claude-3-opus",
"provider": "anthropic",
"version": "20240229",
},
},
}
response, err := client.Documents.Update(ctx, "document-id", request)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Updated to version %d\n", response.Version)request := &pluggedin.CreateDocumentRequest{
Title: "API Integration Guide",
Content: "# API Integration Guide\n\n## Introduction\n\n...",
Metadata: map[string]interface{}{
"format": "md",
"category": "documentation",
"tags": []string{"api", "guide"},
"model": map[string]string{
"name": "gpt-4",
"provider": "openai",
"version": "0613",
},
"prompt": "Create an API integration guide",
"visibility": "workspace",
},
}
doc, err := client.Documents.Create(ctx, request)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created document: %s\n", doc.ID)// Simple query
answer, err := client.RAG.AskQuestion(ctx, "What are the deployment procedures?")
if err != nil {
log.Fatal(err)
}
fmt.Println(answer)
// Query with sources
result, err := client.RAG.QueryWithSources(
ctx,
"Explain the authentication flow",
"project-uuid", // Optional
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Answer: %s\n", result.Answer)
fmt.Println("Sources:")
for _, source := range result.Sources {
fmt.Printf("- %s (relevance: %.0f%%)\n", source.Name, source.Relevance)
}documents, err := client.RAG.FindRelevantDocuments(
ctx,
"user authentication",
"project-uuid",
5, // Top 5 documents
)
if err != nil {
log.Fatal(err)
}
for _, doc := range documents {
fmt.Printf("- %s\n", doc.Name)
if doc.Model != nil {
fmt.Printf(" By: %s/%s\n", doc.Model.Provider, doc.Model.Name)
}
}metadata := &pluggedin.UploadMetadata{
Name: "Q4 Report.pdf",
Description: "Quarterly financial report",
Tags: []string{"finance", "q4", "2024"},
Purpose: "Financial documentation",
RelatedTo: "PROJECT-123",
}
// Progress callback
onProgress := func(percent int) {
fmt.Printf("Upload progress: %d%%\n", percent)
}
response, err := client.Uploads.UploadFile(
ctx,
"./report.pdf",
metadata,
onProgress,
)
if err != nil {
log.Fatal(err)
}
if response.Success {
fmt.Printf("Uploaded: %s\n", response.DocumentID)
// Track processing
if response.UploadID != "" {
onUpdate := func(status *pluggedin.UploadStatus) {
fmt.Printf("Status: %s - %s\n", status.Status, status.Message)
}
client.Uploads.TrackUpload(ctx, response.UploadID, onUpdate)
}
}file, err := os.Open("document.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
fileInfo, _ := file.Stat()
response, err := client.Uploads.UploadReader(
ctx,
file,
fileInfo.Size(),
metadata,
nil,
)files := []pluggedin.FileUpload{
{
Path: "doc1.pdf",
Metadata: &pluggedin.UploadMetadata{Name: "doc1.pdf", Tags: []string{"batch"}},
},
{
Path: "doc2.txt",
Metadata: &pluggedin.UploadMetadata{Name: "doc2.txt", Tags: []string{"batch"}},
},
}
onProgress := func(current, total int) {
fmt.Printf("Uploaded %d/%d files\n", current, total)
}
results, err := client.Uploads.UploadBatch(ctx, files, onProgress)
if err != nil {
log.Fatal(err)
}
for i, result := range results {
if result.Success {
fmt.Printf("✓ %s uploaded\n", files[i].Metadata.Name)
} else {
fmt.Printf("✗ %s failed: %s\n", files[i].Metadata.Name, result.Error)
}
}The clipboard provides persistent key-value storage for MCP tools and AI agents.
entry, err := client.Clipboard.Set(ctx, &pluggedin.ClipboardSetRequest{
Name: "user_preferences",
Value: `{"theme": "dark", "lang": "en"}`,
ContentType: "application/json",
Encoding: "utf-8",
Visibility: "private",
TTLSeconds: 86400, // 24 hours
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created entry: %s\n", entry.UUID)
fmt.Printf("Source: %s\n", *entry.Source) // "sdk" - automatically set// By name
entry, err := client.Clipboard.GetByName(ctx, "user_preferences")
if err != nil {
log.Fatal(err)
}
fmt.Println(entry.Value)
// By index (stack access)
latest, err := client.Clipboard.GetByIndex(ctx, 0)entry, err := client.Clipboard.Push(ctx, &pluggedin.ClipboardPushRequest{
Value: "Processing step 1 result",
ContentType: "text/plain",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Pushed to index: %d\n", *entry.Idx)entry, err := client.Clipboard.Pop(ctx)
if err != nil {
log.Fatal(err)
}
if entry != nil {
fmt.Printf("Popped value: %s\n", entry.Value)
}// List entries with pagination (limit: 100, offset: 0)
response, err := client.Clipboard.List(ctx, 100, 0)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Total: %d, Returned: %d\n", response.Total, len(response.Entries))
for _, entry := range response.Entries {
var label string
if entry.Name != nil {
label = *entry.Name
} else if entry.Idx != nil {
label = fmt.Sprintf("idx:%d", *entry.Idx)
}
source := pluggedin.DefaultClipboardSource
if entry.Source != nil {
source = *entry.Source
}
fmt.Printf("%s - source: %s\n", label, source)
}
// Delete by name
name := "old_entry"
deleted, err := client.Clipboard.Delete(ctx, &pluggedin.ClipboardDeleteRequest{
Name: &name,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Deleted: %v\n", deleted)
// Clear all entries (bulk delete)
result, err := client.Clipboard.ClearAll(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Cleared %d entries\n", result.Deleted)type ClipboardEntry struct {
UUID string `json:"uuid"`
Name *string `json:"name"` // Semantic key
Idx *int `json:"idx"` // Stack index
Value string `json:"value"`
ContentType string `json:"contentType"`
Encoding string `json:"encoding"` // utf-8, base64, hex
SizeBytes int `json:"sizeBytes"`
Visibility string `json:"visibility"` // private, workspace, public
CreatedByTool *string `json:"createdByTool"`
CreatedByModel *string `json:"createdByModel"`
Source *ClipboardSource `json:"source,omitempty"` // Auto-set: ui, sdk, mcp
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ExpiresAt *time.Time `json:"expiresAt"`
}Note: The
Sourcefield is automatically set toClipboardSourceSDKwhen using this SDK. It indicates how the entry was created (UI, SDK, or MCP proxy).
doc, err := client.Documents.Get(ctx, "invalid-id", false, false)
if err != nil {
switch e := err.(type) {
case *pluggedin.AuthenticationError:
fmt.Println("Invalid API key")
case *pluggedin.RateLimitError:
fmt.Printf("Rate limited. Retry after %d seconds\n", e.RetryAfter)
case *pluggedin.NotFoundError:
fmt.Printf("Document not found: %s\n", e.ID)
case *pluggedin.ValidationError:
fmt.Printf("Validation error: %s\n", e.Message)
case *pluggedin.APIError:
fmt.Printf("API error (%d): %s\n", e.StatusCode, e.Message)
default:
fmt.Printf("Error: %v\n", err)
}
}import (
"net/http"
"time"
)
// Custom HTTP client
httpClient := &http.Client{
Timeout: 120 * time.Second,
// Add custom transport, etc.
}
client := pluggedin.NewClientWithOptions(
"your-api-key",
"https://plugged.in",
httpClient,
)
// Update API key at runtime
client.SetAPIKey("new-api-key")
// Change base URL
client.SetBaseURL("http://localhost:12005")Store your API key securely:
export PLUGGEDIN_API_KEY=your-api-key
export PLUGGEDIN_BASE_URL=https://plugged.inimport (
"os"
pluggedin "github.com/veriteknik/pluggedinkit-go"
)
client := pluggedin.NewClientWithOptions(
os.Getenv("PLUGGEDIN_API_KEY"),
os.Getenv("PLUGGEDIN_BASE_URL"),
nil,
)The SDK handles rate limiting automatically:
- API Endpoints: 60 requests per minute
- Document Search: 10 requests per hour for AI document creation
- RAG Queries: Subject to plan limits
See the examples directory for complete working examples:
Contributions are welcome! Please see our Contributing Guide for details.
MIT - see LICENSE for details.
- Documentation: https://docs.plugged.in
- Issues: GitHub Issues
- Discord: Join our community
See CHANGELOG.md for release history.