livetie
Three-stage pipeline. You (Claude) perform Stages 2 and 3 directly using
Read/Write — there is no separate LLM SDK. One thin Python command (livetie fetch)
handles Stage 1 data acquisition.
Required credentials
TIKHUB_API_KEY— required (X data source). Production runs need paid TikHub balance: thefetch_user_profileendpoint does not accept free-tier credit, so any run with bridge probing requires a topped-up account (~$5 covers a typical 3-hop run). Runlivetie initin the user's terminal for guided setup.
LinkedIn has no paid integration in this version. Stage 2 fetches the
public-preview page via WebFetch (free; headline + current company +
location only). The previously recommended Proxycurl service shut down
in 2026 — for deeper career history, see candidate replacement vendors
in the apify-migration-experiment branch
(docs/li-providers-research-2026-05-09.md).
Language / i18n
The skill produces reports in either Chinese (zh) or English (en).
Auto-detection (default): --lang auto (the default) detects the language from
the data. It concatenates both subjects' bios + the first 200 characters of each
subject's posts, then counts CJK characters (U+4E00–U+9FFF). If ≥ 25 % of
characters are CJK the run is tagged zh; otherwise en. The detected value is
saved to raw/lang.json so Stage 3 uses the same choice.
Override: pass --lang zh or --lang en to either subcommand to force a
specific language regardless of data content.
Effect on Stage 2: read raw/lang.json to learn which language to use, then
read prompts/<lang>/<name>.md instead of a root-level prompts/<name>.md.
For example, for a Chinese run use prompts/zh/timeline_extract.md; for an
English run use prompts/en/timeline_extract.md.
Stage 1 — Fetch (Python)
Step 0 — Verify setup
Before calling livetie fetch, run livetie check. If exit code is 1
(BLOCKED), stop and tell the user to run livetie init in their
terminal — don't try to run fetch with missing credentials.
livetie check # exit 0 = READY, exit 1 = BLOCKED (needs livetie init)
If BLOCKED, tell the user:
Your TikHub API key is not configured. Run
livetie initin your terminal — it will walk you through signing up and validating your key (~2 minutes).
livetie fetch --you <x_url> --target <x_url> \
[--you-li <li_url>] [--target-li <li_url>] \
[--quick] [--lang {zh,en,auto}] [--output ./output] \
[--max-hops 1..6] [--probe-budget N]
--max-hops— cap the path search depth (1-6, default 3 or whateverrelation_calculator.default_max_hopsis set to in services.yaml). Most useful values:2(direct mutual contacts only, fast),3(default, finds non-obvious bridges),4+(combinatorial explosion, often noise — see init flow's cost guidance).--probe-budget— maximum TikHub search calls during candidate probing (default 600). The orchestrator now ties layer-1 candidate width to this budget (max(50, budget // 2)), so raising the budget actually reaches deeper into the followings graph. Lower values speed up Stage 1 at the cost of fewer candidates explored.
This writes a run directory at output/<YYYYMMDD>-<you>-vs-<target>/ with:
raw/ profiles, followings, candidates, edges, bridges_meta, lang.json
li_urls.json ← manual LI URLs for Stage 2 WebFetch
(no _career.json from Stage 1 — LinkedIn fetch happens in Stage 2)
solved/ real_paths_2hop.json, real_paths_3hop.json, real_paths.json (combined), weak_paths.json
evidence_pool/ you.jsonl, target.jsonl ← input for Stage 2
extracted/ EMPTY — Stage 2 fills this
Print the run directory path.
Stage 2 — Web research + extraction (Claude does this directly)
First, read raw/lang.json to learn the language for this run (zh or en).
Then use prompts/<lang>/ for all prompts below.
Step 0 — Web research
Run this for each subject (you, target) before any extraction step.
It enriches the evidence pool so all downstream extractions have richer data.
0a. LinkedIn URL discovery
Read raw/li_urls.json. If a URL is present for this subject (user passed
--you-li / --target-li), use it. Otherwise:
- Use the WebSearch tool:
"<subject_full_name>" linkedin profile - Pick the first result with a
linkedin.com/in/<slug>URL. - If found, write
raw/<subject>_li_url.txtcontaining the URL. - If none found, write
raw/<subject>_li_url.txtcontaining the stringnulland skip the LinkedIn fetch.
0b. LinkedIn fetch (WebFetch on public preview)
This is the only LinkedIn data path in this version (Proxycurl shut down in 2026). If a LI URL is known from step 0a:
-
Use the WebFetch tool with the LI URL and this prompt:
Extract from this LinkedIn profile public preview (do not require login). Return STRICT JSON with these keys, using null when unknown: full_name, headline, current_company, current_title, location, jobs (list of {company, title, start_year, end_year}), education (list of {school, degree, field, start_year, end_year}). Use only what's actually visible on the public preview; do not fabricate. Return ONLY the JSON object.
-
Map the WebFetch result to the career shape (same keys as above) and add
_source: "li_webfetch"plus a_confidencelabel:"medium"when bothjobsandeducationare populated;"low"when only one is present;"none"when neither is available. -
Save to
raw/<subject>_career.json. -
If the fetch returned nothing useful, write
{"_source": "li_webfetch", "_confidence": "none", "found": false}.
0c. Wikipedia fetch (always-on)
For each subject, regardless of whether LinkedIn data exists:
-
WebSearch:
"<subject_full_name>" wikipedia -
If a
en.wikipedia.org/wiki/<slug>URL appears in the top 3 results, WebFetch it with the prompt:Extract from this Wikipedia article: birth year + place, education milestones (school, year), key career milestones (event, year, organization), notable public events. Return as a JSON object with a
paragraphsarray, each entry with{year, fact, source_section}. -
Append each paragraph to
evidence_pool/<subject>.jsonlaswiki_paragraph#Nentries (continue numbering from existing entries).
0d. Interview / podcast / long-form (only if NOT --quick)
Use livetie.adapters.web_research.WebResearchPlanner.plan() output
(saved to raw/web_research_plan.json if Stage 1 wrote it; otherwise
generate it inline by importing the planner). Execute up to 4 search queries
per subject + 1 joint query, take the top 2 hits each, fetch them with
WebFetch, append snippets to evidence_pool as interview_quote#N /
blog_excerpt#N.
Step 1-N — Extraction (existing flow, now with richer evidence_pool)
After Step 0 has populated the evidence_pool, read raw/lang.json and
follow these prompts. Each extraction now benefits from LI career data and
Wikipedia paragraphs added in Step 0.
For each subject (you, target), Read its evidence_pool/<subject>.jsonl
and follow these prompts to produce JSON files in extracted/:
| Output file | Prompt to follow |
|---|---|
extracted/you_timeline.json | prompts/<lang>/timeline_extract.md |
extracted/target_timeline.json | prompts/<lang>/timeline_extract.md |
extracted/you_interests.json | prompts/<lang>/interests_extract.md |
extracted/target_interests.json | prompts/<lang>/interests_extract.md |
extracted/you_stances.json | prompts/<lang>/stance_extract.md |
extracted/target_stances.json | prompts/<lang>/stance_extract.md |
extracted/cross_experience.json | prompts/<lang>/cross_experience_extract.md (reads raw/{you,target}_career.json + evidence_pool/*.jsonl) |
Then cross-pair: