Skip to main content

unit-text

Unit tests for plain text

CI

unit-text logo


Don't let LLMs write blog posts for you. Do your research, bring your own voice, and use LLMs to criticise and iterate on your writing.

🤌 Why unit-text?

If you're a developer like us:

  • You're probably aware you should write more (either because your leadership asks for it, or because you'd like to be invited as a conference speaker, or ...)
  • You don't know what to write about.
  • You have considered letting ChatGPT write blog posts for you.

If you tried the last option (or read anything on the Internet in the past 2 years) you would also know why it's not really that good of an idea.

Sure, you may get a perfectly good post, but it won't be your own.

unit-text applies the concept of unit tests to prose. You are the one writing, the LLM is just your critic.

First, you define a goal, the audience you have in mind, and what you wanted them to do differently after they read your post. Then, you start writing and iterating on your draft. unit-text gives you feedback: you run tests to validate whether your draft is going in the right direction.

An AI copy editor, you could say.

⚙️ Installation

We recommend uv to run the CLI.

# to run the CLI straight away
uvx unit-text --help

# or if you prefer to install it
uv tool install unit-text

You may of course also use pip to install the CLI - or pipx if you prefer to install it in an isolated environment.

pipx install unit-text

# ...or if you like to live on the edge
pip install unit-text

🔨 Usage

Requirements

Either:

  • Ollama must be running locally;
  • OLLAMA_HOST should point to an Ollama server.
# To generate a blog idea
unit-text ideate

# To validate the working draft
unit-text test <path-to-the-draft.md>

API

The package also provides a FastAPI server for programmatic access:

# Start the development server
uv run fastapi dev ./src/unit_text/api

# Start the production server
uv run fastapi run ./src/unit_text/api

# or for convenience
uv run unit-text-api

The server exposes a /test endpoint that accepts POST requests with two files:

  • file: Your draft text file
  • config: Your idea configuration JSON file

Example using curl:

curl -X POST http://localhost:8000/test \
  -F "file=@draft.md" \
  -F "config=@unit-text.json"

📝 Process

The ideation phase is where you define your blog idea. It looks something like this:

Showing an example blog idea

Your idea is now stored in a unit-text.json file, in the current directory.

You may run unit-text ideate again at any time to finetune it.

Now you can start writing, let's say you're writing in a file called draft.md.

At any time, you can run unit-text test draft.md to validate it. Initially, it may look something like this:

Showing a failing test execution

Keep iterating on your draft, based on feedback from unit-text, until it passes all tests:

Showing a passing test execution

💻 Contributing

If you want to contribute to the project, please read the CONTRIBUTING.md file.

It contains information on how to set up your development environment, submit issues, and create pull requests.

📜 License

This project is licensed under the AGPLv3 License. See the LICENSE file for details.

Release files for unit-text 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for unit-text 0.3.0
File Size Uploaded
unit_text-0.3.0.tar.gz 1.7 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for unit-text 0.3.0
File Interpreter ABI Platform
unit_text-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.7 MB

Release files / unit_text-0.3.0.tar.gz

Download URL unit_text-0.3.0.tar.gz
Size 1.7 MB
Tags Source
SHA-256 checksum
How to use checksums
84677b2fa67998ec31fb03e62c51062e2d412b8bfba3039ef602273c4feba850
BLAKE2b-256 checksum
How to use checksums
09e1efd110fe14598eee69234a3e52d50c81b8073900654c4cda08ad68deaf6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 26, 2025.

Transparency log

Release files / unit_text-0.3.0-py3-none-any.whl

Download URL unit_text-0.3.0-py3-none-any.whl
Size 21.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6d081a00a2b2949f7f3d44b78b8eb0ffbb96cf42dc532f2b8ad362dd0d4ee17c
BLAKE2b-256 checksum
How to use checksums
3d343e7cf10e31e5d6b01d38ed69a79df9b057e94fff9c92837a9d8ca3c633a9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.12.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 26, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page