X posting agent
One measured finding a day becomes an X post. The API posts it; nobody types.
An X account that posts once a week reads as abandoned, and one that posts generic advice reads as a bot. What holds up is a steady run of specific, measured observations, one a day, and writing that takes an hour nobody has once the first week’s enthusiasm is gone.
Running on our own company since Oct 14, 2026 · X · Risk: Medium. Everything on this page is public; there is nothing to sign in for.
Tasks and outputs
What it takes on
Take the row
Reads the calendar top to bottom and takes the first row still pending: the finding, the angle, the form. Never by date, never out of order.
Write and lint
Writes the post from the finding to the voice guide, in a session with no way to post, then runs lint: segment count, length, links, brand, banned words, the row’s day and form.
Post and record
Posts through the X API as the calendar’s account, writes the registry entry after the first 201, flips the row, commits both files and triggers the deploy.
Who it is for: Founders and small teams who have real findings to share (measurements, experiments, numbers from their own work) and want them on X every day without a person at the keyboard, and without the browser automation X suspends accounts for.
How we use it: We built it for our own new X account in October 2026: every day, at a random minute of the morning, it takes the next row of a calendar of findings from the free AI-visibility reports we wrote for fifty startups, writes a short post or a thread from it, checks the draft by rule, and posts it through the X API. No link and no brand in any post for the first two weeks; the clients the findings come from are never named. The registry behind the run log records every post that went out.
What a post looks like
01The first line is a number or a counter-intuitive result. Never a definition, never “a thread on”, never a preview.
02A short post is one segment. A thread is four to six: a hook, three or four segments with one number or one mechanism each, a last one with the lesson or the open question.
03Each segment 260 characters or fewer (lint allows 280). No link, no domain, no “link in bio”.
04No brand before 2026-10-26. No client name ever: the company in a finding is “a startup”, “one company”, “a vendor”.
05None of the banned words, no em or en dash, no hashtag, no call to action, at most one emoji. Every number is in the calendar row or in a report file the draft names; lint reads those files and refuses a number it cannot find.
06A draft that fails lint twice is not posted; the calendar is never edited to make one pass.
The rules the agent’s output is written to, from the file named above. This site prints no example output; what the agent has shipped is in its run log.
Workflow
How a run goes, step by step
Pick a step to see what goes in, what comes out, and where a person is involved.
Step 1 of 6
Take the first pending row
Once a day, at a random minute inside a morning window, the wrapper brings its checkout to the latest main, checks that the posting account’s credentials are there, and reads the calendar for the first row still pending. An empty calendar ends the run before any session starts, with a line in the log on the machine and an exit code the watchdog reports.
Workflows/x-post/geo-topics.md
One row: day, finding, angle, form
Nobody. When the calendar is empty, a person adds rows; the next run takes the first.
Step 2 of 6
Write the draft
A session starts with the row’s day and form, reads the finding and the voice guide, and writes one short post or one thread. The session can read the repository and run the calendar reader and lint, and nothing else: it holds no credentials and cannot run the posting script. The first line is the number or the result; each thread segment carries one point; no link, no brand before the date in the guide, no client name.
The row and Workflows/x-post/voice.md
A draft file: day, form, segments
Nobody. A session that writes nothing within ten minutes is stopped and the run ends with no post.
Step 3 of 6
Lint, twice
The session runs lint on its draft and, when it passes, lint copies the draft to the file the posting script takes. The wrapper runs the same lint again on that file before posting. The rules are form, not taste: segment count for the form, 280 characters a segment as X counts them, links, the brand rule, the banned words and dashes, and that the draft is for the row that is due.
The draft
An accepted draft, or the run ends
Nobody. A draft that fails twice ends the run with the errors in the log; the row stays pending for the next day.
Step 4 of 6
Post through the API
The posting script signs each request with the posting account’s OAuth 1.0a credentials and sends it: one request for a short post, one per segment for a thread, each a reply to the one before, two seconds apart. It expects 201 and the post id back. A refused request stops the loop: the segments already posted stay, nothing is retried, and the output names the cause (token, credits, duplicate text, rate limit).
The accepted draft and the credentials file
Post ids, or a named refusal
When a thread stops partway: a person posts the rest by hand or deletes the live segments. The run does not wait.
Step 5 of 6
Record and flip the row
After the first segment went out, the script writes one entry to the registry, keyed by calendar day: the ids, the first post’s link, date and time, the form, the segments as posted, and ok or partial. Then it flips the calendar row to posted with the link. A run that posted nothing writes neither.
The ids and the draft
One entry in web/content/x-posts.json and one posted row
Nobody. The registry is the record; a person never edits it to make a run pass.
Step 6 of 6
Commit and deploy
The wrapper commits exactly the calendar and the registry, pushes, and triggers the deploy that builds this log from the registry. A partial entry shows here as a record that needs a person; a run that ended before posting shows as a gap, with its reason in the log on the machine.
The two changed files
This record
When the push fails: a person pushes. The files are already written locally.
Before you start
What you’ll need to bring
Company material
Findings worth a post: measured results with numbers, one per calendar row, that stand without the name of whoever they were measured on. Ours come from the free AI-visibility reports we wrote for fifty startups.
Source material
The topic calendar: a markdown table a person fills, one row a day, with the finding, an optional angle and the form. The agent reads it top to bottom and flips rows; it never writes findings.
Platform account
An X developer account with pay-per-use credits and an app with write permission, and the posting account authorized once against it through X’s PIN flow. The two can be the same account; ours are not.
Run environment
A machine that is on in the morning: Node.js for the three scripts, an agent runner that follows a written workflow for the writing step, and a scheduler. We use Claude Code under Windows Task Scheduler. No browser is needed.
Run log
Recent runs, as they happened
The full log is public and read-only. It holds every run on record, including the ones that stopped to wait for a person.
View the full run logGuides and files
Set it up yourself
The setup guide, and the files the agent is built from. You run it in your own environment, with your own accounts.
- 01
Runtime
- Node.js 20 or later. The three scripts have no dependencies; the signing is a hundred lines of HMAC-SHA1.
- A scheduler that starts the wrapper once a day at a random minute inside a morning window, and an agent runner that follows the written workflow for the writing step — ours is Claude Code, started by Windows Task Scheduler on the founder’s machine.
- 02
Browser setup
- None. The post goes out through the API; nothing in this agent opens a browser. That is also why it is allowed: X lists browser automation as grounds for permanent suspension and permits automated original posts through the API.
- 03
Account setup
- An X developer account with pay-per-use credits and an app with read and write permission. Posting costs $0.015 a request at 2026 prices, $0.20 when the post carries a URL.
- The posting account, authorized once against that app through X’s PIN flow; its four OAuth 1.0a strings do not expire, so there is no token to refresh on an unattended machine. Ours is a separate account from the developer account.
- 04
Configuration
- The topic calendar: one row per day with a measured finding, an optional angle, the form (short or thread), and the status the script flips. The handle that posts is a line above the table.
- The voice guide: the hook rule, the one-point-per-segment rule, the length, the banned words, the no-link rule and the date before which no brand is named.
- The lint rules, as constants at the top of the lint script: change a rule there, not the flow.
- 05
First run
- Run the wrapper in dry-run mode two or three times and read the drafts; if they are correct but dull, the calendar’s findings are not specific enough. Fix the calendar, not the prompt.
- Post the first one by hand with the posting script, check it on the account’s timeline, check the registry entry and the calendar row, then register the schedule.
x-post.md
Workflow · Markdown. The steps: the row, the voice guide, the draft, the checklist, lint, post, commit and deploy.
voice.md
Voice guide · Markdown. The hook rule, one point per segment, the length, the banned words, the no-link and no-brand rules, the checklist.
geo-topics.md
Calendar · Markdown. One row per day: the finding, the angle, the form, the status the script flips, the date and the link. The handle that posts is a line above the table.
calendar.mjs
Script · Node. Reads the calendar: the first pending row for the wrapper and lint, and the flip to posted for the posting script.
lint.mjs
Script · Node. The deterministic checks on a draft, and the copy of an accepted draft to the file the posting script takes.
post.mjs
Script · Node. Posts the accepted draft through the X API (OAuth 1.0a signing shared with the X comment agent), writes the registry entry, flips the row. Never retries.
run-x-post.ps1
Scheduler · PowerShell. The daily run: the checkout, the row, the writing session, lint, post, one commit of the two files, the deploy trigger.
x-posts.json
Registry · JSON. One entry per post or thread published, keyed by calendar day. The file this log is built from.
Not packaged for public download yet. The guide on the left describes what each one does, step by step, so you can rebuild the setup; the Hosted and Fully managed tiers run them for you today.
Rather have us run it?
Hosted: your accounts in a cloud browser we run, and you review what goes out. Fully managed: we set the strategy and run the agents.
Good to know
Where it stops and asks for you
- The calendar has no pending row. The run ends before any session, with a line in the log and an exit code the watchdog emails about. A person adds rows.
- The posting account’s credentials file is missing. The run ends before any session. A person runs the one-time PIN authorization again.
- The session did not write a draft within ten minutes. The session is stopped; nothing is posted; the row stays pending for the next day.
- The draft failed lint twice. Nothing is posted; the errors are in the log on the machine; the row stays pending. A finding that keeps producing failing drafts is rewritten in the calendar by a person.
- X refused the first request. Nothing is posted and nothing is written; the output says why: 401 token, 402 credits, 403 duplicate text or permission, 429 rate limit.
- X refused a later segment of a thread. The segments before it are live and recorded as partial; the record here needs a person, who posts the rest by hand or deletes the live ones. Nothing is retried.
- The push failed. The commit stays local and a person pushes; the registry entry and the calendar flip are already written.
Risk notice
What to watch for
- X’s developer rules shape this agent: original posts through the paid API, no browser, no automated replies. Keep it to posting; replies are the X comment agent’s, and a person posts those.
- Nobody reads a post before it goes out. The controls are the calendar (a person writes the findings), the voice guide and lint; a post can still be correct and dull. If the drafts are not good enough after two weeks, the fallback is a text column in the calendar: a person writes the posts, the agent only posts them.
- Posting costs money, a dollar or two a month at one post a day; a thread is one request per segment. The developer account’s credits are shared with the X comment agent’s reads. Set a monthly limit in the developer console.
- A new account gets little reach for weeks. Low numbers in the first month are not a signal to post more.
FAQ
Questions about this agent
Why the API and not the browser, like the LinkedIn agent?
X has an API that allows automated original posts and prices them at cents; LinkedIn does not. X also names browser automation as a permanent-suspension offence. The API path is cheaper, more stable, and the one X permits.
Can the writing session post something it should not?
No. The session that writes has no credentials and cannot run the posting script; the worst it can do is write a bad draft, and lint reads the draft before anything is sent. The posting script is run by the wrapper, or by a person.
A thread stopped partway.
The segments that went out are recorded as a partial entry and the record here is marked as needing a person. Post the rest by hand from the registry’s text, or delete the live segments; the agent does not retry a refused request.
The calendar ran out.
The run stops before starting a session, writes a line to its log on the machine, and exits with a code the watchdog emails about. Add rows; the next run takes the first new one.
Would you rather we ran this agent for you? There is a managed service for that.
Talk to us