The python library for research and development in NLP, multimodal LLMs, Agents, ML, Knowledge Graphs, and more.
# npcpy
`npcpy` is a library that provides key primitives for research and development with multimodal language models, agentic AI, and knowledge graphs. Its flexible framework makes it easy to engineer powerful AI applications with support for local (`ollama`, `llama.cpp`, `omlx`, `LM Studio`) and cloud providers. Build multi-agent teams and simplify context engineering through the NPC Context-Agent-Tool data layer which ensures compliance through software rather than prompts.
```bash
pip install npcpy
```
## Quick Examples
### Create and use personas
```python
from npcpy import NPC
simon = NPC(
name='Simon Bolivar',
primary_directive='''
Liberate South America
from the Spanish Royalists.
''',
model='qwen3.5:9b',
provider='ollama'
)
response = simon.get_llm_response("What is the most important territory to retain in the Andes?")
print(response['response'])
```
```
…
```
### Direct LLM call
```python
from npcpy import get_llm_response
response = get_llm_response("Who was the celtic god that helped cuchulainn in his time of need as the forces of medb descended upon the men of ulster?", model='gemma4:31b', provider='ollama')
print(response['response'])
```
```
Cú Chulainn was primarily aided by his divine father, the god Lugh, and his foster-father, the warrior-god Fergus mac Róich, as well as the magical support of his teacher Scáthach.
```
Try out almost 200 different models from 15 different providers with OrcaRouter using our [referral link](https://www.orcarouter.ai/ref/ref_900cb60d234853be6842)!
```python
alicanto_test = get_llm_response('what does alicanto the bird show travelers in the night?', model='google/gemini-3.8-flash', provider='orcarouter')
print(alicanto_test['response'])
```
```
The legend of the **Alicanto** says that at night the bird’s feathers glow like lanterns.
When a traveler sees that soft, phosphorescent light, it isn’t just a pretty sight – it’s a sign‑post.
The bird **shows the way to hidden water (and sometimes to buried silver or gold)** in the Atacama Desert.
```
### Agent with tools
The `Agent` class in `npcpy` comes with a set of default tools (sh, python, edit_file, web_search, etc.)
```python
from npcpy import Agent
agent = Agent(name='File Operator', model='qwen3.5:2b', provider='ollama')
print(agent.run("Find all Python files over 500 lines in this repo and list them"))
```
```
The following Python files contain more than 500 lines:
- `./npcpy/npc_sysenv.py` (1486 lines)
- `./npcpy/memory/knowledge_graph.py` (1449 lines)
- `./npcpy/memory/kg_vis.py` (767 lines)
- `./npcpy/memory/kg_population.py` (618 lines)
...
```
### ToolAgent
Attach custom tools to a `ToolAgent`.
Here is an example which lets an agent generate images, fine-tune diffusion models, and then use the fine-tuned models for generation.
```
…
```
### CodingAgent — auto-executes code blocks from LLM responses
```python
from npcpy import CodingAgent
coder = CodingAgent(name='coder', language='python', model='qwen3.5:2b', provider='ollama')
print(coder.run("Write a script that finds duplicate files by hash in the current directory"))
```
```
…
```
### Multi-Agent Debate with NPCArray
To run a true multi-agent debate where agents react to each other's responses:
```
…
```
For iterative refinement (same prompt to all agents, updating each round):
```python
# Simple chain refinement: all agents see same synthesis
from npcpy.npc_array import NPCArray
def synthesis_round(all_responses):
return f"""Given these perspectives:
{chr(10).join([f'- {r[:200]}...' for r in all_responses])}
Re-solve the problem incorporating insights from all approaches."""
# Chain runs the synthesis function on all responses, then feeds result back
refined = team.infer(f"Solve: {problem}").chain(
synthesis_round,
n_rounds=3
).collect()
```
### Knowledge Graph with Sleep/Dream Lifecycle
```
…
```
### Flask Serving for NPC Teams
```python
from npcpy.serve import start_flask_server
import os
# Serve your NPC team via REST API
if __name__ == "__main__":
is_dev = not getattr(os.sys, 'frozen', False)
port = os.environ.get('INCOGNIDE_PORT', '5437' if is_dev else '5337')
frontend_port = os.environ.get('FRONTEND_PORT', '7337' if port == '5437' else '6337')
start_flask_server(
port=port,
cors_origins=f"localhost:{frontend_port}",
db_path=os.path.expanduser('~/npcsh_history.db'),
user_npc_directory=os.path.expanduser('~/.npcsh/npc_team'),
debug=False
)
```
### Streaming
```
…
```
### JSON output
Include the expected JSON structure in your prompt. With `format='json'`, the response is auto-parsed — `response['response']` is already a dict or list.
```
…
```
Pydantic structured output
Pass a Pydantic model and the JSON schema is sent to the LLM directly.
```python
from npcpy import get_llm_response
from pydantic import BaseModel
from typing import List
class Planet(BaseModel):
name: str
distance_au: float
num_moons: int
class SolarSystem(BaseModel):
planets: List[Planet]
response = get_llm_response(
"List the first 4 planets from the sun.",
model='qwen3.5:2b', provider='ollama',
format=SolarSystem
)
for p in response['response']['planets']:
print(f"{p['name']}: {p['distance_au']} AU, {p['num_moons']} moons")
```
Image, audio, and video generation
```
…
```
### Multi-agent team
```python
from npcpy import NPC, Team
team = Team(team_path='examples/npc_team')
result = team.orchestrate("Analyze the latest sales data and draft a report")
print(result['output'])
```
Or define a team in code:
```python
from npcpy import NPC, Team
coordinator = NPC(name='lead', primary_directive='Coordinate the team. Delegate to @analyst and @writer.')
analyst = NPC(name='analyst', primary_directive='Analyze data. Provide numbers and trends.', model='gemini-2.5-flash', provider='gemini')
writer = NPC(name='writer', primary_directive='Write clear reports from analysis.', model='qwen3:8b', provider='ollama')
team = Team(npcs=[coordinator, analyst, writer], forenpc='lead')
result = team.orchestrate("What are the trends in renewable energy adoption?")
print(result['output'])
```
Team from files — .npc, .jinx, team.ctx
**team.ctx:**
```yaml
context: |
Research team for analyzing scientific literature.
The lead delegates to specialists as needed.
forenpc: lead
model: qwen3.5:2b
provider: ollama
output_format: markdown
max_search_results: 5
mcp_servers:
- path: ~/.npcsh/mcp_server.py
```
**lead.npc:**
```yaml
#!/usr/bin/env npc
name: lead
primary_directive: |
You lead the research team. Delegate literature searches to @searcher,
data analysis to @analyst. Synthesize their findings into a coherent summary.
jinxes:
- {{ Jinx('sh') }}
- {{ Jinx('python') }}
- {{ Jinx('delegate') }}
- {{ Jinx('web_search') }}
```
**searcher.npc:**
```yaml
#!/usr/bin/env npc
name: searcher
primary_directive: |
You search for scientific papers and extract key findings.
Use web_search and load_file to find and read papers.
model: gemini-2.5-flash
provider: gemini
jinxes:
- {{ Jinx('web_search') }}
- {{ Jinx('load_file') }}
- {{ Jinx('sh') }}
```
**Jinxes can reference a specific NPC** to always run under that persona, and **access `ctx` variables** from `team.ctx`:
**jinxes/search_and_summarize.jinx:**
```yaml
#!/usr/bin/env npc
jinx_name: search_and_summarize
description: Search for papers and summarize findings using the searcher NPC.
npc: {{ NPC('searcher') }}
inputs:
- query
steps:
- name: search
engine: natural
code: |
Search for papers about {{ query }}.
Return up to {{ ctx.max_search_results }} results.
- name: summarize
engine: natural
code: |
Summarize the findings in {{ ctx.output_format }} format:
{{ output }}
```
The `npc:` field binds the jinx to a specific NPC — when this jinx runs, it always uses the `searcher` persona regardless of which NPC invoked it. Any custom keys in `team.ctx` (like `output_format`, `max_search_results`) are available as `{{ ctx.key }}` in Jinja templates and as `context['key']` in Python steps.
```
my_project/
├── npc_team/
│ ├── team.ctx
│ ├── lead.npc
│ ├── searcher.npc
│ ├── analyst.npc
│ ├── jinxes/
│ │ └── skills/
│ └── models/
├── agents.md # Optional: define agents in markdown
└── agents/ # Optional: one .md file per agent
└── translator.md
```
`.npc` and `.jinx` files are directly executable:
```bash
./npc_team/lead.npc "summarize the latest arxiv papers on transformers"
./npc_team/jinxes/lib/sh.jinx bash_command="echo hello"
```
MCP server integration
Add MCP servers to your team for external tool access:
**team.ctx:**
```yaml
forenpc: assistant
mcp_servers:
- path: ./tools/db_server.py
- path: ./tools/api_server.py
```
**db_server.py:**
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Database Tools")
@mcp.tool()
def query_orders(customer_id: str, limit: int = 10) -> str:
"""Query recent orders for a customer."""
# Your database logic here
return f"Found {limit} orders for customer {customer_id}"
@mcp.tool()
def search_products(query: str) -> str:
"""Search the product catalog."""
return f"Products matching: {query}"
if __name__ == "__main__":
mcp.run()
```
The team's NPCs automatically get access to MCP tools alongside their jinxes.
For a remote server that uses Streamable HTTP, set its transport explicitly.
For example, Parallel Search MCP provides live web search and URL fetching
without requiring an account or API key:
```yaml
forenpc: assistant
mcp_servers:
- url: https://search.parallel.ai/mcp
transport: streamable-http
tools:
- web_search
- web_fetch
```
Remote URLs continue to use SSE when `transport` is omitted.
Agent definitions in markdown & Skills
**agents.md** — multiple agents in one file:
```markdown
## summarizer
You summarize long documents into concise bullet points.
Focus on key findings, methodology, and conclusions.
## fact_checker
You verify claims against reliable sources and flag inaccuracies.
Always cite your sources.
```
**agents/translator.md** — one file per agent with optional frontmatter:
```markdown
---
model: gemini-2.5-flash
provider: gemini
---
You translate content between languages while preserving tone and idiom.
```
Skills are knowledge-content jinxes that provide instructional sections to agents on demand.
**npc_team/jinxes/skills/code-review/SKILL.md:**
```markdown
---
name: code-review
description: Use when reviewing code for quality, security, and best practices.
---
# Code Review Skill
## checklist
- Check for security vulnerabilities (SQL injection, XSS, etc.)
- Verify error handling and edge cases
- Review naming conventions and code clarity
## security
Focus on OWASP top 10 vulnerabilities...
```
Reference in your NPC:
```yaml
jinxes:
- {{ Jinx('skills/code-review') }}
```
### CLI tools
```bash
# The NPC shell — the recommended way to use NPC teams
npcsh # Interactive shell with agents, tools, and jinxes
# Scaffold a new team
npc-init
# Launch AI coding tools as an NPC from your team
npc-claude --npc corca # Claude Code
npc-codex --npc analyst # Codex
npc-gemini # Gemini CLI (interactive picker)
npc-opencode / npc-aider / npc-amp
# Register MCP server + hooks