Hello, I'm Maneshwar. I'm building git-lrc, a Micro AI code reviewer that runs on every commit. It is free and source-available on Github. Star git-lrc to help devs discover the project. Do give it a try and share your feedback.
Remember when posting to social media meant actually going to the website and clicking "post"? Wild concept.
I don't do that anymore, because that's clearly a lifestyle for people with free time.
Here's my week, most weeks. I write something. I paste it into X. I reformat it and paste it into LinkedIn. I reformat it again and paste it into dev.to.
I forget to post one of them for three days and pretend that was intentional.
Buffer exists to fix exactly this problem, and Buffer also exists to charge you a subscription for the privilege of not context-switching.
So I went looking for the self-hosted version, and found @nevodavid's Postiz.
This is the story of standing it up with Docker, getting mildly betrayed by Postgres, wiring up three platforms, and accidentally learning more about durable workflow engines than I signed up for.
There's some actual depth here, so get comfortable.
Postiz is an open source, AGPL-3.0 licensed alternative to Buffer, Hypefury, and Twitter Hunter.
You connect your accounts, and it becomes one calendar for scheduling posts across lot of platforms: X, LinkedIn, dev.to, YouTube, TikTok, Instagram, Facebook, Threads, Bluesky, Mastodon, Discord, Slack, Reddit, Pinterest, and Dribbble and more
A few things stood out while reading the docs:
docker-compose.yaml
, and the plan is simple in theory: clone it, run docker compose up
, done. In practice, here is a lightly condensed transcript of my evening:
$ docker compose up
✔ Image postgres:16 Pulled 573.9s
✔ Image redis:7.2 Pulled 353.7s
✔ Image temporalio/ui:2.34.0 Pulled 329.3s
✔ Image temporalio/admin-tools:1.28.1-tctl-1.18.4-cli-1.4.1 Pulled 792.1s
✔ Image temporalio/auto-setup:1.28.1 Pulled 894.6s
✔ Image elasticsearch:7.17.27 Pulled 875.1s
✔ Image ghcr.io/gitroomhq/postiz-app:latest Pulled 1206.3s
✔ Network temporal-network Created 1.3s
✔ Network postiz-docker-compose_postiz-network Created 0.1s
✔ Volume postiz-docker-compose_temporal-postgres-data Created 0.1s
✔ Volume postiz-docker-compose_postiz-config Created 0.0s
✔ Volume postiz-docker-compose_postiz-uploads Created 0.0s
✔ Volume postiz-docker-compose_postiz-redis-data Created 0.1s
✔ Volume postiz-docker-compose_temporal-elasticsearch-data Created 0.0s
✔ Container temporal-elasticsearch Created 25.7s
✔ Container postiz-redis Created 25.7s
✔ Container temporal-postgresql Created 25.7s
✔ Container temporal Created 0.8s
✔ Container temporal-ui Created 0.7s
✔ Container postiz Created 0.7s
✔ Container temporal-admin-tools Created
Yes, that's Elasticsearch and Temporal and Postgres and the whole app image, all pulling at once, over 10 minutes. Nobody tell me this is a well documented Docker pattern. I know. I did it anyway.
Once it's up, it's worth knowing what you actually deployed, because it's more than "one container that posts tweets."
Postiz leans on Temporal for durable workflow orchestration, which is a genuinely interesting choice for a scheduler (more on why in a second).
Notice there are two separate Postgres databases in play: one that Temporal owns for itself, and one that Postiz uses for your actual data (users, posts, integrations).
They don't share a database, which is a small detail that saved me some confusion later when I went looking for my own tables in the wrong instance.
To actually post anywhere, Postiz needs API credentials per platform.
Getting these ranges from "mildly annoying" to "a small quest."
For X, you go to the developer console, create a project and an app, accept the terms, then dig through the app's Keys and Tokens tab to generate an API Key and Secret (sometimes labeled Consumer Keys, because naming things is hard).
For LinkedIn, you create an app at their developer portal, go to the Products tab and request "Share on LinkedIn," then flip to the Auth tab to grab your Client ID and Secret.
The gotcha: you also have to manually add an authorized redirect URL, matching your Postiz install, like http://localhost:5000/integrations/social/linkedin
. Miss that step and the OAuth flow just quietly fails on you.
Both sets of credentials go into the postiz
service's environment block in docker-compose.yaml
, right alongside placeholders for Reddit, GitHub, TikTok, Pinterest, Discord, Slack, Mastodon, and a dozen others. Fun detail while I was in there: the compose file already has FEE_AMOUNT
and STRIPE_*
variables sitting in it, unused until you touch them.
The default compose file ships its own Postgres container for Postiz, which is fine, except I already run Postgres on the host for other projects and did not want a second copy quietly eating disk and RAM for no reason.
So I pointed Postiz at my existing instance instead:
CREATE USER "postiz-user" WITH PASSWORD 'postiz-password';
CREATE DATABASE "postiz-db-local" OWNER "postiz-user";
GRANT ALL PRIVILEGES ON DATABASE "postiz-db-local" TO "postiz-user";
Then a few host-level changes: set listen_addresses = '*'
in postgresql.conf
(it defaults to localhost
only, which a container can't reach), add a rule to pg_hba.conf
so Docker's network range is allowed in:
host postiz-db-local postiz-user 172.16.0.0/12 scram-sha-256
restart Postgres, then update the compose file: drop the bundled postiz-postgres
service and its volume entirely, remove it from depends_on
, and point DATABASE_URL
at postgresql://postiz-user:postiz-password@host.docker.internal:5432/postiz-db-local
.
On Linux, host.docker.internal
doesn't resolve by default the way it does on Docker Desktop, so you also need extra_hosts: ["host.docker.internal:host-gateway"]
on the postiz
service, or the container just can't find your host at all.
More work than clicking "use the default," sure.
But now backups, extensions, and monitoring are all in one place instead of scattered across five Postgres containers I'll forget about in a month.
This is the part I found genuinely cool enough to diagram twice.
Scheduling a post sounds like it should be a cron job checking "is it time yet?" every minute.
Temporal does it differently: it starts a durable workflow that just sleeps until the exact moment, survives restarts of the app itself, and wakes up precisely on time instead of polling.
You can actually watch this happen instead of trusting it blindly.
The compose file exposes a Temporal UI on port 8080, where every scheduled post shows up as a workflow you can inspect, complete with its history and current state.
It is oddly satisfying to watch a "post to dev.to" workflow just sit there patiently for two days before firing exactly on schedule.
This part is refreshingly simple. Head to dev.to's extensions settings and generate a DEV Community API Key, then paste it into Postiz when adding a new provider.
From there, creating a post is what you'd expect from any scheduler: click the time slot you want on the calendar, pick dev.to from the side panel, expand the settings accordion to fill in the title and cover image, and hit add to calendar.
That's it. No copy-pasting into four tabs. No forgetting the one platform I always forget.
If you're setting this up yourself, save some time with what I tripped over:
host.docker.internal
needs extra_hosts
on Linux, it is not automatic like on Docker Desktop.depends_on: condition: service_healthy
actually matter, Temporal and Redis need to report healthy before Postiz starts, or you'll chase phantom connection errors.JWT_SECRET
invites you to "just type random characters here," please actually do that with something long and random, not literally the word "secret."AI agents write code fast. They also silently remove logic, change behavior, and introduce bugs — without telling you. You often find out in production.
git-lrc fixes this. It hooks into git commit and reviews every diff before it lands. 60-second setup. Completely free.
Any feedback or contributors are welcome! It's online, source-available, and ready for anyone to use.
⭐ Star it on GitHub:
| 🇩🇰 Dansk | 🇪🇸 Español | 🇮🇷 Farsi | 🇫🇮 Suomi | 🇯🇵 日本語 | 🇳🇴 Norsk | 🇵🇹 Português | 🇷🇺 Русский | 🇦🇱 Shqip | 🇨🇳 中文 | 🇮🇳 हिन्दी |
GenAI today is a race car without brakes. It accelerates fast -- you describe something, and large blocks of code appear instantly. But AI agents silently break things: they remove logic, relax constraints, introduce expensive cloud calls, leak credentials, and change behavior -- without telling you. You often find out in production.
** git-lrc is your braking system.** It hooks into
git commit
and runs an AI review on every diff In short, git-lrc helps Prevent Outages, Breaches, and Technical Debt Before They Happen
At a glance: 10 risk categories · 100+ failure patterns tracked · every commit…