A dual-mode personal site that serves the same content as styled HTML to browsers and as ANSI-colored plain text to terminal clients (curl, w3m, etc.). Ships with a standalone interactive CLI client built on prompt_toolkit.
uv sync
uv run uvicorn server.app:app --reloadServer runs at http://localhost:8000.
Try it in your terminal:
curl http://localhost:8000
curl http://localhost:8000/blog
curl http://localhost:8000/cheatsThe CLI client provides a navigable terminal UI with command history and tab-completion.
# Install standalone
cd client && pip install -e .
# Run (server must be running first)
datafoolCommands inside the CLI: 1 (Blog), 2 (Cheat Sheets), 3 (About), back, menu, exit.
server/ FastAPI app — dual HTML/plain-text responses
app.py Routes + CLI detection via User-Agent
content.py Loads markdown files from contents/ at startup
templates.py Paired *_cli / *_html render functions per section
ansi.py ANSI color constants and helper
state.py In-memory session state (keyed by short UUID)
static/ CSS for the HTML version
client/
datafool_cli.py Interactive prompt_toolkit CLI
contents/
about.md About page content
blog/ Blog post markdown files
cheats/ Cheat sheet markdown files
Drop a .md file into contents/blog/ or contents/cheats/ and restart the server. The filename stem becomes the URL slug and a title-cased version becomes the display title.
contents/blog/my-new-post.md → /blog/my-new-post → title: "My New Post"
docker build -t datafoolweb-cli .
docker run -p 8080:8080 datafoolweb-cliManaged with uv. Python 3.13+.
| Package | Purpose |
|---|---|
fastapi + uvicorn |
Web server |
markdown |
Markdown → HTML/text conversion |
prompt_toolkit |
Interactive CLI (client only) |
requests |
HTTP client (CLI only) |