Files
outline-sync/RALPH_PROMPT.md
Claude d9161f64f5 Initial commit: Export tools and import script requirements
- export_with_trees.sh: Bash wrapper for Outline export
- outline_export_fixed.py: Python export implementation
- IMPORT_SCRIPT.MD: PRD for import script (to be built)
- RALPH_PROMPT.md: Ralph Loop prompt for building import script
- CLAUDE.md: Project documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 22:33:55 +01:00

6.0 KiB

Outline Import Script - Ralph Loop Prompt

Your Mission

Build import_to_outline.sh and outline_import.py - companion scripts to the existing export tools that import markdown files back into Outline wiki.

Requirements Document: Read IMPORT_SCRIPT.MD for full specifications.

Reference Implementation: Study export_with_trees.sh and outline_export_fixed.py for patterns.


Iteration Protocol

Each iteration, follow this cycle:

1. Assess Current State

# Check what exists
ls -la *.sh *.py 2>/dev/null
git status
git log --oneline -5 2>/dev/null || echo "No git history"

2. Read Requirements (if needed)

  • Review IMPORT_SCRIPT.MD for specifications
  • Review outline_export_fixed.py for API patterns and settings.json structure
  • Review settings.json for configuration format

3. Implement Next Phase

Work on the current phase until complete, then move to the next.

4. Test Your Work

  • Run syntax checks: python3 -m py_compile outline_import.py
  • Run bash checks: bash -n import_to_outline.sh
  • Test --help output
  • Test --dry-run mode against outline_export/ directory

5. Commit Progress

git add -A && git commit -m "Phase X: description"

Implementation Phases

Phase 1: Core Python Structure

Create outline_import.py with:

  • OutlineImporter class with settings loading (copy pattern from outline_export_fixed.py)
  • API helper methods: _api_request(), _get_collections(), _create_collection()
  • Argument parsing with all CLI options from spec
  • Basic logging setup

Verification: python3 -m py_compile outline_import.py passes

Phase 2: Metadata Loading

  • Load _collection_metadata.json from each collection directory
  • Build document tree from documents array
  • Implement topological sort for parent-before-child ordering
  • Handle missing/invalid metadata gracefully

Verification: Can parse metadata from outline_export/*/

Phase 3: Collection Import Logic

  • Check if collection exists via /api/collections.list
  • Create collection via /api/collections.create
  • Handle --force mode (delete and recreate)
  • Skip existing collections by default

Verification: --dry-run shows correct collection operations

Phase 4: Document Import with Hierarchy

  • Read markdown content from files
  • Create documents via /api/documents.create
  • Maintain ID mapping: old_id -> new_id
  • Set parentDocumentId using mapped IDs
  • Handle missing parent (create as root-level)

Verification: --dry-run shows correct document hierarchy

Phase 5: Single Collection Mode

  • Implement --single flag
  • Create timestamped collection name import_YYYYMMDD_HHMMSS
  • Convert original collection folders to parent documents
  • Preserve nested hierarchy under these parents

Verification: --dry-run --single shows consolidated structure

Phase 6: Progress Visualization

  • Tree-style output matching spec (├──, └──, │)
  • Status indicators (✓ created, ✗ error, ○ skipped)
  • Summary statistics (collections/documents created/skipped/errors)
  • Duration tracking

Verification: Output matches examples in IMPORT_SCRIPT.MD Section 7

Phase 7: Bash Wrapper Script

Create import_to_outline.sh with:

  • Docker execution (matching export_with_trees.sh pattern)
  • CLI argument passthrough
  • Help text
  • Pre-flight checks (settings.json exists, source directory exists)

Verification: ./import_to_outline.sh --help works

Phase 8: Error Handling & Polish

  • Retry logic for API failures (3 attempts, exponential backoff)
  • Proper error messages for all failure modes
  • Rate limiting delay between API calls
  • Verbose/debug output levels

Verification: All error scenarios from spec handled


Success Criteria

All of the following must be true:

  1. Files exist: import_to_outline.sh and outline_import.py
  2. Syntax valid: Both pass syntax checks without errors
  3. Help works: ./import_to_outline.sh --help shows usage
  4. Dry-run works: ./import_to_outline.sh --dry-run parses outline_export/ and shows planned operations
  5. Single mode: ./import_to_outline.sh --dry-run --single shows consolidated import plan
  6. Matches spec: Output format matches IMPORT_SCRIPT.MD Section 7 examples

Completion Signal

When ALL success criteria are met, output:

<promise>IMPORT SCRIPT COMPLETE</promise>

Do not output this promise until:

  • Both files exist and pass syntax checks
  • --help displays properly
  • --dry-run successfully parses metadata and shows planned operations
  • Output format matches the specification

Anti-Patterns to Avoid

  1. Don't skip phases - Complete each phase before moving on
  2. Don't forget commits - Commit after each successful phase
  3. Don't ignore errors - Fix syntax/import errors before proceeding
  4. Don't deviate from spec - Follow IMPORT_SCRIPT.MD precisely
  5. Don't over-engineer - Implement exactly what's specified, no more

Helpful Context

API Endpoint Examples (from spec)

# Create collection
POST /api/collections.create
{"name": "Bewerbungen", "permission": "read_write"}

# Create document
POST /api/documents.create
{
  "collectionId": "col-uuid",
  "title": "Document Title",
  "text": "# Content\n\nMarkdown here...",
  "parentDocumentId": "parent-uuid-or-null",
  "publish": true
}

Docker Execution Pattern

docker run --rm --network domnet \
    --user "$(id -u):$(id -g)" \
    -e HOME=/tmp \
    -v "$WORK_DIR:/work" \
    -w /work \
    python:3.11-slim \
    bash -c "pip install -qqq requests 2>/dev/null && python3 outline_import.py $CLI_ARGS"

Settings Structure (existing in settings.json)

{
  "source": {
    "url": "http://outline:3000",
    "token": "ol_api_xxx"
  }
}

Current Iteration

Read the files, check git history, determine which phase you're on, and continue from there.

If starting fresh: Begin with Phase 1.