Releases: ihuzaifashoukat/x-use
Release list
x-use 2.4.1 — repair SKILL.md frontmatter
Patch release. 2.4.0 shipped every bundled skill with invalid YAML frontmatter; this repairs them.
Fixed
Every shipped SKILL.md had invalid YAML frontmatter. 2.4.0 removed em dashes from the skills pack and replaced several of them with colons, which landed inside unquoted description values. A colon followed by a space makes YAML read the rest of the line as a nested mapping, so all eleven files failed to parse with mapping values are not allowed in this context and no skill consumer could load them.
The descriptions are rewritten to carry no colon at all.
tests/test_skills_pack.py now parses frontmatter as real YAML instead of matching line prefixes, which is exactly why the original slipped through. It also checks the Agent Skills spec limits: name charset and length, description length, no XML tags, and name matching its directory. The em-dash house rule is pinned in the same file so fixing one cannot break the other again.
Adds pyyaml as a dev dependency. 670 to 694 tests.
Upgrade
pip install --upgrade x-use-mcpIf you installed the skills from 2.4.0, reinstall them:
x-use skills install --forceNo other changes. Everything in 2.4.0 applies.
x-use 2.4.0 — search_profile, MCP prompts and resources
Adds a read-only profile-timeline tool, the prompt and resource surfaces of the MCP protocol, and a root SKILL.md. Also fixes a version drift that had the package reporting 2.0.0 to external scanners since the v2.0 release.
Added
search_profile, a read-only tool for one profile's recent posts. 32 to 33 tools. The scraper could already read profile timelines, but the only tool that reached that path was run_cycle, which is the one tool with no draft gate in front of it. Watching a competitor should not require the ungated batch path.
profile accepts a handle (@nasa or nasa), a profile URL, or a tweet URL, which resolves to its author. The handle is validated against X's charset and a canonical https://x.com/<handle> is rebuilt from it, so query strings, fragments, and extra path segments are discarded rather than navigated. Foreign hosts and x.com app routes (/home, /i, /search) error before a browser starts.
It also closes a gap in performance tracking: nothing reported how a published post did, because approve_draft returns no URL. Re-reading your own timeline is the answer.
MCP prompts. Five workflow prompts: research_niche, draft_replies, review_and_publish, daily_check, setup_account. The bundled SKILL.md pack only works in clients that implement Agent Skills; prompts are the protocol-native equivalent and work anywhere, including Claude Desktop, Cursor, and Windsurf, with nothing installed. draft_replies is lane-aware, because drafts and queued items live in separate stores with no bridge between them.
MCP resources. Four read-only context surfaces: xuse://accounts, xuse://accounts/{account_id}, xuse://accounts/{account_id}/persona, and xuse://drafts/pending. None start a browser, and all run the same masking as the tools. The persona resource is the point: it is exactly the context a drafting turn needs, and attaching it costs no turn.
SKILL.md at the repository root, generated by scripts/sync_skills.py from the canonical router skill plus an install footer, with a CI drift guard so it stays a mirror rather than a hand-edited copy.
Fixed
The package reported version 2.0.0. src/xuse/__init__.py had been stale since the v2.0 release because nothing inside the package read it. External directory scanners do, and listed x-use as 2.0.0 next to a 2.3.1 release. The version now lives in exactly one place and pyproject.toml derives its own from it, so a second literal cannot reintroduce the drift.
The MCP handshake advertised the SDK's version as x-use's. FastMCP takes no version argument, so the wrapped low-level server's stayed None and every client was told x-use was "1.28.1".
Upgrade
pip install --upgrade x-use-mcpNo configuration changes and no breaking changes. 670 tests, none of which need a network or a browser.
Note for contributors: the release rule changed. Bump __version__ in src/xuse/__init__.py, not pyproject.toml, which now derives its version from that attribute.
v2.3.1 — MCP registry manifest, docs consolidation
Packaging, documentation, and release plumbing. No src/ changes, so behaviour is identical to 2.3.0.
This exists as a release rather than a docs commit for one reason: the official MCP Registry verifies PyPI ownership by reading an mcp-name marker out of the package description, PyPI descriptions are immutable once uploaded, and 2.3.0 shipped before the marker existed. Registration needs a version that carries it.
Added
server.jsonat the repo root, the manifest for the official MCP Registry.- An
mcp-nameownership marker in the README, which flows into the PyPI description automatically sincepyproject.tomlsetsreadme = "README.md". - An
mcp-registryjob inpublish.ymlthat publishes to the registry after PyPI on every release. It authenticates with GitHub OIDC so no secret is stored, rewrites theserver.jsonversion from the release tag so the manifest cannot drift from the release, and refuses to publish unless the released PyPI description actually carries the marker.
Changed
BEST_PRACTICES.mdmoved todocs/BEST_PRACTICES.mdand rewritten for 2.3. It had drifted badly: it referencedsrc/main.pyand pre-src-layout module paths, described the gemini/openai/azure provider stack that 2.2 replaced with a single OpenAI-compatible client, said LLM keys could not come from the environment when.envnow takes precedence oversettings.json, and listed draft mode andx-use doctoras planned when both had shipped. It now covers the queue gate, the proxy MCP tools, cookie expiry checks, and the percent-encoding rule for proxy credentials.- GitHub Actions moved off the deprecated Node 20 runtime:
checkoutv4 to v7,setup-pythonv5 to v7,upload-artifactv4 to v7,download-artifactv4 to v8. - Em dashes removed throughout the user-facing documentation.
Full detail in CHANGELOG.md. 599 tests passing.
v2.3.0 — agent media, personas, composite drafts, proxy pools
Agent-native media, personas, composite draft staging, and proxy pool management — followed by a hardening wave driven by live testing against a real X account. 25 → 32 MCP tools.
Full detail in CHANGELOG.md.
Added
get_tweet(account, tweet_url, include_images=true)— text, author, public counts, typed media and persona in one read.- Typed media on tweets — photos with alt text and video posters, deduped, avatars excluded. Photos return to vision-capable clients as MCP
ImageContent; fetches are allowlisted to*.twimg.com, capped at 8 MB / 5 s, and re-encoded to JPEG ≤1024 px. Any failure degrades to URL-only and never errors the tool. include_imagesonsearch_tweetsandprepare_reply.- Freeform account
persona, prepended to reply and post prompts. - Composite draft-only tools —
research_and_stageanddraft_post_variations, both persona-aware and both refusing paused accounts. - Proxy pool management —
list_proxies,add_proxy,remove_proxy,test_proxy, fully masked, with validated atomicsettings.jsonwrites. - Bundled 5-skill agent pack —
x-use skills install|list, offered at the end ofx-use init, plus a Claude plugin marketplace kept byte-identical by a CI drift guard. - Docs —
docs/MCP_GUIDE.md(32-tool reference) anddocs/SETUP_PROMPT.md(one-prompt setup).
Changed
- Default LLM
max_tokensraised to 1200 — reasoning models were spending the whole budget on reasoning and returning empty replies. An empty completion withfinish_reason="length"now retries once atmax(2x, 1200). - The cookie handshake drops its redundant post-cookie refresh, removing one full page load from every cold start.
Fixed
Highlights — the full grouped list is in the changelog.
- A failed
add_account/update_accountno longer deletes the account's live cookie file. Importing acookie_fileoverwritesconfig/<id>_cookies.json, and orphan cleanup then unlinked that path on a failed config write — soupdate_account(cookie_file=…, proxy="bad-url")returnedok:falseand destroyed a working login that nothing backs up. The import now stashes any pre-existing file and restores it on rollback, deleting only files it created. - Userinfo masking now handles passwords containing
/, whitespace, or a second@. The previous regex could not match those, sohttp://user:pa/ss@hostwas emitted completely unmasked — reachable vialist_proxies,get_account, and proxy error text. Masking now scans the URL authority directly, and the three copies of that regex are collapsed into one shared implementation. - Security — whole-userinfo masking everywhere, sanitized queue
last_error,*.twimg.comfetch allowlist. - Queue — cancel-during-sleep honored, zombie
processingitems recovered, paused accounts skipped on drain-all, dedup keys include media and community. - Sessions — cancel-safe cold start and close, unresponsive drivers force-quit, cookie shape validation, proxy pool import fix.
- Config writes — backup failures block the write, shared proxy validation, corrupt configs surfaced rather than treated as empty.
- Engine truthfulness — no action reports success without confirmation; navigation failures are respected instead of swallowed.
Both of the first two fixes were regressions introduced within this release cycle and never reached a published version — 2.2.0 is unaffected. Each is now pinned by regression tests.
Testing
599 tests passing, up from 551, requiring no network and no browser.
v2.2.0 — agent-native MCP, single LLM client
v2.2 makes the MCP server agent-native: interactive use needs no LLM key at all — your MCP client (Claude, Codex, ...) does the analysis and writing, and the server drives the browser. The old three-provider LLM stack collapses into a single OpenAI-compatible client for the paths that genuinely need one (background automation, "auto" text). This release was audited end to end and live-tested against a real X account: 25/25 tools exercised, real post + self-reply + like executed through the draft and queue gates.
Highlights
- One OpenAI-compatible LLM client:
llmblock in settings.json (api_key, base_url, model), env fallbacks OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL. OpenAI, OpenRouter, Azure, Gemini, and local servers (Ollama, vLLM) all speak this API. Legacyapi_keys.openai_api_keyis honored as a last-resort key source; gemini/azure keys warn-and-ignore.service_preferencerouting and the langchain-google-genai dependency are gone. - Agent-native interactive path: every write tool takes explicit text, and the new read-only
prepare_reply(account, tweet_url)tool returns a tweet's content plus account context so your agent can compose the reply itself. 25 tools total. - Hardening from a full audit: concurrent queue drains are refused (
already_running), account-tool session closes wait for in-flight actions, browsers that cold-start past their timeout are closed instead of leaked, crash-window drafts recover to pending,get_account_healthreports invalid configs instead of failing, paused accounts are refused on every write path, and the mcp pin is now >=1.6 (first release with FastMCP lifespan). - Fixes found by live testing: undetected-chromedriver no longer receives excludeSwitches (modern chromedriver rejected the session), UC is pinned to the installed Chrome major version, successful likes are no longer misreported as failures (verification now watches the button flip to "unlike"), cookie imports already at the convention path work, handles render without "@@", and the settings template defaults to Chrome.
Details
- doctor: single
llmcheck; a missing key is SKIP (keyless interactive use is valid), not FAIL. The init wizard writes OPENAI_API_KEY / OPENAI_BASE_URL / OPENAI_MODEL. - LLMService returns None when unconfigured, so heuristic fallbacks (e.g. the analyzer's keyword relevance) keep working keyless. Tools that strictly need generation return a clear envelope pointing at the llm block or the explicit-text path.
- Runtime state (data/drafts.jsonl, data/engagement_queue.jsonl, data/metrics/*.json) is now gitignored.
- Tests: 234 -> 258, all passing; the 25-tool contract is pinned so signature drift fails CI.
Upgrade notes
pip install -U x-use-mcp- If you used Gemini or Azure keys before: set the
llmblock (api_key + base_url + model) — both providers offer OpenAI-compatible endpoints. Legacyopenai_api_keykeeps working with no changes. - Interactive MCP use needs no key at all: prefer explicit text from your MCP client; use
prepare_replyto give it the tweet context. - Background automation (
run_cycle, pipelines, "auto" text in the queue) requires thellmblock or env vars and errors clearly without them.
x-use v2.1.0 - scheduled-action queue, account management, 24 MCP tools
The MCP server grows from 9 to 24 tools: a persistent scheduled-action queue with safety pacing, full account management from your MCP client, and the operational tools that were missing. Additive only; everything from v2.0.0 keeps working unchanged.
Highlights
- Scheduled-action queue:
queue_postandqueue_engagementstore fully-rendered payloads (LLM text generated at enqueue time, solist_queueshows exactly what will fire).process_queueis the explicit approval gate and drains with jittered 90-240s pacing, per-action daily caps (posts 5, replies 15, likes 30, retweets 10 per day by default), and retry backoff. An opt-inauto_drainbackground worker (default off) trickles the queue on an interval. - Account management:
add_account,update_account,set_account_active,remove_account(confirm-gated),get_account. Every write toconfig/accounts.jsonis validated, backed up toconfig/backups/, and applied atomically. Cookies import from a server-side file path only, never inline through the chat. Paused accounts are rejected at enqueue and skipped on drain-all. - Support tools:
list_drafts,get_draft,reject_draft(drafts can now be reviewed and rejected, not just approved),get_run_status(pollrun_cyclehandles),get_account_health(config, cookie validity, metrics, session, queue depth, pending drafts in one read-only call).
Details
- New standalone
xuse/queue/package (store, runner, scheduler) with no MCP imports, ready for a futurex-use queueCLI - New
xuse/core/config_writer.py: load-fresh, validate-every-account, timestamped pruned backups, atomic replace - The queue subsystem has its own top-level
queueblock in settings.json; see docs/CONFIG_REFERENCE.md - Legacy account-key normalization consolidated into
xuse/core/config_loader.py(shared by core, MCP, and the init wizard) config/backups/added to .gitignore (backup copies may contain secrets)- Tests: 148 -> 234, all passing; the 24-tool contract is pinned so signature drift fails CI
Upgrade notes
pip install -U x-use-mcp- No config changes required; every new setting defaults conservatively (auto_drain off, pacing 90-240s, daily caps as above)
- Drafts file gains one status value (
rejected); older servers simply never produce it
x-use 2.0.0
The v2 relaunch of twitter-automation-ai: an installable package, a proper CLI, and a first-class MCP server. The automation engine is unchanged; everything around it is new.
Highlights
- One-line installers for Windows, macOS, and Linux (
install.ps1/install.sh): clone, venv, install, config bootstrap, andx-use doctorin a single command - New CLI:
x-use init(interactive setup wizard),x-use run,x-use doctor(preflight checks),x-use mcp - MCP server over stdio with 9 tools, so Claude Desktop, Claude Code, Cursor, and other MCP clients can post, reply, search, and engage directly
- Draft mode on by default: write tools return reviewable drafts and nothing reaches X until
approve_draftis called - Installable from PyPI:
pip install x-use-mcp(PyPI rejected the barex-usename as too similar to an existing project;import xuseand thex-usecommand are unchanged)
What changed since v1
- Packaging: src-layout
src/xuse/package,pyproject.toml, Python 3.10+ floor,x-useconsole script, project-root anchoring that survives install location - CLI: Typer app with in-memory
--accountand--pipelinescoping (config files never mutated) - MCP: 9 tools on the official MCP Python SDK (FastMCP, pinned
mcp>=1,<2), lazy per-account browser session pool with idle reaping, persistent draft store indata/drafts.jsonl, structured secret-sanitized error envelopes - LLM keys: env /
.envoverrides aboveconfig/settings.json, placeholder rejection from both sources, key values never logged - Engine fixes: FileHandler now honors the configured
processed_tweets_file; proxy poolhashstrategy pins accounts with sha256 (stable across restarts); engagement count parsing handles lowercasek/msuffixes and comma separators - Pipeline names shared between the CLI and MCP
run_cycleviaxuse/pipelines.py - Security:
config/accounts.jsonuntracked (shipsaccounts.example.json), cookie paths explicitly gitignored,get_metricsvalidates account ids against path traversal - Tests: 148 pytest tests (pure logic, MCP contract/drafts/sessions, CLI, env keys) plus CI on Python 3.10/3.11/3.12
- Docs: README rewritten, ARCHITECTURE.md and BEST_PRACTICES.md refreshed, CONFIG_REFERENCE.md now covers the
mcpsettings block
Upgrade notes
- Python 3.10 or newer is required
- The legacy
python src/main.pyentry point still works via a deprecation shim (removal no earlier than v2.1) - Config file formats are unchanged; existing
config/settings.jsonandconfig/accounts.jsonkeep working