A writer-first terminal writing app
Project description
Prosaic
A writer-first terminal writing app built with Python and Textual, built with the assistance of LLM/Copilot tools.
Website: prosaic.dimwit.me
Motivation
I write on multiple devices (an iPad, a laptop, even more), and I wanted a quick way to start every day, get some frontmatter ready for my daily pieces on journal.coffee, jot down notes and even work on books. I have tried several software, some stellar, some half-assed, some bloated, some minimal, but I felt like I needed something of my own.
So, I decided that the best way to go about it is to have a TUI. I can access it from anywhere, and mostly, it will do the job. This way, I can access it from a terminal app on the iPad or Windows (cue: Termix on a browser) and on the Macbook. Hence, Prosaic was born.
Full disclosure: I did rely on LLMs to make it, but as much as I could, I tried to get it to follow best practices, good architecture, and clean code principles.
Publish with Ode
Looking somewhere to publish your writing that is philosophically compatible with Prosaic? Check out Ode. You can also go to the GitHub directly.
Ode is for writers who want to publish in an aesthetically pleasing website, ignoring the bells and whistles of the modern internet. It is opinionated, minimal, and easy to use, guided by an Ethos that prioritizes the craft of writing and the joy of reading over metrics and engagement.
Screenshots
Installation
# Install (requires Python 3.11+)
pipx install prosaic-app
# Run (first launch runs setup wizard)
prosaic
# Re-run setup wizard anytime
prosaic --setup
Features
- Markdown-first: Live outline, word counting
- Focus mode: Hide everything except your writing
- Reader mode: Distraction-free reading
- Start writing: Quick writing session with all panes open
- Continue writing: Resume your last edited document
- Daily metrics: Track words and characters written each day
- Git-ready: Archive is Git-initialized for versioning
Keybindings
| Category | Key | Action |
|---|---|---|
| Dashboard | s |
Start writing (quick session) |
| Dashboard | c |
Continue writing (if last file exists) |
| Dashboard | p |
Write a piece |
| Dashboard | b |
Work on a book |
| Dashboard | n |
Add a note |
| Dashboard | r |
Read notes |
| Dashboard | f |
Find files |
| Dashboard | ? |
Help |
| Dashboard | q |
Quit |
| Editor | Ctrl+e |
Toggle file tree |
| Editor | Ctrl+o |
Toggle outline |
| Editor | Ctrl+s |
Save |
| Editor | Ctrl+q |
Go home |
| Editor | F5 |
Focus mode |
| Editor | F6 |
Reader mode |
| Writing | Ctrl+z |
Undo |
| Writing | Ctrl+y |
Redo |
| Writing | Ctrl+x |
Cut |
| Writing | Ctrl+c |
Copy |
| Writing | Ctrl+v |
Paste |
| Writing | Ctrl+a |
Select all |
Themes
- Prosaic Light (default): Warm white background with brick accents
- Prosaic Dark: Deep charcoal with warm tan accents
# Light mode (default)
prosaic
# Dark mode
prosaic --dark
Configuration
Config location (in order of priority):
PROSAIC_CONFIG_DIRenv var (explicit override)$XDG_CONFIG_HOME/prosaic/(Linux standard)~/.config/prosaic/(default)
Override with environment variable:
PROSAIC_CONFIG_DIR=~/custom/path prosaic
Git Integration
If your chosen archive directory already contains a git repository, the wizard will:
- Detect the existing
.gitdirectory - Inherit the repository (no re-initialization)
- Read the remote URL if configured
- Prompt for a remote URL if none exists
- Store this info in
settings.json
Example settings.json:
{
"setup_complete": true,
"archive_dir": "/Users/you/Prosaic",
"init_git": true,
"git_remote": "git@github.com:you/writing.git",
"git_inherited": true,
"last_file": "/Users/you/Prosaic/pieces/2026-02-21-example.md"
}
Archive Structure
~/Prosaic/ # Default archive (configurable)
pieces/ # Pieces with preloaded markdown frontmatter
books/ # Long-form projects with Outline already open
notes.md # Quick notes with auto date headers
metrics.json # Daily statistics for archival and display
.git/ # Version control
License
MIT
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 prosaic_app-1.0.0.tar.gz.
File metadata
- Download URL: prosaic_app-1.0.0.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
863e45b6cd8a2399b1be704754073d8ce826cef1fd7bea895c7d2d8d10c7f93e
|
|
| MD5 |
f9f3c7b04da26b95f19ca3740d488e00
|
|
| BLAKE2b-256 |
7e34f163571bcb5e7a8e5c2da39e28dc6279311eef15f97eeda3f5c4c6b6181d
|
Provenance
The following attestation bundles were made for prosaic_app-1.0.0.tar.gz:
Publisher:
publish.yml on DeepanshKhurana/Prosaic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prosaic_app-1.0.0.tar.gz -
Subject digest:
863e45b6cd8a2399b1be704754073d8ce826cef1fd7bea895c7d2d8d10c7f93e - Sigstore transparency entry: 982038216
- Sigstore integration time:
-
Permalink:
DeepanshKhurana/Prosaic@315a1fa5351f0d961f1627a66341c538bd76317c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/DeepanshKhurana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@315a1fa5351f0d961f1627a66341c538bd76317c -
Trigger Event:
push
-
Statement type:
File details
Details for the file prosaic_app-1.0.0-py3-none-any.whl.
File metadata
- Download URL: prosaic_app-1.0.0-py3-none-any.whl
- Upload date:
- Size: 26.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29e89bd045d4c3b2e40d1e74d70e9edbc7f92070a9423ca44589d824a289fae6
|
|
| MD5 |
f7f112cf581dfd0bc5dcb241002d07a6
|
|
| BLAKE2b-256 |
73250c1b123fcf9ec533f6bdb8c1c0ee24e4d90a39ab2cb2b9418b7b6edb5d05
|
Provenance
The following attestation bundles were made for prosaic_app-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on DeepanshKhurana/Prosaic
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
prosaic_app-1.0.0-py3-none-any.whl -
Subject digest:
29e89bd045d4c3b2e40d1e74d70e9edbc7f92070a9423ca44589d824a289fae6 - Sigstore transparency entry: 982038265
- Sigstore integration time:
-
Permalink:
DeepanshKhurana/Prosaic@315a1fa5351f0d961f1627a66341c538bd76317c -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/DeepanshKhurana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@315a1fa5351f0d961f1627a66341c538bd76317c -
Trigger Event:
push
-
Statement type: