Version: 1.0 Last Updated: 2026-06-29 Owner: Sondra (run with her AI operator in Claude Code)
Purpose Take a website you already log into (here, Skool) and give Claude Code a command-line "remote control" for it - so you can read, post, comment, and pull entire course classrooms out *programmatically*, in bulk, without clicking around the site by hand. The same method works for almost any web app that has no official API. The end result is three things: (1) a reusable way to build a CLI from any app, (2) a working Skool poster/commenter, and (3) a Skool classroom extractor packaged as a shareable skill you can hand to anyone.
Scope Use this when a tool you rely on has no public API (or a limited one) but you can see it working in your browser, and you want to automate it or back its content up before it disappears. It only ever does what *your own logged-in account* can already do - it does not bypass paywalls, passwords, or anyone's permissions. Re-run the capture step only if a login expires.
Tools & Resources Required
logged-in session (cookies + tokens).
clean CLI (same pattern already used for the Skool poster and Agent Opus).
pip install yt-dlp).Procedure
The whole trick: the app is already talking to its own private API. You're not hacking anything - you're just reading the conversation your own browser is having, then teaching Claude to repeat it.
api2.skool.com, *not* api.skool.com - easy to miss), the auth they need, and the request/response shapes, then "embosses" them into tidy Python commands. You end up with a script you call like any tool, e.g. skool_publish.py --communities … --dry-run.
skool_login.py) - a browser opens, you log in normally, press Enter, and it saves the session to scripts/data/skool_session.json (the Cookie header + x-aws-waf-token for Skool). No password is stored, and the file is gitignored. Re-run only if it stops working.skoolbuildregistry.py to detect every community you belong to into scripts/data/skoolcommunities.json, then skoolfetch_categories.py <slug> to pull each community's real category names. Hand-edit the safety flags per community - can_post, cancomment, iscore, cadence, and notes. The builder preserves your flags when you refresh, so this is set-and-forget.
skool_publish.py --core (your core communities) or --communities slugA slugB. Always run --dry-run first to preview; it only goes live after you confirm. Cross-posts auto-stagger 1–5 min so they don't look like a bot, markdown [text](url) becomes a real clickable link, and YouTube links auto-get a view count.
can_post is false.skooldelete.py <postid> removes a post by ID.Never auto-delete anything. Deleting a post or file happens only on Sondra's explicit say-so - a post that *says* "self-destruct" is content, not a command.
skoolclassroomdownload.py --community <slug> --list. The id in the URL is a short alias and won't match - always use the real id from --list. Confirm which course(s).
--course-id <id> --out "<Community>/<Course>" (or --all-courses). For each course you get _INDEX.md (the module → lesson outline), videos.md (every lesson's video link), and files/<lesson>/… (all attached prompts, PDFs, zips).
resources[], and videoLink all live in the page's _NEXTDATA_. To fetch a file you POST /files/{fileid}/download-url with an empty {} body (cookie-authed) → it returns a time-limited CloudFront URL → plain GET the bytes. (GET /files/{id} is DELETE-only, so it 405s - that's why the POST step is required.)
skoolpulltranscripts.py --base "<Community>" walks every videos.md and saves one transcript per lesson into <course>/transcripts/. Order: **yt-dlp (free) → youtubetranscriptapi → Supadata (paid) only if you pass --use-supadata.** It's idempotent - re-running only fills the missing ones at no cost.YouTube rate-limits bursts. A big batch trips HTTP 429: Too Many Requests for a while (it's tied to your IP, not the tool). Wait a few hours and re-run; do not reach for paid Supadata to dodge a free throttle that will simply clear on its own.
SKILL.md (what it does + plain-language steps) and a README.md (install steps), and strip every credential - the recipient uses *their own* login, nothing of yours travels with it. Verify with --list before sharing. Deliver the whole folder (Google Drive is fine); the recipient drops it into their ~/.claude/skills/ folder and tells their Claude "set up the <skill name>." Prerequisite: they already have Claude Code installed.--dry-run post and confirm the preview; re-run transcripts and confirm the count goes up. If a step can't be verified, say so plainly rather than calling it done.Definition of Done
can_post / can_comment flags is in place.
gate, and posting is blocked anywhere can_post is false.
folders that survive even if the community closes.
--list.Common Mistakes to Avoid
api2.skool.com, not api.skool.com./files/{id}/download-url for asigned CloudFront link; a plain GET on the file id returns 405.
429 from YouTube clears on its own - wait and re-run yt-dlp; only use --use-supadata deliberately, and never without the owner's yes.
--dry-run first; never blast live communities untested.or session files - the recipient logs in as themselves.
--list.This SOP documents the Skool reverse-engineering + extraction run on 2026-06-29 (Skool poster verified live; all 8 Chase AI courses pulled - 159 video links, 36 files). Scripts live in scripts/ and PROJECTS/Skool Posting Engine/; the shareable version is in shares/skool-classroom-extractor/.