<h1 align="center">unit-text</h1>
<h3 align="center">Unit tests for plain text</h3>
<p align="center">
    <a  href="https://pypi.org/project/unit-text/">
        <img alt="CI" src="https://img.shields.io/pypi/v/unit-text.svg?style=flat-round&logo=pypi&logoColor=white">
    </a>
</p>
<div align="center">

</div>
---
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 <insert your own reason here>...)
- 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](https://sealambda.com/blog/hygienic-python-in-2025) [uv](https://github.com/astral-sh/uv) to run the CLI.
```bash
# 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.
```bash
pipx install unit-text
# ...or if you like to live on the edge
pip install unit-text
```
## 🔨 Usage
### Requirements
Either:
- [Ollama](https://ollama.com) must be running locally;
- `OLLAMA_HOST` should point to an Ollama server.
```bash
# To generate a blog idea
unit-text ideate
# To validate the working draft
unit-text test <path-to-the-draft.md>
```
## 📝 Process
The ideation phase is where you define your blog idea. It looks something like this:

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:

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

## 💻 Contributing
If you want to contribute to the project, please read the [CONTRIBUTING.md](./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](LICENSE) file for details.
            
         
        Raw data
        
            {
    "_id": null,
    "home_page": null,
    "name": "unit-text",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.11",
    "maintainer_email": null,
    "keywords": "ai, blog, cli, editor, language, llm, ollama, test, unit",
    "author": null,
    "author_email": "Giorgio Azzinnaro <giorgio.azzinnaro@sealambda.com>, Sealambda <hello@sealambda.com>",
    "download_url": "https://files.pythonhosted.org/packages/2c/44/ef8e8145b748c7569425f93684afcec280ae22fff82739389a26db31f795/unit_text-0.2.5.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\">unit-text</h1>\n<h3 align=\"center\">Unit tests for plain text</h3>\n\n<p align=\"center\">\n    <a  href=\"https://pypi.org/project/unit-text/\">\n        <img alt=\"CI\" src=\"https://img.shields.io/pypi/v/unit-text.svg?style=flat-round&logo=pypi&logoColor=white\">\n    </a>\n</p>\n\n<div align=\"center\">\n\n\n\n</div>\n\n---\n\nDon't let LLMs write blog posts for you. Do your research, bring your own voice,\nand use LLMs to criticise and iterate on your writing.\n\n## \ud83e\udd0c Why unit-text?\n\nIf you're a developer like us:\n\n- You're probably aware you should write more (either because your leadership asks for it,\n  or because you'd like to be invited as a conference speaker, or <insert your own reason here>...)\n- You don't know what to write about.\n- You have considered letting ChatGPT write blog posts for you.\n\nIf you tried the last option (or read anything on the Internet in the past 2 years)\nyou would also know why it's not really that good of an idea.\n\nSure, you may get a perfectly good post, but it won't be your own.\n\n`unit-text` applies the concept of unit tests to prose. You are the one writing, the LLM is just your critic.\n\nFirst, you define a goal, the audience you have in mind,\nand what you wanted them to do differently after they read your post.\nThen, you start writing and iterating on your draft. `unit-text` gives you feedback: you run _tests_\nto validate whether your draft is going in the right direction.\n\nAn AI copy editor, you could say.\n\n## \u2699\ufe0f Installation\n\n[We recommend](https://sealambda.com/blog/hygienic-python-in-2025) [uv](https://github.com/astral-sh/uv) to run the CLI.\n\n```bash\n# to run the CLI straight away\nuvx unit-text --help\n\n# or if you prefer to install it\nuv tool install unit-text\n```\n\nYou may of course also use `pip` to install the CLI - or `pipx` if you prefer to install it in an isolated environment.\n\n```bash\npipx install unit-text\n\n# ...or if you like to live on the edge\npip install unit-text\n```\n\n## \ud83d\udd28 Usage\n\n### Requirements\n\nEither:\n\n- [Ollama](https://ollama.com) must be running locally;\n- `OLLAMA_HOST` should point to an Ollama server.\n\n```bash\n# To generate a blog idea\nunit-text ideate\n\n# To validate the working draft\nunit-text test <path-to-the-draft.md>\n```\n\n## \ud83d\udcdd Process\n\nThe ideation phase is where you define your blog idea. It looks something like this:\n\n\n\nYour idea is now stored in a `unit-text.json` file, in the current directory.\n\nYou may run `unit-text ideate` again at any time to finetune it.\n\nNow you can start writing, let's say you're writing in a file called `draft.md`.\n\nAt any time, you can run `unit-text test draft.md` to validate it.\nInitially, it may look something like this:\n\n\n\nKeep iterating on your draft, based on feedback from `unit-text`, until it passes all tests:\n\n\n\n## \ud83d\udcbb Contributing\n\nIf you want to contribute to the project, please read the [CONTRIBUTING.md](./CONTRIBUTING.md) file.\n\nIt contains information on how to set up your development environment, submit issues, and create pull requests.\n\n## \ud83d\udcdc License\n\nThis project is licensed under the AGPLv3 License. See the [LICENSE](LICENSE) file for details.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Unit tests for plain text",
    "version": "0.2.5",
    "project_urls": {
        "issues": "https://github.com/sealambda/unit-text/issues",
        "source": "https://github.com/sealambda/unit-text"
    },
    "split_keywords": [
        "ai",
        " blog",
        " cli",
        " editor",
        " language",
        " llm",
        " ollama",
        " test",
        " unit"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "784ee94d91a0d71394a030baca5837c2b51c56bf677db6250166d618eed2ce08",
                "md5": "0fd40b2349c9456884adeea561e10f19",
                "sha256": "0a90aea9fd44c040af2ea9a5a3b4eb9bb8fa7ab702d5188b317989719e845139"
            },
            "downloads": -1,
            "filename": "unit_text-0.2.5-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0fd40b2349c9456884adeea561e10f19",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.11",
            "size": 18289,
            "upload_time": "2025-03-09T16:39:47",
            "upload_time_iso_8601": "2025-03-09T16:39:47.128056Z",
            "url": "https://files.pythonhosted.org/packages/78/4e/e94d91a0d71394a030baca5837c2b51c56bf677db6250166d618eed2ce08/unit_text-0.2.5-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2c44ef8e8145b748c7569425f93684afcec280ae22fff82739389a26db31f795",
                "md5": "8b467a68fe8fe325b4f74cc9806e15f3",
                "sha256": "7579f61fcf7aab7c795afd830f832d60dfe203898a42d87fd613eea25058b802"
            },
            "downloads": -1,
            "filename": "unit_text-0.2.5.tar.gz",
            "has_sig": false,
            "md5_digest": "8b467a68fe8fe325b4f74cc9806e15f3",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.11",
            "size": 1708323,
            "upload_time": "2025-03-09T16:39:49",
            "upload_time_iso_8601": "2025-03-09T16:39:49.074556Z",
            "url": "https://files.pythonhosted.org/packages/2c/44/ef8e8145b748c7569425f93684afcec280ae22fff82739389a26db31f795/unit_text-0.2.5.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-03-09 16:39:49",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "sealambda",
    "github_project": "unit-text",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "unit-text"
}