diff --git a/hands/reddit/HAND.toml b/hands/reddit/HAND.toml index b27a93c..167ecff 100644 --- a/hands/reddit/HAND.toml +++ b/hands/reddit/HAND.toml @@ -44,7 +44,7 @@ steps = [ "Select 'script' as the app type", "Fill in name and redirect URI (http://localhost:8080)", "Copy the client ID (under the app name) and secret", - "Set REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, REDDIT_USERNAME, and REDDIT_PASSWORD as environment variables", + "Set REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET as environment variables", "Restart LibreFang or reload config for the change to take effect", ] @@ -70,42 +70,6 @@ steps = [ "Restart LibreFang or reload config for the change to take effect", ] -[[requires]] -key = "REDDIT_USERNAME" -label = "Reddit Username" -requirement_type = "api_key" -check_value = "REDDIT_USERNAME" -description = "Reddit account username. Required for OAuth2 password-grant authentication to post and comment." - -[requires.install] -signup_url = "https://www.reddit.com/register" -docs_url = "https://www.reddit.com/dev/api/" -env_example = "REDDIT_USERNAME=your_reddit_username" -estimated_time = "1-2 min" -steps = [ - "Use the Reddit account username you want the hand to act as", - "Set REDDIT_USERNAME as an environment variable", - "Restart LibreFang or reload config for the change to take effect", -] - -[[requires]] -key = "REDDIT_PASSWORD" -label = "Reddit Password" -requirement_type = "api_key" -check_value = "REDDIT_PASSWORD" -description = "Reddit account password. Required for OAuth2 password-grant authentication to post and comment." - -[requires.install] -signup_url = "https://www.reddit.com/register" -docs_url = "https://www.reddit.com/dev/api/" -env_example = "REDDIT_PASSWORD=your_reddit_password" -estimated_time = "1-2 min" -steps = [ - "Use the password for the Reddit account configured in REDDIT_USERNAME", - "Set REDDIT_PASSWORD as an environment variable", - "Restart LibreFang or reload config for the change to take effect", -] - # ─── Configurable settings ─────────────────────────────────────────────────── [[settings]] @@ -260,19 +224,20 @@ Detect the operating system: python -c "import platform; print(platform.system())" ``` -Authenticate with Reddit API using OAuth2: +Authenticate with Reddit API using OAuth2 client_credentials (app-only auth): ``` curl -s -X POST "https://www.reddit.com/api/v1/access_token" \ -u "$REDDIT_CLIENT_ID:$REDDIT_CLIENT_SECRET" \ - -d "grant_type=password&username=$REDDIT_USERNAME&password=$REDDIT_PASSWORD" \ + -d "grant_type=client_credentials" \ -A "LibreFang Reddit Hand/1.0" \ -o reddit_auth.json ``` Extract the access_token from the response for subsequent API calls. +Note: This is app-only authentication — most read endpoints work, but posting and commenting require the app's identity. No user-level context is available. Recover state: 1. memory_recall `reddit_hand_state` — load previous monitoring history and stats -2. Read **User Configuration** for subreddits, monitor_mode, content_style, approval_mode, etc. +2. Read **Hand Settings** for subreddits, monitor_mode, content_style, approval_mode, etc. 3. file_read `reddit_queue.json` if it exists — pending posts/replies 4. knowledge_query for previously tracked threads and engagement data diff --git a/hands/reddit/SKILL.md b/hands/reddit/SKILL.md index fa3f7c1..6a6130e 100644 --- a/hands/reddit/SKILL.md +++ b/hands/reddit/SKILL.md @@ -13,15 +13,17 @@ runtime: prompt_only Reddit API requires OAuth2 authentication for all endpoints. -**Step 1: Get access token**: +**Step 1: Get access token (app-only / client_credentials)**: ```bash curl -s -X POST "https://www.reddit.com/api/v1/access_token" \ -u "$REDDIT_CLIENT_ID:$REDDIT_CLIENT_SECRET" \ - -d "grant_type=password&username=$REDDIT_USERNAME&password=$REDDIT_PASSWORD" \ + -d "grant_type=client_credentials" \ -A "LibreFang Reddit Hand/1.0" ``` Response: `{"access_token": "...", "token_type": "bearer", "expires_in": 86400, "scope": "*"}` +> **Note:** `client_credentials` provides app-only access. Most read endpoints (listing posts, fetching comments, searching) work normally. Posting and commenting use the app's identity. For full user-level actions (e.g., voting, managing subscriptions), the more complex OAuth2 authorization code flow is required. + **All subsequent requests** must include: ``` Authorization: Bearer $ACCESS_TOKEN @@ -101,7 +103,7 @@ curl -s -H "Authorization: Bearer $ACCESS_TOKEN" \ | Type | Limit | Window | |------|-------|--------| | OAuth authenticated | 10 requests | 1 minute | -| With user-level auth | 30 requests | 1 minute | +| With app-only auth | 30 requests | 1 minute | | Posting | ~1 post | 10 minutes (varies by karma) | | Commenting | ~1 comment | varies by karma | diff --git a/hands/twitter/HAND.toml b/hands/twitter/HAND.toml index 2fc4454..865a805 100644 --- a/hands/twitter/HAND.toml +++ b/hands/twitter/HAND.toml @@ -59,6 +59,84 @@ steps = [ "Restart LibreFang or reload config for the change to take effect", ] +[[requires]] +key = "TWITTER_API_KEY" +label = "Twitter API Key (Consumer Key)" +requirement_type = "api_key" +check_value = "TWITTER_API_KEY" +optional = true +description = "OAuth 1.0a Consumer Key. Optional — only needed for user-context operations (liking, retweeting, following as a specific user)." + +[requires.install] +signup_url = "https://developer.twitter.com/en/portal/dashboard" +docs_url = "https://developer.twitter.com/en/docs/authentication/oauth-1-0a" +env_example = "TWITTER_API_KEY=your_api_key_here" +estimated_time = "5-10 min" +steps = [ + "Go to developer.twitter.com and open your App settings", + "Navigate to 'Keys and tokens' page", + "Copy the 'API Key' (also called Consumer Key)", + "Set it as TWITTER_API_KEY environment variable", +] + +[[requires]] +key = "TWITTER_API_SECRET" +label = "Twitter API Secret (Consumer Secret)" +requirement_type = "api_key" +check_value = "TWITTER_API_SECRET" +optional = true +description = "OAuth 1.0a Consumer Secret. Optional — only needed alongside TWITTER_API_KEY for user-context operations." + +[requires.install] +signup_url = "https://developer.twitter.com/en/portal/dashboard" +docs_url = "https://developer.twitter.com/en/docs/authentication/oauth-1-0a" +env_example = "TWITTER_API_SECRET=your_api_secret_here" +estimated_time = "2-3 min" +steps = [ + "On the same 'Keys and tokens' page as the API Key", + "Copy the 'API Secret' (also called Consumer Secret)", + "Set it as TWITTER_API_SECRET environment variable", +] + +[[requires]] +key = "TWITTER_ACCESS_TOKEN" +label = "Twitter Access Token" +requirement_type = "api_key" +check_value = "TWITTER_ACCESS_TOKEN" +optional = true +description = "OAuth 1.0a user Access Token. Optional — only needed for user-context operations." + +[requires.install] +signup_url = "https://developer.twitter.com/en/portal/dashboard" +docs_url = "https://developer.twitter.com/en/docs/authentication/oauth-1-0a" +env_example = "TWITTER_ACCESS_TOKEN=your_access_token_here" +estimated_time = "2-3 min" +steps = [ + "On the 'Keys and tokens' page, scroll to 'Authentication Tokens'", + "Generate an Access Token and Secret", + "Copy the Access Token", + "Set it as TWITTER_ACCESS_TOKEN environment variable", +] + +[[requires]] +key = "TWITTER_ACCESS_TOKEN_SECRET" +label = "Twitter Access Token Secret" +requirement_type = "api_key" +check_value = "TWITTER_ACCESS_TOKEN_SECRET" +optional = true +description = "OAuth 1.0a user Access Token Secret. Optional — only needed alongside TWITTER_ACCESS_TOKEN for user-context operations." + +[requires.install] +signup_url = "https://developer.twitter.com/en/portal/dashboard" +docs_url = "https://developer.twitter.com/en/docs/authentication/oauth-1-0a" +env_example = "TWITTER_ACCESS_TOKEN_SECRET=your_access_token_secret_here" +estimated_time = "2-3 min" +steps = [ + "Generated alongside the Access Token above", + "Copy the Access Token Secret", + "Set it as TWITTER_ACCESS_TOKEN_SECRET environment variable", +] + # ─── Configurable settings ─────────────────────────────────────────────────── [[settings]] diff --git a/hands/twitter/SKILL.md b/hands/twitter/SKILL.md index a4b2a47..b949f79 100644 --- a/hands/twitter/SKILL.md +++ b/hands/twitter/SKILL.md @@ -19,6 +19,12 @@ Authorization: Bearer $TWITTER_BEARER_TOKEN **Environment variable**: `TWITTER_BEARER_TOKEN` +**Authentication modes**: +- **Bearer Token only** (default): Sufficient for posting tweets, reading timelines, and searching. All core functionality works with just the Bearer Token. +- **Bearer Token + OAuth 1.0a** (optional): Required for user-context operations such as liking tweets, retweeting, following/unfollowing, and accessing DMs. Set `TWITTER_API_KEY`, `TWITTER_API_SECRET`, `TWITTER_ACCESS_TOKEN`, and `TWITTER_ACCESS_TOKEN_SECRET` to enable these features. + +> **Note**: The Like endpoint (`POST /2/users/:id/likes`) and Retweet endpoint (`POST /2/users/:id/retweets`) require OAuth 1.0a User Context authentication. If only Bearer Token is configured, these operations will be skipped with a warning. + ### Core Endpoints **Get authenticated user info**: