Skip to content

CLI to turn Markdown notes into SEO briefs, drafts, metadata, and translations using LLMs.

License

Notifications You must be signed in to change notification settings

fmueller/scribae

Repository files navigation

Build

Scribae

From Latin scribae, "the scribes." The professional copyists and secretaries of the ancient world.

Scribae is a CLI that turns local Markdown notes into structured SEO content packages with human-in-the-loop review. It keeps the research-to-publication flow reproducible by combining deterministic prompts, typed outputs, and LLMs via OpenAI-compatible APIs.

Why Scribae?

  • Keep source material local. Point the CLI at a Markdown note and run everything against an OpenAI-compatible API endpoint you control.
  • Human in the loop. Each stage is designed for review and editing before you publish.
  • Repeatable prompts. Each command builds structured prompts and validates model responses to catch schema drift early.
  • End-to-end workflow. Move from ideation to translation within one tool instead of juggling separate scripts.

Installation

pip install scribae

Or with pipx for isolated installation:

pipx install scribae

Translation support

Translation uses PyTorch and Hugging Face Transformers. Install with the translation extra:

pip install scribae[translation]

Prerequisites

Scribae requires an OpenAI-compatible API endpoint. The easiest option is Ollama running locally:

# Install Ollama (see https://ollama.com for other platforms)
curl -fsSL https://ollama.com/install.sh | sh

# Start the server
ollama serve

# Pull the default model
ollama pull ministral-3:8b

Alternatively, point Scribae at any OpenAI-compatible endpoint:

export OPENAI_BASE_URL="https://api.openai.com/v1"
export OPENAI_API_KEY="sk-..."

Quick start

  1. Generate ideas from a Markdown note:

    scribae idea --note my-notes.md --json
  2. Create an SEO brief from your note:

    scribae brief --note my-notes.md --out brief.json
  3. Write a draft using the brief:

    scribae write --note my-notes.md --brief brief.json --out draft.md
  4. Add metadata to your draft:

    scribae meta --body draft.md --brief brief.json --format frontmatter --out draft.md
  5. Translate to another language:

    scribae translate --src en --tgt de --in draft.md --out draft.de.md

Run scribae --help to see all commands and options.

Core workflow

idea → brief → write → meta → translate
  1. idea — Brainstorm article ideas from a note with project-aware guidance.
  2. brief — Generate a validated SEO brief (keywords, outline, FAQ, metadata).
  3. write — Produce an article draft using your note, project context, and brief.
  4. meta — Create publication metadata/frontmatter for a finished draft.
  5. translate — Translate Markdown using MT + LLM post-edit while preserving formatting.

Configuration

Environment variables

Variable Default Description
OPENAI_BASE_URL http://localhost:11434/v1 API endpoint URL
OPENAI_API_KEY no-key API key (not needed for Ollama)

You can also use OPENAI_API_BASE as an alternative to OPENAI_BASE_URL.

Project files

Create a scribae.yaml in your project directory to set defaults:

site_name: My Blog
domain: https://example.com
audience: developers interested in Python
tone: conversational
language: en
keywords:
  - python
  - programming

Usage examples

Idea discovery

Start with a note and generate a structured list of candidate articles:

scribae idea --note notes.md --project demo --out ideas.json

Use --language or --model to override project defaults, and --dry-run to preview the prompt without calling the model.

SEO brief creation

Convert a note into a validated brief, optionally anchored to a specific idea:

# From a note directly
scribae brief --note notes.md --out brief.json

# From a specific idea
scribae brief --note notes.md --ideas ideas.json --idea-index 1 --out brief.json

# Generate briefs for all ideas
scribae brief --note notes.md --ideas ideas.json --idea-all --out-dir briefs/

Draft writing

Turn a note + brief into a draft:

# Full article
scribae write --note notes.md --brief brief.json --out draft.md

# Only sections 1-3
scribae write --note notes.md --brief brief.json --section 1..3 --out draft.md

# Require citations
scribae write --note notes.md --brief brief.json --evidence required --out draft.md

Metadata generation

Create JSON frontmatter or merge into an existing draft:

scribae meta --body draft.md --brief brief.json --format both --out meta.json

Use --overwrite to control how existing fields are preserved.

Translation

Translate Markdown while preserving structure:

scribae translate --src en --tgt de --in draft.md --out draft.de.md

Options:

  • --glossary — Lock specific terminology
  • --postedit / --no-postedit — Toggle LLM cleanup pass
  • --allow-pivot — Enable English pivoting for unsupported language pairs
  • --debug — Write detailed translation report

Supported language pairs

Direct MarianMT pairs: ende/es/fr/it/pt, dees/fr/it/pt, esde/fr/it/pt

Pivoting: When no direct pair exists and --allow-pivot is enabled, Scribae routes through English (src → en → tgt).

NLLB fallback: For other pairs, the pipeline falls back to NLLB. Standard ISO codes (en, de, es) are mapped automatically, or pass NLLB codes directly (eng_Latn, deu_Latn).

Development

Setup

git clone https://github.com/fmueller/scribae.git
cd scribae
uv sync --locked --all-extras --dev

For CPU-only PyTorch (~200MB vs ~2GB):

uv sync --locked --all-extras --dev --index pytorch-cpu

Running from source

uv run scribae --help

Testing

uv run ruff check   # Lint
uv run mypy         # Type check
uv run pytest       # Run tests

License

This project is licensed under the Apache License 2.0. See LICENSE for details.