NodeTool Core is the open‑source Python engine that powers NodeTool.
- 🧩 Node-Based DSL – Declare graphs in pure Python or JSON; no vendor lock‑in.
- 🤖 First‑Class Agents – Planner, browser, search & tool‑calling baked in.
- 🌐 Multi‑Provider Models – OpenAI, Anthropic, Ollama, Hugging Face.
- 🔄 RAG & Vector Stores – Native adapters for Chroma.
- ⚡ Actor-Based Execution Engine – One actor per node, streaming-first.
- 🔌 Plugin SDK – Bring your own node.
# Install using pip
pip install nodetool-core
# Or install from source (recommended for development)
git clone https://github.com/nodetool-ai/nodetool-core
cd nodetool-core
# Option 1: Using conda + uv (recommended - includes system dependencies)
conda create -n nodetool python=3.11 pandoc ffmpeg -c conda-forge
conda activate nodetool
uv sync
# Option 2: Using pip only
pip install .
# Note: Install pandoc and ffmpeg separately for full functionality
import asyncio
from nodetool.dsl.graph import graph, run_graph
from nodetool.dsl.providers.openai import ChatCompletion
from nodetool.metadata.types import OpenAIModel
# Create a simple workflow
g = ChatCompletion(
model=OpenAIModel(model="gpt-4"),
messages=[{"role": "user", "content": "Explain quantum computing in simple terms"}]
)
# Run the workflow
result = asyncio.run(run_graph(graph(g)))
print(result)
python -m nodetool.cli --help
See docs/cli.md for all commands.
NodeTool's architecture is designed to be flexible and extensible.
graph TD
A[NodeTool Editor<br>ReactJS<br>DAG Templates] -->|HTTP/WebSocket| B[API Server<br>Workflow Orchestration]
A <-->|WebSocket| C[Workflow Runner<br>CPU/GPU Local/Cloud]
B <-->|Internal RPC| C
C -->|Optional API Calls| F[External Providers<br>OpenAI / Replicate / Anthropic / HF / Others]
classDef default fill:#e0eee0,stroke:#333,stroke-width:2px,color:#000;
classDef frontend fill:#ffcccc,stroke:#333,stroke-width:2px,color:#000;
classDef server fill:#cce5ff,stroke:#333,stroke-width:2px,color:#000;
classDef runner fill:#ccffe5,stroke:#333,stroke-width:2px,color:#000;
classDef api fill:#e0e0e0,stroke:#333,stroke-width:2px,color:#000;
classDef other fill:#d3d3d3,stroke:#333,stroke-width:2px,color:#000;
class A frontend;
class B server;
class C runner;
class E other;
class F api;
• Each node runs in its own async task. No central loop.
• Every node has an input queue (NodeInbox) that delivers data in order and tracks when it ends.
• Streaming nodes handle data piece by piece (gen_process); batch nodes handle all at once (process).
• When finished or failing, nodes signal “done” downstream so others don’t wait forever.
• GPU jobs run one at a time with a global lock, with retries and cleanup if memory runs out.
🤝 Contributing
We welcome contributions from the community! Please see our Contributing Guidelines for more information on how to get involved.
This setup is for developing the nodetool-core
library itself. If you want to set up the full NodeTool application (UI, backend, etc.), please refer to the development setup instructions in the main NodeTool repository.
-
Clone the repository
git clone https://github.com/yourusername/nodetool-core.git cd nodetool-core
-
Install dependencies
# Using conda + uv (recommended) conda create -n nodetool python=3.11 pandoc ffmpeg -c conda-forge conda activate nodetool uv sync --group dev # Or using pip only pip install . pip install -r requirements-dev.txt
-
Environment Configuration
Set up your environment configuration for development:
# Copy the example file to create your local config cp .env.example .env.development.local
Edit
.env.development.local
and add your API keys:# Required for most functionality OPENAI_API_KEY=your_openai_key_here ANTHROPIC_API_KEY=your_anthropic_key_here # Optional - add as needed GEMINI_API_KEY=your_gemini_key_here HF_TOKEN=your_huggingface_token_here REPLICATE_API_TOKEN=your_replicate_token_here
Security Note: Never commit
.env.*.local
files - they contain your actual API keys and are automatically gitignored. -
Environment Files Overview
.env.example
- Template with all configuration options.env.development
- Development defaults (committed, no secrets).env.test
- Test environment configuration.env.production
- Production configuration template.env.*.local
- Your actual secrets (gitignored)
The system automatically loads the appropriate config based on your environment.
This example shows how to create a workflow that loads a PDF document, extracts text, splits it into sentences, and indexes the chunks in a ChromaDB vector database for later retrieval:
import asyncio
import os
from nodetool.dsl.graph import graph, run_graph
from nodetool.dsl.chroma.collections import Collection
from nodetool.dsl.chroma.index import IndexTextChunks
from nodetool.dsl.lib.langchain import SentenceSplitter
from nodetool.dsl.lib.pymupdf import ExtractText
from nodetool.dsl.nodetool.os import LoadDocumentFile
from nodetool.metadata.types import FilePath, LlamaModel
# Set up paths
dirname = os.path.dirname(__file__)
file_path = os.path.join(dirname, "deepseek_r1.pdf")
# Create indexing workflow
g = IndexTextChunks(
collection=Collection(name="papers"),
text_chunks=SentenceSplitter(
text=ExtractText(
pdf=LoadDocumentFile(path=FilePath(path=file_path)),
),
document_id=file_path,
),
)
# Run the workflow
asyncio.run(run_graph(graph(g)))
When using NodeTool programmatically, keep these key concepts in mind:
-
Nodes: Each node represents a specific operation or function. Nodes have inputs and outputs that can be connected to form a workflow.
-
Graph: A collection of nodes and their connections, representing the entire workflow.
-
DSL (Domain-Specific Language): NodeTool provides a Python DSL for creating workflows, with specialized modules for different domains (e.g.,
nodetool.dsl.google.mail
,nodetool.dsl.chroma.collections
). -
Execution: Workflows are executed using the
run_graph
function, which takes a graph object created with thegraph
function.
NodeTool provides a powerful Workflow API that allows you to integrate and run your AI workflows programmatically.
You can use the API locally now, api.nodetool.ai
access is limited to Alpha users.
const response = await fetch("http://localhost:8000/api/workflows/");
const workflows = await response.json();
curl -X POST "http://localhost:8000/api/workflows/<workflow_id>/run" \
-H "Content-Type: application/json" \
-d '{
"params": {
"param_name": "param_value"
}
}'
const response = await fetch(
"http://localhost:8000/api/workflows/<workflow_id>/run",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
params: params,
}),
}
);
const outputs = await response.json();
// outputs is an object with one property for each output node in the workflow
// the value is the output of the node, which can be a string, image, audio, etc.
The WebSocket API is useful for getting real-time updates on the status of the workflow. It is similar to the streaming API, but it uses a more efficient binary encoding. It offers additional features like canceling jobs.
See run_workflow_websocket.js for an example.
const socket = new WebSocket("ws://localhost:8000/predict");
const request = {
type: "run_job_request",
workflow_id: "YOUR_WORKFLOW_ID",
params: {
/* workflow parameters */
},
};
// Run a workflow
socket.send(
msgpack.encode({
command: "run_job",
data: request,
})
);
// Handle messages from the server
socket.onmessage = async (event) => {
const data = msgpack.decode(new Uint8Array(await event.data.arrayBuffer()));
if (data.type === "job_update" && data.status === "completed") {
console.log("Workflow completed:", data.result);
} else if (data.type === "node_update") {
console.log("Node update:", data.node_name, data.status, data.error);
} else if (data.type === "node_progress") {
console.log("Progress:", (data.progress / data.total) * 100);
}
// Handle other message types as needed
};
// Cancel a running job
socket.send(msgpack.encode({ command: "cancel_job" }));
// Get the status of the job
socket.send(msgpack.encode({ command: "get_status" }));
NodeTool Core uses environment-specific configuration files for managing different deployment scenarios. The configuration system supports multiple environments with automatic loading based on context.
.env.example
- Complete template with all available options.env.development
- Development environment defaults.env.test
- Test environment configuration.env.production
- Production environment template.env.*.local
- Local overrides with actual secrets (gitignored)
Configuration is loaded in this order (later sources override earlier ones):
- Default values from code
- Base
.env
file - Environment-specific file (
.env.development
,.env.test
, or.env.production
) - Local override file (
.env.{environment}.local
) - System environment variables
- YAML settings/secrets files
Variable | Description | Default |
---|---|---|
ENV |
Environment name (development , test , production ) |
development |
DEBUG |
Enable debug mode | None |
LOG_LEVEL |
Logging level | INFO |
REMOTE_AUTH |
Enable remote authentication | 0 |
Variable | Description | Group |
---|---|---|
OPENAI_API_KEY |
OpenAI API key for GPT models, DALL-E | LLM |
ANTHROPIC_API_KEY |
Anthropic API key for Claude models | LLM |
GEMINI_API_KEY |
Google Gemini API key | LLM |
HF_TOKEN |
Hugging Face token for gated models | Hugging Face |
REPLICATE_API_TOKEN |
Replicate API token | Replicate |
ELEVENLABS_API_KEY |
ElevenLabs text-to-speech API key | ElevenLabs |
FAL_API_KEY |
FAL.ai serverless AI infrastructure key | FAL |
AIME_USER |
Aime service username | Aime |
AIME_API_KEY |
Aime API key | Aime |
Variable | Description | Default |
---|---|---|
DB_PATH |
SQLite database path | ~/.config/nodetool/nodetool.sqlite3 |
POSTGRES_DB |
PostgreSQL database name | - |
POSTGRES_USER |
PostgreSQL username | - |
POSTGRES_PASSWORD |
PostgreSQL password | - |
POSTGRES_HOST |
PostgreSQL host | - |
POSTGRES_PORT |
PostgreSQL port | - |
SUPABASE_URL |
Supabase project URL | - |
SUPABASE_KEY |
Supabase service key | - |
Variable | Description | Default |
---|---|---|
ASSET_BUCKET |
S3 bucket for assets | images |
ASSET_TEMP_BUCKET |
S3 bucket for temporary assets | - |
ASSET_DOMAIN |
Asset CDN domain | - |
ASSET_TEMP_DOMAIN |
Temporary asset domain | - |
S3_ACCESS_KEY_ID |
AWS access key ID | - |
S3_SECRET_ACCESS_KEY |
AWS secret access key | - |
S3_ENDPOINT_URL |
S3 endpoint URL | - |
S3_REGION |
S3 region | - |
AWS_REGION |
AWS region | us-east-1 |
Variable | Description | Default |
---|---|---|
CHROMA_PATH |
ChromaDB storage path | ~/.local/share/nodetool/chroma |
CHROMA_URL |
Remote ChromaDB URL | - |
CHROMA_TOKEN |
ChromaDB authentication token | - |
OLLAMA_API_URL |
Ollama API endpoint | http://127.0.0.1:11434 |
OLLAMA_MODELS |
Custom Ollama models path | - |
Variable | Description | Group |
---|---|---|
GOOGLE_MAIL_USER |
Gmail address for email integration | |
GOOGLE_APP_PASSWORD |
Google app password | |
SERPAPI_API_KEY |
SerpAPI key for web scraping | SerpAPI |
DATA_FOR_SEO_LOGIN |
DataForSEO login | DataForSEO |
DATA_FOR_SEO_PASSWORD |
DataForSEO password | DataForSEO |
BROWSER_URL |
Browser automation endpoint | Browser |
Variable | Description | Default |
---|---|---|
FFMPEG_PATH |
Path to ffmpeg executable | ffmpeg |
FFPROBE_PATH |
Path to ffprobe executable | ffprobe |
FONT_PATH |
Font directory for text rendering | - |
COMFY_FOLDER |
ComfyUI integration folder | - |
Variable | Description | Default |
---|---|---|
NODETOOL_API_URL |
NodeTool API base URL | http://localhost:8000 |
RUNPOD_API_KEY |
RunPod API key for cloud deployment | - |
SENTRY_DSN |
Sentry error tracking DSN | - |
MEMCACHE_HOST |
Memcache server host | - |
MEMCACHE_PORT |
Memcache server port | - |
The system automatically detects the environment from:
ENV
environment variablePYTEST_CURRENT_TEST
(automatically sets test environment)- Defaults to "development"
For a complete template with all options, see .env.example
in the repository.
-
Clone the repository
-
Install dependencies :
# Using conda + uv (recommended) conda create -n nodetool python=3.11 pandoc ffmpeg -c conda-forge conda activate nodetool uv sync # Or using pip only pip install .
Run tests with pytest:
# Using uv (recommended)
uv run pytest
# Or directly if using activated environment
pytest