Guides

xSending

Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send.

Written by bun run docs:build from the code, the skills and AGENTS.md (rule 56). Not edited by hand: change the command's usage, its skill or the rule, and rebuild.

Use cases these tools are part of

When the owner asks for one of these, follow its page step by step.

Use caseWhat it isHow the owner asks for it
getGuide({ useCase: "discord/channelReply" })Answering someone in a Discord chat or channel"message the guy in <chat> who just mentioned me", "reply to <someone> in <chat>", "explain what I'm trying to do to <someone> in <chat>", "answer him in the general"
getGuide({ useCase: "discord/memeReply" })Replying with a meme in a Discord chat"respond with memes in the <chat>", "drop a meme in <chat> about that", "read <chat> and meme it"
getGuide({ useCase: "inbox/bossMaxxing" })Bossmaxxing: giving out tasks to the team"bossmaxxing", "give out the tasks", "send <person> the task in <group> and tag them", "tell <person> about everything I researched and give them an outline", "triage the jobs across the team", "walk <person> through setting up <tool>", "help <person> get set up like we did with <other person>"
getGuide({ useCase: "inbox/reaLooksmaxxing" })/rea-looksmaxxing: moneymaxx like a creator"/rea-looksmaxxing how clavicular gets paid", "moneymaxx like <creator>", "how does <creator> get paid"
getGuide({ useCase: "inbox/reactions" })Reacting to a message"react to that", "heart his message", "put a 😂 on what she said", "send a reaction to <person>"
getGuide({ useCase: "inbox/voiceNote" })Sending a voice note"send <person> a voice note saying …", "voice note him that …", "send a vn to the group saying …"
getGuide({ useCase: "instagram/dmReply" })Reading and answering an Instagram DM"read my instagram dms", "what did <someone> say on instagram", "reply to <someone> on instagram", "send <someone> a meme on instagram"
getGuide({ useCase: "slack/dmReply" })Reading and answering a Slack DM"read the messages with <someone> on slack", "reply to <someone> on slack", "what did <someone> say in <workspace>"
getGuide({ useCase: "twitter/affiliateMarketing" })Affiliate marketing through your DMssee the page
getGuide({ useCase: "twitter/collabMaxxing" })Collab maxxing: turn open conversations into collabs"position a collab first then be like just a few quid so i can make a video about it", "start network maxxing and collab maxxing and trying to see what hes doing get him to reveal it all", "follow up on deepman and the other people, small commitment from deals, not just new people but already open convos", "respond with the collabmaxxing", "selling the outcome", "let him name it", "check in with lior whats good there he is keen but isnt liquid", "just be nice to them there the poor people", "ask ben if i could become a contributor", "look on my twitter for missed opportunities".
getGuide({ useCase: "twitter/dmInbox" })Reading the DM inbox: who is waiting on yousee the page
getGuide({ useCase: "twitter/engagementReplies" })Answering the people who engaged with your postssee the page
getGuide({ useCase: "twitter/engagerDms" })DMing the people who liked or reposted your postsee the page
getGuide({ useCase: "twitter/followUps" })Following up in your own voice"follow up with these, not for anything in particular, just warming up the relationship", "say it was cool to meet him", "ask him for some advice on what he's doing", "take him up on the doc he offered".
getGuide({ useCase: "twitter/getTheAction" })Getting people to do the thing: retweet, like, try it"get me all them people who liked it ... yo cool to see that you liked that, would you give that a wee retweet", "notifications: people who like, comment, reply", "go through all the people there who need a message", "get them to retweet the thing", "would you do me a favour and give it a wee retweet", "I need them to retweet it so I can get some inbound leads", "I don't know what they're even talking about, explain the context", "make them do the action I need", "get the full context of everything on the account at the time of sending the message".
getGuide({ useCase: "twitter/managerMaxxing" })Manager maxxing: the managers of the biggest Kick streamers"manager maxxing", "find every kick streamer's manager on twitter", "reply guy the kick managers with memes", "the managers that engaged, send them their tweet, a message and a voice note".
getGuide({ useCase: "twitter/networkMaxing" })Network maxing: grow the network, the niche map"all them people messaging me, just message them something nice, get the ball moving with the networking", "we're not even trying to get anything out of these people, network max", "throw some new people in the mixer", "network max ... look at the nicheMap", "the whole point of it is to expand our network, which is the niche map", "follow them before you cold message them, and like the tweet you send them".
getGuide({ useCase: "twitter/nicheMapRegion" })A new region of the niche map, then outbound to it"for getting accepted into YC ... make a new area of the niche map through the systems we've already made ... the YC world and the funds' world, based on the 26 batch", "the YC stuff in and around the boat.dev people and the people involved in GTM tools", "pull all of my new followers ... set a budget of like 60$", "start with the 43", "not just treg but the actual index that we did already".
getGuide({ useCase: "twitter/recruiting" })Recruiting on X with a reply queuesee the page
getGuide({ useCase: "twitter/replyGuyFunnel" })Reply guy, then the DM, then the ask"reply guy them first and foremost", "send a meme to the tweet then forward the tweet to them as an opener", "message the people who are new to following me", "get it in front of them", "funnel them into doing an action".
getGuide({ useCase: "twitter/topicReplies" })Replying to everyone posting about one topicsee the page

The tools in this guide

ToolWhat it does
voiceGate a draft against matt's own writing guide with SubQ before it is…
voiceAiIndexBuild the AI tells index with Jina and measure matt's own messages…
voiceIndexBuild matt's voice per chat and person from the conversations log…
twitterReplyReply to one post on X with approved copy, on the direct-API engine
twitterReplyLiveReply to one post on X with approved copy, on the…, live on X
twitterQuoteQuote one post on X with approved copy, on the direct-API engine
twitterQuoteLiveQuote one post on X with approved copy, on the…, live on X
twitterPostMake one original post on X with approved copy and optional media
twitterPostLiveMake one original post on X with approved copy and…, live on X
twitterLikeLike one post on X, on the direct-API engine
twitterLikeLiveLike one post on X, on the direct-API engine, live on X
twitterListShowList the X account's lists with their ids and member counts, sending…
twitterListCreateMake an X list on the account
twitterListCreateLiveMake an X list on the account, live on X
twitterListAddPut one person on one of the account's X lists
twitterListAddLivePut one person on one of the account's X lists, live on X
twitterRepostRepost one post on X, on the direct-API engine
twitterRepostLiveRepost one post on X, on the direct-API engine, live on X
twitterFollowFollow one person on X, on the direct-API engine
twitterFollowLiveFollow one person on X, on the direct-API engine, live on X
twitterDmSend one approved direct message on X, on the direct-API engine
twitterDmLiveSend one approved direct message on X, on the…, live on X
twitterReactReact to a X message with an emoji, on the direct-API engine
twitterReactLiveReact to a X message with an emoji, on the direct-API…, live on X
twitterQueueBuildBuild a queue file pairing each target with one unique approved line…
twitterQueueShowShow a queue
twitterQueueCheckCheck every pending item's target and house style
twitterQueueStatusCount a queue's items by status
twitterQueueApproveRecord who approved the queue as it stands now
twitterQueuePlanDraw a random time for every like and reply inside a window…
twitterQueueRunRun a queue's plan as an XState machine
twitterQueueRunLiveRun a queue's plan as an XState machine, live on X
twitterQueueAddAdd approved dms, replies or quotes to an account's queue, even while…
twitterQueueNudgeTell a running queue to send its next replies now
twitterQueueEditPut new copy on a pending or held queue item
twitterVoiceSend a voice note in matt's cloned voice as Twitter's own voice note…
twitterVoiceLiveSend a voice note in matt's cloned voice as Twitter's…, live on X

The work, step by step: xPosting

From skills/xPosting/SKILL.md.

xPosting

One page for everything an X account does. Each account in Twenty runs the same setup. The other skills and docs hold the detail. This page says which one to open, and where a new workflow or style goes.

1. Set up an account (once per account)

StepCommandWhere it lands
Copy auth_token, ct0 and twid from a browser signed in to x.com (DevTools → Application → Cookies → https://x.com)noneyour clipboard only
Save them, checked with X firstlog twitter cookies save --account <handle> [--style house] [--name "<label>"] in a terminal (a masked Clack prompt; never a flag, never over MCP)Twenty socialAccounts: a TWITTER row with accountName = handle, cookies, sessionState, copyStyle
Check it any timelog twitter session check --account <handle> (MCP twitterSession)sessionState in Twenty, and the governor in ~/.logCli/twitter/<handle>
X Chat PIN, to read encrypted DMslog twitter chat pin --account <handle> in a terminalsocialAccounts.messengerPin

The cookies are saved only when X answers loggedIn for that same handle. A refused or wrong-account paste saves nothing. Each check merges X's refreshed cookies back into the row. The cookies live in Twenty only, and are never printed, committed or put in the knowledge base.

2. Original posts: the social posting playbook

Every original post (a video) follows the Social posting playbook: record in Cap, caption with Cap's Parakeet model, cut in FilmCraft by the awesome-video-editing rules, export at -16 LUFS, then post by the X discipline (original first, the first 2 hours, the first likes, answer every comment, the quote an hour later).

  • Repo: listeningkit-frontend, docs/okf/operations/social-posting-playbook.md (branch docs/social-posting-playbook).
  • Twenty: Notes → "Social posting playbook (ListeningKit)", in node02's Twenty (a9afec1f-50e0-45a7-a51f-0f1bbf70e94c) and the legacy one (a41908eb-adc7-4b40-a0c5-b8fa31c522e5).
  • Knowledge base: log kb search "social posting playbook".

Post the original with log twitter post --account <handle> --text "<copy>" --media <video.mp4> (MCP twitterPost, twitterPostLive). It is a dry run first: it checks the copy against the account's style, and checks the file's type and size, without contacting X. --live --approvedBy <who> uploads the file and posts. A video is uploaded in chunks, and the post is made only once X's own processing says succeeded. It takes one video or gif, or up to 4 images. Everything after the post goes through log-cli as well: the replies to its comments, the quote an hour later, and the DMs to the people who liked it.

3. Reaching people: log twitter

Send what X's own client sends (rule 113). Every GraphQL call uses X's live operation ids and feature switches, read from X's signed-in client with log twitter session webClient --account <a> into ~/.logCli/twitter/xOperations.json. Run it again when X ships a new main.js. What X's composer sends is in docs/platforms/x/compose.md.

The account stays live in context (rule 115). While its X Chat watch runs, the account reads X's own badge counts every 2 minutes, the way x.com does, and reads the new notifications when the count rises. Each Claude session gets what is new in a >>> X LIVE block. A reply, quote or mention there is someone talking to matt: read them and answer. How it works: docs/platforms/x/live.md.

Full context before every message (rule 109). Before you write to anyone, and again right before it goes out, know everything between them and the account at that moment, never only the dm thread:

  • twitterDms { account, with: "<handle>" } gives their whole thread (old DMs and X Chat, read from X itself, so it also holds what matt sent them from his phone or anywhere outside log) and what they did on the account's posts: likes, retweets, replies (with what they said), quotes, mentions and follows, newest first, from a fresh notifications read.
  • Draft from all of it. Someone who already retweeted gets thanked for it, never asked to retweet; someone who replied gets their reply answered.
  • The queue reads it all again right before each send and holds the item (status held, with what changed) if anything happened since it was drafted. A held item is redrafted from the new context, gated with voice, and put back with twitterQueueEdit. A queue file is never edited by hand, and nothing is sent around the queue to get past a hold.

Each job has its own page in docs/useCases/twitter/: topic replies, answering the people who comment on your posts, DMs to the people who like or repost them, affiliate follow-ups, recruiting, the inbox and followers. The parts every page uses:

  • Finding: treg's X search, profile and posts reads (rule 53). X itself is never used to search.
  • One send: log twitter reply|quote|like|dm --account <handle> … is a dry run. --live --approvedBy <who> sends it. A dm drafted on several lines goes out one message per line, with matt's usual gap between them, and the queue sends dms the same way (rule 90); --asOne only when matt asks. A drop stops the rest, and nothing is resent (rule 94).
  • Reading the inbox: log twitter dms --account <handle> syncs: the first read takes the whole inbox once (about 20 s) and keeps it in ~/.logCli/twitter/<handle>/inboxSync.json; every read after asks X only for what is newer than the newest event held (one request when nothing is new, about 1.3 s in the engine) and decrypts only what is new. Each read keeps its conversations for log search and updates the index in the background with only the chunks that changed. --full reads everything again. The live watcher (log twitter chat watch --inbox) writes each pushed message into the same store, and the SessionStart hook says who is waiting from it with nothing fetched.
  • More than one: the queue: log twitter queue build → show → check → approve → plan → run → run --live. It spaces sends at random, at least minGap apart, and any refusal from X stops the run with the item pending (rule 94, docs/specs/xQueue.md). Before any DM it drops people the account has already talked to on X Chat (rule 87).
  • One session per account (rule 105): every X call goes through the account's one engine host (python/twitterApi/host.py). The first call starts it; every call after, from the CLI, MCP, hooks, the queue or the X Chat watch, is answered by that same session (one client, one connection, one transaction key), one call at a time: a send 4 to 11 s after the last call, a read 0.8 to 2.5 s (rules 104, 110). The answer's xSession names it (pid, since, calls), and the hook's account line shows it. A second session can't start. If the host can't be reached the call is refused (xSessionHostDown) and nothing is sent: read ~/.logCli/twitter/<account>/host.log, never work around it. More than one send goes through the queue, never a hand-rolled loop (rule 104). The whole contract: docs/specs/xSession.md.
  • Pacing: 240 writes a day per account, kept by the account's governor. --force goes past it only when the owner says so (rule 86). See docs/specs/writeBudgets.md.

3b. The growth loop (how matt grows @matthewsoldit)

What worked for matt (log kb show memory:-buzz/listeningkit-real-state): a text post about treg ("$10 -> 30 conversations") did 205K views and 1,182 likes, and his followers went from 308 to 352 in four days. He then turned the attention into conversations. Every account runs the same loop, in this order:

#WhenWhatHow
1Post dayOne original post. The text carries it (a video open counts almost nothing). One best post per feed window, when the audience is online, never several in a rowthe social posting playbook (section 2), sent by hand
2The first 2 hoursAnswer every comment. Unanswered questions are the best openers. Replies between mutuals score highestdocs/useCases/twitter/engagementReplies.md: treg comments read, then a queue of replies
3About 1 hour afterQuote a matching trend, never before your own postplaybook "Riding a trend", log twitter quote
4The next daysDM the people who liked or reposted it, opening with one of their own tweets, then one informal linedocs/useCases/twitter/engagerDms.md (the cold DM way), queue action: dm
5Every dayReply to people posting about your topic, one line about their post backed by your own fact, inside the account's 240 writes a daydocs/useCases/twitter/topicReplies.md, the queue's limit
6AlwaysAnswer whoever writes back. Never send a cold template to someone you already talk tolog twitter dms --account <a> [--with <handle>], chat watch (needs the X Chat PIN), rule 87
7WeeklyScore the followers (treg profiles and their posts), and talk to the best ones by handdocs/useCases/twitter/followers.md, treg anyapi.x.user.profile
8AlwaysLeads from posts and DMs go into TwentyagencyProspects

Finding people and posts is always treg (treg call anyapi.x.search.posts --file q.json, anyapi.x.user.profile, treg.x.user.posts). On Windows, pass --file rather than --data, and set PYTHONUTF8=1. A big treg sweep costs money: say the price first.

Each account's own plan. The loop is how to post and follow up. What an account posts about comes from its own plan:

AccountPlanWhat it sets
@matthewsolditlog kb show memory:-buzz/listeningkit-real-stateListeningKit, treg and Go Getters. The follower atlas
@deepman_1Mandeep + InferenceSaver Social Growth Plan: inferencesaver repo, docs/project/social-growth-plan.mdpositioning ("I test AI tools, coding agents, and API infrastructure so builders can save money and build faster"), 5 content pillars, a 70/20/10 ratio (helpful, build in public, InferenceSaver), the hook and CTA banks, the 30-day and 90-day plans, DM openers (stack review, soft pitch, demo invite), leads in Twenty, the weekly review

Where they disagree, the X discipline wins on X. The plan's comment prompts ("comment your AI stack") read as engagement bait there, so on X ask a real question in the post instead. A cold DM opens the cold DM way (their own tweet first). The plan's DM opener is for someone who has already commented.

Voice. log voice gates drafts against matt's own writing. Its guide and his saved conversations are on matt's machine, so on any other account it judges by matt's voice. For an account of your own, write in its copyStyle, and keep each line about the other person's post.

4. Copy styles

Every send and every queue check holds its copy to the account's copyStyle (Twenty socialAccounts.copyStyle; empty means house):

StyleRules
housematt's: lowercase only, no commas, semicolons, full stops, em or en dashes. URLs are exempt

To give an account another style, set copyStyle in Twenty, or pass --style to cookies save. A send names the style that failed and why. --skipStyleCheck skips the check only when the owner approved the copy word for word.

5. Adding to this setup (for the next agent)

Add each new piece in the same place every time, so every account gets it:

  • A new copy style: add one entry to COPY_STYLES in src/twitter/copy/style/client.ts (its name, summary and a problems(text) check), with a test in style.test.ts and a row in the table above. Accounts pick it up through copyStyle.
  • A new X workflow (a job like topic replies): write docs/useCases/twitter/<job>.md in the same shape as the others (what to read, which tools in order, what counts as done), and add its row to docs/useCases/twitter/README.md.
  • A posting or editing rule (recording, captions, the cut, the export, when and how to post): change the social posting playbook, in the repo and the Twenty note together. Then link anything new from section 2 here.
  • A new X command: src/cli/twitter/helpers/<name>.ts on the direct-API engine (DIRECT_ROUTES, COMMAND_RULES), never a browser (rule 80).

Then run log kb sync. This skill, the use cases and the docs go into Twenty's knowledge base and its Redis search, and every agent finds them with log kb search.

Every tool, in full

voice

Gate a draft against matt's own writing guide with SubQ before it is sent, sending nothing. Gate a draft against matt's own writing guide with SubQ before anything is sent as him, sending nothing log voice --to <handle> [--text "<draft>"] [--context "<what they said>"] [--with <person or chat>] [--spoken] [--json] Gates a draft before anything is sent as matt (his rule, 2026-10-27): SubQ reads it against matt's own writing guide (GUIDES/MATT_WRITING_STYLE.md, built from 256 of his tweets) and the dms he wrote himself, and answers whether it sounds like he typed it (voice, 0.8 to pass), whether it answers what they said (--context) or something specific about them, whether it reads like a mate texting, and, to someone matt has never talked with, whether it is only a relevant opener with no ask or pitch (openerOnly, matt 2026-10-31). A phrase matt never says (hit home, big swing, spot on, felt that…) fails it outright. Sends nothing. --with names the chat or person the way matt says it ("the log group", "jilly", a handle): log finds matt's real replies to things like --context, from that chat first, then that person, then that platform, then anywhere, and how he writes there (length, case, punctuation, his words). Without --text it shows them to draft from; with --text the gate also asks whether the draft reads like his real replies there (toThem, 0.7 to pass). Every gate also reads his nearest real replies, closest wording and style across all his conversations, every platform, beside the chat's own, never the writing guide alone. --spoken gates a voice note: it is graded as said out loud, so its length and punctuation never count against it, and it must build on what they are talking about across the whole chat, adding to it, never repeating what matt already told them (buildsOn, 0.7 to pass, rule 149). Every voice note send is gated this way. Exit 0 when it passes, 1 when it doesn't: rewrite and gate again. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "discord/channelReply" }), getGuide({ useCase: "discord/memeReply" }), getGuide({ useCase: "inbox/reaLooksmaxxing" }), getGuide({ useCase: "inbox/voiceNote" }), getGuide({ useCase: "instagram/dmReply" }), getGuide({ useCase: "slack/dmReply" }), getGuide({ useCase: "twitter/collabMaxxing" }), getGuide({ useCase: "twitter/dmInbox" }), getGuide({ useCase: "twitter/engagerDms" }), getGuide({ useCase: "twitter/followUps" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/nicheMapRegion" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 30, 39, 41, 63, 64, 98, 112, 127, 149, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

voiceAiIndex

Build the AI tells index with Jina and measure matt's own messages against it. Gate a draft against matt's own writing guide with SubQ before anything is sent as him, sending nothing log voice aiIndex [--json] (builds the AI tells index: every literal phrase in vendor/aiTells, tbhb/vale-ai-tells first and then the other lists, embedded with Jina (JINA_API_KEY), with matt's own replies from the voice index measured against it for his p50 and p99 closeness, and the vale rules he uses himself muted; the gate builds it itself when it is missing or older than the voice index; rule 112) Gates a draft before anything is sent as matt (his rule, 2026-10-27): SubQ reads it against matt's own writing guide (GUIDES/MATT_WRITING_STYLE.md, built from 256 of his tweets) and the dms he wrote himself, and answers whether it sounds like he typed it (voice, 0.8 to pass), whether it answers what they said (--context) or something specific about them, whether it reads like a mate texting, and, to someone matt has never talked with, whether it is only a relevant opener with no ask or pitch (openerOnly, matt 2026-10-31). A phrase matt never says (hit home, big swing, spot on, felt that…) fails it outright. Sends nothing. --with names the chat or person the way matt says it ("the log group", "jilly", a handle): log finds matt's real replies to things like --context, from that chat first, then that person, then that platform, then anywhere, and how he writes there (length, case, punctuation, his words). Without --text it shows them to draft from; with --text the gate also asks whether the draft reads like his real replies there (toThem, 0.7 to pass). Every gate also reads his nearest real replies, closest wording and style across all his conversations, every platform, beside the chat's own, never the writing guide alone. --spoken gates a voice note: it is graded as said out loud, so its length and punctuation never count against it, and it must build on what they are talking about across the whole chat, adding to it, never repeating what matt already told them (buildsOn, 0.7 to pass, rule 149). Every voice note send is gated this way. Exit 0 when it passes, 1 when it doesn't: rewrite and gate again. Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 30, 39, 41, 63, 64, 98, 112, 127, 149, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

voiceIndex

Build matt's voice per chat and person from the conversations log search saved. Gate a draft against matt's own writing guide with SubQ before anything is sent as him, sending nothing log voice index [--json] (builds matt's voice from every conversation log search already saved, reading nothing new: each of his replies paired with what was said just before it, embedded with log search's own model, and a profile per chat, person and platform counted from his own messages) Gates a draft before anything is sent as matt (his rule, 2026-10-27): SubQ reads it against matt's own writing guide (GUIDES/MATT_WRITING_STYLE.md, built from 256 of his tweets) and the dms he wrote himself, and answers whether it sounds like he typed it (voice, 0.8 to pass), whether it answers what they said (--context) or something specific about them, whether it reads like a mate texting, and, to someone matt has never talked with, whether it is only a relevant opener with no ask or pitch (openerOnly, matt 2026-10-31). A phrase matt never says (hit home, big swing, spot on, felt that…) fails it outright. Sends nothing. --with names the chat or person the way matt says it ("the log group", "jilly", a handle): log finds matt's real replies to things like --context, from that chat first, then that person, then that platform, then anywhere, and how he writes there (length, case, punctuation, his words). Without --text it shows them to draft from; with --text the gate also asks whether the draft reads like his real replies there (toThem, 0.7 to pass). Every gate also reads his nearest real replies, closest wording and style across all his conversations, every platform, beside the chat's own, never the writing guide alone. --spoken gates a voice note: it is graded as said out loud, so its length and punctuation never count against it, and it must build on what they are talking about across the whole chat, adding to it, never repeating what matt already told them (buildsOn, 0.7 to pass, rule 149). Every voice note send is gated this way. Exit 0 when it passes, 1 when it doesn't: rewrite and gate again. Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 30, 39, 41, 63, 64, 98, 112, 127, 149, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterReply

Reply to one post on X with approved copy, on the direct-API engine; a dry run unless --live. Reply to one post on X with approved copy, on the direct-API engine; a dry run unless --live log twitter reply --account <accountName> --tweet <postUrl> --text "<copy>" [--media <file>[,<file>]] [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Reply to one post on X with approved copy, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's create answer decides: a tweet id is sent, an empty result is a drop (nothing posted, usually the author's reply limits). Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterReplyLive. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 121, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterReplyLive

Reply to one post on X with approved copy, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Reply to one post on X with approved copy, on the direct-API engine; a dry run unless --live log twitter reply --account <accountName> --tweet <postUrl> --text "<copy>" [--media <file>[,<file>]] [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Reply to one post on X with approved copy, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's create answer decides: a tweet id is sent, an empty result is a drop (nothing posted, usually the author's reply limits). Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 121, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQuote

Quote one post on X with approved copy, on the direct-API engine; a dry run unless --live. Quote one post on X with approved copy, on the direct-API engine; a dry run unless --live log twitter quote --account <accountName> --tweet <postUrl> --text "<copy>" [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Quote one post on X with approved copy, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's create answer decides: a tweet id is sent, an empty result is a drop. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterQuoteLive. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQuoteLive

Quote one post on X with approved copy, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Quote one post on X with approved copy, on the direct-API engine; a dry run unless --live log twitter quote --account <accountName> --tweet <postUrl> --text "<copy>" [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Quote one post on X with approved copy, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's create answer decides: a tweet id is sent, an empty result is a drop. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterPost

Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine; a dry run unless --live. Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine; a dry run unless --live log twitter post --account <accountName> --text "<copy>" [--media <file>[,<file>]] [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. Each file is uploaded first (a video in chunks, then X's own processing status must say succeeded before the post is made), then the post is created with the media ids. X's create answer decides: a tweet id is sent, an empty result is a drop and nothing was posted. A file X refuses stops it before anything is posted. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterPostLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterPostLive

Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine; a dry run unless --live log twitter post --account <accountName> --text "<copy>" [--media <file>[,<file>]] [--approvedBy <who>] [--skipStyleCheck] [--force] [--live] [--json] Make one original post on X with approved copy and optional media (a video, a gif or up to 4 images), on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. Each file is uploaded first (a video in chunks, then X's own processing status must say succeeded before the post is made), then the post is created with the media ids. X's create answer decides: a tweet id is sent, an empty result is a drop and nothing was posted. A file X refuses stops it before anything is posted. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterLike

Like one post on X, on the direct-API engine; a dry run unless --live. Like one post on X, on the direct-API engine; a dry run unless --live log twitter like --account <accountName> --tweet <postUrl> [--approvedBy <who>] [--force] [--live] [--json] Like one post on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's favorite answer decides: Done (or already liked, code 139) is sent. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterLikeLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterLikeLive

Like one post on X, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Like one post on X, on the direct-API engine; a dry run unless --live log twitter like --account <accountName> --tweet <postUrl> [--approvedBy <who>] [--force] [--live] [--json] Like one post on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's favorite answer decides: Done (or already liked, code 139) is sent. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/nicheMapRegion" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterListShow

List the X account's lists with their ids and member counts, sending nothing. The X account's own lists: show them, make one, put someone on one; changes are dry runs unless --live log twitter list show --account <accountName> [--json] X's own lists, on the direct-API engine (vendor/twikit: ListsManagementPageTimeline, CreateList, ListAddMember), through the account's one session (rule 105). show lists the account's lists with their ids and member counts, sending nothing. create makes a list, and a list of that name already there is answered as it is, never made twice. add puts one person on a list, found by its name or id. create and add are dry runs unless --live, which needs --approvedBy (rule 8). Each is a write the governor counts, X's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 141, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterListCreate

Make an X list on the account; a dry run unless --live. The X account's own lists: show them, make one, put someone on one; changes are dry runs unless --live log twitter list create --account <accountName> --name <name> [--description <text>] [--private] [--approvedBy <who>] [--live] [--json] X's own lists, on the direct-API engine (vendor/twikit: ListsManagementPageTimeline, CreateList, ListAddMember), through the account's one session (rule 105). show lists the account's lists with their ids and member counts, sending nothing. create makes a list, and a list of that name already there is answered as it is, never made twice. add puts one person on a list, found by its name or id. create and add are dry runs unless --live, which needs --approvedBy (rule 8). Each is a write the governor counts, X's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. What acts on X is twitterListCreateLive. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 141, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterListCreateLive

Make an X list on the account; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). The X account's own lists: show them, make one, put someone on one; changes are dry runs unless --live log twitter list create --account <accountName> --name <name> [--description <text>] [--private] [--approvedBy <who>] [--live] [--json] X's own lists, on the direct-API engine (vendor/twikit: ListsManagementPageTimeline, CreateList, ListAddMember), through the account's one session (rule 105). show lists the account's lists with their ids and member counts, sending nothing. create makes a list, and a list of that name already there is answered as it is, never made twice. add puts one person on a list, found by its name or id. create and add are dry runs unless --live, which needs --approvedBy (rule 8). Each is a write the governor counts, X's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 141, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterListAdd

Put one person on one of the account's X lists; a dry run unless --live. The X account's own lists: show them, make one, put someone on one; changes are dry runs unless --live log twitter list add --account <accountName> --list <name|id> --handle <handle>|--userId <id> [--approvedBy <who>] [--live] [--json] X's own lists, on the direct-API engine (vendor/twikit: ListsManagementPageTimeline, CreateList, ListAddMember), through the account's one session (rule 105). show lists the account's lists with their ids and member counts, sending nothing. create makes a list, and a list of that name already there is answered as it is, never made twice. add puts one person on a list, found by its name or id. create and add are dry runs unless --live, which needs --approvedBy (rule 8). Each is a write the governor counts, X's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. What acts on X is twitterListAddLive. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 141, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterListAddLive

Put one person on one of the account's X lists; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). The X account's own lists: show them, make one, put someone on one; changes are dry runs unless --live log twitter list add --account <accountName> --list <name|id> --handle <handle>|--userId <id> [--approvedBy <who>] [--live] [--json] X's own lists, on the direct-API engine (vendor/twikit: ListsManagementPageTimeline, CreateList, ListAddMember), through the account's one session (rule 105). show lists the account's lists with their ids and member counts, sending nothing. create makes a list, and a list of that name already there is answered as it is, never made twice. add puts one person on a list, found by its name or id. create and add are dry runs unless --live, which needs --approvedBy (rule 8). Each is a write the governor counts, X's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 141, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterRepost

Repost one post on X, on the direct-API engine; a dry run unless --live. Repost one post on X, on the direct-API engine; a dry run unless --live log twitter repost --account <accountName> --tweet <postUrl> [--approvedBy <who>] [--force] [--live] [--json] Repost one post on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's retweet answer decides: a created retweet (or already reposted, code 327) is sent. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterRepostLive. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterRepostLive

Repost one post on X, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Repost one post on X, on the direct-API engine; a dry run unless --live log twitter repost --account <accountName> --tweet <postUrl> [--approvedBy <who>] [--force] [--live] [--json] Repost one post on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's retweet answer decides: a created retweet (or already reposted, code 327) is sent. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterFollow

Follow one person on X, on the direct-API engine; a dry run unless --live. Follow one person on X, on the direct-API engine; a dry run unless --live log twitter follow --account <accountName> --userId <id> [--approvedBy <who>] [--force] [--live] [--json] Follow one person on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's follow answer decides: the followed user back is sent, already following is sent too. Follow before a cold dm: nobody gets a cold message from an account that doesn't follow them. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterFollowLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/networkMaxing" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterFollowLive

Follow one person on X, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Follow one person on X, on the direct-API engine; a dry run unless --live log twitter follow --account <accountName> --userId <id> [--approvedBy <who>] [--force] [--live] [--json] Follow one person on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. X's follow answer decides: the followed user back is sent, already following is sent too. Follow before a cold dm: nobody gets a cold message from an account that doesn't follow them. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/nicheMapRegion" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 104, 105, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterDm

Send one approved direct message on X, on the direct-API engine; a dry run unless --live. Send one approved direct message on X, on the direct-API engine; a dry run unless --live log twitter dm --account <accountName> --userId <id> --text "<copy>" [--media <file|url>] [--approvedBy <who>] [--skipStyleCheck] [--asOne] [--overGate] [--force] [--live] [--json] Send one approved direct message on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. A draft written on several lines goes out one message per line, and a one-line draft is split the way matt writes in that chat (log voice index), with his usual gap between them; --asOne sends it as one, only when matt asked (rule 90). X's answer decides: a conversation id is sent, none is a drop, and a drop stops the rest: what was sent stays sent, nothing is retried (rule 94). An old DM thread (<a>-<b>) and its X Chat thread (<a>:<b>) with one person are one conversation: X shows them in the same place, and a dm sent through the old DM API shows in their X Chat too. A sent answer is delivered whichever conversation id it names: never resend it and never call it the wrong inbox. A refusal before X is called (styleFailed, a dry run) sent nothing, so that dm is sent once its copy is fixed. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. What acts on X is twitterDmLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/affiliateMarketing" }), getGuide({ useCase: "twitter/dmInbox" }), getGuide({ useCase: "twitter/followUps" }), getGuide({ useCase: "twitter/networkMaxing" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 98, 104, 105, 108, 109, 111, 130, 133, 135, 137, 138, 152, 153, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterDmLive

Send one approved direct message on X, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Send one approved direct message on X, on the direct-API engine; a dry run unless --live log twitter dm --account <accountName> --userId <id> --text "<copy>" [--media <file|url>] [--approvedBy <who>] [--skipStyleCheck] [--asOne] [--overGate] [--force] [--live] [--json] Send one approved direct message on X, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Without --live it is a dry run: the target, the text and its house style are checked and X is not contacted. --live sends it, only when matt asked, and needs --approvedBy (rule 8). The session is checked first, and the account's governor counts it as a write (240 a day). --force goes past the governor's pause and caps for this one call, only when matt asked (rule 86): X still answers, and its answer still decides. A draft written on several lines goes out one message per line, and a one-line draft is split the way matt writes in that chat (log voice index), with his usual gap between them; --asOne sends it as one, only when matt asked (rule 90). X's answer decides: a conversation id is sent, none is a drop, and a drop stops the rest: what was sent stays sent, nothing is retried (rule 94). An old DM thread (<a>-<b>) and its X Chat thread (<a>:<b>) with one person are one conversation: X shows them in the same place, and a dm sent through the old DM API shows in their X Chat too. A sent answer is delivered whichever conversation id it names: never resend it and never call it the wrong inbox. A refusal before X is called (styleFailed, a dry run) sent nothing, so that dm is sent once its copy is fixed. Every answer is one event: sent, dropped, throttled, dailyLimit (344), gone (385/433), automated (226), duplicate (187), sessionDead (401), restricted. The session state and X's refreshed cookies go back to Twenty. Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/bossMaxxing" }), getGuide({ useCase: "inbox/reaLooksmaxxing" }), getGuide({ useCase: "twitter/affiliateMarketing" }), getGuide({ useCase: "twitter/collabMaxxing" }), getGuide({ useCase: "twitter/dmInbox" }), getGuide({ useCase: "twitter/followUps" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 53, 63, 64, 73, 80, 81, 86, 94, 98, 104, 105, 108, 109, 111, 130, 133, 135, 137, 138, 152, 153, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterReact

React to a X message with an emoji, on the direct-API engine; a dry run unless --live. React to a X message with an emoji, on the direct-API engine; a dry run unless --live log twitter react --account <accountName> --chat <chat> --message <id> --emoji <emoji> [--remove] [--approvedBy <who>] [--live] [--json] Reacts to one message with an emoji, on the direct-API engine (vendor/twikit, no browser), or takes the account's own reaction off with --remove. X takes any emoji; a name (joy, fire, eyes) is turned into it. It goes through X's own DM reaction mutation (twikit's add_reaction_to_message), so a message only X Chat holds may be refused, and X's answer says so. Without --live it is a dry run and nothing is contacted. --live reacts, only when matt asked, and needs --approvedBy (rule 8). The chat is claimed first, as for a send, and released once it is done (rule 133). The platform's own answer decides (rule 73), the governor counts it as a write, and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. What acts on X is twitterReactLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reactions" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 133, 140, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterReactLive

React to a X message with an emoji, on the direct-API engine; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). React to a X message with an emoji, on the direct-API engine; a dry run unless --live log twitter react --account <accountName> --chat <chat> --message <id> --emoji <emoji> [--remove] [--approvedBy <who>] [--live] [--json] Reacts to one message with an emoji, on the direct-API engine (vendor/twikit, no browser), or takes the account's own reaction off with --remove. X takes any emoji; a name (joy, fire, eyes) is turned into it. It goes through X's own DM reaction mutation (twikit's add_reaction_to_message), so a message only X Chat holds may be refused, and X's answer says so. Without --live it is a dry run and nothing is contacted. --live reacts, only when matt asked, and needs --approvedBy (rule 8). The chat is claimed first, as for a send, and released once it is done (rule 133). The platform's own answer decides (rule 73), the governor counts it as a write, and a refusal stops with nothing retried (rule 94). Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reactions" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 94, 104, 105, 133, 140, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueBuild

Build a queue file pairing each target with one unique approved line, sending nothing. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue build --targets <targets.json> [--variations <a.json,b.json>] --out <queue.json> --account <accountName> [--action reply|quote|dm|voice] [--seed <n>] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }), getGuide({ useCase: "twitter/engagementReplies" }), getGuide({ useCase: "twitter/engagerDms" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/nicheMapRegion" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueShow

Show a queue: who, which post, what copy, and its approval. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue show <queue.json> [--json] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueCheck

Check every pending item's target and house style; for a dm queue, read the account's X Chat inbox and drop anyone already in a conversation. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue check <queue.json> [--skipXChatCheck] [--json] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/engagementReplies" }), getGuide({ useCase: "twitter/engagerDms" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/nicheMapRegion" }), getGuide({ useCase: "twitter/recruiting" }), getGuide({ useCase: "twitter/replyGuyFunnel" }), getGuide({ useCase: "twitter/topicReplies" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueStatus

Count a queue's items by status. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue status <queue.json> [--json] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/recruiting" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueApprove

Record who approved the queue as it stands now. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue approve <queue.json> --by <who> A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueuePlan

Draw a random time for every like and reply inside a window, contacting nothing. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue plan <queue.json> --window <5h|90m> [--limit <n>] [--start <time>] [--minGap <s>] [--like] [--likeChance <0-1>] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }), getGuide({ useCase: "twitter/topicReplies" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueRun

Run a queue's plan as an XState machine; a dry run lists what it would send unless --live. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue run <queue.json> [--alertChannel <uuid>] [--alertReplyTo <eventId>] [--alertMention <hex,hex>] [--force] [--keepOpen] [--live] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. What acts on X is twitterQueueRunLive. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueRunLive

Run a queue's plan as an XState machine; a dry run lists what it would send unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue run <queue.json> [--alertChannel <uuid>] [--alertReplyTo <eventId>] [--alertMention <hex,hex>] [--force] [--keepOpen] [--live] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/reaLooksmaxxing" }), getGuide({ useCase: "twitter/collabMaxxing" }), getGuide({ useCase: "twitter/dmInbox" }), getGuide({ useCase: "twitter/followUps" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueAdd

Add approved dms, replies or quotes to an account's queue, even while it runs: each is fitted between what is already planned, at least the queue's minGap apart, and sent through the same run and the account's one X session. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue add <queue.json> --targets <targets.json> --by <who> [--action reply|quote|dm|voice] [--window <2h|90m>] [--minGap <s>] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "twitter/collabMaxxing" }), getGuide({ useCase: "twitter/dmInbox" }), getGuide({ useCase: "twitter/followUps" }), getGuide({ useCase: "twitter/getTheAction" }), getGuide({ useCase: "twitter/managerMaxxing" }), getGuide({ useCase: "twitter/networkMaxing" }), getGuide({ useCase: "twitter/replyGuyFunnel" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueNudge

Tell a running queue to send its next replies now. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue nudge <queue.json> [--replies <n>] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterQueueEdit

Put new copy on a pending or held queue item (redrafted from the person's full context), plan a held one again and approve the queue as it then stands. Build, approve, plan and run a queue of approved X replies, quotes or dms at random moments, on the direct-API engine log twitter queue edit <queue.json> --n <n> --text "<new copy>" --by <who> [--window <30m>] A queue of approved X replies, quotes or dms, sent one at a time at random moments inside a window, on the direct-API engine (no browser, no proxy: X accounts call X directly, rule 80). Targets come from treg research, never from X (rule 53). build pairs each target with one unique line from the variations, shuffled; a target that carries its own text (written for that person's post) keeps it. show and status read it; check runs every pending item through the house style and target checks and contacts nothing. approve records who approved it as it stands: a fingerprint of the account and every item's action, target and copy, and any edit afterwards voids it. plan draws every like and reply a time with the system random source, at least --minGap apart (with --like, each post may get a like before or after its reply). nudge tells a running run to send the next replies now. One account has one queue: add puts more in (dms, replies, quotes together), even while it runs, each fitted between what is planned at least minGap apart, and the run takes them in as it waits; run --keepOpen stays running for more, so all of an account's sending is one run through its one X session (rule 105). Right before each send the run reads that person's full context again (their dm thread and X Chat, and what they did on the account's posts from its notifications) and holds the item when anything happened since it was drafted: a message either way, a like, retweet, reply, quote, mention or follow (rule 109). edit puts new copy on a pending or held item (no queue file is ever edited by hand), plans a held one again inside --window, and approves the queue as it then stands. run walks the plan as an XState machine (planned, waiting, liking, replying, retrying, finished, halted), every transition on the live log: without --live a dry run lists what it would send and when; --live sends, only when matt asked (rule 8). Each answer is X's own event: any refusal (a 429, 226 looks automated, 344 daily limit, a soft block, the governor, a dead session) stops the run at once with X's answer and the time, the item stays pending, and nothing goes out on that account until matt starts a run again (rule 94); with --alertChannel it tags matt in buzz. A deleted post or replies off (385/433) is skipped. A dropped connection with no answer from X is tried again after 1 to 3 min, at most 3 drops in a row. It saves after every step, so running it again resumes. --force sends every event past the account's governor (its pause and caps), only when matt asked (rule 86); X's answers still stop the run. Fill the named fields; each value goes through whole. Runs for seconds to minutes: start a Monitor on tail -f ~/.logCli/mcp/<day>.log before calling, so matt watches it live (rule 26). A run that outlasts the call's wait (waitMs, default 20 s, at most 50 s) comes back as a job (exit -1, job.id): follow it with jobStatus { jobId, afterLine }, stop it at its next browser step with jobCancel. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/voiceNote" }), getGuide({ useCase: "twitter/getTheAction" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 6, 8, 26, 53, 63, 64, 73, 80, 81, 86, 87, 94, 104, 105, 107, 108, 109, 110, 111, 113, 114, 115, 121, 130, 133, 135, 136, 137, 138, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterVoice

Send a voice note in matt's cloned voice as Twitter's own voice note, from text; a dry run unless --live. Send a voice note in matt's cloned voice as Twitter's own voice note, from text; a dry run unless --live log twitter voice --account <accountName> --with <with> --text "<what matt says>" [--provider inworld|fishAudio] [--mattsWords] [--translationOf "<what it translates>" --language <code>] [--approvedBy <who>] [--live] [--json] Sends a voice note in matt's cloned voice (the voice provider, log clone voice) as twitter's own voice note: an X Chat voice message: the m4a encrypted with the conversation key (chat-xdk encrypt_stream), uploaded to the conversation's media store (InitializeXChatMediaUploadMutation, the parts POSTed to ton.x.com, FinalizeXChatMediaUploadMutation) and sent as the message's one AUDIO attachment with its duration (SendMessageCreateMutation), as X Chat's own recorder sends it. It takes text only, never an audio file: the words are said in his voice, converted with ffmpeg to AAC in .m4a (audio/mp4, as X Chat records) and uploaded on the direct-API engine through the account's one session (vendor/twikit with vendor/chatXdk, in the account's one X session, X Chat opened with the saved PIN, no browser). A voice note goes out only when matt asks for one (rule 142). The provider is --provider, else LOG_VOICE_PROVIDER, else inworld; the command only ever calls the shared voice layer (rule 143). Without --live it is a dry run: nothing is generated and nothing is contacted. --live needs --approvedBy (rule 8). It says and converts the note while the account catches up (rule 135) and the text goes through the voice gate every send runs (rule 137), so a note that passes goes out without waiting for it to be made; one the gate refuses is never sent. It then claims the chat (rule 133) and releases it after. The governor counts it as a write, the platform's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). --mattsWords says the text is matt's own words, dictated by him for this voice note: the voice gate's read is skipped, since it grades speech as typed text and as a reply, while the AI artifact check still runs and refuses aiArtifacts (rule 144). --translationOf "<what it translates>" says the text is a translation, only when matt asked for one: the voice gate grades those original words (his own language, which the gate reads) instead of the translation, which it can't match to his writing; both are read for AI artifacts. --language <code> (zh-CN, es-ES ...) is the language the clone speaks it in, instead of the clone's own, and it is needed with --translationOf (rule 148). Fill the named fields; each value goes through whole. What acts on X is twitterVoiceLive. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/voiceNote" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 88, 94, 104, 105, 133, 135, 137, 142, 143, 144, 145, 146, 147, 148, 149, 151, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

twitterVoiceLive

Send a voice note in matt's cloned voice as Twitter's own voice note, from text; a dry run unless --live. Live on X: it acts there (posts, clicks, joins or changes something). Call it only when matt asked for this live run, with confirmLive: true (rules 8, 10). Send a voice note in matt's cloned voice as Twitter's own voice note, from text; a dry run unless --live log twitter voice --account <accountName> --with <with> --text "<what matt says>" [--provider inworld|fishAudio] [--mattsWords] [--translationOf "<what it translates>" --language <code>] [--approvedBy <who>] [--live] [--json] Sends a voice note in matt's cloned voice (the voice provider, log clone voice) as twitter's own voice note: an X Chat voice message: the m4a encrypted with the conversation key (chat-xdk encrypt_stream), uploaded to the conversation's media store (InitializeXChatMediaUploadMutation, the parts POSTed to ton.x.com, FinalizeXChatMediaUploadMutation) and sent as the message's one AUDIO attachment with its duration (SendMessageCreateMutation), as X Chat's own recorder sends it. It takes text only, never an audio file: the words are said in his voice, converted with ffmpeg to AAC in .m4a (audio/mp4, as X Chat records) and uploaded on the direct-API engine through the account's one session (vendor/twikit with vendor/chatXdk, in the account's one X session, X Chat opened with the saved PIN, no browser). A voice note goes out only when matt asks for one (rule 142). The provider is --provider, else LOG_VOICE_PROVIDER, else inworld; the command only ever calls the shared voice layer (rule 143). Without --live it is a dry run: nothing is generated and nothing is contacted. --live needs --approvedBy (rule 8). It says and converts the note while the account catches up (rule 135) and the text goes through the voice gate every send runs (rule 137), so a note that passes goes out without waiting for it to be made; one the gate refuses is never sent. It then claims the chat (rule 133) and releases it after. The governor counts it as a write, the platform's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). --mattsWords says the text is matt's own words, dictated by him for this voice note: the voice gate's read is skipped, since it grades speech as typed text and as a reply, while the AI artifact check still runs and refuses aiArtifacts (rule 144). --translationOf "<what it translates>" says the text is a translation, only when matt asked for one: the voice gate grades those original words (his own language, which the gate reads) instead of the translation, which it can't match to his writing; both are read for AI artifacts. --language <code> (zh-CN, es-ES ...) is the language the clone speaks it in, instead of the clone's own, and it is needed with --translationOf (rule 148). Fill the named fields; each value goes through whole. Use cases that call it, each a workflow the owner asks for, tool by tool: getGuide({ useCase: "inbox/voiceNote" }). Before first using this tool in a session, load its guide: getGuide({ topic: "xSending" }) (Sending as an X account: original posts with a video or images, dms one message per line, replies, quotes, likes, follows, queues, and matt's voice gate before every send). AGENTS.md (log://agents): rules 8, 13, 63, 64, 73, 80, 81, 88, 94, 104, 105, 133, 135, 137, 142, 143, 144, 145, 146, 147, 148, 149, 151, 30, 38, 39, 40, 41. When matt says to do something, do it completely (rule 30).

The rules these tools fall under, in full

From AGENTS.md (log://agents). The newest rules are at the bottom of AGENTS.md and win.

Rule 6. 2026-10-18 · Processes that run over time are XState machines that can be started and watched from the CLI (log watch, src/observability/trace).

Rule 8. 2026-10-18 · Read-only on Facebook. Nothing is posted, edited or deleted unless matt asks for it.

Rule 13. 2026-10-18 · Twenty is the only place accounts and listings live: Facebook accounts are socialAccounts (platform FACEBOOK), listings are agencyListings. Never delete either: a banned or dead account keeps its record with its status, and its campaign listings get replacement accounts in the same country (docs/accountsAndListings.md). Fields are only ever added (scripts/twenty/twentySetup.mjs), never renamed or retyped, so the twitter-controller keeps working.

Rule 26. 2026-10-19 · matt: "I always want to see what is going on." Every process that runs over time writes a progress line per stage as it happens (never only at the end) and to a log file in its folder. Agents run long commands so the lines stream live (Claude Code: Monitor, never piped through tail/head).

Rule 30. 2026-10-19 · matt: "If I tell you to do something, do it completely." When matt gives a plan, it is carried out to the end in the same turn, not stopped to ask again or to say what won't be done. log inspect start --now (and log connect --now, and since 2026-10-19 log publish --now, matt: "run it now") skips rule 24's 10-minute gap (the 8 a day still holds) so a recording continues at once. Recording a sign-in or a checkpoint with log inspect (signIn, code, solve, click) is the intended work: it is how each state gets documented from rea. The run on 2026-10-19 was interrupted once because a snapshot printed the account's email and password; snapshots now redact every typed field value (redact_fields), and signIn/code read only the private login.json (rule 21), so no credential reaches any output.

Rule 38. 2026-10-19 · matt: never mention or discuss Meta's or Facebook's rules, terms, policies, eligibility or account ownership with him unless he raises them first. Research text that does is not his, and is never repeated to him. Top of this file.

Rule 39. 2026-10-19 · matt: "If I never mentioned it, if I never inferred it, if I never outlined it as an option, therefore it is not an option." Deep research prompts, searches, SubQ matrices, plans and write-ups use only what matt said, or clearly meant through a misspelling. Nothing added, nothing steered towards. Top of this file.

Rule 40. 2026-10-19 · matt: no physical options. He is in Vietnam with no physical access. Phones, SIMs, mini PCs, laptops, phone farms and home devices are never options unless he names them. In scope: hosted and cloud options, the tools he named and their competitors, and what our four projects already use.

Rule 41. 2026-10-19 · matt: "any time any task correlates to money, and I never say something, that means you shouldn't do what you think. You should do what I say." Paid work (deep research, SubQ, proxies, captcha, vendors) does exactly what he asked, nothing more. Ask before anything else.

Rule 53. 2026-10-20 · matt: when something has to be found (a group to join, a provider, a price, a fact), it comes from an external source, never from memory or a guess: search with TinyFish through treg (treg call tinyfish.web.search, tinyfish.web.fetch, free) as the basis for every lookup, and pull the actual candidates from it. A suggestion names where it came from (the page, the search), and a pick is one of what the search returned.

Rule 63. 2026-10-22 · matt: the platform comes first. Every command that acts on one platform is log <platform> <command> … (log facebook warmup reel, log facebook join group); there is no form without it. The poll is log facebook poll <group> <account> <how long to poll>. Old forms are refused with the form they became. This replaces rule 60's log warmup <platform> <activity> and settles issue #20. OpenMagpie's worker is log facebook poll --request (it was read group --worker), a read in the account's open browser. bun run check:docs refuses a usage line without the platform first. Top of this file; the table is docs/commandNaming.md.

Rule 64. 2026-10-22 · matt: the code is by platform first, as the commands are, "because each has different approaches": src/<platform>/<area>/<domain>. Facebook's groups are src/facebook/group/{join,read,answer} (were src/group/…, rule 45) and its warm-up src/facebook/warmup/activities and src/facebook/warmup/stages (were src/warmup/facebook and src/warmup/facebookStages, rule 49). What every platform's warm-up draws from stays shared: src/warmup/persona, src/warmup/viewer. Each area has an index.ts (check:naming). Top of this file.

Rule 73. 2026-10-23 · matt: "IT MUST ALWAYS READ THEM." The number one rule of the stack, above rule 30 and every other: Facebook's internal API answers are the decision-making factor of what and when something is relevant, and the deterministic factor of the system. Every browser step reads the internal API answers it triggers and the requests it sent, keeps them past the prune, and decides on them, never on a page loading, a timer or the step having run. The MCP instructions put it first. Inspect steps read theirs since rule 74, and every flow, warm-up and host step on AdsPower that makes a call since 2026-10-23; the Camoufox-only machines don't yet (#35). Top of this file.

Rule 80. 2026-10-25 · matt: X (Twitter) is log-cli's second platform, built around a vendored client the way Facebook's direct API is built around fbk: twikit (vendor/twikit, unclecode's fork) and twitter-controller (vendor/twitterController, the code being ported). Its commands are log twitter <command> (src/twitter/<area>/<domain>, python/twitterApi/engine.py), declared directApiOnly in DIRECT_ROUTES. matt: "No: X accounts call X directly as the controller does today": no proxy is required or used for an X account, and rule 12 stays Facebook's. X's own answer decides (socialAccounts.sessionState: loggedIn, loggedOut, restricted), each account has its own governor under ~/.logCli/twitter/<account>, and X's refreshed cookies are merged back into the row. Discovery stays treg's (rule 53). First command: log twitter session check. Plan: docs/twitterPlatform.md.

Rule 81. 2026-10-25 · matt: we own vendor/twikit and keep it up to date ourselves, since nobody upstream maintains it. Its HTTP transport is curl_cffi, the way vendor/fbk does it, never httpx: self.http is a curl_cffi AsyncSession pinned to one impersonation target (IMPERSONATE, safari17_0, matching twikit's Safari user agent), redirects not followed (as httpx did), the proxy kept in the session's proxies, media chunks sent as a CurlMime. Only the transport changed. python/checks/twikitTransport.py finds every httpx touchpoint by syntax tree (--map), rewrites the ones with a curl_cffi equivalent (--apply) and refuses any left (--check, bun run check:twikitTransport, pre-commit and pre-push); vendor/twikit/tests/test_transport.py holds the behaviour.

Rule 86. 2026-10-26 · matt: "if I say to do something it can force past it." An X send can go past the account's governor (its pause after a block, its hourly, daily and write caps) when matt says so: --force on log twitter reply|quote|like|dm and log twitter queue run (MCP force). Only for that call or that run, only when matt asked; never by default. X's own answer still decides (rule 73) and the queue's own cool-offs still apply. The answer says what it went past (forcedPast). The governor still counts the request.

Rule 87. 2026-10-26 · matt: a cold dm never goes to someone he has already spoken to. X's newer encrypted Chat is a separate inbox that log twitter dms (twikit's legacy dm/inbox_initial_state) can't see, so a "never messaged" filter built on it is wrong: on 2026-10-26 a 40-person treg dm run reached 7 people matt already knew. log twitter queue check on a dm queue now reads the account's own X Chat inbox (api.x.com/graphql GetInitialXChatPageQuery, then paged with GetInboxPageRequestQuery; the account's session, no PIN, who and when are readable, the text isn't) and drops (status skipped, priorConversation) every pending dm whose recipient the account already has a conversation with. --skipXChatCheck bypasses it only when matt asks. The X Chat reads live in vendor/twikit (rule 81: client.get_xchat_conversations(), endpoints in twikit/client/gql.py), so the knowledge is in the client, not hand-rolled; the engine action xchatContacts (python/twitterApi/engine.py) calls it, read-only. docs/platforms/x/xchat / RESEARCH/X_CHAT_ENCRYPTED_INBOX_API_2026-10-26.md.

Rule 88. 2026-10-26 · matt: "DONT OPEN IT IN MY CHROME WE FUCKING BUILT IT OUT BECAUSE THE vendor/twikit hasnt been updated." X Chat (encrypted DMs) is read through log only, in the same shapes as the legacy DMs, never by opening x.com in a browser. X's own encryption SDK is vendored at vendor/chatXdk (xdevplatform/chat-xdk v0.5.2: its Rust source and the prebuilt Python wheel, installed from there). vendor/twikit reads the account's keys and Juicebox token map (GetPublicKeysQuery), unlocks them with the account's X Chat PIN (client.unlock_xchat) and decrypts every conversation's events (client.get_xchat_messages). The PIN is saved by matt once in a masked Clack prompt, log twitter chat pin --account <a>, kept in Twenty (socialAccounts.messengerPin on the X row) and handed to the engine only in the run's private folder. log twitter dms fills each X Chat thread's last message, and --with <handle> merges a person's legacy and X Chat threads into one timeline. Nobody is answered on X without reading their X Chat side first.

Rule 94. 2026-10-29 · matt: "whatever you did in such quick succession lead to my account getting disabled, never do that again." Never act on an account in quick succession. What happened (matt's Discord, sourcedandsoldtothehighestbidder, 2026-10-29 00:47-01:00 UTC): in about 13 minutes an agent replied in 3 chats, read 1,400 messages from a server (Finn Automated) with a scratch script that went around log-cli (.scratch/finn/dc.ts: its own fetch to discord.com/api/v9 with the session token, pages back to back, retrying straight through 429s), pulled the account's relationships, then opened new DMs to strangers from that server 30 s apart. Discord disabled the account. From now on: - Every call to a platform goes through log-cli's own commands and their governor. Never a hand-rolled script with an account's token or cookies. - A 429 or a failed send stops the run. It is never retried through, and the next action waits for matt. - Reading a server, group or member list in bulk is its own session. It never runs in the same session as sending. - Cold DMs to people the account has never talked to go out at most a few a day, minutes apart, never back to back. Each new DM channel opened counts as a write. - After a block, disable, captcha or cooldown, nothing resumes on that account until matt says so.

Rule 98. 2026-10-31 · matt: "So the opener always relevant. Don't just go in for the jugular. Go in with the opener." A first message to someone matt has never talked with is the opener and nothing else: about them and something they posted (or reposted, or that they reposted him), always relevant, and never the ask: no pitch, no "you using treg yet", no call, no link to his own stuff. The ask waits until they have answered. log voice fails a first message with an ask in it (openerOnly, src/twitter/copy/voice), and someone with nothing relevant to open on isn't messaged yet. docs/useCases/twitter/engagerDms.md, networkMaxing.md, GUIDES/MATT_WRITING_STYLE.md.

Rule 104. 2026-11-01 · matt: "the timing stuff there i saw you hand rolled the outbound stuff when it should be queued and it has to have random intervals, but the bundle itself actually reveals more information". On 2026-11-01 matthewsoldit got a soft block, then X's 226 ("looks automated") on a reply. The live log showed 8 thread reads fired in 0.2 s by two parallel helpers while sends went out from a hand-written loop, and every log twitter call was a fresh client that loaded x.com's home page and its signer before acting, so a 3-line dm was 3 cold starts in 9 s. X's own web client (sign.o in its x-web bundle, read 2026-11-01) loads the page once and signs every call from it. From now on: more than one send goes through the queue (log twitter queue build|plan|run, random times), never a hand-rolled loop and never helpers reading or sending on one account in parallel. The X engine takes one call per account at a time (engine.lock, refused with accountBusy after 15 min), waits 4 to 11 s after the last call, and keeps the transaction key in clientTransaction.json for 3 hours (python/twitterApi/engine.py, vendor/twikit ClientTransaction.state and restore).

Rule 105. 2026-11-01 · matt: "we cannot be opening multiple sessions there, that defeats the core purpose of what we use this tool for ... it should always be one, and then it needs to loudly create issues". An X account has one session, always. Every X call (CLI, MCP, hooks, the queue, the X Chat watch) goes through the account's one engine host (python/twitterApi/host.py, started on the first call, closed after 30 idle minutes or when the engine code changes): one twikit client, one connection, one cookie jar and one transaction key, the way X's own web app keeps one page and signs every call from it (x-web startup-dynamic, read with rea 2026-11-01). A second host can't start (host.lock); a call that can't reach the host is refused with xSessionHostDown and sends nothing, never falls back to a session of its own. The hook's account line shows the open session (pid, since, calls). LOG_TWITTER_HOST=inline runs the old way, for tests only.

Rule 107. 2026-11-01 · matt: "the queue connects to the one process, and it can do these at the same time, yet it's only on one". An account has one queue, and everything it sends goes into it: the dms, the reply-guy replies and the answers to people who message, together (each item keeps its own action). log twitter queue add <queue> --targets <file> --action dm|reply|quote --by <who> puts more in, even while it runs: the run takes them in as it waits and fits each one between what is planned, at least the queue's minGap apart, and one due sooner than the send it waits on goes first. queue run --keepOpen keeps the run going once it has sent everything, taking in what is added, until it is cancelled. So one run sends all of an account's work through its one X session (rule 105), never a second queue or run beside it. src/twitter/queue (addToQueue, fitTimes, takeIncoming, mergeAdded).

Rule 108. 2026-11-01 · matt: "if something doesn't seem to be working, you need to fix it", "make sure it's always up to date", and "if someone responds to me ... you have full authority to be able to send a follow-up message to them if it is in the context of the right thing to do with that said conversation". Three things: - Fix it, don't report it. Something broken is never told to matt as a fact and left. Find the cause and fix it in the same turn. Only when the fix needs something from him, say exactly what (a restart, a login, a key, a yes), and say that first. - Nothing runs stale. The inbox hook runs a silent cleanup on every event: a queue lock whose run died is cleared (and queue run, add and nudge take it over themselves), and an inbox watcher started before the newest code is stopped and started again (stopStaleWatchers, clearDeadQueueLocks, src/inbox/watch). An X session host closes when any of its code changes (python/twitterApi, python/platformKit, vendor/twikit), even while an X Chat watch is open on it, so the next call runs the new code. A read receipt X Chat can't verify is a read marker, never a message (unopened_of, vendor/twikit). - Answer straight away. When someone answers matt, a reply that answers what they said and fits that conversation is drafted, gated and sent at once, then matt is told what they said and what went out. Only a meeting, a promise, a price or money, or a conversation that can't be placed waits for him. Hook times are in matt's own clock.

Rule 109. 2026-11-01 · matt: "before you do an action with someone, you need to figure out the context of that person ... if they liked something, if they commented on something, if they replied to them recently, if I send them a message outside of the tool". Full context at the time of sending, every time, through the tool: - Before drafting, log twitter dms --with <handle> (MCP twitterDms { with }) gives the whole thread, read from X so it holds what matt sent from anywhere, and what that person did on the account's posts (likes, retweets, replies with their words, quotes, mentions, follows), from a fresh notifications read (activityOf, src/twitter/dm/person). Someone who already did the action is thanked for it, never asked for it. - Right before each send, the queue run reads both again and holds the item (status held, heldFor saying what changed) when anything happened since it was drafted (draftedAt): a message either way, a like, retweet, reply, quote, mention or follow (contextChangesSince, contextChanged in src/twitter/queue/run). - A held item is redrafted from the new context, gated, and put back with log twitter queue edit <queue> --n --text --by (MCP twitterQueueEdit). A queue file is never edited by hand, and nothing is sent around the queue to get past a hold (rule 106).

Rule 110. 2026-11-02 · matt: "we need to be faster with the mcp commands ... why is it taking so long for something which is not even something that should take long". Reads on an X account are spaced 0.8 to 2.5 s after the last call (READ_SPACING_SECONDS: inbox, a person's thread, notifications and their pages, follows, followers), the way X's own app fires reads back to back when a screen opens; only sends keep rule 104's 4 to 11 s (SPACING_SECONDS). Still one call per account at a time through its one session (rules 104, 105). Reading a person's full context (rule 109) pulls notifications only when they weren't synced in the last 2 minutes (notificationsFresh). A queue run never sends two things closer than its minGap, and items added to it keep that gap.

Rule 111. 2026-11-02 · matt: find GitHub repos "good for claude watermarking ... so we're able to pass it through context into the sends so that we can see how likely it is to be watermarked". Claude's own watermark is statistical (word choice under a secret key) and Anthropic's text detector is private preview, so no public repo can score it (RESEARCH/CLAUDE_WATERMARK_REPOS_2026_11_02.md). What can be read is what AI chat interfaces leave in text: OfirYC/claude-watermark-checker is vendored at vendor/claudeArtifactDetector (MIT, no dependencies) and every send's copy is read by it (watermarkReadingOf, src/twitter/copy/watermark): clean, stylistic (curly quotes, em dashes) or artifacts (zero-width or other hidden characters, odd spaces, pasted Claude HTML), with statistical: unknown always said. planSend refuses a send with artifacts (aiArtifacts) and carries the reading in its plan; log voice shows it and fails a draft with artifacts; a direct send and each queue send log it.

Rule 112. 2026-11-02 · matt: "there is definitely a dictionary of the common phrases which we can then have a p99 p50 search across to basically see and match the likelihood of this here to the common AI phrase ... use tbhb/vale-ai-tells". The voice gate also reads a draft for AI phrasing. The lists live in vendor/aiTells (SOURCES.md): tbhb/vale-ai-tells first (its 130 rules run on the draft exactly as Vale would), then FeedHive/ai-slop-detector, SanderFrentz/ai-vocabulary, SicariusSicariiStuff/SLOP_Detector, real AI-written samples, and fsu-nlp/lexa-index's words Claude and GPT overuse. log voice aiIndex embeds every literal phrase with Jina (jina-embeddings-v3, JINA_API_KEY in .env.local) and measures matt's own replies from the voice index against them: his p50 and p99 closeness, and the vale rules he uses himself in over 2% of his messages, which are muted. Each draft is cut into lines and word windows, every chunk's closest AI phrase found by cosine, the closest reranked with jina-reranker-v2-base-multilingual, and the draft fails when a vale rule hits or it sits closer to AI phrasing than matt's own p99. src/voice/aiTells. A phrase vale flags that matt says himself in 5 or more of his own messages ("to be honest", "for example") is his voice and never fails a draft (mattsOwnPhrases). Phrases people quote on X as AI tells (treg's X search, vendor/aiTells/xComplaints) are indexed only when they sit close in meaning (cosine 0.6) to a curated phrase.

Rule 113. 2026-11-02 · matt: "what is hitting the session ... call the rea bundle checker for the exact actions and outline it and then force it to then be part of the MCP guides so we can then stop doing this handrolling". On 2026-11-02 matthewsoldit had 30 X session starts and 67 X Chat socket reconnects in an evening, then X's 226 on a reply: the stale-watcher cleanup (rule 108) restarted the X Chat watcher on every code edit, and each restart reopened X's chat socket, fetched the keys again and paged the inbox, and during a governor cool-off the watcher was started again on every hook. Now the watcher is restarted only when the engine's own code changes (python/, vendor/twikit), never while the account's governor is cooling off (coolingDown, src/inbox/watch), and a call to a session that is restarting waits for the new one (connect_host). What X's own signed-in client does is read with rea from its own scripts, never guessed: log twitter session webClient --account <a> (MCP twitterSessionWebClient) loads x.com/home through the account's one session, as twikit already does to sign its calls, and saves the page and its scripts for rea. What it shows about a reply is written in docs/platforms/x/compose.md and the xPosting skill, and the engine sends what X's client sends. Read on 2026-11-02: twikit called 22 of X's operations by old ids (CreateTweet SiM_cAu… where X's client sends l4hk8uVG…) with the wrong feature switches (21 where X sends 39). Now webClient writes X's live operation table and switch values to ~/.logCli/twitter/xOperations.json, every session loads it, and each GraphQL call takes X's live id and exactly X's switches with X's values (live_call). A closing session drops its open connections and exits at once, so an open X Chat watch can't hold it half-closed.

Rule 114. 2026-11-02 · matt: "the queue will always need to be in context ... are we using the queue as a monitor or as a background pid that then isn't being inserted into context via the hooks into the agent context?" A queue run is a job inside the MCP server, and until now nothing put what it did in front of the agent: a held item sat unredrafted until someone read the log. The queue hook (scripts/hooks/queue.ts, on SessionStart, every prompt and every log tool or shell call) reads every queue's log since the last look (newQueueEvents, src/twitter/queue/events) and puts each held item, send, cool-off with X's answer, stop and start into the agent's context (>>> QUEUE), saying what to do: a held item is redrafted from what changed, gated and put back (rule 109); a cool-off or stop means nothing more goes out until matt says so (rule 94).

Rule 115. 2026-11-02 · matt: "go through the actual bundle itself for the actual client ... pass the live context into the actual context ... persistent realtime context ... scoped per session". X's own client stays live with its notification refresher (bundle.Notifications, module 726194, read with rea through the account's one session, log twitter session webClient, which now also saves the DM, X Chat and notification chunks the page loads on demand): every 30 s while the tab is in front, and only every 120 s while its push is subscribed, it reads ViewerBadgeCounts with x-twitter-polling: true, then the DM updates, and the notifications when the count rises. The account's X Chat watch (the socket is our push) now does the same through the one session: ViewerBadgeCounts with that header every 120 s, and when ntab_unread_count rises, one page of new notifications (badge_poll, python/twitterApi/engine.py). Each count and each new like, retweet, reply, quote, mention or follow goes to ~/.logCli/twitter/<account>/live.jsonl. The X live hook (scripts/hooks/xLive.ts, SessionStart, every prompt, every log tool or shell call) puts it in front of the agent (>>> X LIVE, src/twitter/live/feed), each Claude session with its own offsets (src/agentHooks/sessionOffsets, keyed by the hook's session_id), so two sessions both see every event once. The queue hook (rule 114) reads per session the same way. A refused read stops the poll and is said to matt (rule 94).

Rule 121. 2026-11-03 · matt: "those accounts are too big, a person who is too large isn't worth it yet, sub 1500 is ideal". A reply goes only to an author with 1500 followers or fewer. Reply-guy targets come from the niche map under 1500 followers. Before a reply likes, follows or sends anything, the engine reads the author's follower count (author_too_big, MAX_AUTHOR_FOLLOWERS in python/twitterApi/engine.py), and a larger author gets nothing (authorTooBig). The queue marks that item skipped (TOO BIG) and goes on: it is not a refusal (rule 118). A reply matt asks for by name goes out whatever the author's size, with force (rule 86), as his reply to @sporadica (222k) did on 2026-11-03. Every reply that does go out likes the post and follows the author first. Spec: docs/specs/xQueue.md (REQ-QUEUE-15).

Rule 127. 2026-11-03 · matt: "the watermarking has began ... research the saying 'is wild' no one says that", then "B is the only right option ... we're writing across everything i said and how i write it", and "install this and add it to the subq" (novatechflow/ai-watermark-scrambler). The voice gate passed "yc and a pageant in the same week is wild" because nothing compared a draft with what matt has actually written. His 66,116 messages never say "is wild", and another account's reply had used the same line word for word three hours earlier. Now the gate also measures his phrasing (src/voice/phrases): every reply in the voice index is cut into word pairs, a draft's share of pairs he has written at least twice (leaving out words from what they said) is set against his own 10th percentile, measured over his replies with each one's own pairs left out (phrases.json, built with the voice index), and a draft below it fails with the pairs he never wrote named. The vendored scrambler (vendor/aiWatermarkScrambler, Apache-2.0, layer A inspect_text.py) reads every draft for invisible and lookalike characters, and a hit fails it. Both readings go to SubQ with the draft. Its layer B rewrite needs a local model (Ollama or vLLM), which this machine doesn't have, so it isn't wired. Spec: docs/specs/voiceGate.md (REQ-VOICE-07, 08).

Rule 130. 2026-11-04 · matt: "we need to make it so we have a monitor on there that will then listen for the new info coming over via the websocket, because look, he responded halfway through ... he just asked something, it breaks the flow". On 2026-11-03 Abel wrote "is this ai" on Discord while an 8-line send was going out, and lines 6 to 8 went on top of his question. A message sent one line at a time stops the moment they write: before each line after the first, the send reads what the platform's push channel put in the inbox for that chat since the send began (incomingSince, src/inbox/watch, from pending.jsonl), and if they wrote, the rest is held and the answer leads with >>> INTERRUPTED: what they said and the lines not sent (interruptedLines). It holds for log discord send, log slack send, log twitter dm (old DMs and X Chat), the queue's dms and log instagram send (in its engine). What was sent stays sent, nothing is resent, and they are answered first (rule 109). An agent following a conversation keeps a Monitor on ~/.logCli/inbox/pending.jsonl so each push wakes it. Spec: docs/specs/messageSplit.md (REQ-SPLIT-08).

Rule 133. 2026-11-04 · matt, to deepman: "whenever the agent wants to perform an action based on the streamed event information, it must first claim the relevant event ... only the session that successfully claims an event should be allowed to perform the corresponding action. Once the action has been executed through the state machine, the lock is released ... every time an action is executed, the system should also index and persist the associated information". Every message a push channel brings in has an event id (eventIdOf, shown in the hook's >>> CLAIM BEFORE YOU ACT beside who holds its chat). A session claims a chat before it drafts (log inbox claim, MCP inboxClaim, 10 minutes, renewed by claiming again; claimChat, src/inbox/claims, an exclusive claim file per chat, the session being its MCP server's process), and a second session is refused (chatClaimedElsewhere). Every send (log discord send, log slack send, log twitter dm, the queue's dms, log instagram send) claims the chat itself first (guardSend) and releases it once it is sent, interrupted or failed, so two sessions never answer the same chat. An X chat is one chat whether it is named by the person's id or the X Chat pair. A claim held by a session that ended, or past its time, frees itself. Every claim, renewal, refusal, send, interruption, failure and release is written to ~/.logCli/inbox/actions.jsonl, read with log inbox actions --chat <id> (MCP inboxActions) before acting; log inbox claims lists who holds what. Spec: docs/specs/agentHooks.md (REQ-HOOKS-15).

Rule 135. 2026-11-04 · matt (through his side session): missing context "is filled by catching up, never by every caller re-reading the client". Each account's owner keeps the platform's own last position in the .db (positions: X Chat's sequence id, Discord's last message id per DM, Slack's last ts per chat, Instagram's last activity). A gap opens (gaps: from, to, reason, status) when an owner takes over from a stopped or dead one (from its last heartbeat), when the first owner starts on an account that already has events (from the newest), or when the push channel drops. While a gap is open the account is behind, and one catch-up job inside the owner (catchUpRunner, src/inbox/catchUp) pulls only the delta through the account's own session and governor, paced like reads (0.8 to 2.5 s): X's delta sync after its saved sequence id, Discord's DMs after each one's saved message id, Slack's history after each chat's saved ts (oldest), and Instagram's threads active since its last activity. What it pulls is appended to events like live pushes, marked source: catchUp, and the gap closes. A send (Discord, Slack, X dm and the queue's sends, Instagram) waits up to 90 s for the account to catch up (waitCaughtUp) and never reads the platform itself; still behind, it is refused with accountBehind. A refused catch-up (a 429 or any refusal) stops, keeps the account behind, alerts (catchUpRefused), and nothing resumes until matt says so (rule 94). Discord's gateway RESUME is not used yet. Spec: docs/specs/agentHooks.md (REQ-HOOKS-17).

Rule 136. 2026-11-04 · matt: "these must be completed", with the direction that the context before a send comes from the .db, not from a fresh platform read. This changes rule 109's last read: right before each queued send, the run reads that person's messages both ways and what they did on the account's posts from the .db (chatContextOf, src/inbox/context), once the account has caught up (rule 135), and holds the item when anything happened since its draft, as before. X is not read for it. The platform is read only by the catch-up job, by backfill (history from before the push channel existed) and by discovery (unknown event types). Every owner stores the account's own messages (ownMessage) as well as theirs, and X's notifications arrive through the owner's badge poll (rule 115). Spec: docs/specs/fullContext.md (REQ-CONTEXT-04, 10).

Rule 137. 2026-11-04 · matt: keep every part of the voice gate ("necessary") and run it "as the whole voice process on the new .db", required inside every send, only at send time, scoped to that send, quiet; then "Yes, both" to jina-embeddings-v5-omni and the local media model. The voice gate is one step (gateSend, src/cli/twitter/helpers/voice.ts) inside log discord send, log slack send, log twitter dm, the queue's sends and log instagram send, after the account has caught up (rule 135) and before the chat is claimed (rule 133): a draft that fails is refused with voiceGateFailed whether or not log voice ran first, and in the X queue the item is held to be rewritten with twitterQueueEdit. All five checks stay: SubQ's read of matt's voice, the AI tells index with its reranker (rule 112), his own phrasing (rule 127), the watermark checker (rule 111) and the scrambler (rule 127). It reads the chat's context from the .db (rule 136), embeds it, ranks it against the moment being answered (cosine, then jina-reranker-v3.5) and gives SubQ the top moments in full (rankedContext, thisConversationRankedForThisMoment). Only embeddings are kept, in the .db (embeddings: the text's hash, model, dimensions and vector, each made once), with the AI tells index's phrase list and matt's baseline (aiIndexes); every result is worked out fresh for each send, never saved. Jina is jina-embeddings-v5-omni-small at 1024 dimensions (text-matching), and an index made with another model is rebuilt. The local embedder stays loaded in its process. A pass is one line; a fail names only what failed and why. Spec: docs/specs/voiceGate.md (REQ-VOICE-09 to 11), docs/specs/aiTells.md (REQ-AITELLS-05, 10, 12).

Rule 138. 2026-11-04 · matt: "a smaller local model" turns every piece of media into "a text representation", labelled with what it is, after a message went out answering only the text around a video someone sent; then "Yes, both" to downloading it. One media describer per machine (log media describer, src/media/describer), started by the inbox hook and locked like an owner (rule 131, a second is refused), loads onnx-community/LFM2.5-VL-450M-ONNX once (SubQ's pick, q4, on the transformers.js runtime log already uses) and keeps it warm. Every image, meme, gif and video a watch receives goes into the .db's media queue (enqueueAttachments). The describer takes one at a time, describes a video from three frames (ffmpeg), labels each description with its kind, stores it with its jina-embeddings-v5-omni-small vector, beats every 5 s, and stops loudly past its memory ceiling (describerMemory). The queue holds 20 at most: past that, an item is marked not described yet and alerted (mediaQueueFull). Media with no description is shown as [video clip.mp4 not described yet: …] in the inbox hook and in the voice gate's ranked context, so nobody replies to it blind; a description reaches both in its place. Audio stays with AssemblyAI (rule 126). A file the platform engine hasn't saved locally yet is listed as not described, with why. log media describe <path> queues one local file, and log media status shows the queue. Spec: docs/specs/mediaDescriber.md.

Rule 140. 2026-11-04 · matt: "we're able to send reactions as well, across all of the clients. We need to be able to send reactions to messages as well." Every chat platform reacts to a message with an emoji through its own engine and its one session, never the browser: log twitter react, log discord react, log slack react and log instagram react (MCP twitterReact, discordReact, slackReact, instagramReact, each with its …Live twin), --remove taking the account's own reaction off. Each calls the platform's own reaction call: X's DM reaction mutation in vendor/twikit (an X Chat id is tried as the same pair, and X's answer decides), endcord's send_reaction, Slack's reactions.add (by name; the common emoji are turned into their names, python/platformKit/reactions.py) and instagrapi's direct_send_reaction. A dry run unless --live with --approvedBy (rule 8). The chat is claimed first and released after, as for a send (rule 133), the governor counts it as a write, the platform's answer decides (rule 73), and a refusal stops with nothing retried (rule 94). src/cli/react. Spec: docs/specs/reactions.md.

Rule 141. 2026-11-04 · matt: "We're able to add people to a list, like the actual Twitter lists ... make a new Twitter list called Go-Getters". An X account's own lists are worked through its one session (rule 105) on vendor/twikit's list calls, sent with X's live operation ids (rule 113): log twitter list show lists them with their ids and member counts, list create --name makes one (a list of that name already there is answered as it is, never made twice), and list add --list <name|id> --handle|--userId puts one person on one (MCP twitterList…). create and add are dry runs unless --live with --approvedBy (rule 8), each a write the governor counts; X's answer decides (rule 73) and a refusal stops (rule 94). src/cli/twitter/helpers/list.ts. Spec: docs/specs/xLists.md.

Rule 142. 2026-11-05 · matt: "make it so that we can send audio, like upload natively into the platform, voice notes ... directly into the actual clients themselves ... we need to voice clone ourselves from audio ... it will then be an extension, like we have for the meme board stuff", with Fish Audio (hosted) his pick. A voice note only ever goes out when matt asks for one, in his cloned voice, as the platform's own voice note: never on the agent's own initiative and never any other audio. Fish Audio is an extension (src/extensions/fishAudio, docs/extensions/fishAudio.md): log fish clone makes his voice model once from the voice notes he sent himself (fromMe in the conversation store or his ownMessage in the .db; Discord voice messages and Instagram voice clips the engines kept, 10 to 60 s in all; nobody else's voice), a dry run listing them unless --apply, its id kept in ~/.logCli/voice/fishClone.json; log fish speak --text says words in it to a file under ~/.logCli/voiceNotes and sends nothing, on the free s2.1-pro-free model unless --model. log discord voice, log instagram voice and log slack voice take text only (an audio file is refused with voiceNoteInvalid), are dry runs unless --live with --approvedBy (rule 8), wait for the account to catch up (rule 135), run the text through the voice gate (rule 137), make it with the clone, convert it with ffmpeg (Discord ogg/opus, sent as a voice message with flags 8192, its waveform and duration; Instagram AAC in .m4a through instagrapi's direct_send_voice, its upload on curl_cffi under the one-call lock, rule 129; Slack AAC in .m4a through files.getUploadURLExternal, the upload on gabriel's curl_cffi transport and files.completeUploadExternal, rule 125), claim the chat (rule 133), count as a write, and stop on any refusal (rule 94). An engine sends only a file log made under ~/.logCli/voiceNotes. X isn't built: twikit has no audio send and no vendored code or doc shows X's DM voice upload, so nothing is guessed. src/cli/voiceNote. Spec: docs/specs/voiceClone.md (was fishVoice.md).

Rule 143. 2026-11-05 · matt: "the voice cloning and the voice note stuff will be agnostic", after Fish Audio refused the clone without API credit (403, model creation limit 0/0) and he had none to put in. The voice layer is provider-agnostic, the way proxies are (rule 52): src/extensions/ voiceClone holds one interface (its models, cheapest model, clone limits, the reference format it takes, clone and speak), and each provider is an extension of its own: src/extensions/inworld (the default: instant cloning free, about 70 free speech minutes, wav references 3 to 30 s, inworld-tts-2-flash, INWORLD_API_KEY) and src/extensions/fishAudio. The provider is --provider, else LOG_VOICE_PROVIDER in .env.local, else inworld. log fish clone|speak became log clone voice|speak (MCP cloneVoice, cloneSpeak); log fish is refused with the form it became (rule 63's pattern). Each provider's clone is kept in ~/.logCli/voice/clone.json, keyed by provider, made once. log discord|instagram|slack voice take --provider and call only the shared layer, never a provider. Everything else in rule 142 holds. Spec: docs/specs/voiceClone.md.

Rule 144. 2026-11-05 · matt: "bro fuckign send th efuckign shit", after the voice gate refused three times the voice note he dictated to deepman word for word ("my phone screen is broken the phone is fine like theres two big green lines going down the side of it and that but it still works thank the lord"). The gate grades speech as typed text and as a reply (voice 0.06 to 0.48, inContext 0.21), so it can't read a voice note in his own spoken words. --mattsWords on log discord|instagram|slack voice (MCP mattsWords) says the text is matt's own words, dictated by him for this voice note: the voice gate's SubQ read is skipped, and the AI artifact check (watermarkReadingOf) still runs and refuses aiArtifacts. Only when matt gave the exact words; words the agent drafted are always gated (rule 137). Sent live 2026-11-05 08:04 UTC, Discord message 1567811929500811294. Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-10).

Rule 145. 2026-11-05 · matt: "Yes, re-clone it", because the Inworld clone was made with languageCode en-US, which pulled his voice towards an American accent, and he is Northern Irish. The voice is cloned and spoken in his accent: LOG_VOICE_ACCENT (.env.local, default Northern Irish) and LOG_VOICE_LANGUAGE (default en-IE, sent again as en-GB when Inworld answers INVALID_ARGUMENT). The clone sends that language, a description naming the accent and each sample's AssemblyAI transcript from ~/.logCli/transcripts when there is one (none is paid for: TTS-2 makes its own), and keeps the language Inworld accepted. log clone voice --apply --replace (MCP replace) makes it again over the old one, which stays in the clone file under previous, never deleted. Speech sends the clone's language; on inworld-tts-2 the text starts with [say it in a <accent> accent], an instruction Inworld removes before synthesis, and inworld-tts-2-flash, which ignores steering, gets none. Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-11). (Its accent steer was replaced by rule 147, matt 2026-11-05.)

Rule 146. 2026-11-05 · matt: "the second one but why does it speak so slowly" and "use the discord audio for the samples". The clone speaks at LOG_VOICE_SPEED (.env.local, default 1.15, kept between 0.8 and 1.5), sent as Inworld's speakingRate, and a clone made on Inworld speaks with inworld-tts-2 (the provider's preferred model, which takes emotion tags), not the cheapest. log clone voice --from <file>[,<file>] clones from recordings of matt's own that he names instead of his voice notes, each one's words read from a .txt of the same name beside it. Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-12).

Rule 147. 2026-11-05 · matt: "ITS IRISH", none of the accent-steered clips sounded like him, "11_script_long272_b ... was pretty good", then "go through my voice notes ... analyse it", "it still doesn't have that distortion", and "op is real like op not o p ... make it the gate for the voice ... or it won't pass". A voice note sounds like his own voice notes and says what was written, measured both times: - The clone is Inworld instant cloning from one continuous 30 s of his own Discord voice note (matt-long272_b, 2:30 into his 4.5 minute note), the accent Irish (LOG_VOICE_ACCENT). No accent instruction is sent with the text: the clone carries the accent. On inworld-tts-2 breaths are put in ([breathe] at the start and once at least 8 words have gone by, withBreaths). - Shaped like his notes (processLikeMatt, src/extensions/voiceClone/helpers/realism.ts), every number measured from five of his real Discord voice notes against the clone: phone squash (dynaudnorm), the phone mic's own tone curve measured from his notes (REALISM.phoneCurve: its low cut under 160 Hz, its dip around 2 to 3 kHz and its dull top over 5 kHz), his slow mic drift (1.9 dB), tone sway as the phone moves, phone-mic saturation on loud words, and his own room tone taken from the gaps in his own voice notes (never a sound effect), laid 22 dB under the voice so it lands where his do (30 to 33 dB). Seeded by the text, so the same words come out the same. - Listened back (readSpoken, spoken.ts): the shaped note is transcribed with AssemblyAI's word timings and lined up with the text. A word in the spoken lexicon (SPOKEN_LEXICON: op said as a word, written OP for the clone, since a lower-case op came out as "up") must be heard as itself, as one word under 400 ms; spelled out, heard as something else, or more than a quarter of the words different, and it is refused with spokenMismatch, naming what was heard. An acronym the lexicon doesn't have is refused before anything is spoken (pronunciationUnknown): how matt says it is never guessed. A note that can't be listened back is never sent (spokenCheckFailed). It runs in log clone speak and every log discord|instagram|slack voice. This replaces rule 145's accent steer. Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-13, 14).

Rule 148. 2026-11-05 · matt: "send it in chinese aswell", then "ADD A BYPASS PERMISSION FOR IT BECAUSE OFC IT WONT MATCH UP", after the voice gate scored the Chinese translation of a voice note it had passed in English at 0.13: it compares a draft with matt's own writing, which is English. --translationOf "<the original>" on log discord|instagram|slack voice (MCP translationOf) says the text is a translation matt asked for: the voice gate grades the original words instead of the translation, both are read for AI artifacts, and it needs --language <code> (zh-CN, es-ES ...), the language the clone speaks it in instead of the clone's own (Inworld's language). With en-IE the clone said the Chinese with two words wrong; with zh-CN it said them right. It is only for a translation matt asked for, never paired with --mattsWords. The listen-back check (rule 147) reads Chinese, Japanese and Korean one character at a time (wordsOf), so a translated note is checked too. Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-15).

Rule 149. 2026-11-05 · matt: "it keeps doing this weird exhale at the beginning ... the lengths of the things are always like 5 seconds", then "READ THE CONVERSATION ... I'M ASKING YOU TO RESPOND AT LENGTH ... BUILDING ON WHAT HE'S SAYING AS A 40 SECOND VOICE NOTE IN ENGLISH, YET YOU'RE JUST RE-EXPLAINING SOMETHING I ALREADY SAID". Three things: - No breath at the start. withBreaths never opens a note with [breathe] (that was the exhale). A breath goes in only between sentences (.!? and the Chinese 。!?), after a gap of 8 to 18 spoken words drawn from the text's own seed (BREATH_WORDS; a Chinese character counts half), so no two notes breathe alike. - The pace drifts. Each note is spoken at LOG_VOICE_SPEED moved by up to 7% from its text's seed (paceOf, PACE_JITTER), within the speed range. - A voice note is written at the length matt asks for and builds on the whole conversation. Read the whole chat first, then write to the length asked (a 40 s note is about 100 to 110 words), taking what they are talking about further and adding to it, never re-explaining what matt already told them. Note lengths vary: not every note is three short lines. The voice gate grades a voice note as spoken (spoken, set by every log discord|instagram|slack voice and by log voice --spoken): its length and punctuation never count against it, offProfile (his typed habits in the chat) isn't applied, and a new question, buildsOn (0.7 to pass), refuses a note that repeats what matt already said or ignores what they are talking about. Its voice question reads how matt actually talks first: the transcripts of his own voice notes from before the clone existed (howMattTalks, mattsOwnVoiceNotes), never his typing alone and never a note the clone made. Spec: docs/specs/voiceGate.md (REQ-VOICE-13), docs/specs/voiceClone.md (REQ-VOICE-CLONE-16).

Rule 151. 2026-11-05 · matt: "build the voice nots on X from X's own client so we'll figure out how it's done via the bundle itself ... and then we'll add it into the vendor itself", then "Yes, build it". An X voice note is an X Chat voice message, sent the way X Chat's own app sends one, read from its own code: log twitter session webClient now saves X Chat's whole app, following each script's imports (rule 150), so its engine, dm-core (Kotlin compiled to JS), is saved too. In it: the recorder makes audio/mp4; the file is encrypted with the conversation key (chat-xdk encrypt_stream); InitializeXChatMediaUploadMutation (6M543IPabOfZm7-yyIczdw) answers a media_hash_key and resume_id; the parts are POSTed as application/octet-stream to ton.x.com/i/ton/data/xchat_media/<conversation>/<media_hash_key>?concurrent=true&resumeId=<id>&partNumber=<n> from 0; FinalizeXChatMediaUploadMutation (3O4jPQ2hwW9LbqCc-wFmqA) closes it; and SendMessageCreateMutation (TWRPP7gnKwV_R8-tE-Dd3Q) sends chat-xdk's encrypt_message (its encrypted_content and encoded_event_signature) with one attachment, media type AUDIO (4) and duration_millis. This is in vendor/twikit (xchat_latest_key, upload_xchat_media, send_xchat_message, send_xchat_voice; the operations in client/gql.py), so twikit can now send in X Chat. log twitter voice --account <a> --with <handle|id> --text "…" (MCP twitterVoice, twitterVoiceLive) is the voice note command on X, the same as on Discord, Instagram and Slack (rules 142 to 149): made in matt's cloned voice, AAC in .m4a, gated, claimed, a dry run unless --live with --approvedBy, and sent by the engine action xchatVoice through the account's one session, X Chat opened with the saved PIN (rule 88; xchatPinMissing when there is none). The engine sends only a voice note log made under ~/.logCli/voiceNotes. chat-xdk mints the message's own id, so the upload carries an id of its own, as X's official upload takes none. This replaces rule 142's "X isn't built". Spec: docs/specs/voiceClone.md (REQ-VOICE-CLONE-09), docs/specs/xChat.md (REQ-XCHAT-11).

Rule 152. 2026-11-05 · matt: "Send it anyway", after the voice gate inside log twitter dm refused a short dm to @AjeetVermai that he had asked for. The gate inside every send (rule 137) had no way to take his word over it. --overGate on log twitter dm (MCP overGate) is that word: the gate's SubQ read is skipped for that dm, and the AI artifact check still runs and refuses aiArtifacts (rule 111). Only when matt said to send that exact message over the gate's refusal, never on the agent's own, and never for a queue. The send says it went over the gate. The same day the gate found a person named only by user id by their handle (handleOfUserId), so it reads their chat. Spec: docs/specs/voiceGate.md (REQ-VOICE-14).

Rule 153. 2026-11-05 · matt: "say idk to matt in the groupchat", then "Yes, wire it". log sends text into an X Chat group: log twitter dm --userId g<digits> (the group's id) goes to the engine, which opens X Chat with the account's saved PIN and sends it with twikit's send_xchat_message (xchat_group_text), the way X Chat's own app sends (rule 151). With no PIN it is refused xchatPinMissing. A person's id must still be digits, and only a dm takes a group id. log twitter voice --with g<digits> sends a voice note into the group the same way, and it was sent there live on 2026-11-05. X Chat ties a media upload to the message that carries it: the upload and the message share one message id (chat-xdk's encrypt_message takes message_id, rebuilt into vendor/chatXdk/wheels), Initialize is sent without a content type, and each part is posted to the resume_upload_url Initialize answers, as raw application/octet-stream with the bearer, the auth_token and ct0 cookies and the CSRF token (stephancill/stupid-social's working client). Building the URL ourselves was refused 401 every time. Spec: docs/specs/xChat.md (REQ-XCHAT-12).