Skip to content
Back to skills

People Intel

ASecurity

This skill should be used when the user asks to 'research person', 'person intel', 'people intel', 'who is [person]', 'who created [project]', 'who maintains [package]', 'add person to knowledge graph', 'enrich person note', 'update person note', 'document [person]', 'create person note for [name]'. Researches a person using five-source enrichment (Basic Memory, Raindrop, Readwise, Tavily, DeepWiki) and creates/updates a structured Basic Memory person note with post-write cross-linking.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 26, 2026
researchgogitapisecuritydocumentation

Works with

  • api
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned May 27, 2026

npx -y skills add voxpelli/vp-claude --skill people-intel --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of People Intel?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for People Intel
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/voxpelli-people-intel/badge)](https://www.skillsdirectory.com/skills/voxpelli-people-intel)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: people-intel
description: "This skill should be used when the user asks to 'research person', 'person intel', 'people intel', 'who is [person]', 'who created [project]', 'who maintains [package]', 'add person to knowledge graph', 'enrich person note', 'update person note', 'document [person]', 'create person note for [name]'. Researches a person using five-source enrichment (Basic Memory, Raindrop, Readwise, Tavily, DeepWiki) and creates/updates a structured Basic Memory person note with post-write cross-linking."
user-invocable: true
argument-hint: "<Full Name>"
allowed-tools:
  - Read
  - mcp__basic-memory__search_notes
  - mcp__basic-memory__read_note
  - mcp__basic-memory__write_note
  - mcp__basic-memory__edit_note
  - mcp__basic-memory__build_context
  - mcp__deepwiki__ask_question
  - mcp__tavily__tavily_search
  - mcp__tavily__tavily_extract
  - mcp__raindrop__find_bookmarks
  - mcp__raindrop__fetch_bookmark_content
  - mcp__readwise__readwise_search_highlights
  - mcp__readwise__reader_search_documents
---

# People Intelligence

Research a person and synthesize a structured Basic Memory person note using
five enrichment sources, then cross-link existing notes.

## Arguments

One argument: the person's full name. No prefix required — person names are
unique identifiers in this graph.

| Form | Example |
|------|---------|
| `<Full Name>` | `Linus Torvalds` |
| `<Full Name>` | `Tim Berners-Lee` |
| `<Full Name>` | `Aaron Gustafson` |

If the argument contains ` - ` (the title separator), split into `name` and
`descriptor`. Otherwise treat the full argument as `name` and derive the
descriptor from research.

### Step 0: Normalize input

Strip leading/trailing whitespace. If the argument looks like a BM note title
(contains ` - `), split into name and descriptor. Otherwise treat the whole
argument as the person's name.

### Step 1: Check for existing note

<!-- This pattern is mirrored in package-intel and tool-intel — update all when changing -->

Search by name across person notes:
```
search_notes(query="<name>", note_types=["person"], page_size=5)
```

Also do a broad text search in case the note uses a different title format:
```
search_notes(query="<name>", search_type="text", page_size=10)
```

If a matching person note is found, read it:
```
read_note(identifier="<title>", include_frontmatter=true, output_format="json")
```

**Freshness check:** Scope research based on note age (check `updated_at`):

| Note age | Sources to run | Sources to skip |
|----------|---------------|-----------------|
| Missing or >180 days | All 5 (full pipeline) | None |
| 60–180 days | All except Raindrop | Raindrop |
| <60 days | Tavily bio + DeepWiki only | Raindrop, Readwise |

Note any previous `[gotcha]` or `[controversy]` observations — these guide
what to look for in new research.

Append new observations rather than overwriting.

### Step 2: Five-source enrichment (run in parallel)

**Multi-query strategy:** For Tavily, ask 2 targeted questions (bio/role and
contributions/influence) rather than one broad query.

Launch these research queries simultaneously:

**a) Basic Memory context — deep graph traversal:**

People are key connectors in the knowledge graph — a single person may be
referenced across engineering, indieweb, security, and accessibility clusters.
The BM step is therefore deeper than in package-intel or tool-intel.

If a note exists, build context with depth 2 to discover second-hop connections:
```
build_context(url="<note-title>", depth=2, max_related=15)
```

Then search broadly for mentions across all note types:
```
search_notes(query="<name>", search_type="text", page_size=20)
```

If no note exists, run the text search first, then build context from the
highest-scoring related note to explore its neighborhood:
```
search_notes(query="<name>", search_type="text", page_size=20)
build_context(url="<highest-scoring-related-note>", depth=1, max_related=10)
```

**Relation mining:** For each note that mentions the person, note:
- What role the person plays in that note (creator, advocate, author, inventor)
- Whether the mention is substantive or passing
- Which relation verb from the person schema best describes the connection

This produces a richer set of relations than just `relates_to` — use `created`,
`founded`, `maintains`, `works_with`, `enables` where they apply.

**Cross-cluster discovery:** People often bridge unrelated graph clusters.
After the initial search, check if results span multiple directories
(e.g., results appearing in 3+ distinct directories). If so, the person is a
cross-cluster connector — document this in a `[connection]` observation.

**b) Raindrop — bookmarked articles by or about the person:**
```
find_bookmarks(search="<name>")
```

If fewer than 3 results, search again with a known alias, project name, or
domain (e.g., `find_bookmarks(search="adactio")` for Jeremy Keith):
```
find_bookmarks(search="<alias-or-project>")
```

If bookmarks are found, fetch content from the top 2-3 most relevant results:
```
fetch_bookmark_content(bookmark_id=<id>)
```

These are articles the user deliberately saved — high relevance signal.

**c) Readwise — highlights from their writing:**
```
readwise_search_highlights(vector_search_term="<name> <primary-domain>")
reader_search_documents(query="<name>")
```

Highlights contain expert-selected passages from the user's reading (books,
articles, documentation). These have high signal-to-noise ratio and may surface
insights not found in any other source. Reader documents may contain in-depth
articles by or about the person.

If both return empty, note "source c: no Readwise content found" and proceed.

**d) Tavily — biographical and professional data:**

Two targeted queries:
```
tavily_search(query="<name> bio role current work projects contributions", max_results=5)
tavily_search(query="<name> <primary-domain> influence controversy", max_results=5)
```

If the person has a personal site (identifiable from Raindrop or Readwise
results), extract the about page:
```
tavily_extract(urls=["<personal-site-url>/about"], query="role bio current projects")
```

This is the primary source for the `role` and `impact` fields.

**e) DeepWiki — GitHub repository analysis (conditional):**

Only run if Tavily or Raindrop surfaces a GitHub username or the person is
primarily known as a developer/maintainer of open source projects.

```
ask_question(repo="<github-username>/<primary-repo>", question="What are this project's goals, design philosophy, and key patterns?")
```

The goal is understanding the person's approach through their work, not
documenting the package API (that's what `/package-intel` does).

If no GitHub presence is evident, skip and note "source e: no GitHub
presence found".

### Step 3: Synthesize into note

Read the note template:
`${CLAUDE_PLUGIN_ROOT}/skills/people-intel/references/note-template-person.md`

Read the source guide for query refinement tips:
`${CLAUDE_PLUGIN_ROOT}/skills/people-intel/references/source-guide.md`

**Fourth-wall guardrail:** Before writing, verify every sentence passes the
export test — "would someone unfamiliar with Basic Memory understand this
paragraph?" Delete any sentence that:
- Claims the person "has no presence in Raindrop/BM"
- Explains where the note fits in the knowledge graph
- References the research process rather than the person
- Describes the note's coverage status rather than the person's work

This prevents the fourth-wall anti-pattern (self-referential content in
subject-domain notes). See the `vp-note-quality` skill checklist for the
full ruleset.

**Title convention:** `<Full Name> - <Brief Descriptor>`. The descriptor
should be a concise phrase (3-8 words) capturing the person's primary
contribution or role. Examples:
- `Linus Torvalds - Linux Creator`
- `Tim Berners-Lee - World Wide Web Inventor`
- `Aaron Gustafson - Web Standards and Accessibility Advocate`

**Directory:** Default to `people/`. If the person clearly belongs to a
domain cluster with an existing directory convention, use that directory.
When uncertain, use `people/`.

**No wiki-links in observations.** Never use `[[Target]]` syntax in observation
lines. BM's parser treats any `[[` as a relation boundary — the text before it
becomes the `relation_type` field (max 200 chars), causing validation failures.
Put all wiki-links in `## Relations` only.

### Step 4: Write or update the note

<!-- This pattern is mirrored in package-intel and tool-intel — update all when changing -->

**New person:** Use `write_note` with the full template. Set
`note_type="person"`.

**Existing person:** Pick the operation based on the note's current state:

| Note state | Use |
|------------|-----|
| `## Observations` has at least one `- [category]` line | `find_replace` anchored on the last observation line |
| `## Observations` exists but is empty | `find_replace` anchored on `## Observations\n` |
| `## Observations` is absent entirely | `find_replace` anchored on the next section header (typically `## Relations\n`); prepend a new `## Observations` section before it |
| Last observation wraps across multiple lines | Include all continuation lines in both `find_text` and the prefix of `content`, then append the new observation after |

Canonical call (populated section):

````
edit_note(
  identifier="<person-title>",
  operation="find_replace",
  find_text="- [<last-category>] <last observation text>",
  content="- [<last-category>] <last observation text>\n- [<new-category>] <new observation text>"
)
````

Empty-section fallback (anchor on header):

````
edit_note(
  identifier="<person-title>",
  operation="find_replace",
  find_text="## Observations\n",
  content="## Observations\n- [<new-category>] <new observation text>\n"
)
````

Do NOT use `operation="append"` with `section="Observations"` when the section
already exists — it appends to end of file, not end of section. The substring
match in `find_replace` is byte-exact: use the observation text verbatim, no
whitespace normalization or escaping.

If `find_replace` fails (no match found), the note may have been edited since
you last read it. Re-run `read_note`, re-derive the anchor, and retry once.
If the second attempt also fails, stop and report the error to the user — do
not loop.

### Step 5: Confirm and summarize

Report to the user:
- Note location (directory/title)
- Key findings from each source (1 line each)
- Any controversies or sensitivities surfaced
- Cross-links to be added in Step 6

### Step 6: Cross-link existing notes

After writing the note, search for existing notes that reference this person
in their body text or observations but lack a wiki-link back to them:

```
search_notes(query="<name>", search_type="text", page_size=15)
```

The page size is larger than in package-intel because person names appear in
prose more often than package names. Filter carefully — only add links where
the mention is substantive (attributing a quote, citing their work, listing
them as a creator). Do not link notes that mention the name only in passing.

For each qualifying result (excluding the note just written):
1. Read its `## Relations` section
2. If the person is mentioned in body/observations but not linked in Relations,
   add a link via `edit_note` with `find_replace`:

```
edit_note(
  identifier="<existing-note-title>",
  operation="find_replace",
  find_text="- <last_relation_type> [[<Last Existing Relation>]]",
  content="- <last_relation_type> [[<Last Existing Relation>]]\n- relates_to [[<person-title>]]"
)
```

Cross-linking is bidirectional: also check the new person note's
`## Relations` section. If source a) surfaced related project, standard, or
concept notes that should link back, add `created [[Project]]`,
`maintains [[Project]]`, or `relates_to [[Standard]]` relations using the
person schema's relation vocabulary.

For adding outbound relations to the new person note itself:

```
edit_note(
  identifier="<person-title>",
  operation="find_replace",
  find_text="- <last_relation_type> [[<Last Existing Relation>]]",
  content="- <last_relation_type> [[<Last Existing Relation>]]\n- created [[<Project-Title>]]"
)
```

Only add links where the relationship is genuine. Skip this step for updates to
existing notes where cross-links likely already exist.

Files in this skill

  • SKILL.md12.1 KB
  • references/note-template-person.md3.5 KB
  • references/source-guide.md6.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.