https://github.com/fmueller/scribae
CLI to turn Markdown notes into SEO briefs, drafts, metadata, and translations using LLMs.
https://github.com/fmueller/scribae
ai-tools cli content-generation knowledge-management llm machine-translation markdown nlp python seo text-generation transformers
Last synced: 5 months ago
JSON representation
CLI to turn Markdown notes into SEO briefs, drafts, metadata, and translations using LLMs.
- Host: GitHub
- URL: https://github.com/fmueller/scribae
- Owner: fmueller
- License: apache-2.0
- Created: 2025-11-06T21:29:40.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-02-18T18:44:18.000Z (5 months ago)
- Last Synced: 2026-02-18T19:52:51.330Z (5 months ago)
- Topics: ai-tools, cli, content-generation, knowledge-management, llm, machine-translation, markdown, nlp, python, seo, text-generation, transformers
- Language: Python
- Homepage:
- Size: 908 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# Scribae
[](https://github.com/fmueller/scribae/actions/workflows/build.yml)
[](https://pypi.org/project/scribae/)
[](https://pypi.org/project/scribae/)
[](https://github.com/fmueller/scribae/blob/main/LICENSE)
> *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
Run Scribae without installing it:
```bash
uvx scribae --help
```
Run with translation support enabled:
```bash
uvx "scribae[translation]" --help
```
> **Note:** `uvx` creates a temporary environment on each run. With the translation extra, this downloads PyTorch (~2GB) every time. For repeated use, install with pipx or pip instead.
Install it globally with an isolated environment using `uv`:
```bash
uv tool install scribae
```
Or using `pipx`:
```bash
pipx install scribae
```
Or use pip directly:
```bash
pip install scribae
```
### Translation support
Translation uses PyTorch and Hugging Face Transformers. Install with the translation extra:
```bash
pip install scribae[translation]
```
Prefer a CPU-only PyTorch wheel with pipx:
```bash
pipx install "scribae[translation]" --pip-args="--index-url https://download.pytorch.org/whl/cpu"
```
## Prerequisites
Scribae requires an **OpenAI-compatible API endpoint**. The easiest option is [Ollama](https://ollama.com) running locally:
```bash
# 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:
```bash
export OPENAI_BASE_URL="https://api.openai.com/v1"
export OPENAI_API_KEY="sk-..."
```
## Quick start
1. **Generate ideas** from a Markdown note:
```bash
scribae idea --note my-notes.md --json
```
2. **Create an SEO brief** from your note:
```bash
scribae brief --note my-notes.md --out brief.json
```
3. **Write a draft** using the brief:
```bash
scribae write --note my-notes.md --brief brief.json --out draft.md
```
4. **Add metadata** to your draft:
```bash
scribae meta --body draft.md --brief brief.json --format frontmatter --out draft.md
```
5. **Translate** to another language:
```bash
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 → feedback → refine → 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. **feedback** — Review a draft against a brief and generate a focused improvement report.
5. **refine** — Improve a draft against a brief while preserving intent and structure.
6. **meta** — Create publication metadata/frontmatter for a finished draft.
7. **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:
```yaml
site_name: My Blog
domain: https://example.com
audience: developers interested in Python
tone: conversational
language: en
keywords:
- python
- programming
```
### LLM settings
All commands that use LLMs support `--temperature`, `--top-p`, and `--seed` for controlling output variability:
| Option | Default | Description |
|--------|---------|-------------|
| `--temperature` | 0.2–0.4 | Sampling temperature. Lower values produce more deterministic output. |
| `--top-p` | (none) | Nucleus sampling threshold. Set to `1.0` for full distribution. |
| `--seed` | (none) | Random seed for reproducible outputs. |
For fully deterministic output, set `--temperature 0`. For reproducible creative output, combine `--seed` with `--top-p 1.0`.
```bash
# Deterministic mode
scribae brief --note notes.md --temperature 0 --out brief.json
# Reproducible creative mode
scribae write --note notes.md --brief brief.json --seed 42 --top-p 1.0 --out draft.md
```
The `translate` command uses `--postedit-temperature`, `--postedit-top-p`, and `--postedit-seed` for the LLM post-edit pass.
> **Note:** Seed behavior depends on the underlying model. Some models (e.g., certain Ollama models) may not fully support deterministic output even with `--seed` set. For guaranteed reproducibility, test with your specific model and endpoint.
## Usage examples
### Idea discovery
Start with a note and generate a structured list of candidate articles:
```bash
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:
```bash
# 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:
```bash
# 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:
```bash
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:
```bash
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
The `--all-extras` flag is required for development as it installs PyTorch, which is needed for mypy type checking to pass.
```bash
git clone https://github.com/fmueller/scribae.git
cd scribae
uv sync --locked --all-extras --dev
```
For CPU-only PyTorch (~200MB vs ~2GB):
```bash
uv sync --locked --all-extras --dev --index pytorch-cpu
```
### Running from source
```bash
uv run scribae --help
```
### Testing
```bash
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](LICENSE) for details.