AgentSkillsCN

entity-manager

在 Neo4j 数据库中创建并编辑历史实体(人物、事件、QA 卡片、填空卡)。适用于用户希望新增人物、事件、QA 或填空,建立实体间关系,或探索现有实体以查找相关内容时使用。

SKILL.md
--- frontmatter
name: entity-manager
description: Create and edit historical entities (persons, events, QA cards, cloze cards) in the Neo4j database. Use when the user wants to add a new person, event, QA, or cloze, create relationships between entities, or explore existing entities to find related content.
allowed-tools: Bash, Read, Grep, Glob

Entity Manager Skill

Manage historical entities (persons, events, QA, cloze) in the Neo4j graph database.

Prerequisites

Environment variables must be set:

  • NEO4J_URI - Database connection URI
  • NEO4J_PASSWORD - Database password

NEVER read the .env file - credentials are loaded from environment.

NEVER read the CSV files in src/data/ - always use Neo4j queries to look up entity data.

CLI Tool

All commands use: uv run tools/neo4j_query.py <command>

Query Commands

bash
# List all tags with usage counts
uv run tools/neo4j_query.py tags

# List entities by type
uv run tools/neo4j_query.py list person
uv run tools/neo4j_query.py list event
uv run tools/neo4j_query.py list qa
uv run tools/neo4j_query.py list cloze

# Search entities (fuzzy, case-insensitive)
uv run tools/neo4j_query.py search "napoleon"

# Show all properties of an entity (name, dates, known_for/summary, notes, source, tags)
uv run tools/neo4j_query.py show "Napoleon Bonaparte"

# Get all relationships for an entity
uv run tools/neo4j_query.py relations "Napoleon Bonaparte"

# Find potentially related entities by time period and tags
uv run tools/neo4j_query.py find-related "New Entity" --start 1789 --end 1815 --tag "UH::Region::Europe"

Create Commands

bash
# Create a person
uv run tools/neo4j_query.py create-person "Otto von Bismarck" \
  --known-for "German chancellor who unified Germany" \
  --birth 1815 --death 1898 \
  --tag "UH::Region::Europe::Central" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::Politics"

# Create an event
uv run tools/neo4j_query.py create-event "Franco-Prussian War" \
  --summary "War between France and Prussia leading to German unification" \
  --start 1870 --end 1871 \
  --tag "UH::Region::Europe::Western" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::War"

# Create a QA card
uv run tools/neo4j_query.py create-qa "What triggered the Franco-Prussian War?" \
  --answer "The Ems Dispatch, a telegram edited by Bismarck to provoke France" \
  --tag "UH::Region::Europe" \
  --tag "UH::Period::19th_Century"

# Create a Cloze card (must have valid {{c1::deletion}} syntax)
uv run tools/neo4j_query.py create-cloze \
  "The {{c1::Franco-Prussian War}} (1870-1871) led to {{c2::German unification}}." \
  --tag "UH::Region::Europe" \
  --tag "UH::Period::19th_Century"

# Create a new Region or Period tag
uv run tools/neo4j_query.py create-tag "UH::Region::Europe::Central"
uv run tools/neo4j_query.py create-tag "UH::Period::19th_Century"

# Add relationship between entities
uv run tools/neo4j_query.py add-rel "Otto von Bismarck" "Franco-Prussian War" \
  "orchestrated the war to complete German unification"

# Delete a relationship between entities
uv run tools/neo4j_query.py delete-rel "Otto von Bismarck" "Franco-Prussian War"

# Delete an entity
uv run tools/neo4j_query.py delete "Some Entity"

Update Commands

Update existing entities (only specified fields are modified):

bash
# Update a person
uv run tools/neo4j_query.py update-person "Otto von Bismarck" \
  --known-for "Unified Germany through diplomacy and war" \
  --death 1898

# Update an event
uv run tools/neo4j_query.py update-event "Franco-Prussian War" \
  --summary "War that unified Germany" \
  --end 1871

# Update a QA card
uv run tools/neo4j_query.py update-qa "What triggered the Franco-Prussian War?" \
  --answer "The Ems Dispatch provoked France into declaring war"

# Update a Cloze card
uv run tools/neo4j_query.py update-cloze "The {{c1::Franco-Prussian War}}..." \
  --notes "Updated context"

# Rename an entity
uv run tools/neo4j_query.py update-person "Old Name" --new-name "New Name"
uv run tools/neo4j_query.py update-event "Old Event" --new-name "New Event Name"

Tagging System

Every card needs at least one Region and one Period tag. Theme tags are optional.

Region Tags (Hierarchical, 2 levels)

Format: UH::Region::<Continent> or UH::Region::<Continent>::<SubRegion>

ContinentSub-regions
EuropeWestern, Eastern, Northern, Southern, Central
AsiaEast, Southeast, South, Central, West (Middle East)
AfricaNorth, West, East, Central, Southern
AmericasNorth, Central, South, Caribbean
OceaniaAustralia, Pacific
Global(no sub-regions - for worldwide events)

Always use the most specific level that applies:

  • French Revolution → UH::Region::Europe::Western
  • Mongol Empire → Multiple tags: UH::Region::Asia::Central, UH::Region::Asia::East, UH::Region::Europe::Eastern
  • World War II → UH::Region::Global

Period Tags (Centuries)

Format: UH::Period::<Century>

Examples:

  • UH::Period::19th_Century
  • UH::Period::5th_Century_BCE
  • UH::Period::Prehistory

Guidelines:

  • Tag based on when the event primarily occurred
  • For events spanning centuries, use multiple period tags
  • For persons, tag based on their active period

Theme Tags (Curated List)

Format: UH::Theme::<Theme>

ThemeUse For
WarBattles, conflicts, military history
PoliticsGovernance, diplomacy, revolutions
EconomyTrade, industry, economic systems
SocietySocial movements, daily life
CultureArt, literature, music, architecture
ScienceTechnology, medicine, discoveries
ReligionFaiths, religious movements

Theme tags cannot be created directly - they are auto-created when used. New themes require GitHub discussion.

Entity Types

Date Format

Dates support:

  • Plain years: 1815, 500
  • Approximate dates: c. 1760 (prefix with "c. ")
  • BCE dates: 500 BCE, c. 1,700,000 BCE
  • Empty for unknown

IMPORTANT: If start and end years are the same, ONLY specify the start year (birth/start), not the end year (death/end).

Examples:

  • --birth 1815 → stored as year 1815, not approximate
  • --birth "c. 500 BCE" → stored as year -500, approximate
  • --start "c. 1760" → stored as year 1760, approximate
  • --start 1914 --end 1914 → ❌ Wrong! Use --start 1914 only
  • --birth 1889 --death 1889 → ❌ Wrong! Use --birth 1889 only

Person

  • name: Full name
  • known_for: Brief description of significance (used in isolation for quiz questions - must be distinctive and informative without being verbose)
  • birth/death: Years (see Date Format above)
  • tags: Required (at least Region + Period)
  • notes: Additional context (see Notes Field below) - avoid duplicating information from known_for or relationships
  • source: Attribution

Event

  • name: Event name
  • summary: Brief description (used in isolation for quiz questions - must be distinctive and informative without being verbose)
  • start_date/end_date: Years (see Date Format above - remember: if same year, only specify start)
  • tags, notes, source: Same as Person
  • notes: Avoid duplicating information from summary or relationships

Notes Field

The notes field is valuable for adding historical context that doesn't fit elsewhere.

IMPORTANT: Avoid duplication. Don't repeat information already in:

  • known_for or summary fields
  • Relationship descriptions
  • Other notes

Use notes to include:

  • Interesting historical details and trivia not mentioned elsewhere
  • Context that helps understand the person/event's significance
  • Explanations of unusual names, terms, or dating systems
  • Key dates and specific facts worth remembering
  • Pronunciation guides for names not intuitive to English speakers

Pronunciation Guidelines

For names whose pronunciation is not intuitive for English speakers, add the IPA pronunciation at the end of the notes field. Format: Language: [IPA transcription]

Examples:

  • Giuseppe Mazzini: Italian: [dʒuˈzɛppe matˈtsiːni]
  • Klemens von Metternich: German: [ˈkleːmɛns fɔn ˈmɛtɐnɪç]
  • Maximilien Robespierre: French: [maksimiljɛ̃ ʁɔbɛspjɛʁ]

When to add pronunciation:

  • Non-English names with unintuitive spelling (Italian, German, French, Hungarian, Russian, etc.)
  • Names with silent letters or unusual letter combinations
  • Names where English speakers commonly mispronounce

When NOT to add pronunciation:

  • Common English names or anglicized versions
  • Names that are pronounced as they are spelled in English

Examples of notes with context and pronunciation:

  • For "Thermidorian Reaction": "Named after 9 Thermidor Year II in the French Republican Calendar (July 27, 1794). The Republican Calendar was adopted in 1793, replacing the Gregorian calendar with 12 months of 30 days each, named after natural phenomena. French: [teʁmidɔʁ]"
  • For "Otto von Bismarck": "Bismarck began as an outspoken conservative firebrand but became famous for his pragmatic 'Realpolitik,' often outmaneuvering rivals through alliances, timing, and controlled crises. German: [ˈɔto fɔn ˈbɪsmaʁk]"

Always consider adding notes when creating or updating persons and events—they enrich the learning experience.

Picture and Source Fields (Persons only)

Images, source URLs, and licenses are provided by the user. Do not add these fields unless the user provides the information.

When the user provides an image:

  • Images are stored in src/media/ with naming convention uh_<name-in-lowercase-kebab-case>.jpg
  • The --picture field takes an HTML <img> tag:
    bash
    --picture '<img src="uh_otto-von-bismarck.jpg">'
    

When the user provides source/license info, use this format for the --source field:

bash
--source 'Claude Sonnet 4.5<br><br>Image: <a href="https://en.wikipedia.org/wiki/...">Wikipedia</a> (Public domain)'

The source field has two parts separated by <br><br>:

  1. Data source: Who created/verified the entity data (e.g., "Claude Sonnet 4.5")
  2. Image attribution: Link to source and license provided by user

QA (Question & Answer)

  • question: The question to ask
  • answer: The expected answer
  • tags, notes, source: Same as above

Cloze

  • text: Text with Anki cloze deletions {{c1::text}} or {{c1::text::hint}}
  • Must have at least one cloze deletion starting at c1
  • tags, notes, source: Same as above

Cloze Syntax

Valid cloze formats:

  • {{c1::answer}} - Basic cloze
  • {{c1::answer::hint}} - Cloze with hint
  • Multiple clozes: {{c1::first}} and {{c2::second}}

Examples:

code
"{{c1::Napoleon}} was emperor of {{c2::France}}."
"The {{c1::Treaty of Westphalia::1648}} ended the {{c2::Thirty Years' War}}."

Workflow for Adding New Entities

1. Research and Verify

Before creating, search to avoid duplicates:

bash
uv run tools/neo4j_query.py search "bismarck"

2. Find Related Entities

Use time period and tags to discover relationships:

bash
uv run tools/neo4j_query.py find-related "Otto von Bismarck" \
  --start 1815 --end 1898 \
  --tag "UH::Region::Europe"

3. Review Existing Tags

Check available tags to use consistent naming:

bash
uv run tools/neo4j_query.py tags

4. Create the Entity

Use appropriate tags following the hierarchy. The script will warn about invalid tags.

5. Add Relationships

Link to related persons and events with descriptive relationships:

bash
uv run tools/neo4j_query.py add-rel "Person A" "Person B" "was mentor to"
uv run tools/neo4j_query.py add-rel "Person A" "Event X" "led the"

6. Verify Creation

bash
uv run tools/neo4j_query.py relations "Otto von Bismarck"

Relationship Guidelines

Relationships should be:

  • Directional: Source -> Target with a description
  • Verbose and contextual: Describe the relationship's historical significance, not just the connection type
  • Historical: Focus on significant historical connections
  • Non-duplicative: Don't repeat information already in "known_for"/"summary" or vice versa

When to Add Reverse Relationships

IMPORTANT: In most cases, add BOTH directions (A → B and B → A) with distinct contextual descriptions.

General rule: Add the reverse relationship unless the relationship is insignificant from one perspective.

Since each entity is limited to 5 related people and 5 related events, prioritize historically significant relationships. Sometimes a relationship is crucial from one entity's perspective but minor from the other's.

Example of asymmetric significance:

bash
# Franz Ferdinand's assassination was THE defining event of his life
add-rel "Archduke Franz Ferdinand" "Assassination of Archduke Franz Ferdinand" "was killed in this event that triggered World War I"

# But World War I had many more significant causes and events than just this assassination
# From WWI's perspective, you might prioritize:
# - Treaty of Versailles, Battle of Verdun, Russian Revolution, etc.
# So you might SKIP the reverse relationship to save space for more significant events

Another example:

bash
# For a minor composer who studied with Beethoven:
add-rel "Johann Minor Composer" "Ludwig van Beethoven" "studied composition with in Vienna (1815-1820)"

# But Beethoven had many more significant students and relationships
# You might NOT add the reverse to preserve space for:
# - Beethoven -> Archduke Rudolph (major patron)
# - Beethoven -> Ninth Symphony (masterwork)
# - etc.

Default approach: Add both directions unless you have a specific reason not to (like the 5-item limit forcing prioritization).

IMPORTANT: Write detailed, contextual relationship descriptions. Short descriptions like "led" or "participated in" are insufficient. Instead, explain the nature and significance of the relationship.

Examples of good relationship descriptions:

  • ❌ Bad: "was advisor to"

  • ✅ Good: "conservative advisor who guided Alexander III's autocratic governance"

  • ❌ Bad: "fought against"

  • ✅ Good: "rival-turned-ally-turned-opponent whose conflicts with Russia shaped Alexander's reign"

  • ❌ Bad: "participated in"

  • ✅ Good: "promoted Russian industrialization through protective tariffs and initiated the Trans-Siberian Railway in 1891"

  • ❌ Bad: "was father of"

  • ✅ Good: "father whose assassination brought Alexander III to power and shaped his reactionary policies"

Common patterns:

  • Person -> Person: "was teacher of", "married", "succeeded", "defeated"
  • Person -> Event: "led", "participated in", "caused", "died during"
  • Event -> Person: "resulted in rise of", "led to death of"
  • Event -> Event: "caused", "preceded", "was part of"

Complete Example

bash
# 1. Search for existing content
uv run tools/neo4j_query.py search "bismarck"

# 2. Find related entities
uv run tools/neo4j_query.py find-related "Otto von Bismarck" --start 1815 --end 1898

# 3. Create person with proper tags
uv run tools/neo4j_query.py create-person "Otto von Bismarck" \
  --known-for "Prussian statesman who unified Germany through diplomacy and war" \
  --birth 1815 --death 1898 \
  --tag "UH::Region::Europe::Central" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::Politics"

# 4. Create related event
uv run tools/neo4j_query.py create-event "Franco-Prussian War" \
  --summary "War between France and Prussia resulting in German unification" \
  --start 1870 --end 1871 \
  --tag "UH::Region::Europe::Western" \
  --tag "UH::Region::Europe::Central" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::War"

# 5. Add relationship
uv run tools/neo4j_query.py add-rel "Otto von Bismarck" "Franco-Prussian War" \
  "orchestrated through the Ems Dispatch"

# 6. Create QA card
uv run tools/neo4j_query.py create-qa "How did Bismarck provoke France into the Franco-Prussian War?" \
  --answer "By editing and publishing the Ems Dispatch to make it appear insulting to France" \
  --tag "UH::Region::Europe" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::Politics"

# 7. Create Cloze card
uv run tools/neo4j_query.py create-cloze \
  "{{c1::Otto von Bismarck}} unified Germany through {{c2::three wars}}: against {{c3::Denmark}} (1864), {{c4::Austria}} (1866), and {{c5::France}} (1870-71)." \
  --tag "UH::Region::Europe::Central" \
  --tag "UH::Period::19th_Century" \
  --tag "UH::Theme::War"

# 8. Verify
uv run tools/neo4j_query.py relations "Otto von Bismarck"