Skip to main content

blog-cli

Agent-friendly CLI for managing a personal blog: create drafts, upload media, generate preview links, publish articles, and manage project tags.

Install

From PyPI:

pip install -U blog-cli

Or install it as an isolated command-line tool:

pipx install blog-cli
uv tool install blog-cli

For development:

git clone https://github.com/tanaka-mambinge/personal-cli
cd personal-cli
uv sync --extra dev

Configure

The CLI requires the API URL and API key. The site URL is required for preview links.

export PERSONAL_SERVER_URL="https://api.example.com"
export PERSONAL_API_KEY="your-api-key"
export PERSONAL_SITE_URL="https://example.com"

For local development, put the same variables in a .env file in the current directory. Do not commit that file.

Production installations use the same environment variables. For example:

PERSONAL_SERVER_URL="https://api.example.com" \
PERSONAL_API_KEY="your-production-api-key" \
PERSONAL_SITE_URL="https://example.com" \
blog-cli article list --type blog

All commands support --json for machine-readable output and --server-url to override the configured API URL for one command. Commands also support --insecure to skip TLS certificate verification when needed for local development.

Check the installed version:

blog-cli version

Articles

Create a blog post

Blog posts are drafts by default:

blog-cli article blog create \
  --title "My Post" \
  --description "A short summary" \
  --markdown "# My Post\n\nHello."

Use a Markdown file instead:

blog-cli article blog create \
  --title "My Post" \
  --description "A short summary" \
  --markdown-file post.md

Create a project

blog-cli article project create \
  --title "My Project" \
  --description "A short summary" \
  --tag python \
  --tag agents \
  --markdown-file project.md

Projects can also use --pinned and --sort-order.

List and show articles

# List all articles
blog-cli article list

# List published blog posts
blog-cli article list --type blog --status published

# List projects
blog-cli article list --type project

# Show one article
blog-cli article show my-post

Update an article

blog-cli article update my-post --title "A Better Title"
blog-cli article update my-post --description "An updated summary"
blog-cli article update my-post --markdown-file updated-post.md
blog-cli article update my-post --cover-image hero-image
blog-cli article update my-post --clear-cover-image

The update command also accepts --type, --status, --tag, --pinned, --not-pinned, and --sort-order.

Preview and publish

Generate a time-limited preview link:

blog-cli article preview my-post
blog-cli article preview my-post --ttl-hours 4

Override the configured site URL for a preview:

blog-cli article preview my-post --site-url https://preview.example.com

Revoke an existing preview link:

blog-cli article revoke-preview my-post

Publish an article explicitly:

blog-cli article publish my-post --published-by agent

Archive or restore an article:

blog-cli article delete my-post
blog-cli article unarchive my-post

Project tags

# List tags on a project
blog-cli article tag-list my-project

# Add tags
blog-cli article tag-add my-project --tag python --tag agents

# Remove a tag
blog-cli article tag-remove my-project --tag agents

Categories

Categories are first-class models that group private content pages. The slug is auto-derived from the name. A category cannot be deleted while pages still belong to it.

# Create (slug auto from name, e.g. "YouTube Notes" -> "youtube-notes")
blog-cli category create --name "Ideas" --icon bulb --description "Captured ideas"

# List / show / update / delete
blog-cli category list
blog-cli category show ideas
blog-cli category update ideas --name "Idea Box" --icon lightbulb
blog-cli category delete ideas

Pages

Pages are private content shown only on the dashboard at /d/<slug>. They are for your eyes only. Each page belongs to a category and supports MDX with prebuilt components (<Callout>, <Steps>, <ImageGrid>, <Video>, <Figure>).

# Create a page
blog-cli page create \
  --title "An idea" \
  --description "Short summary" \
  --category ideas \
  --tag web --tag ai \
  --markdown-file idea.mdx

# List (optionally filter by category)
blog-cli page list
blog-cli page list --category ideas

# Show / update / delete
blog-cli page show an-idea
blog-cli page update an-idea --title "A better title"
blog-cli page update an-idea --markdown-file updated.mdx
blog-cli page delete an-idea

Page bodies are MDX. Referenced media uses names uploaded via blog-cli media upload --name <name> <file>; the site resolves names to media URLs at render time.

ChatGPT / Codex skill

The CLI ships a bundled content-pipeline skill that routes blog, project, and page tasks to the right reference doc. Install it into the user-level skills directory:

blog-cli skill install
blog-cli skill uninstall
blog-cli skill path

Media

Upload media using a stable name, then reference that name from article Markdown:

blog-cli media upload --name hero-image ./hero.jpg

Replace an existing file without changing its name:

blog-cli media update --name hero-image ./new-hero.jpg

Soft-delete media:

blog-cli media delete --name hero-image

Markdown references use the media name:

![Hero image](hero-image)

<video controls width="100%" src="demo-video"></video>

The site resolves these names to their full media URLs.

Publishing new CLI versions

The repository includes a GitHub Actions workflow at .github/workflows/publish.yml. It runs when you push a version tag matching v*.*.* and will:

  1. Install dependencies with uv.
  2. Run the test suite.
  3. Build the wheel and source distribution with uv build --no-sources.
  4. Publish both distributions to PyPI with uv publish.

After configuring PyPI Trusted Publishing for the GitHub Actions workflow, release a new version with:

uv version --bump patch
git add pyproject.toml uv.lock
git commit -m "Release blog-cli"
git tag v0.2.4
git push origin main --tags

Use the version from pyproject.toml when creating the tag.

Testing

uv run pytest -v

The CLI tests use an in-memory fake API client, so they run without MongoDB or the personal server. The CLI architecture is:

blog-cli (httpx) → FastAPI server → MongoDB/GridFS

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

blog_cli-0.4.1.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

blog_cli-0.4.1-py3-none-any.whl (21.1 kB view details)

Uploaded Python 3

File details

Details for the file blog_cli-0.4.1.tar.gz.

File metadata

  • Download URL: blog_cli-0.4.1.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for blog_cli-0.4.1.tar.gz
Algorithm Hash digest
SHA256 cbee57b7d70587afc5581001bac040de4f2723d81f9846f8a321cae84542725b
MD5 09113cd76b65699eddd2784a65675c2f
BLAKE2b-256 9cf7b93adebc36e7045b1fc01e80eafb24a38dac96873a03c69d8285f71f806c

See more details on using hashes here.

File details

Details for the file blog_cli-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: blog_cli-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 21.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for blog_cli-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0e0bb1a81c41ebce64b3cf18e0d0064b22bd3f3bd42c0763a9e5a851e0766993
MD5 173bd7222d4cd411f8158e1fd3d74407
BLAKE2b-256 0f9c4544e86c3785b96ad14150ab096c575f4aee41865cb000baf33e7455219e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page