Article Exporter logo

Article Exporter

OrganizationPopular
actionbook
article-exporter

Export any web article to a local Obsidian-ready Markdown directory. Fetches page content via actionbook CLI, downloads images locally, rewrites image references to relative paths, and optionally translates the article using AI. Produces a self-contained folder with README.md, images/, and an index.md navigation file.

Overview

Publisheractionbook
Repositoryactionbook
Skill namearticle-exporter
Stars
1.6K
Forks
120
Bundled files
7
LicenseApache-2.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 7 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by actionbook on GitHub. Read the source before you install it.

Installation

Install the Article Exporter AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/actionbook/actionbook/tree/main/playground/article-exporter
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/actionbook/actionbook.git /tmp/actionbook
mkdir -p .claude/skills
cp -r /tmp/actionbook/playground/article-exporter .claude/skills/article-exporter
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Article Exporter in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Article Exporter on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Article Exporter is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Article Exporter - Export Articles to Obsidian

Version: 0.5.0 | Last Updated: 2026-03-13

You are an expert at web content archiving and Obsidian workflow automation.

Lessons from Failed Exports

These rules were extracted from real export failures. Each one prevents a specific class of error:

  1. Twitter/X needs AI reformatting — fetch returns flat text because Twitter uses custom UI without semantic HTML. The AI reformatting step reconstructs headings, lists, and code blocks. See references/twitter-handling.md.
  2. Ask for output path first — users have different vault locations. Assuming a default creates files in the wrong place and wastes time moving them.
  3. Check actionbook version >= 0.9.1 — the --wait-hint parameter was added in 0.9.1. Without it, dynamic content (SPAs, lazy-loaded pages) returns empty or partial results.
  4. Wait after navigation — use --wait-hint heavy for Twitter, Medium, and other dynamic sites. Without it, the page hasn't finished rendering when content is extracted.
  5. Rate limit batch exports — 3-5s delay between requests prevents being flagged as a bot (ToS compliance).

Quick Reference

TaskCommandSuccess Criteria
Check depsactionbook --versionShows version >= 0.9.1
Fetch articleactionbook browser fetch <url> --wait-hint heavyReturns plain text (AI reformats to Markdown in Step 1b)
TranslateAI session directlyREADME_CN.md created
Open in Obsidianobsidian-cli open "path/index.md"File opens in Obsidian

Complete Export Workflow

Goal: Export web article to Obsidian directory with images and optional translation

Success criteria:

  • Article directory created with README.md
  • All images downloaded to images/
  • index.md navigation file created
  • Optional: README_CN.md translation
  • Opened in Obsidian (if obsidian-cli available)

Step 1: Fetch Article Content

Execution: Direct (Bash)

bash
# Fetch article as readability text (with log cleaning)
actionbook browser fetch "$URL" --wait-hint heavy 2>/dev/null | \
  sed '/^[[:space:]]*$/d;/^\x1b\[/d;/^INFO/d' > /tmp/article_raw.txt

Success criteria:

  • /tmp/article_raw.txt exists and size > 0 bytes
  • Content contains the article's main text

The fetch command returns readability-extracted plain text (not Markdown). AI reformatting in Step 1b is always needed to produce proper Markdown.

Rules:

  • Use --wait-hint heavy for Twitter, Medium, dynamic content
  • Use --wait-hint light for static blogs
  • 2>/dev/null suppresses stderr logs
  • sed removes ANSI codes, INFO lines, empty lines

Twitter/X Special Handling

Twitter uses non-semantic HTML, so fetch output loses all structure (headings become flat text, code blocks disappear). If the URL contains x.com or twitter.com, pay extra attention to structure reconstruction in Step 1b. See references/twitter-handling.md.


Step 1b: AI Reformat to Markdown

Execution: Direct (AI session)

Read /tmp/article_raw.txt and convert the plain text into well-structured Markdown. Save the result to /tmp/article.md.

Reformatting rules:

  • Reconstruct headings (#, ##, ###) from the text structure
  • Preserve original image URLs as ![alt](url) references
  • Format code blocks, lists, tables, and blockquotes
  • Keep the original article title as the first # H1 heading

Success criteria:

  • /tmp/article.md exists and starts with # <Title>
  • Image URLs are preserved as Markdown image syntax

Step 2: Extract Metadata

Execution: Direct (Bash)

bash
# Extract title (first H1 heading from AI-reformatted markdown)
TITLE=$(grep -m 1 "^# " /tmp/article.md | sed 's/^# //')

# Extract image URLs (filter out data: URLs)
IMAGE_URLS=$(grep -o '!\[[^]]*\]([^)]*)' /tmp/article.md | \
    sed -E 's/!\[[^]]*\]\(([^)]*)\)/\1/' | \
    grep -v '^data:')

Success criteria:

  • $TITLE is non-empty
  • $IMAGE_URLS count matches expected (use wc -l)

Step 3: Ask Output Directory

Execution: [human] Human checkpoint: Confirm output location before creating files

Ask user: "Where should I save the exported article?"

Suggested paths:

  • ~/Work/Write/Articles (default)
  • ~/Documents/Obsidian/Articles
  • ~/Notes/Imported
  • (or custom path from $output_dir argument)

Success criteria: User confirms output directory

Artifacts: $OUTPUT_DIR variable set


Step 4: Create Directory Structure

Execution: Direct (Bash)

bash
# Use argument if provided, otherwise use confirmed path
OUTPUT_DIR="${output_dir:-$USER_CONFIRMED_PATH}"

# Sanitize title for directory name
SAFE_TITLE=$(echo "$TITLE" | sed 's/[/:*?"<>|]//g' | cut -c1-100 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

# Create output directory
ARTICLE_DIR="$OUTPUT_DIR/$SAFE_TITLE"
mkdir -p "$ARTICLE_DIR/images"

Success criteria:

  • Directory $ARTICLE_DIR exists
  • Subdirectory images/ exists
  • Directory is writable

Rules:

  • Remove special characters: / : * ? " < > |
  • Limit title length to 100 characters
  • Trim leading/trailing whitespace

Step 5: Download Images (Parallel if possible)

Execution: Direct (Bash)

bash
counter=1
for url in $IMAGE_URLS; do
    ext=$(echo "$url" | grep -oE '\.(jpg|jpeg|png|gif|webp|svg)' || echo ".jpg")
    curl -L -s "$url" -o "$ARTICLE_DIR/images/image_${counter}${ext}"

    # Check file size (detect 0-byte failures)
    if [ ! -s "$ARTICLE_DIR/images/image_${counter}${ext}" ]; then
        # Try alternative format (Twitter)
        curl -L -s "${url}?format=jpg&name=orig" -o "$ARTICLE_DIR/images/image_${counter}.jpg"
    fi

    counter=$((counter + 1))
done

Success criteria:

  • All image files exist and size > 0 bytes
  • File count matches $IMAGE_URLS count

Rules:

  • Use curl -L to follow redirects
  • Check file size after download
  • Try alternative formats for Twitter images

Step 6: Update Image References

Execution: Direct (Bash)

bash
# Replace remote URLs with local paths
counter=1
for url in $IMAGE_URLS; do
    ext=$(echo "$url" | grep -oE '\.(jpg|jpeg|png|gif|webp|svg)' || echo ".jpg")
    sed -i.bak "s|$url|./images/image_${counter}${ext}|g" /tmp/article.md
    counter=$((counter + 1))
done

# Save updated markdown
cp /tmp/article.md "$ARTICLE_DIR/README.md"
rm /tmp/article.md.bak

Success criteria:

  • README.md contains ./images/image_N.* references
  • No remote URLs remain in image links

Step 7: AI Translation (Optional)

Execution: Direct (AI session)

Human checkpoint: Ask user: "Do you want to translate the article? (y/n)"

If yes:

  1. Read $ARTICLE_DIR/README.md
  2. Translate using AI capabilities (no external API)
  3. Write to $ARTICLE_DIR/README_CN.md (or other language code)

Translation Prompt Template:

Translate the following Markdown article to [LANGUAGE] while preserving:
- All Markdown formatting (headings, lists, code blocks, tables)
- Image references exactly as-is: ![alt](./images/image_N.*)
- Links and URLs unchanged
- Code blocks and technical terms in original language

Only output the translated Markdown content.

---
[Paste README.md content]

Success criteria: Translation file exists and size ≈ original ± 20%

Supported languages: en, zh, es, fr, de, ja, ko


Step 8: Create Navigation Index

Execution: Direct (Bash)

bash
# Auto-detect source from URL
case "$URL" in
    *x.com*|*twitter.com*) SOURCE="X" ;;
    *medium.com*) SOURCE="Medium" ;;
    *dev.to*) SOURCE="Dev.to" ;;
    *openai.com*) SOURCE="OpenAI Blog" ;;
    *substack.com*) SOURCE="Substack" ;;
    *github.com*) SOURCE="GitHub" ;;
    *) SOURCE=$(echo "$URL" | sed 's|https\?://||' | cut -d/ -f1) ;;
esac

# Create index.md
cat > "$ARTICLE_DIR/index.md" <<EOF
# $TITLE

> **Export Date**: $(date +%Y-%m-%d)
> **Original URL**: $URL
> **Source**: $SOURCE

## 📚 Language Versions

- 🇬🇧 **English**: [[README]]
- 🇨🇳 **Chinese**: [[README_CN]]  <!-- if translated -->

## 📊 Metadata

| Property | Value |
|----------|-------|
| **Source** | $SOURCE |
| **Images** | $(ls images/ 2>/dev/null | wc -l) images |
| **Export Tool** | actionbook CLI |
| **Export Date** | $(date +%Y-%m-%d) |

---

**Exported using**: actionbook browser automation + AI assistant
EOF

Success criteria: index.md exists with metadata table


Step 9: Open in Obsidian

Execution: Direct (Bash)

bash
if command -v obsidian-cli &> /dev/null; then
    VAULT_ROOT="$OUTPUT_DIR"
    REL_PATH=$(echo "$ARTICLE_DIR" | sed "s|$VAULT_ROOT/||")
    obsidian-cli open "$REL_PATH/index.md"
    echo "✓ Opened in Obsidian: $REL_PATH/index.md"
else
    # Fallback: Open in file manager
    case "$(uname)" in
        Darwin)  open "$ARTICLE_DIR" ;;
        Linux)   xdg-open "$ARTICLE_DIR" ;;
        CYGWIN*|MINGW*|MSYS*) start "$ARTICLE_DIR" ;;
    esac
    echo "⚠️  Install obsidian-cli for automatic opening: npm install -g obsidian-cli"
fi

Success criteria:

  • File opens in Obsidian OR directory opens in file manager
  • User sees success message

Step 10: Report Success

Execution: Direct (Output)

bash
echo ""
echo "════════════════════════════════════════════"
echo "✓ Article exported successfully!"
echo ""
echo "📁 Location: $ARTICLE_DIR"
echo "📄 Files:"
echo "     - README.md (original)"
[ -f "$ARTICLE_DIR/README_CN.md" ] && echo "     - README_CN.md (translation)"
echo "     - index.md (navigation)"
echo "🖼️  Images: $(ls images/ 2>/dev/null | wc -l) files"
echo "════════════════════════════════════════════"

Common Issues

IssueCauseSolution
"actionbook: command not found"CLI not installednpm install -g @actionbookdev/cli@latest
"unknown flag: --wait-hint"Version < 0.9.1Upgrade: npm install -g @actionbookdev/cli@latest
Twitter format brokenfetch loses structureUse AI reformatting (see references/twitter-handling.md)
Images 0 bytesURL expiredTry ?format=jpg&name=orig
obsidian-cli not foundNot installednpm install -g obsidian-cli
Batch export blockedToo fast, flagged as botAdd 3-5s sleep between requests

Detailed troubleshooting: See ./references/troubleshooting.md


Edge Cases Handled

  • Long titles → Auto-truncate to 100 chars
  • Special characters → Sanitized (/ : * ? " < > | removed)
  • No images → Steps 5-6 skip gracefully
  • 0-byte images → Auto-retry with alternative formats
  • Data URLs → Filtered out in Step 2

When Using This Skill

  1. Check dependencies first — actionbook --version >= 0.9.1
  2. Test with one article — Verify before batch processing
  3. Twitter/X requires special handling — See references/twitter-handling.md
  4. Respect ToS — Personal use only, rate limit batch exports

References (Progressive Disclosure)

For detailed documentation, see:

  • ./references/twitter-handling.md — Twitter/X special handling (AI reformatting)
  • ./references/batch-export.md — Batch export with rate limiting
  • ./references/troubleshooting.md — Detailed troubleshooting guide
  • ./references/obsidian-setup.md — obsidian-cli setup and configuration
  • ./references/supported-websites.md — Complete website compatibility list

Last Updated: 2026-03-13 | Version: 0.5.0

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Article Exporter AI skill do?

Export any web article to a local Obsidian-ready Markdown directory. Fetches page content via actionbook CLI, downloads images locally, rewrites image references to relative paths, and optionally translates the article using AI. Produces a self-contained folder with README.md, images/, and an index.md navigation file.

Why use Article Exporter on TypingMind?

Because you install it once and use it with any model. Article Exporter is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Article Exporter in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/actionbook/actionbook/tree/main/playground/article-exporter. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Article Exporter?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Article Exporter?

As many as you like. As long as a model supports skills, you can use Article Exporter with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Article Exporter AI skill free?

Yes. It is published on GitHub by actionbook under the Apache-2.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇