Claude Code Plugins

Community-maintained marketplace

Feedback

plugin-backend-dev

@jwplatta/prompt-library
0
0

Create and manage backend servers for Obsidian plugins that need server-side processing

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name plugin-backend-dev
description Create and manage backend servers for Obsidian plugins that need server-side processing

You are an expert in creating backend servers for Obsidian plugins.

When Backends Are Needed

  • Python libraries (ML, embeddings, NLP)
  • Heavy computation
  • Database operations not possible in browser
  • Node packages that don't work in browser context
  • Long-running processes

Your Tools

  • Write: Create server files
  • Edit: Update server code
  • Bash: Test server functionality
  • Read: Check existing implementations

Backend Structure

Directory Layout

plugin-root/
├── plugin/              # Obsidian plugin
│   ├── main.ts
│   └── ...
└── server/              # Backend server
    ├── src/
    │   ├── server.ts    # Server entry point
    │   ├── routes/
    │   └── services/
    ├── package.json
    ├── tsconfig.json
    └── .env

Express + TypeScript Server Template

server/package.json

{
  "name": "plugin-server",
  "version": "1.0.0",
  "main": "dist/server.js",
  "scripts": {
    "dev": "ts-node-dev --respawn src/server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "dotenv": "^16.0.3"
  },
  "devDependencies": {
    "@types/express": "^4.17.17",
    "@types/cors": "^2.8.13",
    "@types/node": "^18.15.0",
    "ts-node-dev": "^2.0.0",
    "typescript": "^5.0.0"
  }
}

server/src/server.ts

import express, { Request, Response } from 'express';
import cors from 'cors';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(cors());
app.use(express.json());

// Health check
app.get('/health', (req: Request, res: Response) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

// Example API endpoint
app.post('/api/process', async (req: Request, res: Response) => {
  try {
    const { data } = req.body;
    const result = await processData(data);
    res.json({ success: true, result });
  } catch (error) {
    console.error('Error:', error);
    res.status(500).json({
      success: false,
      error: error.message
    });
  }
});

async function processData(data: any): Promise<any> {
  // Process data here
  return data;
}

app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

server/tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Fastify Alternative (Faster)

import Fastify from 'fastify';
import cors from '@fastify/cors';

const fastify = Fastify({ logger: true });

fastify.register(cors);

fastify.get('/health', async (request, reply) => {
  return { status: 'ok' };
});

fastify.post('/api/process', async (request, reply) => {
  const { data } = request.body as any;
  const result = await processData(data);
  return { success: true, result };
});

const start = async () => {
  try {
    await fastify.listen({ port: 3000 });
  } catch (err) {
    fastify.log.error(err);
    process.exit(1);
  }
};

start();

Python Backend with Flask

server/requirements.txt

Flask==2.3.0
Flask-CORS==4.0.0
python-dotenv==1.0.0

server/server.py

from flask import Flask, request, jsonify
from flask_cors import CORS
import os
from dotenv import load_dotenv

load_dotenv()

app = Flask(__name__)
CORS(app)

@app.route('/health', methods=['GET'])
def health():
    return jsonify({'status': 'ok'})

@app.route('/api/process', methods=['POST'])
def process():
    try:
        data = request.json.get('data')
        result = process_data(data)
        return jsonify({'success': True, 'result': result})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)}), 500

def process_data(data):
    # Process data here
    return data

if __name__ == '__main__':
    port = int(os.getenv('PORT', 3000))
    app.run(host='0.0.0.0', port=port, debug=True)

Plugin-Side Integration

services/BackendService.ts

export class BackendService {
  private baseUrl: string;
  private isHealthy: boolean = false;

  constructor(baseUrl: string = 'http://localhost:3000') {
    this.baseUrl = baseUrl;
    this.startHealthCheck();
  }

  async checkHealth(): Promise<boolean> {
    try {
      const response = await fetch(`${this.baseUrl}/health`, {
        method: 'GET',
        signal: AbortSignal.timeout(5000)
      });
      this.isHealthy = response.ok;
      return this.isHealthy;
    } catch {
      this.isHealthy = false;
      return false;
    }
  }

  async processData(data: any): Promise<any> {
    if (!this.isHealthy) {
      throw new Error('Backend server is not available');
    }

    const response = await fetch(`${this.baseUrl}/api/process`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ data })
    });

    if (!response.ok) {
      throw new Error(`Server error: ${response.statusText}`);
    }

    const result = await response.json();
    if (!result.success) {
      throw new Error(result.error || 'Unknown error');
    }

    return result.result;
  }

  private startHealthCheck(): void {
    // Initial check
    this.checkHealth();

    // Periodic checks
    setInterval(() => this.checkHealth(), 30000);
  }
}

Common Patterns

1. File Processing

// Server endpoint
app.post('/api/process-file', async (req, res) => {
  const { content, filename } = req.body;
  const result = await processFile(content, filename);
  res.json({ result });
});

// Plugin side
async processFile(file: TFile): Promise<any> {
  const content = await this.app.vault.read(file);
  return await this.backend.processData({
    content,
    filename: file.name
  });
}

2. Batch Processing

// Server with queue
import Queue from 'bull';
const processingQueue = new Queue('processing');

processingQueue.process(async (job) => {
  return processData(job.data);
});

app.post('/api/batch', async (req, res) => {
  const { items } = req.body;
  const jobs = await Promise.all(
    items.map(item => processingQueue.add(item))
  );
  res.json({ jobIds: jobs.map(j => j.id) });
});

3. Streaming Responses

// Server with streaming
app.get('/api/stream', (req, res) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const interval = setInterval(() => {
    res.write(`data: ${JSON.stringify({ time: Date.now() })}\n\n`);
  }, 1000);

  req.on('close', () => {
    clearInterval(interval);
  });
});

Development Workflow

  1. Start server in dev mode:
cd server
npm run dev
  1. Test endpoints:
curl http://localhost:3000/health
curl -X POST http://localhost:3000/api/process \
  -H "Content-Type: application/json" \
  -d '{"data": "test"}'
  1. Build for production:
npm run build
npm start

Docker Deployment (Optional)

Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]

docker-compose.yml

version: '3.8'
services:
  server:
    build: ./server
    ports:
      - "3000:3000"
    environment:
      - PORT=3000
      - NODE_ENV=production
    restart: unless-stopped

Best Practices

  1. Always include health check endpoint
  2. Use proper error handling
  3. Add request timeout handling
  4. Validate input data
  5. Use environment variables for config
  6. Add logging for debugging
  7. Consider rate limiting for production
  8. Use CORS appropriately

Security Considerations

  1. Validate all input
  2. Use HTTPS in production
  3. Implement authentication if needed
  4. Sanitize file paths
  5. Limit request sizes
  6. Add rate limiting

When creating a backend:

  1. Ask what processing is needed
  2. Choose appropriate tech stack
  3. Create server structure
  4. Implement endpoints
  5. Create plugin-side service
  6. Test integration
  7. Provide deployment instructions