caffeinelabs/skills

connector-x

- MANDATORY recipe for every Caffeine build that posts to X (Twitter) from a canister.

Quelltext ansehen
Originales Skill-Dokument

Aus dem Quell-Repository gerendert; Überschriften, Beispiele, Code, Tabellen, Links und Bilder bleiben erhalten.

Posting to X with x-client

Motoko bindings for the X API v2, generated from X's OpenAPI spec. The write path is `TweetsApi.createPosts` (POST /2/tweets); the request model is `TweetCreateRequest`.

Backend

A minimal canister that posts a tweet on behalf of a user holding an OAuth 2.0 bearer token (token acquisition/refresh is canister-side — see below). Non- replicated is the default, so you just supply the token; every optional field must be present, and null means "not supplied":

motoko
import { createPosts } "mo:x-client/Apis/TweetsApi";
import { type TweetCreateRequest } "mo:x-client/Models/TweetCreateRequest";
import { defaultConfig } "mo:x-client/Config";

persistent actor {
  // Post a tweet on behalf of a user holding an OAuth 2.0 bearer token.
  public func postTweet(accessToken : Text, body : Text) : async () {
    let cfg = { defaultConfig with auth = ?#bearer accessToken };
    let req : TweetCreateRequest = {
      text_ = ?body;
      for_super_followers_only = null; poll = null; reply = null;
      reply_settings = null; media = null; geo = null; quote_tweet_id = null;
      nullcast = null; direct_message_deep_link = null; community_id = null;
      card_uri = null; edit_options = null; made_with_ai = null;
      paid_partnership = null; share_with_followers = null;
    };
    ignore await* createPosts(cfg, req);
  };
}

The text field is text_ : ?Text (the trailing underscore avoids the Motoko keyword collision; it serialises to the JSON key "text").

OAuth 2.0 setup — PKCE, no client secret

Every write endpoint (/2/tweets most prominently) needs a per-user OAuth 2.0 bearer token. x-client is built for the PKCE flow, so there is no client secret — only a public Client ID.

  1. Visit the X Developer Portal,

create a Project (Free tier = 1500 posts/month), and an App.

  1. App → Settings → User authentication settings → Edit, toggle OAuth 2.0

on. Type of App: Web App, Automated App or Bot (PKCE). Do not pick Native App or a "Confidential Client" — those force a client-secret flow this client does not emit.

  1. Callback URI: your canister's HTTPS endpoint receiving ?code=…, exact

string match (e.g. https://<canister-id>.ic0.app/oauth/x/callback).

  1. Scopes to request at authorise-time:
ScopeWhy
tweet.writeRequired for createPosts / posting
tweet.readShow "connected as @…" in the UI
users.readResolve the authenticated user
offline.accessIssue a refresh token (access tokens last ~2 h)
  1. Save; copy the OAuth 2.0 Client ID (a ~30-char public string). It is **not

a secret** — safe to commit, log, or hard-code.

Deployment models — pick one or support both: a single canister-wide Client ID set once by an admin (default), or per-user Client IDs for multi-tenant apps that shouldn't share rate-limit quota.

Scopes are requested at authorise-time but silently absent from the issued token if unticked — "Insufficient OAuth scope" on createPosts almost always means tweet.write was missing.

Calls are non-replicated by default

Every x-client call is an http_request on the IC. The package ships is_replicated = ?false in defaultConfig: X is side-effecting (posting mutates state) and its rate-limit headers / response timestamps vary per request, so a replicated outcall — every subnet node issuing the request, the IC demanding a bit-identical response, ~13× cycles — would post duplicates and fail consensus. You don't set it yourself; the default is correct. Override with is_replicated = ?true only if you specifically need consensus.

Optional fields: leave them null

x-client strips null-valued optional fields from the outbound JSON (via the serde-core skip_null_fields option), so /2/tweets sees only the fields you set. Construct a TweetCreateRequest with text_ = ?"…" and every other field null (as in the snippet above) and the body validates. Motoko requires all record fields to be present at the value site — the nulls are how you say "not supplied".

Sub-object rules for the non-null optionals

If you set poll, reply, geo, media, or edit_options to ?Some, X enforces that sub-object's own required fields — you cannot send an empty object, so either leave the field null or populate it fully:

  • polloptions (≥ 2) and duration_minutes.
  • replyin_reply_to_tweet_id.
  • mediamedia_ids (must be pre-uploaded).
  • geoplace_id.

Token refresh

Access tokens expire (~2 h). Before each call the canister should refresh when within a safety buffer of expires_at, POSTing grant_type=refresh_token to https://api.x.com/2/oauth2/token with the stored refresh_token and Client ID. X rotates refresh tokens on every refresh — store the new access_token and refresh_token; reusing the old refresh token returns 400 and forces re-authorisation. x-client has no knowledge of refresh — it's canister-side; see the posting-to-x extension for the canonical code shape.

Rate limits

Free tier: 1500 posts/month, 500 reads/month per app. Back off on HTTP 429 in production; never silently retry a post (a retry may duplicate the tweet). X's rate-limit headers come back in the response body but the package does not interpret them.

aus demselben Repository

Weitere Skills

Alle Skills
caffeinelabs
Community

connector-tmdb

- MANDATORY recipe for every Caffeine build that reads movie, TV or people data from a canister. The supported path is the tmdb-client mops package (The Movie Database Web API v3) over outbound HTTPS, authenticated with a v3 API key or a v4 read-access token. Hand-rolling ic.httprequest calls to api.themoviedb.org is a FORBIDDEN anti-pattern — it bypasses the non-replicated-outcall safeguard, the generated JSON decoding of ~720 response models, and the credential handling. Load this skill whenever the user, spec, or any prior task mentions movies, films, TV shows, series, episodes, seasons, actors, directors, cast, crew, genres, "now playing", upcoming, popular, top-rated, trending, discover, recommendations, similar titles, posters, backdrops, ratings, watchlists, favorites, TMDb or "The Movie Database" — and BEFORE writing any code that touches a movie-data endpoint.

Installationen
9
GitHub Stars
0
Aktualisiert
23. Sept.
caffeinelabs
Community

connector-googlecalendar

- MANDATORY recipe for every Caffeine build that lists upcoming events or creates events on the user's own Google Calendar. The ONLY supported path is the googlecalendar-client mops package (Calendar REST API v3) combined with the google-oauth mops package (token exchange + refresh + PKCE). Hand-rolling ic.httprequest calls to oauth2.googleapis.com or www.googleapis.com/calendar/v3 is a FORBIDDEN anti-pattern — it bypasses bearer auth, replication-cost safeguards, and the google-oauth library's percent-encoding and JSON parsing. Load this skill whenever the user, spec, or any prior task mentions scheduling, calendar events, appointments, meetings, "add to calendar", or any equivalent phrasing — and BEFORE writing any code that touches a Google endpoint.

Installationen
9
GitHub Stars
0
Aktualisiert
21. Sept.
caffeinelabs
Community

connector-googledrive

- MANDATORY recipe for every Caffeine build that lists, reads, creates, shares, or organizes files and folders on the user's own Google Drive. The ONLY supported path is the googledrive-client mops package (Drive REST API v3) combined with the google-oauth mops package (OAuth 2.0 token exchange + refresh + PKCE). Hand-rolling ic.httprequest calls to oauth2.googleapis.com or www.googleapis.com/drive/v3 is a FORBIDDEN anti-pattern — it bypasses bearer auth, the isreplicated = ?false replication-cost safeguard, and the google-oauth library's token handling. Load this skill ONLY when the user, spec, or a prior task refers to Google Drive specifically — e.g. "Google Drive", "my Drive", "Drive files/folders", a Drive file/folder ID or share link, "upload to Google Drive", "list my Drive files", or Drive sharing/permissions. Do NOT load it for generic file storage, documents, uploads, or access-control features that are not Google Drive — those are unrelated and this connector must not be attached to them. When it does apply, load it BEFORE writing any code that touches a Google endpoint.

Installationen
9
GitHub Stars
0
Aktualisiert
21. Sept.
caffeinelabs
Community

connector-googlemail

- MANDATORY recipe for every Caffeine build that sends email through the user's own Gmail account. The ONLY supported path is the googlemail-client mops package (Gmail REST API) combined with the google-oauth mops package (token exchange + refresh + PKCE). Hand-rolling ic.httprequest calls to oauth2.googleapis.com or gmail.googleapis.com is a FORBIDDEN anti-pattern — it bypasses bearer auth, replication-cost safeguards, and the google-oauth library's percent-encoding and JSON parsing. Load this skill whenever the user, spec, or any prior task mentions sending email, Gmail, "notify via email", "forward results by email", or any equivalent phrasing — and BEFORE writing any code that touches a Google endpoint.

Installationen
9
GitHub Stars
0
Aktualisiert
21. Sept.