x-engage
CLAUDE.md18 starsChanged 6 months agoMITView on GitHub
Guidance for Claude Code when working in this repo. Read this before changing anything that touches drafting, voice, or the autopilot loop. x-engage is a curation tool for X (Twitter), not a reply bot. It scans a watchlist, surfaces the small subset of posts worth replying to right now, drafts a reply in the user's voice, and queues it for human approval (manual mode) or auto-publishes inside hard safety gates (autopilot mode). All runtime state is local — no cloud,…
- Reads credentials
In this repositoryOne other file it gives its agents.
- x-engageSkill
The file
Show its rules and text
We split this CLAUDE.md into the rules it gives an agent
19 rules. About 0 are common, 8 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈8
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 43
DO:: add the pattern to scripts/lib/safety.py as a post-filter check.
- Very specific: line 44
DON'T: add a "things to avoid" bullet to voice-profile.personal.md or the drafter prompt.
- Very specific: line 53
Add to BANNED_ANYWHERE (or BANNED_OPENERS if position-specific) in scripts/lib/safety.py.
- Distinctive: line 54
Verify: the failed draft rejects, a clean variant still passes.
- Distinctive: line 58
Do not: add to the prompt, add a new template, lower the voice-match threshold "to give the model more room."
- Very specific: line 63
If it demonstrates a *new* pattern (new register, new POV, new receipt shape), append manually to voice-corpus.md so retrieval picks it up …
- Distinctive: line 67
Before adding any lint entry or voice constraint, answer both:
- Distinctive: line 71
If you can't name a real draft, the rule is inferred from training-data intuition.
- Very specific: line 97
No formal test suite. verify is the closest thing — run it after any change to drafter, lint, voice files, or the CLI.
- Very specific: line 111
If you see ACCOUNT_PAUSED, RESTRICTION, CAPTCHA, LOGIN_REQUIRED, or COOKIES_EXPIRED in output, or any command exits with code 2: halt …
- Very specific: line 128
All numeric thresholds live in config/settings.yml.
- Distinctive: line 136
No emojis in code or commits unless the user explicitly asks.
- Distinctive: line 140
Don't add features to the drafter prompt.
- Distinctive: line 141
Don't add "the user dislikes X" instructions anywhere — that's a lint rule.
- Very specific: line 142
Don't lower voice_match_threshold or any cooldown to ship more drafts.
- Distinctive: line 143
Don't create new templates, registers, or shape steers without a flagged draft justifying it.
- Very specific: line 144
Don't restore anything from references/_archive/ — those are pre-rebuild legacy files.
- Very specific: line 145
Don't push without running verify first if you touched safety.py, voice.py, or the voice files.
- Very specific: line 149
Read SKILL_DISCIPLINE.md end-to-end before adding *any* rule, prompt change, or new file in scripts/lib/.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
CLAUDE.md
Guidance for Claude Code when working in this repo. Read this before changing anything that touches drafting, voice, or the autopilot loop.
What this project is
x-engage is a curation tool for X (Twitter), not a reply bot. It scans a watchlist, surfaces the small subset of posts worth replying to right now, drafts a reply in the user's voice, and queues it for human approval (manual mode) or auto-publishes inside hard safety gates (autopilot mode). All runtime state is local — no cloud, no shared backend.
Two long-form docs explain the why:
SKILL.md— user-facing skill spec (subcommands, examples, autopilot contract).SKILL_DISCIPLINE.md— anti-bloat guardrails. Read before adding any rule, lint, or prompt instruction.
Architecture in one minute
Drafts come from corpus retrieval + minimal positive-spec prompt + deterministic post-filter lint. Not from stacking "don't do X" rules in the prompt.
fetch → candidate_pool → voice.draft() → safety.check() → state.insert() → publisher.publish()
↑ ↓ Claude CLI ↓ lint (silent reject)
scan-bg daemon voice-profile + safety.py
(launchd, 10min) corpus + receipts (em-dash, aphorism, AI phrases)Key files (don't re-discover these every session):
| File | Role |
scripts/x_engage.py | CLI orchestrator, all cmd_* subcommands. 1700+ lines. |
scripts/lib/voice.py | Drafter: retrieves corpus + receipts, invokes Claude CLI. |
scripts/lib/safety.py | Post-filter lint. Hard rules live HERE, not in the prompt. |
scripts/lib/state.py | SQLite queue + cooldown ledger + PAUSED flag check. |
scripts/lib/publisher.py | Playwright publisher. Writes ~/.x-engage/PAUSED on safety signal. |
scripts/lib/candidate_pool.py | Pool feeder for scan-bg (10-min cron). |
voice-profile.personal.md | Six positive specs. ~80 lines. Don't bloat. |
voice-corpus.md | Tagged reply examples. Top-3 retrieved per draft. |
voice-receipts.md | Static verifiable facts (Dan's GitHub stats, NodeSparks numbers). |
config/settings.yml | Cadence, thresholds, watchlist. See CONFIG.md for every key. |
The Pink Elephant rule (most important)
Telling an LLM "don't use em-dashes" activates the em-dash representation. Every "DON'T" in the prompt re-anchors the model on the forbidden pattern.
- DO: add the pattern to
scripts/lib/safety.pyas a post-filter check. Silent rejection, no feedback to the model. - DON'T: add a "things to avoid" bullet to
voice-profile.personal.mdor the drafter prompt.
The voice profile says what the user does. The lint catches what slips through.
When the user flags "not my voice"
Protocol (full version in SKILL_DISCIPLINE.md):
- Identify the specific phrase / shape / register collision.
- Add to
BANNED_ANYWHERE(orBANNED_OPENERSif position-specific) inscripts/lib/safety.py. Comment with date + draft ID. - Verify: the failed draft rejects, a clean variant still passes.
- Kill the draft in the queue (
/x-engage kill <id>). - Run
/x-engage verify.
Do not: add to the prompt, add a new template, lower the voice-match threshold "to give the model more room."
When the user flags "yes, this is me"
python3 -m scripts.x_engage good <id>— pins intogood-drafts.md.- If it demonstrates a new pattern (new register, new POV, new receipt shape), append manually to
voice-corpus.mdso retrieval picks it up next time.
Adding rules — the trace test
Before adding any lint entry or voice constraint, answer both:
- What specific user-rejected draft does this prevent? (need the draft ID + date + quote)
- What specific user-approved draft does this enable?
If you can't name a real draft, the rule is inferred from training-data intuition. Don't add it. Wait until a real flagged draft justifies it. Every 30 days, audit lint rules — rules that never fire get deleted.
Common commands
Entry point is always python3 -m scripts.x_engage <subcommand> from the repo root.
# health
python3 -m scripts.x_engage verify # skill health check (line counts, bloat, staleness)
python3 -m scripts.x_engage status # unified snapshot: queue + scan-bg + autopilot + flags
# manual flow
python3 -m scripts.x_engage fetch 15 # draft N candidates (default 15)
python3 -m scripts.x_engage review # show pending drafts
python3 -m scripts.x_engage approve all
python3 -m scripts.x_engage publish
# autopilot (autonomous, bypasses approval, panic ceiling 50/day)
python3 -m scripts.x_engage autopilot start target=50 until=18:00
python3 -m scripts.x_engage autopilot stop
# pool feeder (auto-started by autopilot; advanced standalone use only)
python3 -m scripts.x_engage run-bg
python3 -m scripts.x_engage stop-bgNo formal test suite. verify is the closest thing — run it after any change to drafter, lint, voice files, or the CLI.
Safety contract (don't bypass)
The publisher and autopilot tick check these before every send. Treat as load-bearing:
~/.x-engage/PAUSEDexists → halt everything.X_ENGAGE_HALT=1env var → halt everything.- 90s minimum gap between publishes.
- Per-handle 24h cooldown.
- 4 replies / 30d lifetime cap per author.
- Voice-match threshold 0.45 (in
config/settings.yml). - Autopilot panic ceiling: 50 replies/day. Code refuses higher.
If you see ACCOUNT_PAUSED, RESTRICTION, CAPTCHA, LOGIN_REQUIRED, or COOKIES_EXPIRED in output, or any command exits with code 2: halt immediately, do not retry, surface the screenshot path (~/Downloads/x-incident-*.png) to the user.
Daemon model
Both daemons run via macOS launchd plists in ~/Library/LaunchAgents/:
com.x-engage.scan-bg— pool feeder, fires every 10 min. No drafts, no publishes.com.x-engage.autopilot— autonomous tick every 60s. Drafts, lints, publishes. Self-unloads on target hit,stop_attime, PAUSED flag, or safety signal.
launchd pauses on system sleep / lid close. Lost ticks are not backfilled. The --keep-awake flag on autopilot start blocks idle sleep with a short caffeinate -i lease that every tick renews, so the block lives exactly as long as autopilot ticks and expires on its own if the daemon stops.
Each new day, autopilot must be re-started manually. This is intentional — it forces a calibration gate.
Config style
- Personal voice files (
voice-profile.personal.md,voice-corpus.md,voice-receipts.md,good-drafts.md) are gitignored;.exampleversions are checked in as templates. .envholds X session cookies. Never commit..env.exampleshows shape.- All numeric thresholds live in
config/settings.yml. Don't hardcode in Python.
Code conventions
- Python 3.10+, no type-checker enforced but type hints are used throughout
scripts/lib/. - Structured logging via
scripts.lib.log— JSON one-liners tologs/*.errfor grepability. - Subcommands print one-line human summary to stdout for the skill wrapper to surface in chat. Don't add multi-line UX without checking SKILL.md's "After completion" section.
- Exit codes:
0success,1user error,2safety halt (skill wrapper treats this specially). - No emojis in code or commits unless the user explicitly asks.
What NOT to do
- Don't add features to the drafter prompt. The prompt is intentionally ~100 lines.
- Don't add "the user dislikes X" instructions anywhere — that's a lint rule.
- Don't lower
voice_match_thresholdor any cooldown to ship more drafts. - Don't create new templates, registers, or shape steers without a flagged draft justifying it.
- Don't restore anything from
references/_archive/— those are pre-rebuild legacy files. - Don't push without running
verifyfirst if you touchedsafety.py,voice.py, or the voice files.
When in doubt
Read SKILL_DISCIPLINE.md end-to-end before adding any rule, prompt change, or new file in scripts/lib/. It exists because the previous iteration of this skill regressed into a 600-line slop machine, and the rebuild is one careless commit away from doing it again.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

