Atlas / Skills / aden-hive / X Automation

X AutomationSAFE

skills/aden-hive/x-automation

Multi-Agent Harness for Production AI

Verdict
SAFE
Grade
B
Trust score
89 /100
Version
1.0
Hosts
—
License
Apache-2.0
Stars
11,091
01

Overview

Multi-Agent Harness for Production AI

Read from source at commit e9251a22710aOBSERVED · 2026-10-07
02

What it tells the agent

The instruction file, verbatim from the audited commit — this is the text the model reads, and the surface the audit's instruction layer examines. Quoted here so you can judge it without cloning anything.

---
name: hive.x-automation
description: Read before automating X / Twitter with browser_* tools. Verified flows for post, reply, delete, search-and-engage, plus the Draft.js compose quirks that silently disable the send button. Includes the daily-reply and job-market-reply playbooks. Requires hive.browser-automation for the underlying screenshot + coordinate workflow. Verified 2026-04-11.
metadata:
  author: hive
  type: default-skill
  version: "1.0"
  verified: 2026-04-11
  requires_skill: hive.browser-automation
---

# X / Twitter Automation

X uses **Draft.js** (the original Facebook rich-text editor) for the compose text area, which was the original canary for all the rich-text editor quirks the `browser-automation` skill now documents. Most of the site is otherwise stable — `data-testid` attributes have held up for years, the SPA is reasonably honest about what it renders, and shadow DOM is minimal. The hard parts are the composer, rate limiting, and the occasional anti-bot challenge.

**Always activate `browser-automation` first.** This skill assumes you already know about CSS-px coordinates, click-first typing, and `Input.insertText`. The guidance below is X-specific.

## Timing expectations

- `browser_navigate(wait_until="load")` returns in **1.3–1.6 s** on a warm cache.
- After navigation, **`sleep(2–3)`** for SPA hydration before querying selectors.
- Compose modal slide-in: **~1.5 s** after clicking reply / compose.
- First 1–2 characters typed into the compose editor **may be dropped** — see "Draft.js quirks" below.

## Verified selectors (2026-04-11)

| Target | Selector |
|---|---|
| Home nav link | `a[data-testid='AppTabBar_Home_Link']` |
| Explore nav link | `a[data-testid='AppTabBar_Explore_Link']` |
| Notifications | `a[data-testid='AppTabBar_Notifications_Link']` |
| Main search input | `input[data-testid='SearchBox_Search_Input']` |
| Compose text area | `[data-testid='tweetTextarea_0']` (Draft.js contenteditable) |
| Post / Tweet submit button | `[data-testid='tweetButton']` |
| Reply button (on feed / tweet detail) | `[data-testid='reply']` |
| Like button | `[data-testid='like']` |
| Retweet / repost button | `[data-testid='retweet']` |
| Caret (⋯) menu on a post | `[data-testid='caret']` |
| Confirmation sheet confirm button | `[data-testid='confirmationSheetConfirm']` |
| Tweet article wrapper | `article[data-testid='tweet']` |
| Close modal / composer | `[aria-label='Close']` or press `Escape` |

All of these are light-DOM `data-testid` attributes — `wait_for_selector` and `browser_type(selector=...)` work on them directly, no shadow piercing needed.

## Post new tweet flow

```
browser_navigate("https://x.com/home", wait_until="load")
sleep(3)

# Open the compose UI (click the post-new-tweet nav or use shortcut N)
browser_press("n")   # keyboard shortcut — opens compose modal
sleep(1.5)

# Click the textarea to make sure Draft.js is in edit mode
ta_rect = browser_get_rect("[data-testid='tweetTextarea_0']")
browser_click_coordinate(ta_rect.cx, ta_rect.cy)
sleep(0.5)

# Type — browser_type handles Draft.js correctly now via Input.insertText
browser_type("[data-testid='tweetTextarea_0']", tweet_text)
sleep(1.0)  # let Draft.js commit state

# Verify the Post button is enabled — never click blindly, Draft.js sometimes
# doesn't register the input even with a prior click.
state = browser_evaluate("""
  (function(){
    const btn = document.querySelector('[data-testid="tweetButton"]');
    if (!btn) return {found: false};
    return {
      found: true,
      disabled: btn.disabled || btn.getAttribute('aria-disabled') === 'true',
    };
  })();
""")
if state['found'] and not state['disabled']:
    browser_click("[data-testid='tweetButton']")
    sleep(2)
    browser_press("Escape")  # close any leftover modal
```

## Posting a tweet WITH an image

**Critical: NEVER click the photo button.** On `x.com/compose/post` the media button is a styled `<button>` that triggers Chrome's native OS file picker when clicked — that dialog is unreachable via CDP and will wedge the automation. Instead, set the file directly on the hidden `<input type='file'>` element using `browser_upload`:

```python
# 1. Open the compose modal as usual
browser_press("n")
sleep(1.5)
browser_click_coordinate(ta_rect.cx, ta_rect.cy)
sleep(0.5)
browser_type("[data-testid='tweetTextarea_0']", tweet_text)

# 2. Find the hidden file input X uses for media uploads.
#    X's input is marked with data-testid='fileInput' and accepts
#    image/*,video/*. It's hidden (display:none) but still mounted.
inputs = browser_evaluate("""
  (function(){
    return Array.from(document.querySelectorAll('input[type="file"]'))
      .map(el => ({
        testid: el.getAttribute('data-testid') || '',
        accept: el.accept || '',
        multiple: el.multiple,
      }));
  })();
""")
# Expect to see: [{testid: 'fileInput', accept: 'image/jpeg,...', multiple: true}]

# 3. Set the file WITHOUT opening any dialog
browser_upload(
    selector="input[data-testid='fileInput']",
    file_paths=["/absolute/path/to/photo.png"],
)
sleep(2)  # X takes ~1-2s to show the preview thumbnail

# 4. Verify the preview rendered before posting — if not, the upload
#    didn't land and Post button will fail.
preview = browser_evaluate("""
  (function(){
    // X renders uploaded media as an <img> with data-testid='attachments'
    // (or similar) inside the composer.
    const att = document.querySelector('[data-testid="attachments"] img');
    return { hasPreview: !!att };
  })();
""")
if not preview['hasPreview']:
    raise Exception("Upload didn't render in composer — do NOT click Post")

# 5. Now click Post as usual
browser_click("[data-testid='tweetButton']")
sleep(3)  # media upload + post takes longer than text-only
browser_press("Escape")
```

If you don't already have the image file on disk, write it first: `write_file("/tmp/x_upload.png", base64_bytes)` or copy from a known location. `browser_upload` requires an absolute file pa
03

Trust audit

SAFEgrade B · trust 89/100 Nothing in the source contradicts what it says it does. Grade A is reserved for packages that have also passed the behavioural sandbox.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeNA
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
none-observed
Network
none-observed
Shell
none-observed
Dependencies
pinned
Secrets in source
none-found

Findings (1)

LOWInventory / provenance · inv.symlink · CWE-1104
CLAUDE.md
CLAUDE.md
Why it matters. link not followed

Gates applied: no_behavioural_pass.

Audited 2026-10-07 · audit v0.4.1 · source sha e9251a22710afull audit observations/trust-audit/skill/aden-hive__x-automation.json · Report an issue / request a re-scan
04

Audit history

Every audit this skill has had.

DateSourceVerdictGradeScoreChange
2026-10-07e9251a22710aSAFEB89first audit
05

Questions

What does the X Automation skill do?

Multi-Agent Harness for Production AI

Is X Automation safe to install?

The audit found nothing in the source that contradicts what it says it does, and graded it B (89/100). Grade A is held back for packages that have also passed a sandboxed behavioural run, which is why a clean skill reads B.

What can X Automation access on my machine?

The audit observed no filesystem, network or shell use at all in its source.

How current is this page?

The grade is for one exact copy of the source (e9251a22710a), read on 2026-10-07. The repository is watched, and a new audit runs when it changes — this is the first audit.

Advertisement