Getting Started
Build agents
- Agent architecture
- Builder SDK
- Node types
- Edges
- Tools reference
- Execution flow
- Build with AI editors
Flows
Test agents
Integrations
- AI models
- WhatsApp
- API & Webhooks
Build agents
Build with AI editors
Add this to your .cursorrules or CLAUDE.md file.
Copy
## Quick Start
```bash
pip install kapso
kapso init # Create new project
kapso run # Test locally
kapso run --cloud # Test in cloud (with visual debugger)
kapso deploy # Deploy to cloud
```
## Core Architecture Pattern (Recommended)
```python
from kapso.builder import Agent
from kapso.builder.nodes import SubagentNode, WarmEndNode, HandoffNode
from kapso.builder.nodes.subagent import WebhookTool, KnowledgeBaseTool
from kapso.builder.agent.constants import START_NODE, END_NODE
agent = Agent(name="my_agent", system_prompt="You are a helpful assistant")
# Main node: SubagentNode (preferred over individual nodes)
assistant = SubagentNode(
name="assistant",
prompt="Help users with available tools",
global_=False, # or True for global access
global_condition="trigger condition if global"
)
# Add tools to SubagentNode
assistant.add_tool(WebhookTool(...))
assistant.add_tool(KnowledgeBaseTool(...))
# Global handoff
handoff = HandoffNode(
name="human",
global_=True,
global_condition="if user requests human"
)
# Conversation end
end = WarmEndNode(
name="end",
timeout_minutes=30,
prompt="Say goodbye message"
)
# Build graph
agent.add_node(START_NODE)
agent.add_node(assistant)
agent.add_node(handoff)
agent.add_node(end)
agent.add_node(END_NODE)
agent.add_edge(START_NODE, "assistant")
agent.add_edge("assistant", "end", condition="if conversation complete")
agent.add_edge("end", END_NODE)
```
## Node Types & Attributes
### DefaultNode
**Purpose**: Basic conversational node for simple interactions and routing
```python
DefaultNode(
name="string", # Required: alphanumeric + underscore
prompt="string", # Optional: instructions
global_=False, # Optional: global access
global_condition="string" # Required if global_=True
)
```
**Built-in tools**: send_notification_to_user, AskUserForInput, MoveToNextNode, EnterIdleState
### SubagentNode (Recommended)
**Purpose**: The preferred node type - combines multiple tools (webhooks, knowledge bases, WhatsApp, MCP) in one powerful node. Use this unless you need a very specific, tight control flow.
```python
SubagentNode(
name="string",
prompt="string",
global_=False,
global_condition="string"
)
```
**Built-in tools**: All DefaultNode tools + kb_retrieval, SendWhatsappTemplateMessage
**Add custom tools**: WebhookTool, KnowledgeBaseTool, McpServerTool, WhatsappTemplateTool
### WebhookNode
**Purpose**: Single API call node - use when you need tight control over one specific webhook
```python
WebhookNode(
name="string",
url="https://api.example.com/#{variable}",
http_method="GET|POST|PUT|PATCH|DELETE",
headers={"key": "value"},
body_schema={...}, # JSON Schema validation
jmespath_query="data[0]", # Response filtering
mock_response={...}, # Test data
mock_response_enabled=True,
prompt="string",
global_=False,
global_condition="string"
)
```
**Built-in tools**: All DefaultNode tools + webhook_request
### KnowledgeBaseNode
**Purpose**: Single knowledge base access - use when you need tight control over one specific KB
```python
KnowledgeBaseNode(
name="string",
key="unique_key", # Required
knowledge_base_text="...", # Option 1: inline text
knowledge_base_file="path", # Option 2: file path
prompt="string",
global_=False,
global_condition="string"
)
```
**Built-in tools**: All DefaultNode tools + kb_retrieval
### HandoffNode
**Purpose**: Transfer conversation to human agent. Does NOT execute anything - just handoff and stop. Any messages to user must be in previous node.
```python
HandoffNode(
name="string",
global_=False, # Usually True
global_condition="string"
)
```
**Built-in tools**: None (forwards control)
### WarmEndNode
**Purpose**: End conversation with timeout - allows user to continue chatting within timeout window
```python
WarmEndNode(
name="string",
timeout_minutes=30, # Keep conversation open
prompt="string",
global_=False,
global_condition="string"
)
```
**Built-in tools**: send_notification_to_user, EnterIdleState, MoveToNextNode (no AskUserForInput)
### WhatsAppTemplateNode
**Purpose**: Send pre-approved WhatsApp template messages
```python
WhatsAppTemplateNode(
name="string",
template_name="string",
phone_number="#{variable}",
template_parameters={"1": "#{value}"},
wait_for_response=False,
whatsapp_config_id="string",
whatsapp_template_id="string",
prompt="string",
global_=False,
global_condition="string"
)
```
**Built-in tools**: All DefaultNode tools + SendWhatsappTemplateMessage
## SubagentNode Tools
### WebhookTool
```python
WebhookTool(
name="api_call",
url="https://api.example.com",
http_method="POST",
headers={"Authorization": "Bearer #{token}"},
body_schema={...},
jmespath_query="results[0]",
mock_response={...},
mock_response_enabled=True,
description="Tool description"
)
```
### KnowledgeBaseTool
```python
# From text
KnowledgeBaseTool(
name="kb",
knowledge_base_text="Content...",
description="Search knowledge"
)
# From file
KnowledgeBaseTool.from_file(
name="kb",
file_path="docs/manual.pdf",
description="Search docs"
)
```
### McpServerTool
```python
McpServerTool(
name="mcp",
url="https://mcp.example.com",
transport_kind="sse|streamable_http",
jmespath_queries=[
JmespathQuery(
tool_name="calculator",
jmespath_query="tools[?type=='math']"
)
],
description="MCP tools"
)
```
### WhatsappTemplateTool
```python
WhatsappTemplateTool(
name="notify",
template_name="order_update",
phone_number="#{phone}",
template_parameters={"1": "#{name}"},
wait_for_response=True,
whatsapp_config_id="config_123",
whatsapp_template_id="template_456",
description="Send WhatsApp"
)
```
## Graph Rules & Flow Control
### Essential Rules
1. **START_NODE and END_NODE must exist** in every agent
2. **Only ONE node can connect from START** - START → single_node
3. **Node prompts are LLM instructions**, not user-facing messages
4. **A node cannot connect to itself** - no self-loops
5. **Global nodes are NOT connected** - they're available everywhere and return to calling node
6. **HandoffNode stops execution** - put any user messages in previous node
### Edges & Flow
```python
# Simple edge
agent.add_edge("source", "target")
# Conditional edge
agent.add_edge("source", "target", condition="user says X")
# Special nodes
START_NODE # Entry point (exactly one outgoing edge)
END_NODE # Exit point (can have multiple incoming)
# Global nodes - no edges needed
global_node = DefaultNode(name="help", global_=True, global_condition="user asks for help")
# Automatically available from any node when condition is met
```
## CLI Commands
```bash
kapso init [--template basic|support|knowledge-base]
kapso login # Authenticate
kapso compile # Python → YAML
kapso run [--cloud] [--verbose]
kapso test ["Test Name"] [--verbose]
kapso deploy # Upload to cloud
kapso pull # Download from cloud
kapso logout
kapso version
# Global options: --verbose, --config file.yaml
```
## Testing (YAML Format)
### Test Suite Organization
```
tests/
├── customer_support/ # Suite directory (sanitized name)
│ ├── test-suite.yaml # Suite metadata
│ │ id: suite_id # From pull
│ │ name: Customer Support Tests
│ │ description: Test suite description
│ ├── greeting_test.yaml # Test case files
│ └── order_test.yaml
└── product_search/
├── test-suite.yaml
└── search_test.yaml
```
### Test Case Format
```yaml
# tests/suite_name/test_name.yaml
name: greeting_test
description: Test if agent greets appropriately
script: |
1. Start by saying "Hello, how are you?"
2. When the agent responds with a greeting, thank them
3. If they ask how they can help, say "I need help with my order"
4. Observe if they offer to check order status
rubric: |
1. Warm and professional greeting (40%)
2. Acknowledges user's greeting (30%)
3. Offers specific help for orders (30%)
# Note: id field is auto-added during kapso deploy
# Scores range from 0.00 to 1.00
```
### Script Writing (LLM Instructions)
- Use numbered steps for clarity
- Write as instructions: "Start by...", "When agent...", "Say..."
- Include conditionals: "If agent asks X, respond with Y"
- Specify expected behaviors: "Observe if...", "Check that..."
## Environment Variables (.env)
```bash
# LLM Configuration
LLM_PROVIDER_NAME=Anthropic
LLM_PROVIDER_MODEL_NAME=claude-sonnet-4-20250514
LLM_API_KEY=your-key
LLM_TEMPERATURE=0.0
LLM_MAX_TOKENS=8096
# APIs
OPENAI_API_KEY=your-key # For embeddings
# Custom variables
#{variable_name} # Use in nodes/tools
```
## Node Prompts & Tool Usage
### Referencing Tools in Prompts
You can instruct the LLM to use specific built-in tools in node prompts:
```python
DefaultNode(
name="notify",
prompt="Use send_notification_to_user to inform the user about their order status"
)
SubagentNode(
name="assistant",
prompt="When the user asks about weather, use the weather_api tool. For FAQs, use the kb_search tool."
)
WarmEndNode(
name="goodbye",
prompt="Thank the user and use send_notification_to_user to send a follow-up message"
)
```
### Available Built-in Tools by Node
- **send_notification_to_user**: Send messages to user
- **AskUserForInput**: Request specific information from user
- **MoveToNextNode**: Navigate to specific nodes
- **EnterIdleState**: Pause and wait
- **kb_retrieval**: Search knowledge bases (KB/Subagent nodes)
- **webhook_request**: Make API calls (Webhook nodes)
- **SendWhatsappTemplateMessage**: Send WhatsApp templates
## Best Practices
1. **Use SubagentNode** instead of individual nodes when possible
2. **Global nodes**: Use sparingly (handoff, help menus)
3. **Edge conditions**: Natural language, no overlap
4. **Mock responses**: Enable during development
5. **Variables**: #{variable_name} in URLs, headers, bodies
6. **Node names**: lowercase_with_underscores
7. **Validation**: Always call agent.validate()
8. **Tool references**: Name specific tools in prompts when needed
## Quick Examples
### API Integration
```python
tool = WebhookTool(
name="weather",
url="https://api.weather.com/current?city=#{city}",
http_method="GET",
headers={"X-API-Key": "#{WEATHER_KEY}"},
jmespath_query="current.temp_f",
description="Get weather"
)
```
### Knowledge Base Search
```python
tool = KnowledgeBaseTool(
name="faq",
knowledge_base_text="Q: Hours? A: 9-5 M-F",
description="FAQ answers"
)
```
### Global Help Menu
```python
help = DefaultNode(
name="help",
prompt="Show menu: 1) Status 2) Support 3) Info",
global_=True,
global_condition="user says help or menu"
)
```
## Debug Tips
- Run with `--verbose` flag
- Check `.deployed.yaml` for deployment state
- Use mock responses to test without APIs
- Validate before deploying
- Test incrementally with `kapso run`
Assistant
Responses are generated using AI and may contain mistakes.