> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sammylabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Guides System

> Seamless walkthrough and guide functionality for Sammy Agent with URL-based triggering and automatic data fetching

<Note>
  The Guides System provides a composable hook architecture that integrates directly into the `SammyAgentProvider` for seamless walkthrough experiences.
</Note>

<Warning>
  **Performance Update**: Guides now use **lazy loading** to reduce API calls. User guides are only fetched when components call `refreshUserGuides()`, not automatically on initialization. This prevents unnecessary API load from users who never interact with guides. Always call `refreshUserGuides()` in components that display guides.
</Warning>

## Architecture Overview

<Card title="Clean Architecture" icon="sitemap">
  The guides system uses a hook-based composition pattern that integrates directly into the main provider:

  * **No nested contexts** - Integrated directly into main provider
  * **Hook composition** - Clean separation of concerns
  * **Zero overhead** - Returns `null` when disabled
  * **Type-safe** - Full TypeScript support
</Card>

### Data Flow

```mermaid theme={null}
graph TD
    A[URL with ?walkthrough=guide-id] --> B[useGuidesQueryParams]
    B --> C[useGuidesManager]
    C --> D[useGuides]
    D --> E[SammyAgentProvider]
    E --> F[Component via useSammyAgentContext]
```

## Quick Start

### Basic Setup

<CodeGroup>
  ```tsx Provider Configuration theme={null}
  import { SammyAgentProvider } from '@sammy-labs/sammy-three';

  function App() {
    return (
      <SammyAgentProvider
        config={{
          auth: authConfig,
          captureMethod: 'render',
          debugLogs: true,
          model: 'models/gemini-2.5-flash-preview-native-audio-dialog',
        }}
        guides={true} // Enable guides functionality
        autoStartFromURL={true} // Auto-start from ?walkthrough= URLs
        onError={(error) => console.error('Agent error:', error)}
        onTokenExpired={handleTokenExpired}
        onWalkthroughStart={(guideId) => {
          console.log('Starting walkthrough:', guideId);
        }}
      >
        <YourApp />
      </SammyAgentProvider>
    );
  }
  ```

  ```tsx Using Guides in Components theme={null}
  import { useEffect } from 'react';
  import { useSammyAgentContext } from '@sammy-labs/sammy-three';

  function ChatComponent() {
    const { guides } = useSammyAgentContext();

    // IMPORTANT: Lazy load guides when component mounts
    // This reduces API calls - only fetches when UI needs the data
    useEffect(() => {
      if (guides) {
        guides.refreshUserGuides(); // Only fetches on first call, cached after
      }
    }, [guides]);

    // Check if guides are enabled
    if (!guides) {
      return <div>Guides not enabled</div>;
    }

    return (
      <div>
        {/* Display current guide */}
        {guides.currentGuide && (
          <div>
            <h3>{guides.currentGuide.title}</h3>
            <p>{guides.currentGuide.description}</p>
            <span>Completed: {guides.currentGuide.isCompleted ? '✓' : '○'}</span>
          </div>
        )}

        {/* Show loading state while fetching */}
        {guides.isLoadingUserGuides && <div>Loading guides...</div>}

        {/* List user guides */}
        {guides.userGuides.map((guide) => (
          <button
            key={guide.guideId}
            onClick={() => guides.startWalkthrough(guide.guideId)}
            disabled={guide.isCompleted}
          >
            {guide.title} {guide.isCompleted && '✓'}
          </button>
        ))}
      </div>
    );
  }
  ```
</CodeGroup>

### URL-Based Activation

Guides can be automatically triggered via URL parameters, perfect for sharing specific walkthroughs or onboarding flows:

```bash theme={null}
# Trigger a guide directly from URL
https://yourapp.com?walkthrough=onboarding-guide-v1

# Custom parameter name
https://yourapp.com?guide=quick-tour
```

<Info>
  When `autoStartFromURL` is enabled, the guide will automatically start when the page loads with the appropriate query parameter.
</Info>

## Guide Lifecycle

Manage the complete lifecycle of guides from initialization to completion:

<Steps>
  <Step title="Initialization" icon="power">
    ```tsx theme={null}
    // Guides automatically initialize when provider mounts
    // Fetches user guides and checks for URL parameters
    ```
  </Step>

  <Step title="Manual Start" icon="play">
    ```tsx theme={null}
    // Start a guide programmatically
    const success = await guides.startWalkthrough('guide-id');
    if (success) {
      console.log('Guide started successfully');
    }
    ```
  </Step>

  <Step title="URL Detection" icon="link">
    ```tsx theme={null}
    // Check for guide in URL
    const hasGuide = await guides.checkForGuideInUrl();
    if (hasGuide) {
      console.log('Guide found in URL and started');
    }
    ```
  </Step>

  <Step title="Progress Tracking" icon="chart-line">
    ```tsx theme={null}
    // Guides are automatically marked as completed when conversation starts
    // Manual completion is also possible
    guides.markGuideAsCompleted('guide-id');
    ```
  </Step>

  <Step title="Data Refresh" icon="refresh">
    ```tsx theme={null}
    // Refresh guide data at any time
    guides.refreshGuide();        // Current guide
    guides.refreshUserGuides();   // All user guides
    ```
  </Step>

  <Step title="Cleanup" icon="broom">
    ```tsx theme={null}
    // Clean up URL params after use
    guides.cleanupUrlParams();
    ```
  </Step>
</Steps>

## Core Components

### GuidesService

<Info>
  The service layer handles all API communication and transforms snake\_case responses to camelCase.
</Info>

<Tabs>
  <Tab title="Interface">
    ```typescript theme={null}
    export interface GuidesService {
      fetchGuide: (guideId: string) => Promise<SammyGuide | null>;
      getUserGuides: () => Promise<SammyGuide[]>;
    }

    export interface SammyGuide {
      guideId: string;
      title: string;
      prompt: string;
      organisationId: string;
      isCompleted: boolean;
    }
    ```
  </Tab>

  <Tab title="Implementation">
    ```typescript theme={null}
    export const fetchGuide = (apiCaller: SammyApiClient) =>
      async (guideId: string): Promise<SammyGuide | null> => {
        try {
          const response = await apiCaller.get<KeysToSnakeCase<SammyGuide>>(
            `/api/v1/sammy-three/guides/${guideId}`
          );
          
          return {
            guideId: response.guide_id,
            title: response.title,
            prompt: response.prompt,
            organisationId: response.organisation_id,
            isCompleted: response.is_completed,
          };
        } catch (error) {
          console.error('[GuidesService] Failed to validate guide:', error);
          return null;
        }
      };
    ```
  </Tab>
</Tabs>

### useGuides Hook

Provides always-on guide data with automatic fetching:

<CodeGroup>
  ```typescript Return Interface theme={null}
  interface UseGuidesReturn {
    // Data
    currentGuide: SammyGuide | null;
    userGuides: SammyGuide[];
    
    // Loading states
    isLoadingGuide: boolean;
    isLoadingUserGuides: boolean;
    
    // Error states
    guideError: Error | null;
    userGuidesError: Error | null;
    
    // Actions
    refreshGuide: () => void;
    refreshUserGuides: () => void;
    markGuideAsCompleted: (guideId: string) => void;
  }
  ```

  ```typescript Hook Usage theme={null}
  export function useGuides({ authConfig, walkthroughId }: UseGuidesProps) {
    // Memoized service creation
    const sammyApiClient = useMemo(() => 
      authConfig ? new SammyApiClient(authConfig) : null, 
      [authConfig]
    );

    const guidesService = useMemo(() => 
      sammyApiClient ? createGuidesServices(sammyApiClient) : null,
      [sammyApiClient]
    );

    // Auto-fetch current guide
    useEffect(() => {
      if (walkthroughId) {
        fetchGuideInternal(walkthroughId);
      }
    }, [walkthroughId, fetchGuideInternal]);

    // Auto-fetch user guides
    useEffect(() => {
      if (guidesService) {
        fetchUserGuidesInternal();
      }
    }, [guidesService, fetchUserGuidesInternal]);
  }
  ```
</CodeGroup>

## Features

### URL-Based Walkthrough Activation

<Steps>
  <Step title="User Visits URL">
    User visits: `https://app.com?walkthrough=guide-123`
  </Step>

  <Step title="Parameter Detection">
    GuidesProvider detects the parameter
  </Step>

  <Step title="Guide Fetching">
    Guide is fetched automatically
  </Step>

  <Step title="Auto-Start">
    If `autoStartFromURL=true`, agent starts with guide context
  </Step>

  <Step title="URL Cleanup">
    URL parameter is cleaned up
  </Step>

  <Step title="Completion Tracking">
    Guide marked as completed on conversation start
  </Step>
</Steps>

### Guide Discovery & Listing

<CodeGroup>
  ```tsx List All Guides theme={null}
  const { guides } = useSammyAgentContext();

  // List all guides with completion status
  guides?.userGuides.map(guide => ({
    id: guide.guideId,
    title: guide.title,
    completed: guide.isCompleted
  }));
  ```

  ```tsx Guide Selector Component theme={null}
  function GuideSelector() {
    const { guides } = useSammyAgentContext();
    
    if (!guides) return null;
    
    return (
      <div className="guide-selector">
        <h2>Choose a Guide</h2>
        
        {guides.isLoadingUserGuides && <LoadingSpinner />}
        
        {guides.userGuides.map(guide => (
          <GuideCard
            key={guide.guideId}
            guide={guide}
            onStart={() => guides.startWalkthrough(guide.guideId)}
          />
        ))}
        
        <button onClick={guides.refreshUserGuides}>
          Refresh Guides
        </button>
      </div>
    );
  }
  ```
</CodeGroup>

### Manual Walkthrough Triggering

```typescript theme={null}
guides?.startWalkthrough('guide-123');
// This will:
// 1. Call onWalkthroughStart callback
// 2. Start agent with guide context
// 3. Mark guide as completed
```

### Progress Tracking

<Card title="Automatic Completion" icon="check-circle">
  Guides automatically track completion:

  * Marked complete when conversation starts with guide
  * Optimistic UI updates (immediate visual feedback)
  * Persistent across sessions (backend storage)
</Card>

## Query Parameter Detection

### Configuration Options

<Tabs>
  <Tab title="Basic Setup">
    ```tsx theme={null}
    <SammyAgentProvider
      config={authConfig}
      guides={true}                    // Enable guides
      autoStartFromURL={true}          // Auto-start from URL
      guidesQueryParam="walkthrough"   // Query param name (default)
      guidesDebug={true}               // Enable debug logging
    >
      <YourApp />
    </SammyAgentProvider>
    ```
  </Tab>

  <Tab title="Configuration Table">
    | Prop               | Type      | Default         | Description                                 |
    | ------------------ | --------- | --------------- | ------------------------------------------- |
    | `guides`           | `boolean` | `false`         | Enable guides functionality                 |
    | `autoStartFromURL` | `boolean` | `false`         | Auto-start agent when guide detected in URL |
    | `guidesQueryParam` | `string`  | `"walkthrough"` | Name of the query parameter to detect       |
    | `guidesDebug`      | `boolean` | `false`         | Enable debug console logging                |
  </Tab>
</Tabs>

### Usage Examples

<Columns cols={2}>
  <Card title="Share Walkthrough" icon="share">
    ```tsx theme={null}
    function ShareWalkthroughButton({ guideId }) {
      const shareUrl = 
        `${window.location.origin}?walkthrough=${guideId}`;
      
      return (
        <button onClick={() => 
          navigator.clipboard.writeText(shareUrl)
        }>
          Copy Walkthrough Link
        </button>
      );
    }
    ```
  </Card>

  <Card title="Email Campaign" icon="envelope">
    ```html theme={null}
    <a href="https://app.com?walkthrough=new-user-onboarding">
      Start Your Guided Tour
    </a>
    ```
  </Card>

  <Card title="Programmatic Navigation" icon="code">
    ```tsx theme={null}
    function navigateWithWalkthrough(guideId: string) {
      window.location.href = 
        `/dashboard?walkthrough=${guideId}`;
    }
    ```
  </Card>

  <Card title="Manual URL Check" icon="search">
    ```tsx theme={null}
    const { guides } = useSammyAgentContext();

    const handleCheckUrl = async () => {
      if (guides) {
        const found = await guides.checkForGuideInUrl();
        if (found) {
          console.log('Guide found and started!');
        }
      }
    };
    ```
  </Card>
</Columns>

### Advanced Features

<Tabs>
  <Tab title="Custom Query Parameter Names">
    ```tsx theme={null}
    <SammyAgentProvider
      guides={true}
      guidesQueryParam="tutorial"  // Now use ?tutorial=guide-id
    >
    ```
  </Tab>

  <Tab title="Conditional Auto-Start">
    ```tsx theme={null}
    function App() {
      const [userReady, setUserReady] = useState(false);
      
      return (
        <SammyAgentProvider
          guides={true}
          autoStartFromURL={userReady}  // Only auto-start when ready
        >
          <YourApp />
        </SammyAgentProvider>
      );
    }
    ```
  </Tab>

  <Tab title="Debug Mode">
    Enable detailed console logging:

    ```tsx theme={null}
    <SammyAgentProvider
      guides={true}
      guidesDebug={true}  // Logs all detection and cleanup
    >
    ```

    Example debug output:

    ```
    [useGuidesQueryParams] Guide detected in URL: onboarding-guide
    [useGuidesQueryParams] Starting guide: onboarding-guide
    [GuidesProvider] Guide detected from URL: onboarding-guide
    [GuidesProvider] 🚀 Auto-starting walkthrough: onboarding-guide
    [useGuidesQueryParams] Guide started successfully: onboarding-guide
    [useGuidesQueryParams] Cleaned up 'walkthrough' parameter from URL
    ```
  </Tab>
</Tabs>

## Implementation Details

### Conditional Provider Wrapping

<Info>
  The system uses a clever pattern to conditionally wrap providers without nesting:
</Info>

```typescript theme={null}
// When guides={true}, wrap with GuidesProvider
if (guides) {
  return (
    <GuidesProvider>
      <InternalProvider>
        {children}
      </InternalProvider>
    </GuidesProvider>
  );
}

// When guides={false}, skip the wrapper
return <InternalProvider>{children}</InternalProvider>;
```

### Dependency Injection for Agent Start

```typescript theme={null}
// Extract startAgent function from inner context
const StartAgentExtractor = ({ onStartAgentReady }) => {
  const context = useContext(SammyAgentContext);
  
  useEffect(() => {
    if (context?.startAgent) {
      onStartAgentReady(context.startAgent);
    }
  }, [context?.startAgent, onStartAgentReady]);
  
  return null;
};
```

### Optimistic Updates

<Card title="Immediate UI Feedback" icon="lightning-bolt">
  Guide completion is updated optimistically for better UX:

  ```typescript theme={null}
  const markGuideAsCompleted = useCallback((guideId: string) => {
    // Update current guide immediately
    if (currentGuide?.guideId === guideId) {
      setCurrentGuide(prev => 
        prev ? { ...prev, isCompleted: true } : null
      );
    }
    
    // Update user guides list immediately
    setUserGuides(prev => 
      prev.map(guide => 
        guide.guideId === guideId 
          ? { ...guide, isCompleted: true }
          : guide
      )
    );
  }, [currentGuide]);
  ```
</Card>

## API Reference

### Provider Props

```typescript theme={null}
interface SammyAgentProviderProps {
  guides?: boolean;           // Enable guides functionality
  autoStartFromURL?: boolean; // Auto-start from URL params
  onWalkthroughStart?: (guideId: string) => void;
  // ... other props
}
```

### Context API

```typescript theme={null}
const { guides } = useSammyAgentContext();

if (guides) {
  // All guides functionality available
  guides.currentGuide;        // Current active guide
  guides.userGuides;          // All user's guides
  guides.isLoadingGuide;      // Loading state
  guides.guideError;          // Error state
  guides.refreshGuide();      // Refresh current
  guides.refreshUserGuides(); // Refresh list
  guides.markGuideAsCompleted(id); // Mark complete
  guides.startWalkthrough(id); // Start walkthrough
}
```

### Service Endpoints

<CodeGroup>
  ```http Single Guide theme={null}
  GET /api/v1/sammy-three/guides/{id}
  ```

  ```http User Guides List theme={null}
  GET /api/v1/sammy-three/guides
  ```
</CodeGroup>

## Complete Example

<Tabs>
  <Tab title="Provider Setup">
    ```tsx theme={null}
    import { SammyAgentProvider, useSammyAgentContext } from '@sammy-three/react';

    function App() {
      return (
        <SammyAgentProvider
          config={{
            auth: { token: 'xxx', baseUrl: 'https://api.sammy.ai' },
            model: 'gemini-2.0-flash-exp',
          }}
          guides={true}
          autoStartFromURL={true}
          guidesQueryParam="walkthrough"
          guidesDebug={process.env.NODE_ENV === 'development'}
          onWalkthroughStart={(guideId) => {
            console.log(`Walkthrough started: ${guideId}`);
            // Track analytics event
            analytics.track('walkthrough_started', { guideId });
          }}
        >
          <Dashboard />
        </SammyAgentProvider>
      );
    }
    ```
  </Tab>

  <Tab title="Dashboard Component">
    ```tsx theme={null}
    function Dashboard() {
      const { guides } = useSammyAgentContext();
      
      // Share current page with a walkthrough
      const shareWithGuide = (guideId: string) => {
        const url = new URL(window.location.href);
        url.searchParams.set('walkthrough', guideId);
        navigator.clipboard.writeText(url.toString());
      };
      
      return (
        <div>
          {guides?.currentGuide && (
            <div>Active Guide: {guides.currentGuide.title}</div>
          )}
          
          <button onClick={() => shareWithGuide('dashboard-tour')}>
            Share Dashboard Tour
          </button>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Performance & Best Practices

<Columns cols={2}>
  <Card title="Zero-Cost When Disabled" icon="gauge">
    When `guides={false}`:

    * No GuidesProvider rendered
    * No API calls made
    * No state management overhead
    * No event listeners attached
  </Card>

  <Card title="Memoization" icon="memory">
    All expensive operations are memoized:

    ```typescript theme={null}
    const sammyApiClient = useMemo(() => 
      authConfig ? new SammyApiClient(authConfig) : null, 
      [authConfig]
    );
    ```
  </Card>

  <Card title="Automatic Cleanup" icon="broom">
    Resources are properly cleaned up:

    ```typescript theme={null}
    // URL parameter cleaned after detection
    window.history.replaceState({}, '', newUrl.toString());
    ```
  </Card>

  <Card title="TypeScript Best Practices" icon="code">
    Use null checks for type safety:

    ```typescript theme={null}
    // Good - null safe
    if (guides) {
      guides.userGuides.map(...);
    }

    // Bad - assumes guides exists
    guides!.userGuides.map(...);
    ```
  </Card>
</Columns>

## Security Considerations

<Warning>
  Always validate guide IDs on the backend:

  * Check if guide exists
  * Verify user permissions
  * Validate organization access
</Warning>

### URL Parameter Sanitization

The system automatically:

* Sanitizes guide IDs before use
* Prevents XSS through parameter injection
* Cleans up parameters after processing

## Troubleshooting

### Common Issues

<Tabs>
  <Tab title="Guide Not Starting">
    **Troubleshooting Steps:**

    1. Check if `guides={true}` is set
    2. Verify `autoStartFromURL={true}` for automatic start
    3. Ensure guide ID exists and user has access
    4. Enable debug mode to see detailed logs
  </Tab>

  <Tab title="URL Not Cleaning Up">
    **Troubleshooting Steps:**

    1. Check browser console for errors
    2. Ensure `window.history.replaceState` is available
    3. Verify no other code is modifying the URL
  </Tab>

  <Tab title="Multiple Triggers">
    **Troubleshooting Steps:**

    1. Parameters are cleaned after first detection
    2. Check for duplicate provider instances
    3. Ensure `checkQueryOnMount` isn't called multiple times
  </Tab>
</Tabs>

## Summary

<Note>
  The Sammy-Three Guides System provides a robust, performant, and developer-friendly solution for implementing guided experiences. Its clean architecture, type safety, and zero-overhead design make it an excellent choice for applications requiring tutorial or walkthrough functionality.
</Note>

Key takeaways:

* **Clean Architecture**: Separated concerns with proper layering
* **Performance First**: Zero cost when disabled
* **Developer Experience**: Full TypeScript support and simple API
* **User Experience**: Seamless URL-based activation and progress tracking
* **Extensible**: Easy to add new features without breaking existing functionality
