Imported from moeghashim/tenbrains-arch (
skill/SKILL.md). Install upstream withnpx skills add moeghashim/tenbrains-arch --skill skill. Copyright stays with the author.
tenbrains — agent-first X and YouTube research CLI
tenbrains analyzes X/Twitter content and YouTube transcripts with an AI provider and stores every
outcome (posts, analyses, account takeaways, bookmarks, suggestions, learning tracks and materials, objectives)
in a local SQLite database.
It is built to be driven by an agent: each run prints one JSON object you can parse directly.
Prerequisites
- The
tenbrainscommand must be available. Iftenbrains --versionfails, it is a Node CLI (Node >= 24). Install it withnpm i -g tenbrains(published on npm), or runnpm linkinside a clone of the project. As a fallback you can call the built entrypoint directly:node <repo>/dist/bin/tenbrains.js. - A provider for real analysis. Configure a key once (stored in
~/.config/tenbrains/config.jsonat mode 0600, never an env file):tenbrains setup --provider anthropic --api-key sk-ant-.... No key available? Add--provider mockto any analyzing or materializing command for deterministic, offline output — perfect for exercising the flow without network or credentials. - Optional X (Twitter) Bearer token. Only needed to fetch timelines for
takeaway(usually a paid X API tier). Fetching a single tweet foranalyze --urlis free via oEmbed and needs no token. Store one withtenbrains setup --x-bearer <token>ortenbrains config set x.bearerToken <token>.
Output contract — read this first
Every run prints exactly one JSON object on stdout:
- Success:
{ "ok": true, "command": "...", "data": { ... }, "meta": { ... } } - Failure:
{ "ok": false, "command": "...", "error": { "code", "message", "retryable", "details" } }
Parse stdout; diagnostics and progress go to stderr. Branch on ok, then on error.code (never
on message text). The process exit code mirrors the failure class (0 ok, 2 usage, 3 not
found, 4 credentials, 5 provider, 6 validation, 7 conflict, 1 internal).
JSON is the default. Only add --pretty when a human will read the output. meta carries the ids you
chain on: analysisId, postId, snapshotId, bookmarkId, suggestionId, trackId.
Objective creation also returns objectiveId and its stable slug.
The complete envelope, code tables, command catalog, and input forms are in
references/cli-contract.md. For the always-current machine spec, run
tenbrains manifest — it returns the full command tree, flags, providers, and codes as JSON, so
prefer it over guessing.
Inputs
Text/JSON flags accept three forms, so you never fight shell quoting on large content:
- inline:
--text "the post" - a file:
--text @post.txt/--posts @recent.json - stdin:
--text -(pipe content in)
Local web workspace
Serve the local browser workspace with the same database and command handlers as the CLI:
tenbrains serve # http://127.0.0.1:4571; opens the page
tenbrains serve --port 5000 --db ./research.db
tenbrains serve --no-open
serve is localhost-only by default. Each process creates a fresh session token, injects it into
the page, and requires X-Tenbrains-Session on every /api/* request. Its initial API surface is
GET /api/manifest, POST /api/command ({ command, opts }), POST /api/import/x-archive, and
GET /api/events for progress. The import route accepts extracted archive data as JSON
{ files: [{ name, content }], bookmarks?: boolean, limit?: number }; upload like.js,
like-partN.js, tweets.js, tweet.js, and/or account.js (part variants work), after unzipping
the X export. bookmarks: false matches --no-bookmarks; limit is a non-negative per-kind cap.
It returns the normal import x-archive envelope, shares the CLI's idempotent ingest behavior, and
has a 25 MiB total-body cap (VALIDATION / HTTP 400 when exceeded). JSON avoids adding multipart
parsing dependencies, but means the client keeps file contents in memory. Responses are the normal
JSON envelopes, so UI and agent callers branch on ok then error.code. Config reads remain
redacted over the API. Do not bind it beyond loopback unless you understand that any reachable client
can use the session.
The built page is a dependency-free TypeScript SPA for the full local workspace: Today’s daily loop,
Capture and extracted X-archive import, objective creation/detail/focus rollups, suggestions triage,
full-text Search with record hops, markdown Digest windows, and followed-account takeaways. Objective
mode, lesson, and quiz affordances are feature-detected from the manifest. With learn quiz and
learn answer available, Today renders the lesson, per-question state, free-text answers, and
verdict feedback without making quizzes a day-completion gate. Account refresh accepts
supplied post JSON in the page or fetches an X timeline when a bearer token is configured.
Core workflows
Analyze a post
Provide the text, or let the CLI fetch a tweet by URL/id (free, via X's oEmbed — no key needed):
tenbrains analyze --author levelsio --id 1790000000000000000 --text "..." # you supply text
tenbrains analyze --url "https://x.com/jack/status/20" # fetched free (oEmbed)
# data.analysis = { topic, summary, intent, novelConcepts[5] }; meta.analysisId, meta.postId, meta.source
--fetch auto|oembed|api controls fetching (default auto, free-first). Re-using the same --id
dedupes the stored post. Add --learn to also generate a 7-day Feynman learning track in the same
call (--minutes, --ratings optional). If the track has a learn-mode objective, it also
materializes grounded lessons and quizzes unless --no-materialize is supplied.
Analyze a YouTube video
Public captioned videos need no API key. --summarize and --learn can be used independently or
together. If captions are unavailable, use the manual transcript fallback:
tenbrains analyze --url "https://youtu.be/M7lc1UVf-VE" --lang en --summarize --learn
tenbrains analyze --url "https://youtu.be/M7lc1UVf-VE" --transcript @captions.txt
The result includes the usual data.analysis, optional data.summary = { summary, keyPoints[] },
and optional data.track; meta.source is youtube. Do not add audio download or transcription
steps: this release is caption-only.
Account takeaways
Supply the recent posts, or fetch them from X (needs a stored Bearer token and usually a paid X API
tier — single-tweet analyze above stays free).
tenbrains takeaway follow levelsio
tenbrains takeaway refresh levelsio --posts @recent.json # supplied: [{ "text": "...", "externalId": "..." }, ...]
tenbrains takeaway refresh levelsio --count 20 # fetched from X (omit --posts)
tenbrains takeaway show levelsio --history
Suggestions feedback loop
tenbrains suggest generate # saved-signal ranking + current-focus description bias
tenbrains suggest save sug_... # materializes the suggestion as a bookmark
tenbrains suggest dismiss sug_... # suppresses it in future ranking
Daily learning loop
A track generated with --learn (or learn generate) is a 7-day plan you can coach the user
through, one session at a time. Learn-mode objective tracks materialize a lesson and three to five
quiz questions per day in one batched provider call:
tenbrains learn today # next pending day's task (latest active track)
tenbrains learn quiz trk_... # questions + latest status; expected answers stay hidden
tenbrains learn answer trk_... --q 1 --answer "..." --provider mock
tenbrains learn done trk_... --notes "..." # check it off; meta.completed=true on the last day
tenbrains learn materialize trk_... --provider mock # generate later or retry
tenbrains learn materialize trk_... --day 3 --provider mock # regenerate one day
learn today never skips content — it returns the first unfinished day, plus behindBy when the
calendar has moved ahead of the learner. When material is present it returns and prints the lesson
plus a quiz-question count, never the expected answers. --no-materialize preserves the ordinary
track; a failed provider generation also leaves the track available to retry with learn materialize.
learn quiz defaults to that same next pending day (or accepts --day N) and exposes questions
with latest-attempt status only. learn answer accepts inline text, @path, or -, appends every
attempt, and returns one-line verdict feedback; re-answering is allowed and only the latest attempt
stands in quiz status and objective rollups. Quizzes never gate learn done. The mock grader is
offline and deterministic: it requires at least half of an expected answer's unique content tokens,
rounded up with a minimum of one.
Learning objectives
Objectives are first-class learning goals, separate from bookmark tags. Each is learn (the default)
or follow; multiple objectives may be active, with at most one current focus. Focus is only a
default view and never tags content:
tenbrains objective add "Stablecoins" --description "Understand reserves and settlement." --mode learn --focus
tenbrains objective add "AI agents scene" --mode follow
tenbrains objective list
tenbrains objective show # current focus
tenbrains objective focus ai-agents-scene # switch explicitly
tenbrains objective focus --clear
tenbrains objective link post_... --objective stablecoins
tenbrains objective unlink post_... --objective stablecoins
tenbrains objective archive stablecoins
tenbrains objective refresh ai-agents-scene
tenbrains objective mode ai-agents-scene learn
Use the returned obj_... id or slug for later calls. Tag new outcomes explicitly with repeatable
--objective <slug> on analyze, takeaway follow, bookmark add, or learn generate.
bookmark add tags its post, not the bookmark record. learn generate inherits objective tags from
its analysis' source post only when no explicit objective is supplied; explicit values override the
inheritance. The referenced objectives must already exist (NOT_FOUND otherwise). Never infer,
auto-create, or copy the current focus into tags.
Tracks with one or more learn-mode objective tags materialize by default. Their provider prompt is
grounded in the source post/analysis and up to ten other analyzed posts tagged to those objectives.
learn materialize <trackId> [--day N] works for every track, including follow-mode auto-tracks.
Track reads (learn show, record get) carry persisted material and latest quizAttempts entries
alongside progress.
Modes never alter focus or tagging. objective refresh <slug> [--force] [--limit N] is valid only
for follow objectives (CONFLICT otherwise). It collects new analyzed posts tagged directly to the
objective or authored by its tagged accounts, with no X API call. Its deterministic local weight is
3·bookmarked + 2·min(authorTakeaways,5) + min(authorPostCount,10). A refresh needs three new posts
unless forced, pools concepts in weight → description-relevance → original order, creates one track,
and links it to the objective. Auto-tracks persist their consumed source post ids in
learning_tracks.source_post_ids_json, so repeating refresh does not rebuild the same track.
An objective with a description lenses its learning tracks deterministically: concepts with more
description-token overlap come first, with interest/familiarity ratings breaking ties. For multiple
described objectives, use the maximum overlap against any one description rather than summing
matches across objectives. Inspect objective show <slug> for grouped records and raw
data.progress counts covering accounts, analyzed posts/transcripts, saved bookmarks, tracks
completed, learning days completed/total, quiz questions answered, and quiz answers correct. Do not
turn those counts into a made-up percentage.
suggest generate deterministically biases its existing interest score toward token overlap with
the current focus description. No focus or no usable description preserves the ordinary ranking,
and focus never adds tags. Scope recall and recaps explicitly when needed:
tenbrains search "reserve risk" --objective stablecoins
tenbrains digest --objective stablecoins
Both filters require an existing objective (NOT_FOUND otherwise). They include analyses through
tagged posts, takeaways through tagged accounts, and bookmarks tagged directly or through their
posts.
Bookmarks and recall
tenbrains bookmark add --post-id post_... [--tags rag,agents] # auto-tags from the analysis if omitted
tenbrains search "vector databases" --type analysis,bookmark
tenbrains search "reserve risk" --objective stablecoins
Bulk-import the user's X history (free)
If the user has their official X account archive (Settings → "Download an archive of your data",
then extract the zip), import it in one shot — likes become bookmarked posts, which immediately
powers suggest generate:
tenbrains import x-archive ~/Downloads/twitter-archive
Read anything back
tenbrains analyze list --limit 5
tenbrains record get <id> # resolves any post_/ana_/acc_/snap_/bm_/sug_/trk_/obj_ id
tenbrains db stats # row counts + schema version
Conventions worth remembering
- Ids are prefixed and stable (
post_,ana_,acc_,snap_,bm_,sug_,trk_,obj_); chain on the ids inmeta, and resolve any of them withtenbrains record get <id>. - Isolate a workspace with
--db ./scratch.dbso a task doesn't touch the default database. - No environment variables are read for config or secrets — everything goes through
tenbrains setup/tenbrains config set. - The
mockprovider is deterministic keyword extraction, not real model judgement. It also deterministically templates grounded lessons/quizzes and grades at a 50% expected-token overlap threshold. Use it to test the data flow; use a configured provider (anthropicdefault, plusopenai/google/xai) for real analysis.
When this skill does not apply
Posting, replying, or DMing on X, and unrelated research outside X or YouTube. For those, use the appropriate tool instead.