/knowledge-ingest
Upload a file (PDF, DOCX, PPTX, XLSX, HTML, EPUB, image) or URL to the Knowledge base. Triggers Marker parsing, chunking, embedding, and async classification. Use when the user says 'index this PDF', 'add this URL to the knowledge base', 'upload these files to Academy', or
$ npx -y skills add evolution-foundation/evo-nexus --skill knowledge-ingest --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/knowledge-ingest
Context preview
The summary Claude sees to decide when to auto-load this skill.
Upload a file (PDF, DOCX, PPTX, XLSX, HTML, EPUB, image) or URL to the Knowledge base. Triggers Marker parsing, chunking, embedding, and async classification. Use when the user says 'index this PDF', 'add this URL to the knowledge base', 'upload these files to Academy', or
SKILL.md
knowledge-ingest.SKILL.mdname: knowledge-ingest
description: "Upload a file (PDF, DOCX, PPTX, XLSX, HTML, EPUB, image) or URL to the Knowledge base. Triggers Marker parsing, chunking, embedding, and async classification. Use when the user says 'index this PDF', 'add this URL to the knowledge base', 'upload these files to Academy', or pastes a file path/URL with ingestion intent."
knowledge-ingest
Group: **Ingestion**. Upload + automatic classification via pipeline parse → chunk → embed → enqueue classify.
When to trigger
- "Index this PDF"
- "Add this URL to the knowledge base"
- "Upload these files to Academy"
- User passes a file path with ingestion intent
Arguments
| Name | Type | Required | Description | |---|---|---|---| | `file_path` | str | one of two | Local path | | `url` | str | one of two | URL to download first | | `connection` | str | no | Defaults to first ready | | `space` | str | yes | Destination space slug | | `unit_id` | str | no | Associated unit | | `title` | str | no | Derived from filename if absent | | `tags` | list[str] | no | User-defined tags |
Workflow
Step 1 — Validate connection + space
If `connection` not provided, use first `ready`. If none: error ("Run `knowledge-admin action=connect`").
Validate space via `GET /spaces`. If not found: list spaces + ask for confirmation.
Step 2 — Resolve file
If `url`:
import requests, tempfile
from pathlib import Path
from urllib.parse import urlparse
parsed = urlparse(url)
filename = Path(parsed.path).name or "downloaded"
tmp = Path(tempfile.gettempdir()) / filename
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(tmp, "wb") as f:
for chunk in r.iter_content(8192):
f.write(chunk)
file_path = str(tmp)If `file_path`: validate existence.
Step 3 — Multipart upload
from dashboard.backend.sdk_client import evo
with open(file_path, "rb") as f:
result = evo.post(
"/api/knowledge/v1/documents",
files={"file": f},
data={
"space": space,
"unit_id": unit_id,
"title": title or Path(file_path).stem,
"tags": ",".join(tags or []),
},
headers={"X-Knowledge-Connection": connection},
)
document_id = result["document_id"]Endpoint returns 202 Accepted + document_id. Async worker.
Step 4 — Poll status
Interval 2s, timeout 10min:
import time
deadline = time.time() + 600
while time.time() < deadline:
status = evo.get(
f"/api/knowledge/v1/documents/{document_id}/status",
headers={"X-Knowledge-Connection": connection},
)
phase = status.get("phase")
if phase in ("done", "ready"):
break
if phase == "error":
raise RuntimeError(status.get("error"))
time.sleep(2)Step 5 — Fetch classification (non-blocking)
Classification is asynchronous. 1 extra GET on `/documents/{id}`:
- `content_type != null`: show full classification
- Else: "Classification pending — will appear in seconds via async worker"
Output
✓ Document uploaded: {title}
document_id: {uuid}
space: {connection}/{space}
unit: {unit_title or "none"}
status: ready
chunks: {N}
classification:
content_type: {lesson|tutorial|faq|...}
difficulty: {...}
topics: [...]
elapsed: {X}sActionable failures
- File not found → "File does not exist: `{path}`"
- URL fetch failed → "Download failed: {status_code}"
- Space not found → list available spaces
- Marker models missing → "Run `knowledge-admin action=install-parser`"
- Timeout → "Timeout after 10min. Status: `{phase}`. Check `knowledge-browse`."
Read more
name: knowledge-ingest description: "Upload a file (PDF, DOCX, PPTX, XLSX, HTML, EPUB, image) or URL to the Knowledge base. Triggers Marker parsing, chunking, embedding, and async classification. Use when the user says 'index this PDF', 'add this URL to the knowledge base', 'upload these files to Academy', or pastes a file path/URL with ingestion intent."
knowledge-ingest
Group: **Ingestion**. Upload + automatic classification via pipeline parse → chunk → embed → enqueue classify.
When to trigger
- "Index this PDF"
- "Add this URL to the knowledge base"
- "Upload these files to Academy"
- User passes a file path with ingestion intent
Arguments
| Name | Type | Required | Description | |---|---|---|---| | `file_path` | str | one of two | Local path | | `url` | str | one of two | URL to download first | | `connection` | str | no | Defaults to first ready | | `space` | str | yes | Destination space slug | | `unit_id` | str | no | Associated unit | | `title` | str | no | Derived from filename if absent | | `tags` | list[str] | no | User-defined tags |
Workflow
Step 1 — Validate connection + space
If `connection` not provided, use first `ready`. If none: error ("Run `knowledge-admin action=connect`").
Validate space via `GET /spaces`. If not found: list spaces + ask for confirmation.
Step 2 — Resolve file
If `url`:
import requests, tempfile
from pathlib import Path
from urllib.parse import urlparse
parsed = urlparse(url)
filename = Path(parsed.path).name or "downloaded"
tmp = Path(tempfile.gettempdir()) / filename
with requests.get(url, stream=True, timeout=60) as r:
r.raise_for_status()
with open(tmp, "wb") as f:
for chunk in r.iter_content(8192):
f.write(chunk)
file_path = str(tmp)If `file_path`: validate existence.
Step 3 — Multipart upload
from dashboard.backend.sdk_client import evo
with open(file_path, "rb") as f:
result = evo.post(
"/api/knowledge/v1/documents",
files={"file": f},
data={
"space": space,
"unit_id": unit_id,
"title": title or Path(file_path).stem,
"tags": ",".join(tags or []),
},
headers={"X-Knowledge-Connection": connection},
)
document_id = result["document_id"]Endpoint returns 202 Accepted + document_id. Async worker.
Step 4 — Poll status
Interval 2s, timeout 10min:
import time
deadline = time.time() + 600
while time.time() < deadline:
status = evo.get(
f"/api/knowledge/v1/documents/{document_id}/status",
headers={"X-Knowledge-Connection": connection},
)
phase = status.get("phase")
if phase in ("done", "ready"):
break
if phase == "error":
raise RuntimeError(status.get("error"))
time.sleep(2)Step 5 — Fetch classification (non-blocking)
Classification is asynchronous. 1 extra GET on `/documents/{id}`:
- `content_type != null`: show full classification
- Else: "Classification pending — will appear in seconds via async worker"
Output
✓ Document uploaded: {title}
document_id: {uuid}
space: {connection}/{space}
unit: {unit_title or "none"}
status: ready
chunks: {N}
classification:
content_type: {lesson|tutorial|faq|...}
difficulty: {...}
topics: [...]
elapsed: {X}sActionable failures
- File not found → "File does not exist: `{path}`"
- URL fetch failed → "Download failed: {status_code}"
- Space not found → list available spaces
- Marker models missing → "Run `knowledge-admin action=install-parser`"
- Timeout → "Timeout after 10min. Status: `{phase}`. Check `knowledge-browse`."
Other skills on evo-nexus.
- /ai-image-creator
Generate PNG images using AI (multiple models via OpenRouter including Gemini, FLUX.2, Riverflow, SeedDream, GPT-5 Image, proxied through Cloudflare AI Gateway BYOK). Also analyze/describe existing images using multimodal AI vision. Use when user asks to "generate an image",
Open skill - /create-agent
Create a new custom agent for the workspace. Guides the user through defining agent name, domain, personality, skills, model, and memory folder. Use when the user says 'create an agent', 'new agent', 'add an agent', 'I need a custom agent', or wants to create a specialized agent
Open skill - /create-command
Create a new slash command for Claude Code. Guides the user through defining the command name, what it does, and generates the markdown file in .claude/commands/. Use when the user says 'create a command', 'new command', 'add a slash command', 'I want a shortcut for', or wants
Open skill - /create-goal
Create a Mission, Project, or Goal (Mission → Project → Goal → Task hierarchy) in EvoNexus. Guides the user through picking a mission, choosing or creating a project, defining a measurable goal with metric_type and target_value. Writes to the SQLite goals tables via POST
Open skill - /create-heartbeat
Create a new heartbeat (proactive agent scheduled with a decision prompt) for EvoNexus. Guides the user through picking an agent, setting interval, wake triggers, and the decision prompt that governs when the agent acts. Writes to config/heartbeats.yaml with pydantic validation.
Open skill - /create-integration
Create a new custom integration (API/service wrapper) for the workspace. Guides the user through defining the integration's slug, display name, description, category, and required env keys. Writes .claude/skills/custom-int-{slug}/SKILL.md via POST /api/integrations/custom. Use
Open skill

