Last updated: Aug 12, 2025, 01:09 PM UTC

Dynamic Content Loading Implementation Plan

Overview

Transform hardcoded guides and personas in Sasha Studio to load dynamically from markdown files, combining both public user content and private system content with appropriate badging.

Design Philosophy

  • Simple: Fetch fresh content when panels open (no WebSockets)
  • Reliable: Direct file reading with fallbacks
  • Dual Sources: Combine public and private content with "System" badges

Architecture

1. Directory Structure

docs/
β”œβ”€β”€ personas/                    # User-created personas
β”‚   β”œβ”€β”€ marketing-sasha.md
β”‚   └── sales-sasha.md
β”œβ”€β”€ guides/                      # User-created guides
β”‚   └── custom-workflows/
β”‚       └── my-process.md
└── private/                     # System content (badged)
    β”œβ”€β”€ personas/
    β”‚   β”œβ”€β”€ general-sasha.md
    β”‚   β”œβ”€β”€ analyst-sasha.md
    β”‚   β”œβ”€β”€ technical-sasha.md
    β”‚   β”œβ”€β”€ compliance-sasha.md
    β”‚   └── creative-sasha.md
    └── guides/
        β”œβ”€β”€ research-analysis/
        β”‚   β”œβ”€β”€ competitor-analysis.md
        β”‚   └── market-research.md
        β”œβ”€β”€ documentation/
        β”‚   β”œβ”€β”€ technical-docs.md
        β”‚   └── user-guide.md
        └── business-strategy/
            β”œβ”€β”€ swot-analysis.md
            └── business-canvas.md

2. Content Format

Persona Markdown Structure

---
name: General Sasha
icon: Sparkles
description: Your AI assistant with deep knowledge
traits:
  - Comprehensive knowledge
  - Balanced approach
  - Adaptive communication
order: 1
---

# General Sasha

Detailed persona description and capabilities...

Guide Markdown Structure

---
title: Competitor Analysis Framework
description: Comprehensive methodology for analyzing competitors
category: RESEARCH & ANALYSIS
icon: MagnifyingGlass
order: 1
---

# Competitor Analysis Framework

Guide content with markdown formatting...

3. Implementation Components

Backend Service (content-reader.js)

  • Reads markdown files from both docs/ and docs/private/ directories
  • Merges content with source tracking (system vs user)
  • Parses frontmatter using gray-matter
  • Returns JSON with source metadata
  • System content takes priority in ordering

API Endpoints

  • GET /api/personas - Returns all personas (system + user)
  • GET /api/guides - Returns categorized guides (system + user)
  • Each item includes source: 'system' | 'user' field
  • No caching - fresh read on each request

Frontend Updates

  • PersonasPanel fetches on open
  • GuidesPanel fetches on open
  • Shows "System" badge for private content
  • Loading states during fetch
  • Fallback to hardcoded if API fails

Implementation Steps

Phase 1: Core Implementation

  1. Install gray-matter dependency
  2. Create directory structure
  3. Convert existing content to markdown
  4. Create content-reader service
  5. Add API endpoints
  6. Update frontend panels
  7. Test functionality

Phase 2: Future Enhancements (V2)

  • Support for npm package content (@sasha/core-content)
  • Organization-specific content layers
  • Content versioning and updates
  • Remote content loading from CDN

Benefits

  1. Content Management: Non-developers can add/edit content
  2. No Restart Required: Changes visible on panel reopen
  3. Version Control: Track content changes in Git
  4. Scalability: Ready for future content sources
  5. Simplicity: No complex syncing or caching

Technical Details

Dependencies

  • gray-matter: ^4.0.3 (frontmatter parsing)

File Naming Convention

  • Personas: {id}-sasha.md (e.g., general-sasha.md)
  • Guides: {guide-name}.md (e.g., competitor-analysis.md)

Content Reader Implementation Example

// server/services/content-reader.js
export async function readPersonas() {
  const personas = [];
  
  // Read system personas from private directory
  const privateDir = path.join(process.cwd(), 'docs/private/personas');
  if (await fs.access(privateDir).then(() => true).catch(() => false)) {
    const systemPersonas = await readPersonasFromDir(privateDir);
    systemPersonas.forEach(p => {
      p.source = 'system';
      p.order = p.order || 0; // System personas come first
      personas.push(p);
    });
  }
  
  // Read user personas from public directory
  const publicDir = path.join(process.cwd(), 'docs/personas');
  if (await fs.access(publicDir).then(() => true).catch(() => false)) {
    const userPersonas = await readPersonasFromDir(publicDir);
    userPersonas.forEach(p => {
      p.source = 'user';
      p.order = (p.order || 999) + 100; // User personas after system
      personas.push(p);
    });
  }
  
  return personas.sort((a, b) => a.order - b.order);
}

Category Mapping

Folder names map to display categories:

  • research-analysis/ β†’ "RESEARCH & ANALYSIS"
  • documentation/ β†’ "DOCUMENTATION"
  • business-strategy/ β†’ "BUSINESS STRATEGY"

Frontend Badge Implementation

// PersonasPanel.jsx - System badge display
const PersonaCard = ({ persona }) => (
  <div className="persona-card">
    <div className="flex items-center gap-2">
      <h3>{persona.name}</h3>
      {persona.source === 'system' && (
        <span className="px-2 py-0.5 text-xs rounded-full bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300">
          System
        </span>
      )}
    </div>
    {/* Rest of card content */}
  </div>
);

Error Handling

  • Missing directories: Create on first run
  • Missing files: Fall back to hardcoded defaults
  • Parse errors: Log and skip problematic files
  • Network errors: Use cached/default content

Migration Path

Current State

  • Hardcoded arrays in components
  • No external content management

After Implementation

  • Markdown files as source of truth
  • Dynamic loading on demand
  • Extensible for future sources

Future Vision

  • Core content from npm packages
  • Organization content repositories
  • User-generated content
  • Content marketplace

Testing Checklist

  • Add new persona file β†’ appears in panel
  • Edit existing guide β†’ changes reflect
  • Delete file β†’ falls back gracefully
  • Invalid markdown β†’ doesn't break app
  • Multiple categories β†’ organize correctly
  • Performance β†’ loads quickly

Rollback Plan

If issues arise, components can revert to hardcoded content by:

  1. Commenting out fetch logic
  2. Using fallback arrays
  3. No database or complex state to revert

Success Metrics

  • Content loads in < 200ms
  • Zero code changes for content updates
  • Non-technical users can manage content
  • System remains stable with invalid content

Created: 2025-01-09
Status: Ready for Implementation
Author: Sasha Studio Team