X knowledge agent
It turns the posts you saved on X into short knowledge recipes.
Personal use: it reads your own account, through your own session, in read-only mode.
What it is
It turns the posts you saved (bookmarks) on X into short knowledge recipes. Personal use: it reads your own account, through your own session, in read-only mode.
No password and no paid API: the agent never logs in, it uses the session you already have open in the browser. Each step is idempotent: a post already seen is not collected again and a recipe already written does not call the LLM again.
How it works
Flow of the X knowledge agent
- Saved posts on X: the bookmarks of your account.
- Collection (
coletar): headless browser, your session cookies, one collection per day, read-only. It writes<saida>/AAAA-MM-DD.jsonlandvistos.json(ids already collected); it writesERROif the session drops. - Extraction (
extrair): the post becomes data inside a block with a random delimiter; the LLM (claude -p) runs with no tools, no MCP servers and no user settings. - Recipe: validated (frontmatter, size, no URL outside the post links, no dangerous command). With
destino = "biblioteca"it goes to<saida>/receitas/<tema>/<id>-<titulo>.md(statuscurta); with"issue", to<saida>/issues/<id>-<titulo>.md. - Use: the recipe enters the reference library, or becomes issue text, and is applied to real work.
Install
Get the package: it is the hub/x_salvos/ module of the Krohnos repository (https://github.com/BRK13/krohnos). Clone it and run every command on this page from its root:
git clone https://github.com/BRK13/krohnos.git
cd krohnos- Python 3.11 or newer and an installed Chrome or Chromium.
- Only
playwright; the browser is the system one, pointed to by thechromekey: - For
extrair: theclaudeCLI installed and signed in (it runs asclaude -p --tools "" --strict-mcp-config --setting-sources "": text only, no tools, no MCP servers, no user or project settings or hooks), or your ownexecutar_llm(prompt)function if you call the module from Python.
pip install playwrightExport the cookies (next section) and create the x_salvos.toml (Configuration section). Test by hand, first the collection and then the extraction:
python3 -m hub.x_salvos coletar --config x_salvos.toml
python3 -m hub.x_salvos extrair --config x_salvos.tomlTo run every day, schedule this in the system cron (--jitter waits 0 to jitter_max_s before starting; by hand, run without it):
python3 -m hub.x_salvos coletar --jitter --config x_salvos.tomlThe commands are the ones in the module README, hub/x_salvos/README.md.
How to export the cookies
The agent never logs in: it uses the session you already have open in the browser. The session is yours, the password never enters, and there is no paid API.
- Sign in to X in the browser, with your own account.
- With a cookie-export extension, or through DevTools (Application, Cookies,
https://x.com), copy only the value ofauth_token,ct0andtwid. - Save a JSON with just those three keys:
{"auth_token": "...", "ct0": "...", "twid": "..."}chmod 600on the file. A more open file is fixed and reported, and the value never appears in the log.- A file with a password, username or any login credential is refused.
chmod 600 ~/.config/x-salvos/cookies.jsonWhen the session expires, the collection writes ERRO in the output folder and stops (exit code 2): export new cookies.
Configuration
File x_salvos.toml. Precedence: defaults, then file, then environment variables. An unknown key is an error. All the keys:
cookies = "~/.config/x-salvos/cookies.json" # JSON with auth_token, ct0, twid (chmod 600)
cookies_origem = "" # optional: file or folder where the cookies arrive from another machine
saida = "~/x-salvos" # jsonl, vistos.json, ERRO and recipes
temas = ["seo", "automacao"] # optional: a recipe outside the themes is flagged, never discarded
destino = "biblioteca" # "biblioteca" or "issue"
max_itens = 150 # items per run (maximum 500)
max_paginas = 40 # scrolls per run
limite_taxa_s = 1.5 # minimum interval between navigations, in seconds
jitter_max_s = 1200 # with --jitter: waits 0 to this value before starting
chrome = "/usr/bin/google-chrome"
trava = "~/x-salvos/.trava" # flock file against two collections; default <saida>/.trava| Key | What it does |
|---|---|
cookies | JSON with auth_token, ct0, twid (chmod 600) |
cookies_origem | Optional: file or folder where the cookies arrive from another machine (in a folder: the same file name as cookies, or x-cookies.json) |
saida | Output folder: jsonl, vistos.json, ERRO and recipes |
temas | Optional: a recipe outside the themes is flagged, never discarded |
destino | "biblioteca" writes to <saida>/receitas/<tema>/<id>-<titulo>.md (status curta); "issue" writes to <saida>/issues/<id>-<titulo>.md |
max_itens | Limit: items per run, maximum 500 |
max_paginas | Limit: scrolls per run |
limite_taxa_s | Limit: minimum interval between navigations, in seconds |
jitter_max_s | With --jitter: waits 0 to this value before starting |
chrome | Path of the system Chrome or Chromium |
trava | Lock file against two collections at once; default <saida>/.trava |
Environment variables:
KROHNOS_X_SALVOS_CONFIG, KROHNOS_X_SALVOS_COOKIES, KROHNOS_X_SALVOS_COOKIES_ORIGEM, KROHNOS_X_SALVOS_SAIDA, KROHNOS_X_SALVOS_TEMAS, KROHNOS_X_SALVOS_DESTINO, X_MAX_ITENS, KROHNOS_X_SALVOS_MAX_PAGINAS, KROHNOS_X_SALVOS_LIMITE_TAXA_S, KROHNOS_X_SALVOS_JITTER_MAX_S, KROHNOS_X_SALVOS_CHROME, KROHNOS_X_SALVOS_TRAVAThe 6 guardrails and the test that proves each one
All of them are in code (guardrails.py) and each one fails if the code is removed. The tests live in tests/test_x_salvos_guardrails.py, tests/test_x_salvos_extrair.py and tests/test_x_salvos_config.py.
| Guardrail | What it guarantees | Test that proves it |
|---|---|---|
| 1. Read-only | Write methods and write endpoints (even over GET) are aborted and logged without a body. The only click allowed is expanding replies; like, repost and follow are refused. An unreadable URL, encoding tricks or a subdomain open no gap: failure closes. The lock sits in the browser context, including in --refazer-fio. Service Workers are blocked, so nothing slips past the lock. | tests/test_x_salvos_guardrails.py: TestSomenteLeitura.test_metodos_de_escrita_bloqueados, test_endpoints_de_escrita_bloqueados_mesmo_em_get, test_instalar_aborta_escrita_e_registra_sem_corpo, test_clique_de_acao_recusado, test_url_ilegivel_aborta_fail_closed, test_brechas_de_codificacao_e_subdominio, test_abrir_instala_a_trava_no_contexto, test_refazer_fio_abre_pelo_abrir |
| 2. The session is yours | Only auth_token, ct0 and twid; a login credential is refused. There is no login flow and the collection never navigates to the login screen. Cookies arriving from another machine (cookies_origem) are copied only if newer, with chmod 600, with no value in the log. | tests/test_x_salvos_guardrails.py: TestSessaoDoUsuario.test_cookies_so_os_tres, test_rejeita_credencial_de_login, test_fonte_sem_fluxo_de_login, test_nao_navega_para_login, TestCookiesOrigem |
| 3. Rate limit, ceiling and stop if the session drops | Minimum interval between navigations (limite_taxa_s) and a ceiling on scrolls and items per run. If the session drops, the collection detects it from the URL, writes ERRO in the output folder and stops without retrying (exit code 2). | tests/test_x_salvos_guardrails.py: TestLimiteETeto.test_intervalo_minimo_entre_navegacoes, test_ir_respeita_a_taxa, test_teto_de_rolagens, test_teto_de_itens, test_sessao_caiu_por_url, TestParada |
| 4. Post content is data, not instruction | The post text sits inside a block with a random delimiter; a forged delimiter is neutralized. Extraction runs claude -p text-only: no tools, no MCP servers, no user or project settings, and without skipping permissions. The answer is validated: a dangerous command, a URL outside the post links, or an invalid format or size rejects that recipe and the rest goes on. | tests/test_x_salvos_extrair.py: TestPrompt, TestValidacao, TestDestino.test_resposta_perigosa_nao_grava_e_pipeline_segue, TestDestino.test_padrao_nao_usa_bypass |
| 5. Secrets | A cookie value is masked in every log and in the ERRO file. Cookies are written with chmod 600, atomically; a more open permission is fixed and reported, without showing the value. | tests/test_x_salvos_guardrails.py: TestSegredos.test_mascarar, test_log_nunca_mostra_valor, test_erro_gravado_vai_mascarado, test_gravar_cookies_600_atomico, test_permissao_mais_aberta_e_corrigida_sem_valor, test_ler_cookies_corrige_permissao |
| 6. Terms of use: personal use | Reads only your own saved posts; public search is outside this agent. No mass scraping and nothing written to X. At most 500 items per collection (also with --forcar, which is for the first load or a fix), one collection per day and one at a time. The notice is printed by --help and on the first run. Complying with the terms of use of X is the user's responsibility. | tests/test_x_salvos_guardrails.py: TestTermos.test_aviso_tem_o_essencial, test_ajuda_e_primeira_rodada_imprimem_aviso, test_teto_500, test_uma_coleta_por_dia, TestColetorPuro.test_trava_impede_segunda_coleta |
An invalid destination or ceiling is refused before collecting (tests/test_x_salvos_config.py). Run the proof:
python3 -m unittest tests.test_x_salvos_config tests.test_x_salvos_guardrails tests.test_x_salvos_extrairTerms notice
Warning: This tool reads only the saved posts of your own account, read-only; public search is outside this agent. No mass scraping: at most 500 items per collection and one collection per day (--forcar is for the first load or a fix and also respects the ceiling). Personal use. You are responsible for complying with the terms of use of X.