Back to skills
SkillHub ClubShip Full StackFull StackBackend

stirling-pdf

PDF manipulation via Stirling-PDF API. Merge, split, convert, OCR, compress, sign, redact, and more. Self-hosted.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
3,129
Hot score
99
Updated
March 20, 2026
Overall rating
C4.0
Composite score
4.0
Best-practice grade
B80.4

Install command

npx @skill-hub/cli install openclaw-skills-stirling-pdf

Repository

openclaw/skills

Skill path: skills/angusthefuzz/stirling-pdf

PDF manipulation via Stirling-PDF API. Merge, split, convert, OCR, compress, sign, redact, and more. Self-hosted.

Open repository

Best for

Primary workflow: Ship Full Stack.

Technical facets: Full Stack, Backend.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: openclaw.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install stirling-pdf into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/openclaw/skills before adding stirling-pdf to shared team environments
  • Use stirling-pdf for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: stirling-pdf
description: PDF manipulation via Stirling-PDF API. Merge, split, convert, OCR, compress, sign, redact, and more. Self-hosted.
metadata:
  openclaw:
    emoji: πŸ“„
    requires:
      bins: [node, curl]
    env: {
      STIRLING_PDF_URL: "http://localhost:8080",
      STIRLING_API_KEY: "",
    }
---

# Stirling-PDF Skill

Self-hosted PDF manipulation platform with 60+ tools via REST API.

## Configuration

Set these environment variables:
- `STIRLING_PDF_URL` β€” Your Stirling-PDF instance URL (default: `http://localhost:8080`)
- `STIRLING_API_KEY` β€” API key if authentication is enabled

## Docs

- **Official docs:** https://docs.stirlingpdf.com
- **Swagger UI:** `<your-instance>/swagger-ui/index.html` on your deployment

## Quick Commands

```bash
# Use the wrapper script
node ~/.openclaw/skills/stirling-pdf/scripts/pdf.js <operation> [options]

# Examples:
node pdf.js merge file1.pdf file2.pdf -o merged.pdf
node pdf.js split input.pdf -o ./output-dir
node pdf.js compress input.pdf -o compressed.pdf
node pdf.js ocr input.pdf -o searchable.pdf
node pdf.js convert-to-pdf document.docx -o output.pdf
node pdf.js pdf-to-word input.pdf -o output.docx
node pdf.js add-watermark input.pdf "DRAFT" -o watermarked.pdf
```

## Available Operations

### Page Operations
- `merge` - Combine multiple PDFs
- `split` - Split PDF into parts
- `rotate` - Rotate pages
- `extract-pages` - Extract specific pages
- `reorder` - Reorganize pages

### Conversion
- `convert-to-pdf` - Word, Excel, Images, HTML β†’ PDF
- `pdf-to-word` - PDF β†’ Word
- `pdf-to-image` - PDF β†’ Images
- `pdf-to-text` - Extract text

### Content
- `compress` - Reduce file size
- `ocr` - Make scanned PDFs searchable
- `add-watermark` - Add text/image watermark
- `add-stamp` - Add stamp
- `redact` - Remove sensitive content
- `sign` - Add signature

### Security
- `add-password` - Password protect
- `remove-password` - Remove password
- `sanitize` - Remove metadata/scripts

## Direct API Usage

For operations not covered by the script, call the API directly:

```bash
curl -X POST "$STIRLING_PDF_URL/api/v1/general/merge-pdfs" \
  -H "X-API-KEY: $STIRLING_API_KEY" \
  -H "Content-Type: multipart/form-data" \
  -F "[email protected]" \
  -F "[email protected]" \
  -o merged.pdf
```

Check Swagger UI at `<your-instance>/swagger-ui/index.html` for all endpoints.

## Common Endpoints

| Operation | Endpoint |
|-----------|----------|
| Merge | `/api/v1/general/merge-pdfs` |
| Split | `/api/v1/general/split-pages` |
| Compress | `/api/v1/misc/compress-pdf` |
| OCR | `/api/v1/misc/ocr-pdf` |
| PDF to Image | `/api/v1/convert/pdf/img` |
| Image to PDF | `/api/v1/convert/img/pdf` |
| Add Watermark | `/api/v1/security/add-watermark` |
| Add Password | `/api/v1/security/add-password` |

## Notes

- Most endpoints use POST with multipart/form-data
- File input parameter is usually `fileInput`
- Response is the processed PDF file
- Check Swagger UI for exact parameters per operation


---

## Skill Companion Files

> Additional files collected from the skill directory layout.

### _meta.json

```json
{
  "owner": "angusthefuzz",
  "slug": "stirling-pdf",
  "displayName": "Stirling PDF",
  "latest": {
    "version": "1.0.4",
    "publishedAt": 1771083123902,
    "commit": "https://github.com/openclaw/skills/commit/32a519bd3f0ad55b3b4a5358366014d5202deaee"
  },
  "history": []
}

```

### scripts/pdf.js

```javascript
#!/usr/bin/env node
/**
 * Stirling-PDF CLI Wrapper
 * Usage: node pdf.js <operation> <input> [options]
 * 
 * Required environment variables:
 *   STIRLING_PDF_URL - Your Stirling-PDF instance URL
 *   STIRLING_API_KEY - API key (if authentication is enabled)
 */

const fs = require('fs');
const path = require('path');
const { spawn } = require('child_process');

// Config from environment only (no file fallback)
const BASE_URL = process.env.STIRLING_PDF_URL || 'http://localhost:8080';
const API_KEY = process.env.STIRLING_API_KEY || '';

const operations = {
  merge: {
    endpoint: '/api/v1/general/merge-pdfs',
    description: 'Merge multiple PDFs into one',
    multipleFiles: true
  },
  split: {
    endpoint: '/api/v1/general/split-pages',
    description: 'Split PDF into individual pages',
    multipleFiles: false
  },
  compress: {
    endpoint: '/api/v1/misc/compress-pdf',
    description: 'Reduce PDF file size',
    multipleFiles: false
  },
  ocr: {
    endpoint: '/api/v1/misc/ocr-pdf',
    description: 'Add OCR layer to scanned PDF',
    multipleFiles: false
  },
  'pdf-to-image': {
    endpoint: '/api/v1/convert/pdf/img',
    description: 'Convert PDF to images',
    multipleFiles: false
  },
  'image-to-pdf': {
    endpoint: '/api/v1/convert/img/pdf',
    description: 'Convert images to PDF',
    multipleFiles: true
  },
  'add-watermark': {
    endpoint: '/api/v1/security/add-watermark',
    description: 'Add watermark to PDF',
    multipleFiles: false,
    extraParams: ['watermarkText', 'fontSize', 'opacity', 'rotation']
  },
  'add-password': {
    endpoint: '/api/v1/security/add-password',
    description: 'Password protect PDF',
    multipleFiles: false,
    extraParams: ['password']
  },
  'remove-password': {
    endpoint: '/api/v1/security/remove-password',
    description: 'Remove password from PDF',
    multipleFiles: false,
    extraParams: ['password']
  },
  'pdf-to-word': {
    endpoint: '/api/v1/convert/pdf/word',
    description: 'Convert PDF to Word',
    multipleFiles: false
  },
  'word-to-pdf': {
    endpoint: '/api/v1/convert/file/pdf',
    description: 'Convert Word/Office to PDF',
    multipleFiles: false
  },
  'extract-text': {
    endpoint: '/api/v1/convert/pdf/text',
    description: 'Extract text from PDF',
    multipleFiles: false
  },
  info: {
    endpoint: '/api/v1/analysis/basic-info',
    description: 'Get PDF metadata/info',
    multipleFiles: false
  },
  'pdf-to-html': {
    endpoint: '/api/v1/convert/pdf/html',
    description: 'Convert PDF to HTML',
    multipleFiles: false
  },
  'html-to-pdf': {
    endpoint: '/api/v1/convert/html/pdf',
    description: 'Convert HTML to PDF',
    multipleFiles: false
  },
  'pdf-to-pdfa': {
    endpoint: '/api/v1/convert/pdf/pdfa',
    description: 'Convert PDF to PDF/A (archive)',
    multipleFiles: false
  },
  'add-stamp': {
    endpoint: '/api/v1/misc/add-stamp',
    description: 'Add stamp to PDF',
    multipleFiles: false
  },
  'rotate': {
    endpoint: '/api/v1/general/rotate-pdf',
    description: 'Rotate PDF pages',
    multipleFiles: false
  },
  'repair': {
    endpoint: '/api/v1/misc/repair',
    description: 'Repair corrupted PDF',
    multipleFiles: false
  },
  'sanitize': {
    endpoint: '/api/v1/security/sanitize-pdf',
    description: 'Sanitize PDF (remove metadata/scripts)',
    multipleFiles: false
  },
  'redact': {
    endpoint: '/api/v1/security/redact',
    description: 'Redact sensitive content',
    multipleFiles: false
  }
};

function printHelp() {
  console.log('Stirling-PDF CLI Wrapper\n');
  console.log('Usage: node pdf.js <operation> <input> [options]\n');
  console.log('Environment Variables:');
  console.log('  STIRLING_PDF_URL   - Your instance URL (default: http://localhost:8080)');
  console.log('  STIRLING_API_KEY   - API key if auth is enabled\n');
  console.log('Operations:');
  console.log('  merge           - Merge multiple PDFs');
  console.log('  split           - Split PDF into pages');
  console.log('  compress        - Reduce file size');
  console.log('  ocr             - Make scanned PDF searchable');
  console.log('  pdf-to-image    - Convert PDF to images');
  console.log('  image-to-pdf    - Convert images to PDF');
  console.log('  pdf-to-word     - Convert PDF to Word');
  console.log('  word-to-pdf     - Convert Word/Office to PDF');
  console.log('  pdf-to-html     - Convert PDF to HTML');
  console.log('  html-to-pdf     - Convert HTML to PDF');
  console.log('  pdf-to-pdfa     - Convert to PDF/A (archive)');
  console.log('  extract-text    - Extract text from PDF');
  console.log('  add-watermark   - Add watermark (-t "text")');
  console.log('  add-stamp       - Add stamp');
  console.log('  add-password    - Password protect (-p "pwd")');
  console.log('  remove-password - Remove password (-p "pwd")');
  console.log('  rotate          - Rotate pages');
  console.log('  repair          - Repair corrupted PDF');
  console.log('  sanitize        - Remove metadata/scripts');
  console.log('  redact          - Redact sensitive content');
  console.log('  info            - Get PDF metadata');
  console.log('\nOptions:');
  console.log('  -o, --output <file>   Output file path');
  console.log('  -p, --password <pwd>  Password');
  console.log('  -t, --text <text>     Watermark text');
  console.log('  --help                Show this help');
}

function parseArgs(args) {
  const result = {
    operation: null,
    files: [],
    output: null,
    extra: {}
  };

  let i = 0;
  while (i < args.length) {
    const arg = args[i];
    if (arg === '-o' || arg === '--output') {
      result.output = args[++i];
    } else if (arg === '-p' || arg === '--password') {
      result.extra.password = args[++i];
    } else if (arg === '-t' || arg === '--text') {
      result.extra.watermarkText = args[++i];
    } else if (arg === '--help' || arg === '-h') {
      printHelp();
      process.exit(0);
    } else if (!arg.startsWith('-')) {
      if (!result.operation) {
        result.operation = arg;
      } else {
        result.files.push(arg);
      }
    }
    i++;
  }

  return result;
}

function runCurl(op, files, output, extra = {}) {
  return new Promise((resolve, reject) => {
    const args = ['-s', '-X', 'POST', `${BASE_URL}${op.endpoint}`];
    
    // Add headers
    args.push('-H', 'Content-Type: multipart/form-data');
    if (API_KEY) {
      args.push('-H', `X-API-KEY: ${API_KEY}`);
    }

    // Add file inputs
    for (const file of files) {
      const absPath = path.resolve(file);
      if (!fs.existsSync(absPath)) {
        reject(new Error(`File not found: ${file}`));
        return;
      }
      args.push('-F', `fileInput=@${absPath}`);
    }

    // Add extra parameters
    for (const [key, value] of Object.entries(extra)) {
      if (value !== undefined && value !== null) {
        args.push('-F', `${key}=${value}`);
      }
    }

    // Default extra params for specific operations
    if (op.endpoint.includes('ocr')) {
      args.push('-F', 'languages=eng');
    }
    if (op.endpoint.includes('add-watermark')) {
      if (!extra.watermarkText) {
        reject(new Error('Watermark text required. Use -t "your text"'));
        return;
      }
      if (!extra.fontSize) args.push('-F', 'fontSize=30');
      if (!extra.opacity) args.push('-F', 'opacity=0.5');
      if (!extra.rotation) args.push('-F', 'rotation=45');
    }

    // Output
    if (output) {
      args.push('-o', path.resolve(output));
    }

    const curl = spawn('curl', args);
    
    let stderr = '';
    curl.stderr.on('data', (data) => {
      stderr += data.toString();
    });

    curl.on('close', (code) => {
      if (code === 0) {
        if (output) {
          console.log(`βœ… Output saved to: ${output}`);
        }
        resolve();
      } else {
        reject(new Error(`curl exited with code ${code}: ${stderr}`));
      }
    });

    curl.on('error', (err) => {
      reject(err);
    });

    // Pipe stdout to process stdout for non-file output
    if (!output) {
      curl.stdout.pipe(process.stdout);
    }
  });
}

async function main() {
  const args = process.argv.slice(2);

  if (args.length === 0) {
    printHelp();
    process.exit(0);
  }

  const parsed = parseArgs(args);

  if (!parsed.operation) {
    console.error('Error: No operation specified');
    printHelp();
    process.exit(1);
  }

  const op = operations[parsed.operation];
  if (!op) {
    console.error(`Error: Unknown operation "${parsed.operation}"`);
    console.log('Run with --help for available operations');
    process.exit(1);
  }

  if (parsed.files.length === 0) {
    console.error('Error: No input files specified');
    process.exit(1);
  }

  try {
    await runCurl(op, parsed.files, parsed.output, parsed.extra);
  } catch (error) {
    console.error('Error:', error.message);
    process.exit(1);
  }
}

main();

```

stirling-pdf | SkillHub