CLI that turns local Markdown notes into structured SEO content packages using LLMs while keeping the human in the loop.
Project description
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
-
Generate ideas from a Markdown note:
scribae idea --note my-notes.md --json
-
Create an SEO brief from your note:
scribae brief --note my-notes.md --out brief.json
-
Write a draft using the brief:
scribae write --note my-notes.md --brief brief.json --out draft.md
-
Add metadata to your draft:
scribae meta --body draft.md --brief brief.json --format frontmatter --out draft.md
-
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
- idea — Brainstorm article ideas from a note with project-aware guidance.
- brief — Generate a validated SEO brief (keywords, outline, FAQ, metadata).
- write — Produce an article draft using your note, project context, and brief.
- meta — Create publication metadata/frontmatter for a finished draft.
- 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: en↔de/es/fr/it/pt, de→es/fr/it/pt, es→de/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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scribae-0.1.0.tar.gz.
File metadata
- Download URL: scribae-0.1.0.tar.gz
- Upload date:
- Size: 55.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7f86decd71a5b71be7292fdf17b1403800fb9580704f72a0d55dad613f9543c
|
|
| MD5 |
2d394494c07ff8940671ee76a74eda21
|
|
| BLAKE2b-256 |
2a101d96a0465e2eb2590ed94682c06969d483aaa26db66899e40bd34dc57b72
|
File details
Details for the file scribae-0.1.0-py3-none-any.whl.
File metadata
- Download URL: scribae-0.1.0-py3-none-any.whl
- Upload date:
- Size: 68.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2750bd7de3ac880bab2edfb84e2f9174792ea2daf8dfbc3523f839693b5d409d
|
|
| MD5 |
b091465ebea41b5d3f6d980c859d2c7b
|
|
| BLAKE2b-256 |
03ca0fa403597c897b33ae0f40a93f91b3d95b41ac6fcb793aac127e1f9c3494
|