rp-sdk Skill Reference
The
researcher-profilespackage (CLI:rp) reads, validates, indexes, serves, and publishes researcher profiles: self-contained directories of JSON-LD and Markdown describing one researcher. A profile is a folder, so there is no database to provision and no build step to run. This page is the agent-facing quick reference; every claim here links to the page that documents it fully.
Documentation links: links below point to relative
.mdfiles (e.g.reference/cli.md) within this docs tree. Every page on this docs site is also available as raw Markdown; append.mdto any docs URL.
Install
Section titled “Install”Install from a checkout (see the SDK overview). The extras
this page uses are vectors,st for the embedding index, api for the FastAPI
server, client for the HTTP storage backends, sql for the profile store,
and llm for the persona methods.
Python 3.12+. Core depends only on pydantic, pyyaml, and
scholarcore. A plain
import researcher_profiles never pulls in a vector store, an HTTP client, or a
model runtime: install the extra for the job. Full matrix in the
Python API reference.
What a profile is
Section titled “What a profile is”A profile is a directory whose one mandatory entry point is profile.jsonld,
a manifest that identifies the researcher and lists every artifact as a typed
link.
Everything else (persona documents, a works list, per-paper summaries, an
embedding index) is discovered through that manifest, never guessed from a
filename.
jane-doe/ profile.jsonld # identity + manifest (required) personality/SOUL.md # voice personality/expertise.md # what they work on sources/papers.jsonld # works list (required; may be an empty Collection) sources/summaries/*.summary.md # one summary per paper .cache/embeddings.sqlite # the search index (generated)A profile’s identity is its rid: a checksum-validated ORCID, or a
local:<slug>-<hex> id for a researcher with no ORCID. The directory name is a
display slug and carries no authority. Read
the profile format
before writing one, and the
specification
before implementing a consumer.
Load and inspect a profile
Section titled “Load and inspect a profile”from researcher_profiles import ResearcherProfile
p = ResearcherProfile.from_files("profiles/jane-doe")p.name, p.rid, p.level # level is "lite" | "full" | "deep"p.papers # the works listp.soul, p.expertise # persona documentsp.summaries["doe2019methods"] # one paper summaryfrom_files(..., eager=True) validates every artifact up front instead of
lazily; that is the schema-level validation check. Walkthrough:
Getting started.
Validate
Section titled “Validate”rp validate profiles/jane-doe # exits 4 on a conformance violationrp validate profiles/jane-doe --json # machine-readable reportrp manifest profiles/jane-doe --check # exits 4 when the manifest drifted from diskTo validate without installing anything, use the JSON Schemas in schemas/
directly. See
Validate a profile
and the schema reference.
Index and search
Section titled “Index and search”rp index profiles/jane-doe # build .cache/embeddings.sqliterp index profiles/jane-doe --force # rebuild from scratchrp search profiles/jane-doe "chromatin accessibility" -k 5rp search profiles/jane-doe "methods" --type expertiseRequires [vectors,st]. Hits come back ranked by cosine similarity with their
source, section, and a text preview. Details:
Build and search the embeddings index.
Serve profiles over HTTP
Section titled “Serve profiles over HTTP”export RESEARCHER_PROFILES_ROOT=/path/to/profilesexport RESEARCHER_PROFILES_TOKEN="a-long-random-string" # omit to run openpython -m researcher_profiles.apicurl http://127.0.0.1:8109/healthcurl -H "Authorization: Bearer $RESEARCHER_PROFILES_TOKEN" \ http://127.0.0.1:8109/api/v1/profilescurl -X POST -H "Authorization: Bearer $RESEARCHER_PROFILES_TOKEN" \ -H "Content-Type: application/json" \ -d '{"query": "region set enrichment analysis", "k": 5}' \ http://127.0.0.1:8109/api/v1/match/match ranks every indexed profile against a free-text query and returns
ranked_profiles and total_profiles alongside the matches, so you can tell a
narrow result from a broken embedding path. /health answers 503
with status: "degraded" when the host has flagged the embedding backend as
unusable; check it before trusting an empty match list. Every endpoint, field,
and environment variable:
HTTP API reference
and
Serve a profile API.
To read from a server instead of running one, see Access profiles over HTTP.
Talk to a profile
Section titled “Talk to a profile”With [llm] installed and ANTHROPIC_API_KEY set:
resp = p.persona.ask("What is your approach to region-set analysis?", k=5)resp = p.persona.review(material, focus="abstract")resp = p.persona.innovate("single-cell epigenomics")resp = p.persona.riff("what if enrichment were computed on the fly?")Answers are grounded in the profile’s own corpus; with strict_corpus=True the
call refuses rather than inventing when nothing relevant is retrieved. The same
four verbs are exposed as API endpoints. See
Use the persona methods.
To consult a published profile with no package
at all, read the consumer skill a published site serves at
<site base URL>/skills/researcher-profile/SKILL.md and follow it. It teaches
progressive reading: manifest first, persona
documents next, paper summaries on demand. Most questions are then answered from
~30 KB instead of the full bundle.
Store profiles in a database
Section titled “Store profiles in a database”export RESEARCHER_PROFILES_DATABASE_URL="postgresql://user@host/db"rp db initrp db push --all --include-binary # --include-binary carries the search indexrp db listrp db pull jane-doe --to ./pulled # reproduces the directory byte for byteThe store is a peer backend. Pick one backend per
deployment. There is no default URL; a command with no URL exits 2.
See Store profiles in a database.
Publish and push
Section titled “Publish and push”rp render profiles/jane-doe --base-url https://example.org # index.html, in placerp site profiles --out ./site --base-url https://example.org # collection filesrp push profiles/jane-doe --url http://localhost:8109 # upload to a serverrender writes into the profile folder; there is no separate output tree,
because a profile is publishable as it stands. It also refreshes
.publishignore, the list of non-public artifacts a plain sync must not copy.
site writes the
collection-level files for a set of profiles. Deployment is then an rsync.
See How to host a profile
and the static API
for the normative CORS and content-type requirements.
Export for a knowledge base
Section titled “Export for a knowledge base”rp export profiles/jane-doe # one deterministic text blobrp export profiles/jane-doe --json # the full bundle + content hashTwo runs over an unchanged directory produce byte-identical output, so a
knowledge base can upsert only when content_hash changes. Exit 4 means the
profile’s visibility is above public and --allow-nonpublic was not given.
Privacy tiers
Section titled “Privacy tiers”Every artifact carries a visibility of public, internal, or restricted,
and a served response is projected through the caller’s tier. Never assume an
absent field means “no data”; it may mean “not visible to you”. The rules are
normative and short:
Privacy.
Related skills
Section titled “Related skills”The repository also ships task-specific skills, each a SKILL.md you can read
the same way:
| Skill | Use it when |
|---|---|
researcher_profiles/skill/SKILL.md | Reading and answering questions from a published profile (rp skill --install) |
skills/publish-profile/SKILL.md | Publishing profiles as a static site on Cloudflare, S3, nginx, or GitHub Pages |
skills/profile-agent/SKILL.md | Acting as a researcher’s agent with a scoped rpa_ key |
Where to look next
Section titled “Where to look next”| Question | Page |
|---|---|
| Every subcommand and flag | CLI reference |
| Every endpoint and wire model | HTTP API reference |
| Classes, methods, exceptions | Python API reference |
| What a conforming profile must contain | Specification |
| The shared Person / Paper / Award vocabulary | scholarcore |