ABot X Publisher
Publish original text posts to your configured X account from ABot Runtime.
The model writes the content; the plugin handles credentials, verifies the account,
and appends By ABot AI - runtime to every post.
This is an independently installed Marketplace plugin for ABot Runtime 1.7.0 or
later. It is not bundled with the public Runtime or its npm package. The source
package keeps private: true to prevent accidental npm publication; installation
uses its GitHub repository and the prebuilt src/index.cjs.
The stable plugin ID is x-publisher-private. The historical suffix is retained to preserve existing installations and saved configuration; each installation uses its owner's account. There is no default username or shared credential.
Install from GitHub
When the repository has been published, use its URL in the Runtime's plugin installation flow. Review the selected commit, plugin permissions and bundled files, then choose Install, Configure, and Apply changes. For a reproducible installation, select a reviewed commit or release tag instead of a moving branch. Installation does not run npm, build scripts, or a test post.
If this plugin already exists in the installation, remove the existing copy before
installing its reviewed replacement; saved configuration is retained. Two copies exposing
x_publish_post cannot coexist, even under different plugin IDs.
Connect the account locally
Use an X app and OAuth 1.0a user tokens belonging to the account you intend to publish from. No hosted OAuth service or model-managed connection is needed.
-
In X Developer Console, enable OAuth 1.0a / Read and write for the app. No Direct Message permission is needed. If permissions changed after you generated Access Token / Secret, regenerate those user tokens.
-
In the Runtime Web UI, open Plugins > x-publisher-private > Configure. The same form is available during installation review.
-
Set expectedUsername to the intended X username without @: 1–15 ASCII letters, digits or underscores. Surrounding whitespace is trimmed and account comparison is case-insensitive. There is no personal-account default.
-
Enter the four secret fields locally:
- apiKey: OAuth 1.0a Consumer Key / API Key.
- apiSecret: Consumer Secret / API Secret.
- accessToken: the account's OAuth 1.0a Access Token.
- accessTokenSecret: its Access Token Secret.
These are not the app-only Bearer Token or OAuth 2.0 Client ID / Client Secret. Do not put values in chat, screenshots, the manifest or source code.
-
Choose Save changes, then Apply changes when the owning Runtime is idle. Saved UI values load into new Runtime owners through the existing plugin configuration mechanism; no process restart is needed just to reload these locally saved values. Existing owners retain their loaded configuration until Apply succeeds.
-
Ensure the plugin and capability x_publish_post are enabled. Existing allow/deny rules and Runtime request permission policy still apply.
Installation and loading are allowed before setup. Publishing returns
x_not_configured / not_sent until a valid username and all four keys are
available. Identity is verified as part of each authorized publication; there is
no separate connection-test tool and no automatic test post.
Existing installation: retain the plugin ID and set expectedUsername to your intended account in Configure, then save/apply before posting. Existing environment keys can remain in place. A missing setting blocks publication.
The Runtime stores UI values locally outside this package, shared across dev/prod in the same installation. Secret values are not returned to the UI or the model. An untouched secret retains its current value; replacement and clearing are explicit. Clearing a secret suppresses its environment fallback for this plugin. Removing the plugin retains saved configuration. This is the existing Runtime storage contract, not a plugin-specific secret store.
Existing environment-variable setup
The existing .env.example names remain supported when no local secret override
exists: ABOT_X_API_KEY, ABOT_X_API_SECRET, ABOT_X_ACCESS_TOKEN and
ABOT_X_ACCESS_TOKEN_SECRET. Put these in the owning host's environment or root
.env locally, preserving existing entries. The example is not loaded
automatically. Environment changes require restarting the owning process; Apply
alone does not reload .env. The username still comes from Configure.
No scheduler or autonomous posting job is installed. Request a deliberate first post only when ready; automated tests use fake credentials and mocked HTTP.
Contract and failure behavior
- One capability:
x_publish_post; one mutating operation:publish_post. - No public control fields. The model supplies the
textthrough the standard raw-text payload stage. Only this selected capability receives its skill. - Signature, mention blocking and final weighted 280-character validation are
enforced in code using the official
twitter-textparser. Ordinary Hebrew and Latin content has 258 characters left after the two newlines and signature. Long URLs count as 23. Text is never silently truncated. - The request body is constructed as
{ text }against the fixed endpointhttps://api.x.com/2/tweets. No reply, quote, media, DM, repost, thread, deletion, arbitrary endpoint or account override is exposed. User mentions and lists (@user/list, including fullwidth at-signs) are rejected. - Before each post, the plugin calls
GET https://api.x.com/2/users/mewith the same OAuth credential snapshot used for posting. It requires HTTP 200, a valid account ID, and a username matching the installation'sexpectedUsername(case-insensitive). The username is captured fromcontext.configat plugin load; it is never a model-supplied control. Verification is fresh per invocation, with no cached identity or extra model tool. - Credentials stay in the host/plugin layer. The model supplies only post text. One timeout/abort budget covers verification and posting; redirects and automatic retries remain disabled.
- Missing credentials, invalid text, failed account lookup, or an account mismatch
return
not_sent: no post request is dispatched.x_account_unverifiedidentifies a failed identity check;x_account_mismatchidentifies a different account. After post dispatch, X rejection returnsrejected; network failures, timeout, server errors and invalid success receipts returnunknown: the post may exist. There are no automatic POST retries. Check the X profile before attempting a new post after an unknown outcome. - Success requires verified identity and a valid API creation receipt. It returns
the post ID, URL, returned text, and
account: { id, username }. Provider error bodies and transport exception messages are never passed back to the model. - Duplicate prevention across separate model invocations is not provided. Each authorized invocation can create one post. Keep the profile's Automated label and operator disclosure; retain API credits for use.
Develop and validate independently
source/ contains handwritten code; src/index.cjs is generated. The build uses
only the published @abot-ai/runtime/plugin-sdk entrypoint, pinned through the
lockfile, and bundles runtime dependencies. It does not import a Runtime checkout
or require consumer node_modules at execution time. The SDK build dependency is
1.6.0; the installation/configuration flow targets the 1.7.0 host.
From this repository's root:
npm ci --ignore-scripts
npm run build
npm run validate
Tests use fake credentials and mocked HTTP. They exercise plugin configuration, account verification, text policy, OAuth signing, error handling, and the generated bundle. They do not test or import Runtime internals, persistence, or the Web UI. The CI workflow validates the committed bundle on Node 20 and 22.
Prepare a repository export
npm run export:repository -- --output /absolute/path/to/new-empty-directory
The exporter copies only the explicit list in repository-files.json and refuses
an existing output directory or symlinked source files. It never copies Git history,
credentials, installed dependencies, logs, or test artifacts. Inspect and validate
the exported copy before creating or pushing the separate repository. Repository
publication and a Marketplace listing are separate owner-approved actions.
MARKETPLACE.md contains the proposed listing and remaining release checks.
License
MIT. See LICENSE and THIRD_PARTY_NOTICES.md for bundled dependency notices.