# SDKs and Client Libraries

# SDKs and Client Libraries

Official SDKs and client libraries for integrating with the TeamDay platform.

## Overview

TeamDay provides client libraries for building applications on top of the platform. All SDKs use Firebase as the underlying transport layer with Firestore for real-time data and Firebase Auth for authentication.

| SDK | Status | Language | Use Case |
|-----|--------|----------|----------|
| **JavaScript/TypeScript SDK** | ✅ Production | TypeScript | Web apps (Nuxt/Vue) |
| **REST API** | 🚧 Planned | N/A | Server-side integrations |
| **Python SDK** | 📋 Roadmap | Python | Scripts, automation |
| **CLI Tool** | ✅ Production | TypeScript | Development workflow |

---

## JavaScript/TypeScript SDK

The primary SDK is built with Vue 3 composables and works seamlessly with Nuxt 3 applications.

### Installation

```bash
# Using bun (recommended)
bun add firebase firebase/firestore

# Using npm
npm install firebase
```

### Configuration

```typescript
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      firebase: {
        apiKey: process.env.NUXT_PUBLIC_FIREBASE_API_KEY,
        authDomain: process.env.NUXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
        projectId: process.env.NUXT_PUBLIC_FIREBASE_PROJECT_ID,
        storageBucket: process.env.NUXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
        messagingSenderId: process.env.NUXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
        appId: process.env.NUXT_PUBLIC_FIREBASE_APP_ID,
      }
    }
  }
})
```

---

## Core Composables

### Authentication - `useAuth()`

Manages user authentication and session state.

```typescript
const {
  user,           // Current user (reactive)
  loading,        // Auth state loading
  signInWithGoogle,
  signInWithGitHub,
  signOut
} = useAuth()

// Check if user is authenticated
if (user.value) {
  console.log('User ID:', user.value.uid)
  console.log('Email:', user.value.email)
}

// Sign in with Google
await signInWithGoogle()

// Sign out
await signOut()
```

**Available Methods:**
- `signInWithGoogle()` - OAuth with Google
- `signInWithGitHub()` - OAuth with GitHub
- `signInWithEmail(email, password)` - Email/password auth
- `signOut()` - Sign out current user

---

### Organizations - `useOrganizations()`

Manage organizations and team memberships.

```typescript
const {
  organizations,           // Array of user's organizations
  loading,
  error,
  fetchUserOrganizations,
  getOrganization,
  createOrganization,
  updateOrganization
} = useOrganizations()

// Fetch user's organizations
await fetchUserOrganizations()

// Get specific organization
const org = await getOrganization('org_id')

// Create new organization
const newOrg = await createOrganization('Acme Corp')

// Update organization
await updateOrganization('org_id', {
  name: 'Acme Corporation',
  logoUrl: 'https://...'
})
```

**Organization Type:**
```typescript
interface Organization {
  id: string
  name: string
  logoUrl?: string
  ownerId: string
  members: string[]
  subscription?: {
    tier: 'free' | 'pro' | 'enterprise'
    status: 'active' | 'cancelled' | 'expired'
  }
  createdAt: Date
  updatedAt: Date
}
```

---

### Spaces - `useSpaces()`

Manage workspaces where agents operate.

```typescript
const {
  spaces,              // Array of spaces (reactive, real-time)
  chats,               // Chats in current space
  loading,
  error,
  fetchSpaces,
  createSpace,
  updateSpace,
  deleteSpace,
  initializeSpace
} = useSpaces()

// Subscribe to real-time updates
fetchSpaces('org_id')

// Create a new space
const space = await createSpace(
  'org_id',
  'Marketing Workspace',
  'Space for marketing team',
  'organization',  // visibility
  'https://cover-image.jpg'
)

// Update space
await updateSpace('space_id', {
  name: 'Updated Name',
  description: 'Updated description'
})

// Initialize workspace (creates file system)
await initializeSpace('space_id', {
  type: 'empty'  // or 'git', 'readme', 'starterKit'
})

// Soft delete (can be restored)
await softDeleteSpace('space_id')

// Restore deleted space
await restoreSpace('space_id')

// Permanent delete
await deleteSpace('space_id')
```

**Space Type:**
```typescript
interface Space {
  id: string
  organizationId: string
  name: string
  description: string
  visibility: 'private' | 'organization' | 'public'
  ownerId: string
  assignedAgents?: string[]       // Agent IDs
  skillIds?: string[]             // Skill IDs
  pluginIds?: string[]            // Plugin IDs
  chatCount?: number
  fileCount?: number
  createdAt: Date
  updatedAt: Date
}
```

---

### Agents - `useCharacters()`

Manage AI agents. The composable is named `useCharacters()` for historical reasons; it manages agents.

```typescript
const {
  characters,          // Array of characters (reactive, real-time)
  loading,
  error,
  fetchCharacters,
  createCharacter,
  getCharacter,
  updateCharacter,
  deleteCharacter
} = useCharacters()

// Subscribe to real-time updates
fetchCharacters('org_id')

// Create a new agent
const agent = await createCharacter(
  'org_id',
  'Marketing Maven',
  'Marketing Assistant',
  'You are an expert marketing assistant...',
  'organization'  // visibility
)

// Get specific character
const character = await getCharacter('char_id')

// Update character
await updateCharacter('char_id', {
  name: 'Updated Name',
  systemPrompt: 'Updated prompt...',
  skillIds: ['research-assistant', 'technical-writer'],
  advanced_tools: ['mcp_google_analytics']
})

// Soft delete
await softDeleteCharacter('char_id')

// Restore
await restoreCharacter('char_id')

// Archive (soft delete alternative)
await deleteCharacter('char_id')
```

**Character Type:**
```typescript
interface Character {
  id: string
  name: string
  role: string
  initialGreeting: string
  system_message: string
  image: string
  color: string
  model?: string
  visibility: 'private' | 'organization' | 'public' | 'unlisted'
  ownerId: string
  organizationId?: string
  skillIds?: string[]
  advanced_tools?: string[]
  tags?: string[]
  archived?: boolean
  createdAt: Date
}
```

---

### Chats - `useChatCrud()`

Manage conversations with agents.

```typescript
const {
  chats,               // Array of chats (reactive, real-time)
  loading,
  error,
  fetchChats,
  createChat,
  getChat,
  updateChat,
  deleteChat,
  toggleChatClosed
} = useChatCrud()

// Fetch chats for a space
await fetchChats('org_id', 'space_id')

// Create new chat
const chat = await createChat('org_id', 'space_id', 'New Conversation')

// Get specific chat
const chat = await getChat('chat_id')

// Update chat
await updateChat('chat_id', {
  title: 'Updated Title',
  status: 'done'
})

// Toggle closed state
await toggleChatClosed('chat_id')

// Delete chat
await deleteChat('chat_id')
```

**Chat Type:**
```typescript
interface Chat {
  id: string
  organizationId: string
  spaceId: string
  title: string
  subtitle?: string
  status: 'standby' | 'working' | 'done' | 'needs_attention' | 'error'
  ownerId: string
  lastMessage?: string
  sessionId?: string
  closed: boolean
  closedAt?: Date | null
  createdAt: Date
  updatedAt: Date
}
```

---

### Skills - `useSkills()`

Manage reusable prompt packages.

```typescript
const {
  skills,              // Array of skills
  loading,
  error,
  fetchSkills,
  createSkill,
  updateSkill,
  deleteSkill
} = useSkills()

// Fetch skills for organization
await fetchSkills('org_id')

// Create a skill
const skill = await createSkill({
  name: 'custom-researcher',
  displayName: 'Custom Researcher',
  description: 'Custom research skill',
  prompt: '# Research Skill\n\nInstructions...',
  category: 'research',
  builtInTools: ['WebSearch', 'Read'],
  visibility: 'organization',
  organizationId: 'org_id',
  ownerId: 'user_id'
})

// Update skill
await updateSkill('skill_id', {
  displayName: 'Updated Name',
  prompt: 'Updated instructions...'
})

// Delete skill
await deleteSkill('skill_id')
```

**Skill Type:**
```typescript
interface Skill {
  id: string
  name: string                    // kebab-case
  displayName: string
  description: string
  prompt: string                  // Markdown instructions
  category: 'research' | 'writing' | 'data' | 'code' | 'marketing' | 'productivity' | 'file-handling' | 'other'
  builtInTools?: string[]
  requiredMCPs?: string[]
  visibility: 'private' | 'organization' | 'public'
  organizationId: string
  ownerId: string
  version: number
  createdAt: Date
}
```

---

### Missions - `useMissions()`

Manage long-running autonomous tasks.

```typescript
const {
  missions,            // Array of missions
  loading,
  error,
  fetchMissions,
  createMission,
  updateMission,
  pauseMission,
  resumeMission
} = useMissions()

// Fetch missions
await fetchMissions('org_id')

// Create mission
const mission = await createMission({
  title: 'Daily Report',
  goal: 'Generate daily analytics report',
  agentType: 'claude',
  schedule: {
    type: 'cron',
    value: '0 9 * * *'  // Every day at 9 AM
  },
  organizationId: 'org_id',
  userId: 'user_id'
})

// Update mission
await updateMission('mission_id', {
  status: 'paused'
})

// Pause/Resume
await pauseMission('mission_id')
await resumeMission('mission_id')
```

---

## Real-Time Subscriptions

All data composables provide real-time updates using Firestore's `onSnapshot`.

### Subscription Lifecycle

```typescript
const { fetchSpaces, unsubscribeSpaces } = useSpaces()

// Start subscription
fetchSpaces('org_id')

// Data updates automatically when Firestore changes
watch(spaces, (newSpaces) => {
  console.log('Spaces updated:', newSpaces.length)
})

// Cleanup on unmount
onUnmounted(() => {
  unsubscribeSpaces()
})
```

### Auto-Cleanup

Composables handle cleanup automatically in most cases:

```typescript
// This automatically cleans up on component unmount
const { spaces } = useSpaces()
fetchSpaces('org_id')
```

---

## Error Handling

All composables follow a consistent error pattern:

```typescript
const { error, loading } = useSpaces()

// Check loading state
if (loading.value) {
  console.log('Loading...')
}

// Check for errors
if (error.value) {
  console.error('Error:', error.value)
}

// Try-catch for explicit operations
try {
  await createSpace(...)
} catch (err) {
  console.error('Failed to create space:', err)
}
```

---

## TypeScript Support

All types are fully typed with TypeScript:

```typescript
import type { Space, Character, Skill, Chat } from '~/types'

const space: Space = await getSpace('space_id')
const agent: Character = await getCharacter('agent_id')  // Character type represents an agent
```

**Type Exports:**

```typescript
// From ~/types/space
export type { Space, Chat, ChatMessage, SpaceVisibility }

// From ~/types/character (Agent types)
export type { Character, CharacterVisibility }

// From ~/types/skill
export type { Skill, SkillCategory, SkillVisibility }

// From ~/types/mission
export type { Mission, MissionStatus, AgentType }

// From ~/types/task
export type { Task, TaskStatus, TaskPriority }

// From ~/types/execution
export type { Execution, ExecutionStatus }
```

---

## Server API Endpoints

TeamDay provides server-side API endpoints for operations requiring elevated permissions.

### Base URL

```
Production: https://cc.teamday.ai/api
Development: http://localhost:3000/api
```

### Authentication

Use Firebase ID tokens for authentication:

```typescript
const idToken = await user.value?.getIdToken()

const response = await fetch('/api/endpoint', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${idToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
})
```

### Available Endpoints

#### Space Initialization
```http
POST /api/spaces/:spaceId/init
Content-Type: application/json

{
  "type": "empty",      // or "git", "readme", "starterKit"
  "orgId": "org_id",
  "spaceName": "Workspace Name"
}
```

#### Space Environment Variables
```http
POST /api/spaces/:spaceId/environment
Content-Type: application/json

{
  "environmentVariables": {
    "API_KEY": "encrypted_value",
    "DATABASE_URL": "encrypted_value"
  }
}
```

#### Agent Execution
```http
POST /api/agent/execute
Content-Type: application/json

{
  "characterId": "char_id",   // the agent's ID
  "spaceId": "space_id",
  "message": "User message",
  "sessionId": "session_id"
}
```

#### Usage Analytics
```http
GET /api/usage/organization/:orgId?period=daily&start=2024-01-01&end=2024-01-31
Authorization: Bearer <id_token>
```

---

## CLI Tool

The TeamDay CLI provides development workflow commands.

### Installation

```bash
# Using bun
bun add -g @teamday/cli

# Using npm
npm install -g @teamday/cli
```

### Authentication

```bash
# Login via browser OAuth
teamday login

# Verify authentication
teamday whoami
```

### Commands

```bash
# Initialize a new space
teamday space init

# Deploy an agent
teamday agent deploy ./agent-config.json

# Run a mission locally
teamday mission run mission_id

# Tail agent logs
teamday logs --follow --space space_id

# Manage environment variables
teamday env set API_KEY=value
teamday env list
```

### Configuration

Create `.teamdayrc.json` in your project:

```json
{
  "organizationId": "org_abc123",
  "defaultSpace": "space_456",
  "region": "us-central1"
}
```

---

## Best Practices

### 1. Always Clean Up Subscriptions

```typescript
const unsubscribe = ref<Unsubscribe | null>(null)

const subscribe = () => {
  if (unsubscribe.value) {
    unsubscribe.value()
  }

  unsubscribe.value = onSnapshot(query, callback)
}

onUnmounted(() => {
  if (unsubscribe.value) {
    unsubscribe.value()
  }
})
```

### 2. Handle Undefined Values

Firestore doesn't allow `undefined`. Always use `null` or omit:

```typescript
// ❌ Bad
await updateDoc(docRef, {
  optional: undefined
})

// ✅ Good
const cleanData = Object.fromEntries(
  Object.entries(data).filter(([_, v]) => v !== undefined)
)
await updateDoc(docRef, cleanData)
```

### 3. Use Server Timestamps

```typescript
import { serverTimestamp } from 'firebase/firestore'

await updateDoc(docRef, {
  updatedAt: serverTimestamp()
})
```

### 4. Optimistic Updates

For better UX, show changes immediately:

```typescript
// Add optimistically
optimisticSpaces.value.push(newSpace)

// Then persist
await addDoc(collection, spaceData)

// Snapshot updates with real data
```

### 5. Error Boundaries

Wrap operations in try-catch:

```typescript
try {
  await createSpace(...)
} catch (error) {
  console.error('Operation failed:', error)
  // Show user-friendly error message
  toast.error('Failed to create space')
}
```

---

## Migration from v1 to v2

### Breaking Changes

**Authentication:**
- Changed from custom JWT to Firebase Auth
- Update: Replace `useAuthToken()` with `useAuth()`

**Composables:**
- Renamed `useAgents()` to `useCharacters()` (manages agents)
- Removed `skills` inline field, use `skillIds` instead

**Types:**
- `Agent` type renamed to `Character` (represents an agent)
- `systemPrompt` field aliased as `system_message` (both work, `systemPrompt` preferred)

### Migration Guide

```typescript
// v1
const { agents } = useAgents()

// v2
const { characters } = useCharacters()  // manages agents

// v1
const agent = {
  systemPrompt: 'You are...',
  skills: [{ name: 'research', instructions: '...' }]
}

// v2
const agent = {
  systemPrompt: 'You are...',
  skillIds: ['research-assistant']
}
```

---

## Version Compatibility

| TeamDay Version | SDK Version | Firebase SDK | Nuxt Version |
|----------------|-------------|--------------|--------------|
| 1.0.x | 1.0.x | ^10.7.0 | ^3.9.0 |
| 2.0.x | 2.0.x | ^10.12.0 | ^3.13.0 |

---

## Examples

### Complete Workspace Setup

```typescript
<script setup lang="ts">
const { user } = useAuth()
const { organizations, fetchUserOrganizations } = useOrganizations()
const { createSpace, fetchSpaces, spaces } = useSpaces()
const { createCharacter, fetchCharacters } = useCharacters()

// On mount, fetch user's organizations
onMounted(async () => {
  await fetchUserOrganizations()

  if (organizations.value.length > 0) {
    const orgId = organizations.value[0].id

    // Subscribe to spaces and agents
    fetchSpaces(orgId)
    fetchCharacters(orgId)  // fetches agents
  }
})

// Create a complete workspace
const setupWorkspace = async () => {
  const orgId = organizations.value[0].id

  // 1. Create space
  const space = await createSpace(
    orgId,
    'My Workspace',
    'A workspace for my team',
    'organization'
  )

  // 2. Create agent
  const agent = await createCharacter(
    orgId,
    'Research Assistant',
    'Researcher',
    'You are an expert researcher...',
    'organization'
  )

  // 3. Assign agent to space
  if (space && agent) {
    await updateSpace(space.id, {
      assignedAgents: [agent.id]
    })
  }

  console.log('Workspace ready!')
}
</script>
```

### Real-Time Chat

```typescript
<script setup lang="ts">
const { chats, fetchChats } = useChatCrud()
const route = useRoute()

const spaceId = route.params.spaceId as string
const orgId = route.params.orgId as string

// Subscribe to chats in this space
fetchChats(orgId, spaceId)

// Watch for new messages
watch(chats, (newChats) => {
  const latestChat = newChats[0]
  if (latestChat?.status === 'done') {
    console.log('Agent finished:', latestChat.lastMessage)
  }
})
</script>
```

---

## Support

- **Documentation**: https://teamday.ai/docs
- **API Reference**: https://teamday.ai/docs/reference
- **GitHub**: https://github.com/TeamDay-AI/teamday
- **Discord**: https://discord.gg/teamday

---

## Roadmap

### Q1 2025
- ✅ JavaScript/TypeScript SDK
- ✅ CLI Tool
- 🚧 REST API (beta)

### Q2 2025
- 📋 Python SDK
- 📋 Webhook subscriptions
- 📋 GraphQL API

### Q3 2025
- 📋 Go SDK
- 📋 Mobile SDKs (React Native)
- 📋 Streaming API for real-time agent output

---

## Contributing

We welcome contributions! See our [Contributing Guide](https://github.com/TeamDay-AI/teamday/blob/main/CONTRIBUTING.md) for details.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/TeamDay-AI/teamday.git
cd teamday

# Install dependencies
bun install

# Start development server
bun run dev

# Run tests
bun test
```

---

## License

The TeamDay SDK is released under the MIT License. See [LICENSE](https://github.com/TeamDay-AI/teamday/blob/main/LICENSE) for details.
