{"skill":{"slug":"xqueue","displayName":"Xqueue","summary":"File-based X/Twitter post scheduler. Drop tweets into day/time folders, they post automatically. No frontend, no app — your file system is the UI.","description":"---\nname: xqueue\ndescription: File-based X/Twitter post scheduler. Drop tweets into day/time folders, they post automatically. No frontend, no app — your file system is the UI.\nmetadata: {\"openclaw\":{\"requires\":{\"env\":[\"X_CONSUMER_KEY\",\"X_CONSUMER_SECRET\",\"X_ACCESS_TOKEN\",\"X_ACCESS_TOKEN_SECRET\"],\"bins\":[\"python3\"]},\"permissions\":{\"filesystem\":\"read/write within xqueue/ directory\",\"network\":\"api.twitter.com, upload.twitter.com\",\"keychain\":\"optional macOS Keychain if XQUEUE_KEYCHAIN_ACCOUNT is set\"},\"homepage\":\"https://github.com/madebydia/xqueue\",\"author\":\"Diana Park (@madebydia)\"}}\n---\n\n# XQueue\n\nA file-based post scheduler for X (Twitter). Your file system is the UI.\n\n## How It Works\n\nCreate a folder structure with days and times. Drop tweet files into the time slots. A cron job checks every 15 minutes — if it's the right day and time and there's content, it posts and cleans up.\n\n```\nxqueue/\n  config.json\n  backlog/\n    ebook-launch-thread.md\n    ai-tools-roundup.md\n  Sunday/\n    10am/\n      my-tweet.md\n      photo.jpg\n  Monday/\n    9am/\n      thread-about-shipping.md\n    12pm/\n    5pm/\n  Tuesday/\n    ...\n```\n\nThe schedule cycles weekly. Monday's 9am slot fires every Monday at 9am. If the folder is empty, it pulls the oldest file from `backlog/` (sorted alphabetically). If there's content in the slot, it posts that and backlog waits. This means you can schedule up to a week of specific content, and dump everything else in backlog — it'll fill empty slots automatically.\n\nAfter posting, files are deleted (by default) so they don't repeat.\n\n## Setup\n\nRun the setup command to create your queue:\n\n```bash\npython3 xqueue-setup.py\n```\n\nThis asks you:\n1. How many times per day do you want to post?\n2. What times? (or let it pick optimal times)\n3. What timezone?\n4. Any X communities to post to?\n5. Thread separator preference (default: ---)\n6. Delete after posting? (recommended yes — if off, posts may send twice)\n\nCreates the full folder structure + config.json.\n\n## Tweet Format\n\n### Simple tweet\nJust write the text in a `.md` or `.txt` file:\n\n```\nThis is my tweet. It can be up to 280 characters.\n```\n\n### Tweet with community\nStart with `Post to [community name]:` on the first line:\n\n```\nPost to Build in Public: Just shipped my first ClawHub skill. File-based tweet scheduler, no frontend needed.\n```\n\n### Thread\nOne file, tweets separated by your configured separator (default `---`):\n\n```\nI built a file-based tweet scheduler with no frontend. Your filesystem is the UI.\n---\nDrop a .md file into Monday/9am/ and a cron job posts it. Empty slot? It pulls from a backlog/ folder automatically.\n---\nNo database, no app, no dashboard. Just folders and text files. Sometimes the simplest architecture wins.\n```\n\n### Tweet with media\nPut image/video files in the same time folder as the tweet. Supported: JPG, PNG, GIF (under 5MB for images, 15MB for GIF).\n\n```\n9am/\n  tweet.md        ← the text\n  progress.png    ← gets attached\n```\n\nIf multiple media files exist, they attach in alphabetical order (max 4 per tweet).\n\n## Config\n\n`xqueue/config.json`:\n\n```json\n{\n  \"timezone\": \"America/Chicago\",\n  \"separator\": \"---\",\n  \"deleteAfterPost\": true,\n  \"communities\": {\n    \"Build in Public\": \"community_id\",\n    \"Indie Hackers\": \"community_id\"\n  },\n  \"logFile\": \"xqueue/posted.log\",\n  \"dryRun\": false\n}\n```\n\nDuring setup, paste the community URL (like `x.com/i/communities/123456`) or the numeric ID directly. The script extracts the ID and asks for a display name. Plain names without an ID are rejected — everything needed to post is captured upfront.\n\n## Backlog\n\nThe `xqueue/backlog/` folder holds tweets that aren't scheduled for a specific slot. When the cron fires and a time slot is empty, it pulls the oldest file from backlog (alphabetical sort — prefix with numbers like `01-`, `02-` to control order).\n\nThis lets you batch-write content without worrying about fitting it into exactly the right number of weekly slots. Schedule what's time-sensitive, backlog the rest.\n\n## Cron Integration\n\nThe skill includes a cron job that runs every 15 minutes:\n- Checks current day + time against folder structure\n- If slot has content → post it\n- If slot is empty → pull oldest from `backlog/`\n- If both are empty → skip\n- Logs results to posted.log\n- Deletes posted files (if deleteAfterPost is on)\n\n## What Goes Where\n\n| You want to...                        | Do this                                               |\n| ------------------------------------- | ----------------------------------------------------- |\n| Schedule a tweet for Tuesday 9am      | Drop a .md file in `xqueue/Tuesday/9am/`              |\n| Post a thread                         | One .md file with `---` between tweets                |\n| Attach an image                       | Put the image file in the same folder as the .md file |\n| Post to a community                   | Start text with `Post to Community Name:`             |\n| Reorder posts                         | Move files between time folders                       |\n| Skip a time slot                      | Leave the folder empty                                |\n| See what's queued                     | Browse the xqueue folder                              |\n| See what already posted               | Check xqueue/posted.log                               |\n| Queue content without a specific time | Drop it in `xqueue/backlog/`                          |\n| Control backlog order                 | Prefix filenames: `01-first.md`, `02-second.md`       |\n\n## Important\n\n- **deleteAfterPost: true** (default) means each file posts once then gets removed. If you turn this off, the same content will post again next week when the cycle repeats.\n- Tweets over 280 characters are rejected (logged as error, not posted).\n- Thread tweets are each checked for 280 char limit individually.\n- Empty folders are silently skipped.\n- The cron checks every 15 minutes, so posts go out within 0-15 min of the scheduled time.\n","tags":{"latest":"1.0.6"},"stats":{"comments":0,"downloads":1092,"installsAllTime":1,"installsCurrent":1,"stars":0,"versions":7},"createdAt":1771857011890,"updatedAt":1780803113047},"latestVersion":{"version":"1.0.6","createdAt":1780803113047,"changelog":"Refresh publisher identity and metadata for madebydia","license":"MIT-0"},"metadata":{"setup":[{"key":"X_CONSUMER_KEY","required":true},{"key":"X_CONSUMER_SECRET","required":true},{"key":"X_ACCESS_TOKEN","required":true},{"key":"X_ACCESS_TOKEN_SECRET","required":true}],"os":null,"systems":null},"owner":{"handle":"madebydia","userId":"s176b3312npmthbt2chf2mccw183grfh","displayName":"Diana Park","image":"https://avatars.githubusercontent.com/u/223051250?v=4"},"moderation":null}