The official Klarora SDK for Go. Idiomatic Go client with context support and strongly-typed interfaces. It covers tasks, goals, team, documents, whiteboards, and forms, and authenticates with an API key.
go get github.com/moemollaei-org/kairos-connect-sdks/goThe module path ends in /go, but the package name is kairos. Import it with an explicit alias, as shown below.
package main
import (
"context"
"fmt"
"log"
kairos "github.com/moemollaei-org/kairos-connect-sdks/go"
)
func main() {
// Initialize the client
client, err := kairos.New("kairos_sk_...")
if err != nil {
log.Fatal(err)
}
// Create a context
ctx := context.Background()
// List tasks
tasks, pagination, err := client.Tasks.List(ctx, &kairos.ListTasksOptions{
ListOptions: kairos.ListOptions{Limit: 10},
Status: "in_progress",
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d tasks\n", pagination.Total)
for _, task := range tasks {
fmt.Printf("- %s (%s)\n", task.Title, task.Status)
}
}The SDK authenticates with an API key (kairos_sk_...). kairos.New(apiKey, opts...) returns (*Client, error). When apiKey is an empty string, it reads the KAIROS_API_KEY environment variable, and it returns an error if neither is set. Use client.Me(ctx) to validate the key and see its team, scopes, and rate limits.
// Reads KAIROS_API_KEY from the environment
client, err := kairos.New("")
if err != nil {
log.Fatal(err)
}
me, err := client.Me(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(me.TeamID, me.Scopes)
fmt.Println(me.RateLimitPerMinute, me.RateLimitPerHour)package main
import (
"log"
"net/http"
"time"
kairos "github.com/moemollaei-org/kairos-connect-sdks/go"
)
func main() {
// Basic configuration
client, err := kairos.New("kairos_sk_...")
if err != nil {
log.Fatal(err)
}
// With options
client, err = kairos.New(
"kairos_sk_...",
kairos.WithBaseURL("https://gateway.thekairos.app/v1"),
kairos.WithHTTPClient(&http.Client{}),
kairos.WithTimeout(60*time.Second),
kairos.WithMaxRetries(3),
)
if err != nil {
log.Fatal(err)
}
_ = client
}The defaults are a 30 second timeout and 3 retries. Rate-limited (HTTP 429) responses are retried after the Retry-After delay. Options are applied in order, so pass WithHTTPClient before WithTimeout if you use both.
All methods accept a context for cancellation and timeout control:
import (
"context"
"errors"
"log"
"time"
)
// With timeout
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
task, err := client.Tasks.Get(ctx, "task-id")
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Println("Request timed out")
}
return
}
log.Println(task.Title)
// With cancellation
ctx, cancel = context.WithCancel(context.Background())
go func() {
// Cancel after some condition
time.Sleep(5 * time.Second)
cancel()
}()
tasks, _, err := client.Tasks.List(ctx, nil)Optional input fields are pointers. The examples use a small generic helper: func ptr[T any](v T) *T { return &v }.
ctx := context.Background()
// List tasks with filters
tasks, pagination, err := client.Tasks.List(ctx, &kairos.ListTasksOptions{
ListOptions: kairos.ListOptions{Limit: 50, Offset: 0},
Status: "in_progress",
Priority: "high",
AssignedTo: "user-id",
GoalID: "goal-id",
Search: "authentication",
})
// Get a single task
task, err := client.Tasks.Get(ctx, "task-id")
fmt.Println(task.Title, task.Status)
// Create a task
newTask, err := client.Tasks.Create(ctx, kairos.CreateTaskInput{
Title: "Implement new feature",
Description: ptr("Add user authentication"),
GoalID: ptr("goal-id"),
Priority: ptr("high"),
DueDate: ptr("2026-12-15"),
EstimatedHours: ptr(8.0),
})
// Update a task
updatedTask, err := client.Tasks.Update(ctx, "task-id", kairos.UpdateTaskInput{
Status: ptr("completed"),
Priority: ptr("low"),
})
// Delete a task
err = client.Tasks.Delete(ctx, "task-id")
// Labels
labels, err := client.Tasks.ListLabels(ctx, "task-id")
_, err = client.Tasks.AddLabel(ctx, "task-id", "label-id")
err = client.Tasks.RemoveLabel(ctx, "task-id", "label-id")
// Comments
comments, _, err := client.Tasks.ListComments(ctx, "task-id", &kairos.ListOptions{Limit: 10})
comment, err := client.Tasks.AddComment(ctx, "task-id", kairos.CreateCommentInput{
Content: "Ready for review",
})
_, err = client.Tasks.UpdateComment(ctx, comment.ID, kairos.UpdateCommentInput{
Content: "Ready for review, tests added",
})
err = client.Tasks.DeleteComment(ctx, comment.ID)ctx := context.Background()
// List goals
goals, pagination, err := client.Goals.List(ctx, &kairos.ListOptions{Limit: 20})
// Create, get, update, delete
created, err := client.Goals.Create(ctx, kairos.CreateGoalInput{
Title: "Q2 Product Launch",
DueDate: ptr("2026-06-30"),
})
goal, err := client.Goals.Get(ctx, created.ID)
_, err = client.Goals.Update(ctx, goal.ID, kairos.UpdateGoalInput{
Status: ptr("completed"),
})
err = client.Goals.Delete(ctx, goal.ID)
fmt.Printf("Goal: %s\n", goal.Title)
fmt.Printf("Progress: %.0f\n", goal.Progress)
// Tasks that belong to a goal
goalTasks, _, err := client.Goals.ListTasks(ctx, "goal-id", nil)
for _, task := range goalTasks {
fmt.Printf(" - %s\n", task.Title)
}
// Comments on a goal
goalComments, _, err := client.Goals.ListComments(ctx, "goal-id", nil)
_, err = client.Goals.AddComment(ctx, "goal-id", kairos.CreateCommentInput{
Content: "On track",
})ctx := context.Background()
// Get team info
team, err := client.Team.Get(ctx)
fmt.Printf("Team: %s\n", team.Name)
// List team members (teamID required)
members, err := client.Team.ListMembers(ctx, team.ID, nil)
for _, member := range members {
name := member.Email
if member.Name != nil {
name = *member.Name
}
fmt.Printf("%s (%s)\n", name, member.Role)
}ctx := context.Background()
// List documents
docs, pagination, err := client.Documents.List(ctx, nil)
// Get a document
doc, err := client.Documents.Get(ctx, "doc-id")
fmt.Println(doc.Title)
fmt.Println(string(doc.Content)) // Raw JSON content
// Create, update, delete
created, err := client.Documents.Create(ctx, kairos.CreateDocumentInput{
Title: "Meeting notes",
})
_, err = client.Documents.Update(ctx, created.ID, kairos.UpdateDocumentInput{
Title: ptr("Meeting notes (final)"),
})
err = client.Documents.Delete(ctx, created.ID)ctx := context.Background()
// List whiteboards
boards, pagination, err := client.Whiteboards.List(ctx, &kairos.ListOptions{Limit: 20})
// Create, get, update, delete
board, err := client.Whiteboards.Create(ctx, kairos.CreateWhiteboardInput{
Title: "Sprint planning",
IsPublic: ptr(false),
})
fetched, err := client.Whiteboards.Get(ctx, board.ID)
_, err = client.Whiteboards.Update(ctx, board.ID, kairos.UpdateWhiteboardInput{
Title: ptr("Sprint 12 planning"),
})
err = client.Whiteboards.Delete(ctx, board.ID)ctx := context.Background()
// List forms
forms, pagination, err := client.Forms.List(ctx, &kairos.ListOptions{Limit: 20})
// Create a form
form, err := client.Forms.Create(ctx, kairos.CreateFormInput{
Name: "Contact request",
Fields: []kairos.FormField{
{ID: "email", Type: "email", Label: "Email", Required: true},
{ID: "message", Type: "textarea", Label: "Message"},
},
})
// Submit a response and list submissions
_, err = client.Forms.Submit(ctx, form.ID, map[string]interface{}{
"email": "jane@example.com",
"message": "Hello",
})
submissions, _, err := client.Forms.ListSubmissions(ctx, form.ID, nil)
// Get, update, delete
_, err = client.Forms.Get(ctx, form.ID)
_, err = client.Forms.Update(ctx, form.ID, kairos.UpdateFormInput{
IsActive: ptr(false),
})
err = client.Forms.Delete(ctx, form.ID)API errors are returned as *kairos.KairosError, with the fields Code, Message, StatusCode, and RequestID. The helper functions IsAuthError (401), IsForbiddenError (403), IsNotFoundError (404), and IsRateLimitError (429) check the status code.
import (
"errors"
"fmt"
kairos "github.com/moemollaei-org/kairos-connect-sdks/go"
)
task, err := client.Tasks.Get(ctx, "invalid-id")
if err != nil {
var apiErr *kairos.KairosError
switch {
case kairos.IsNotFoundError(err):
fmt.Println("Task not found")
case kairos.IsRateLimitError(err):
fmt.Println("Rate limited")
case kairos.IsAuthError(err):
fmt.Println("Authentication failed")
case kairos.IsForbiddenError(err):
fmt.Println("Missing permission")
case errors.As(err, &apiErr):
fmt.Printf("API error: %s - %s (status %d, request %s)\n",
apiErr.Code, apiErr.Message, apiErr.StatusCode, apiErr.RequestID)
default:
// Network or other error
fmt.Printf("Error: %v\n", err)
}
return
}
fmt.Println(task.Title)The SDK provides strongly-typed structs for all resources. Status, priority, and type fields are plain strings, and optional values are pointers:
import kairos "github.com/moemollaei-org/kairos-connect-sdks/go"
// Task type
type Task struct {
ID string `json:"id"`
TeamID string `json:"team_id"`
GoalID *string `json:"goal_id"`
ParentTaskID *string `json:"parent_task_id"`
Title string `json:"title"`
Description *string `json:"description"`
Type string `json:"type"`
Status string `json:"status"`
Priority string `json:"priority"`
AssignedTo *string `json:"assigned_to"`
EstimatedHours *float64 `json:"estimated_hours"`
ActualHours *float64 `json:"actual_hours"`
DueDate *string `json:"due_date"`
StartDate *string `json:"start_date"`
CompletedAt *time.Time `json:"completed_at"`
OrderIndex int `json:"order_index"`
IsRecurring bool `json:"is_recurring"`
RecurrenceRule *string `json:"recurrence_rule"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Other exported types
// Goal, Comment, Document, Whiteboard, Form, FormField, FormSubmission,
// Team, TeamMember, Pagination, MeResponse, RateLimit
//
// Inputs
// CreateTaskInput, UpdateTaskInput, CreateGoalInput, UpdateGoalInput,
// CreateCommentInput, UpdateCommentInput, CreateDocumentInput, UpdateDocumentInput,
// CreateWhiteboardInput, UpdateWhiteboardInput, CreateFormInput, UpdateFormInput
//
// List options
// ListOptions, ListTasksOptions