poster.llokq

Documentation

How it works

poster.llokq is one queue on your own machine and one agent that drains it. Everything below happens on your computer, against your own accounts.

The pieces

PieceWhat it is
The queueA local database file holding each post: the video path, the caption, the destination account, the due time and the status.
The credentials file~/.poster/.env and ~/.poster/accounts.json, both readable only by your user account. Access tokens for each connected account live here and nowhere else.
The approval gateThe rule that a post only enters the schedule once you have released it. Held posts publish to nothing.
The schedulerA launchd agent on your Mac that wakes on an interval, takes what is due and publishes it.
The dashboardA page served from your own machine, on localhost, for looking at the queue and approving posts without the terminal.

1. Connect an account

Each platform is authorized separately, and each one sends you to that platform's own sign-in and consent screen in your browser. poster.llokq never sees your password. It receives an access token limited to the scopes it asked for, and writes it to your credentials file.

# YouTube
poster auth login
poster auth list          # connected channels, default marked *
poster auth use <handle>

# TikTok
poster tiktok auth        # repeat once per account
poster tiktok list
poster tiktok status      # token lifetimes and app configuration
poster tiktok remove <handle>   # forget a stored account

You can hold several accounts per platform. Commands act on the default one unless you pass --channel <handle>.

2. Describe the post

A post is a small JSON file next to the video it describes. Only the title and the media path are required; relative paths resolve against the manifest's own directory, so a manifest travels with its video.

{
  "title": "Seven layers, episode 4",
  "media_path": "./episode-04.mp4",
  "description": "The fourth pass over the same story.",
  "schedule_at": "2026-09-20T09:00:00Z",
  "privacy_status": "public",
  "platforms": ["youtube", "tiktok"],
  "channel": "layerlang"
}

A misspelled field is refused by name rather than silently ignored, and every problem in a manifest is reported at once instead of one per run. Where a kind of post needs pinning, a platform entry becomes an object:

"platforms": [
  { "platform": "youtube", "target_type": "shorts" },
  { "platform": "instagram", "target_type": "reels",
    "platform_options": { "share_to_feed": true } }
]

The file is checked against each platform's real limits, duration, size and caption length among them, at the moment you queue it. A post that a platform would reject never reaches the schedule.

poster schedule --config episode-04.json
poster schedule --config episode-04.json --schedule 2026-09-20T09:00:00Z
poster schedule --config episode-04.json --platform tiktok

3. Answer what the platform requires

Some platforms require choices that only the creator can make. TikTok is the clearest case: the privacy level, the commercial disclosure and the comment, Duet and Stitch settings are yours to set, per post, every time. poster.llokq asks you and records the answers against that post.

poster tiktok consent <post-id>              # answer later
poster schedule --config post.json --consent  # or answer as you queue

A TikTok post with no recorded consent holds at NEEDS_CONSENT, and the scheduler only ever selects SCHEDULED. It is structurally unable to publish a post you have not answered for. The TikTok page goes through that screen in detail.

4. Approve it

New posts land in AWAITING_APPROVAL. Nothing moves them but you.

poster list                      # the whole queue
poster list AWAITING_APPROVAL    # just what is held
poster approve <post-id>
poster reject <post-id>          # refused, but kept as a record
poster dashboard --port 4000     # the same thing in a browser, on localhost

5. Let it publish

The scheduler is a launchd agent. It ticks on an interval, publishes what is due oldest first, one post at a time, and leaves a gap between uploads so a laptop waking to a week of overdue posts does not fire them all at once.

poster scheduler install --interval 300
poster scheduler status          # installed, loaded, and did the last tick work
poster scheduler run --dry-run   # what would publish, publishing nothing
poster scheduler uninstall

You can also override the clock and publish something by hand:

poster publish <post-id>
poster publish <post-id> --resume   # take over an upload that died mid-flight

The statuses

Every post is in exactly one of these, and poster list <status> filters by any of them.

StatusMeaning
AWAITING_APPROVALQueued and held. The scheduler ignores it.
NEEDS_CONSENTThe platform requires creator choices that have not been recorded yet.
NEEDS_AUTHThe account it targets is not connected, or its token was revoked.
SCHEDULEDApproved and waiting for its due time. The only status the scheduler acts on.
PUBLISHINGClaimed by a run that is uploading it. The claim is what stops two runs publishing the same video twice.
VERIFIEDPublished, and confirmed present on the platform, with the platform's own ID recorded.
FAILEDThe platform refused it, with the reason kept against the post.

A post that already carries a platform video ID is refused for publishing again, whatever its status. Re-uploading it would put the same video out twice, and no flag overrides that.

What it deliberately does not do

Questions about any of the above: hello@llokq.com.