Pipulate Free & Open Source SEO with & for LLMs

Development Guide

This guide provides essential patterns and workflows for developing with Pipulate. These patterns are designed to help you navigate the codebase and maintain consistency in your development work.

Getting Started

1. Installation

2. Project Structure

3. Development Environment

Core Development Patterns

1. Workflow Development Pattern

When creating new workflows in Pipulate, follow this pattern:

class MyWorkflow:
    APP_NAME = "unique_name"        # Unique identifier
    DISPLAY_NAME = "User-Facing Name"  # UI display name
    
    def __init__(self, pipulate, db, pipeline, rt):
        self.pipulate, self.db = pipulate, db
        self.pipeline = pipeline
        
        # Define steps
        Step = namedtuple('Step', ['id', 'done', 'show', 'refill', 'transform'])
        self.steps = [
            Step(id='step_01', done='first_field', show='First Step', refill=True),
            Step(id='step_02', done='second_field', show='Second Step', refill=True),
            # More steps...
        ]
        
        # Register routes
        self.register_routes(rt)

Key points:

2. Chain Reaction Pattern

The chain reaction pattern is crucial for workflow progression:

return Div(
    Card(...),  # Current step content
    # This inner Div triggers loading of the next step
    Div(id=next_step_id, hx_get=f"/{app_name}/{next_step_id}", hx_trigger="load"),
    id=step_id
)

Important:

3. State Management Pattern

Pipulate uses two complementary approaches to state management:

# Workflow state (JSON-based)
pipeline_id = db.get("pipeline_id", "unknown")
state = pip.read_state(pipeline_id)
state[step.done] = value
pip.write_state(pipeline_id, state)

# CRUD operations (table-based)
profiles.insert(name="New Profile")
profiles.update(1, name="Updated Profile")
profiles.delete(1)
all_profiles = profiles()

4. Plugin Development Pattern

Creating new plugins follows a specific workflow:

  1. Copy a Template: Start with a template (e.g., 20_hello_workflow.py) → 20_hello_workflow (Copy).py
  2. Modify: Develop your workflow (won’t auto-register with parentheses in name)
  3. Test: Rename to xx_my_flow.py for testing (server auto-reloads but won’t register)
  4. Deploy: Rename to XX_my_flow.py (e.g., 30_my_flow.py) to assign menu order and activate

5. Data Visualization Pattern

For embedding visualizations in workflows:

import pandas as pd
import matplotlib.pyplot as plt
from io import BytesIO
import base64

# Generate plot
fig, ax = plt.subplots(figsize=(10, 6))
df.plot(ax=ax)
plt.tight_layout()

# Convert to base64 for embedding
buffer = BytesIO()
plt.savefig(buffer, format='png')
buffer.seek(0)
image_base64 = base64.b64encode(buffer.read()).decode('utf-8')

# Return in HTML
return Div(
    Card(
        H4("Data Visualization"),
        Img(src=f"data:image/png;base64,{image_base64}",
            style="width:100%;max-width:800px"),
    ),
    Div(id=next_step_id, hx_get=f"/{app_name}/{next_step_id}", hx_trigger="load"),
    id=step_id
)

Workflow Development

1. Basic Workflow

2. Widget Implementation

3. Testing

CRUD Development

1. MiniDataAPI Usage

2. UI Components

3. Testing

Plugin Development

1. Plugin Structure

2. Development Workflow

3. Best Practices

Common Patterns

1. State Management

2. Error Handling

3. UI Patterns

Testing Guidelines

1. Unit Testing

2. Integration Testing

3. Performance Testing

Deployment

1. Local Deployment

2. Production Deployment

3. Maintenance

Best Practices

  1. Keep it simple. Avoid complex patterns when simple ones will work.
  2. Stay local and single-user. Embrace the benefits of local-first design.
  3. Be explicit over implicit. WET code that’s clear is better than DRY code that’s obscure.
  4. Preserve the chain reaction. Maintain the core progression mechanism in workflows.
  5. Embrace observability. Make state changes visible and debuggable.

Read more about our development philosophy and best practices on our blog →

Contributing

When contributing to Pipulate, please adhere to these principles:

Pipulate uses a “Magic Cookie” system for seamless installation and updates. This approach enables:

How It Works

  1. Initial Installation:
    curl -L https://pipulate.com/install.sh | sh -s AppName
    

This downloads a ZIP archive containing:

  1. First Run Transformation: When nix develop runs for the first time:
    • Detects non-git directory
    • Clones the repository
    • Preserves app identity and credentials
    • Sets up the environment
  2. Automatic Updates: The system performs git pulls:
    • On shell entry
    • Before server startup
    • During application runs

White-Labeling Process

To create a white-labeled version of Pipulate:

  1. Custom Branding:
    # Install with custom name
    curl -L https://pipulate.com/install.sh | sh -s YourBrandName
    
  2. Configuration Files:
    • app_name.txt: Contains the application identity
    • .ssh/rot: ROT13-encoded deployment key
    • flake.nix: Environment configuration
  3. Customization Points:
    • Application name and branding
    • Default workflows and plugins
    • Environment variables
    • Database schema
  4. Deployment Options:
    • Direct installation from pipulate.com
    • Self-hosted installation script
    • Custom domain deployment

Best Practices for White-Labeling

  1. Branding Consistency:
    • Use consistent naming across all files
    • Update all UI elements and documentation
    • Maintain version tracking
  2. Security Considerations:
    • Keep deployment keys secure
    • Use ROT13 encoding for SSH keys
    • Maintain proper file permissions
  3. Update Management:
    • Test updates in development first
    • Maintain separate deployment keys
    • Monitor update logs
  4. User Experience:
    • Provide clear installation instructions
    • Document customization options
    • Include troubleshooting guides

Development Workflow

When developing white-labeled versions:

  1. Local Development:
# Start with a copy
cp 20_hello_workflow.py 20_hello_workflow (Copy).py

# Develop and test
# Rename to xx_ for testing
mv "20_hello_workflow (Copy).py" xx_my_workflow.py

# Deploy when ready
mv xx_my_workflow.py 30_my_workflow.py
  1. Testing Updates:
    • Use xx_ prefix for development versions
    • Test in isolated environments
    • Verify update mechanisms
  1. Deployment:
    • Use numbered prefixes for menu order
    • Maintain consistent naming
    • Document all customizations

This approach ensures smooth development and deployment of white-labeled versions while maintaining the benefits of automatic updates and cross-platform compatibility.