An easy-to-deploy Python-based OpenTelemetry integration for Cursor IDE that captures agent activity and exports detailed traces to any OTEL-compliant receiver.
Developed for use with LangGuard.AI's AI Control Plane
Features
-
LangGuard/LangSmith/LangChain Compatible: Uses official GenAI semantic conventions and LangSmith attribute mappings for seamless integration with:
- LangGuard - LangGuard's AI Control Plane
- Langfuse - Open-source LLM observability
- Any OTLP backend
-
Comprehensive Tracing: Captures all Cursor IDE hook events including:
- Session lifecycle (start/end)
- Tool usage (pre/post/failure)
- Shell command execution
- MCP (Model Context Protocol) calls
- File operations (read/edit)
- Prompt submissions
- Context compaction events
- Subagent activities
-
Generation-based Batching: When using HTTP/JSON protocol, spans are automatically batched by generation_id and sent as a single payload when the 'stop' event is received. This provides better trace coherence and reduces network overhead.
-
Custom JSON Exporter: Includes a custom OTLP/JSON exporter for platforms that require JSON format
-
Privacy Controls: Built-in data masking to protect sensitive user information
-
Flexible Configuration: Support for both environment variables and JSON config files
-
Easy Setup: Automated installation scripts for Windows and macOS/Linux
-
Multiple Protocols: Supports gRPC, HTTP/Protobuf, and HTTP/JSON
Quick Start
Prerequisites
- Python 3.8 or higher
- Cursor IDE
- An OpenTelemetry collector or compatible backend
Installation
macOS/Linux
# Clone or download this repository cd cursor_otel_hook # Run the setup script ./setup.sh
Windows
# Clone or download this repository cd cursor_otel_hook # Run the setup script powershell -ExecutionPolicy Bypass -File setup.ps1
The setup script will:
- Create a Python virtual environment
- Install the package and dependencies
- Create a wrapper script in
~/.cursor/hooks/ - Generate default configuration files
- Configure Cursor hooks to use the OTEL exporter
Enterprise/MDM Deployment
For enterprise deployments via MDM (Mobile Device Management) systems like Jamf Pro or Microsoft Intune, pre-built installer packages are available that support headless installation with centralized configuration.
Features
- Standalone executables - No Python installation required (bundled via PyInstaller)
- MDM variable injection - Configure OTEL endpoint, API keys, and settings at install time
- Per-user deployment - Automatically deploys to each user's
~/.cursor/hooks/directory - Silent installation - Fully headless, no user interaction required
Download
Download the latest packages from the Releases page:
- macOS:
cursor-otel-hook-X.X.X.pkg - Windows:
cursor-otel-hook-X.X.X.msi
macOS MDM Deployment
Installation with Jamf Pro
- Upload the
.pkgto Jamf Pro - Create a Policy with the package
- Add a pre-install script to set configuration variables:
#!/bin/bash # Set these environment variables before the installer runs export OTEL_ENDPOINT="https://otel.company.com:4318/v1/traces" export SERVICE_NAME="cursor-agent-prod" export OTEL_PROTOCOL="http/json" export OTEL_HEADERS='{"Authorization": "Bearer YOUR_API_KEY"}' export MASK_PROMPTS="true"
- Scope to target computers
- Set trigger (enrollment, recurring check-in, etc.)
Command-Line Installation
# Basic installation (uses defaults) sudo installer -pkg cursor-otel-hook-1.0.0.pkg -target / # Installation with custom configuration export OTEL_ENDPOINT="https://otel.company.com:4318/v1/traces" export SERVICE_NAME="cursor-agent-prod" export OTEL_PROTOCOL="http/json" export OTEL_HEADERS='{"Authorization": "Bearer YOUR_API_KEY"}' sudo installer -pkg cursor-otel-hook-1.0.0.pkg -target /
How It Works (macOS)
- System install: Package installs to
/Library/Application Support/CursorOtelHook/ - LaunchAgent: A LaunchAgent runs at each user login to deploy files
- Per-user setup: Copies executable and config to
~/.cursor/hooks/ - Daily sync: LaunchAgent re-runs daily to keep config in sync with system
Windows MDM Deployment
Installation with Microsoft Intune
- Upload the
.msias a Line-of-business app - Set the install command with your configuration:
msiexec /i cursor-otel-hook-1.0.0.msi /qn OTEL_ENDPOINT="https://otel.company.com:4318/v1/traces" SERVICE_NAME="cursor-agent-prod" OTEL_PROTOCOL="http/json"
- Set uninstall command:
msiexec /x {ProductCode} /qn
- Assign to user/device groups
Command-Line Installation
# Basic silent installation msiexec /i cursor-otel-hook-1.0.0.msi /qn # Installation with custom configuration msiexec /i cursor-otel-hook-1.0.0.msi /qn ` OTEL_ENDPOINT="https://otel.company.com:4318/v1/traces" ` SERVICE_NAME="cursor-agent-prod" ` OTEL_PROTOCOL="http/json" ` OTEL_HEADERS="{\"Authorization\": \"Bearer YOUR_API_KEY\"}"
How It Works (Windows)
- System install: MSI installs to
C:\Program Files\CursorOtelHook\ - Active Setup: Registry entry triggers per-user setup at first login
- Per-user setup: PowerShell script copies files to
%USERPROFILE%\.cursor\hooks\
MDM Configuration Variables
| Variable | Description | Default | Required |
|---|---|---|---|
OTEL_ENDPOINT |
OTLP collector endpoint URL | http://localhost:4318/v1/traces |
Yes |
SERVICE_NAME |
Service identifier in traces | cursor-agent |
No |
OTEL_PROTOCOL |
Protocol: grpc, http/protobuf, http/json |
http/json |
No |
OTEL_HEADERS |
JSON object with auth headers | null |
No |
OTEL_INSECURE |
Allow insecure TLS (true/false) |
false |
No |
MASK_PROMPTS |
Mask user prompts for privacy | false |
No |
OTEL_TIMEOUT |
Request timeout in seconds | 30 |
No |
Building Packages from Source
If you need to build custom packages:
Prerequisites
macOS:
- Python 3.8+
- Xcode Command Line Tools
- PyInstaller (
pip install pyinstaller)
Windows:
- Python 3.8+
- WiX Toolset v3.11+
- PyInstaller (
pip install pyinstaller)
Build Commands
macOS:
# Build standalone executable cd packaging/pyinstaller && ./build_macos.sh # Build PKG installer cd ../macos && ./build_pkg.sh # Output: dist/macos/cursor-otel-hook-X.X.X.pkg
Windows:
# Build standalone executable cd packaging\pyinstaller; .\build_windows.ps1 # Build MSI installer cd ..\windows; .\build_msi.ps1 # Output: dist\windows\cursor-otel-hook-X.X.X.msi
CI/CD
GitHub Actions workflows are provided in packaging/ci/:
build-macos.yml- Builds macOS PKG on tag pushbuild-windows.yml- Builds Windows MSI on tag push
Verifying Installation
After MDM deployment, verify the installation:
macOS:
# Check system installation ls -la "/Library/Application Support/CursorOtelHook/" # Check user installation (as the user) ls -la ~/.cursor/hooks/ # Test the hook echo '{"hook_event_name":"test"}' | ~/.cursor/hooks/cursor-otel-hook --config ~/.cursor/hooks/otel_config.json # View setup logs cat /tmp/cursor-otel-hook-setup-$USER.log
Windows:
# Check system installation dir "C:\Program Files\CursorOtelHook" # Check user installation dir "$env:USERPROFILE\.cursor\hooks" # Test the hook echo '{"hook_event_name":"test"}' | & "$env:USERPROFILE\.cursor\hooks\cursor-otel-hook.exe" --config "$env:USERPROFILE\.cursor\hooks\otel_config.json" # View setup logs Get-Content "$env:TEMP\cursor-otel-hook-setup.log"
Uninstalling
macOS:
# Uninstall system files sudo rm -rf "/Library/Application Support/CursorOtelHook" sudo rm -f "/Library/LaunchAgents/com.langguard.cursor-otel-hook-setup.plist" # Uninstall user files (run as user) rm -rf ~/.cursor/hooks/cursor-otel-hook rm -f ~/.cursor/hooks/otel_config.json
Windows:
# Uninstall via MSI msiexec /x cursor-otel-hook-1.0.0.msi /qn # Or via Add/Remove Programs # The per-user files can be cleaned up with: & "C:\Program Files\CursorOtelHook\scripts\Uninstall-UserHook.ps1"
Configuration
JSON Configuration File (Recommended)
The setup script creates a configuration file at otel_config.json in the cursor hooks directory. This is the recommended way to configure the hook as it doesn't require setting environment variables in Cursor.
The config file uses standard OTEL environment variable names as JSON keys:
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317",
"OTEL_SERVICE_NAME": "cursor-agent",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_INSECURE": "true",
"OTEL_EXPORTER_OTLP_HEADERS": null,
"CURSOR_OTEL_MASK_PROMPTS": "false",
"OTEL_EXPORTER_OTLP_TIMEOUT": "30"
}With Authentication:
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-collector:4317",
"OTEL_SERVICE_NAME": "cursor-agent",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_INSECURE": "false",
"OTEL_EXPORTER_OTLP_HEADERS": {
"authorization": "Bearer YOUR_TOKEN"
}
}HTTP Protocol Examples:
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://your-collector/v1/traces",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf"
}HTTP with JSON (for LangSmith/Langfuse):
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://api.smith.langchain.com/v1/traces",
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
"OTEL_EXPORTER_OTLP_HEADERS": {
"Authorization": "Bearer YOUR_API_KEY"
}
}Headers as String (Alternative):
You can also specify headers as a comma-separated string, just like the environment variable:
{
"OTEL_EXPORTER_OTLP_ENDPOINT": "https://your-collector:4317",
"OTEL_EXPORTER_OTLP_HEADERS": "authorization=Bearer TOKEN,x-tenant-id=123"
}The wrapper script automatically uses this config file, so no environment variables are needed in Cursor.
Environment Variables (Alternative)
You can also configure the hook using environment variables in your cursor session:
# Required: OTEL endpoint export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" # Optional: Service name (default: cursor-agent) export OTEL_SERVICE_NAME="my-cursor-agent" # Optional: Use insecure connection (default: true) export OTEL_EXPORTER_OTLP_INSECURE="true" # Optional: Custom headers (comma-separated key=value pairs) export OTEL_EXPORTER_OTLP_HEADERS="api-key=secret123,env=production" # Optional: Timeout in seconds (default: 30) export OTEL_EXPORTER_OTLP_TIMEOUT="30" # Optional: Mask user prompts for privacy (default: false) export CURSOR_OTEL_MASK_PROMPTS="true" # Optional: Protocol - "grpc" or "http" (default: grpc) export OTEL_EXPORTER_OTLP_PROTOCOL="grpc"
Protocol Selection:
- gRPC (default): Binary protocol, most efficient
- http/protobuf: HTTP with protobuf encoding
- http/json: HTTP with JSON encoding (recommended for LangSmith/Langfuse)
# Use gRPC (default) export OTEL_EXPORTER_OTLP_PROTOCOL="grpc" export OTEL_EXPORTER_OTLP_ENDPOINT="http://your-collector:4317" # Use HTTP with Protobuf export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" export OTEL_EXPORTER_OTLP_ENDPOINT="http://your-collector:4318/v1/traces" # Use HTTP with JSON (for LangSmith/Langfuse) export OTEL_EXPORTER_OTLP_PROTOCOL="http/json" export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.smith.langchain.com/v1/traces"
Note:
- Endpoint format depends on your OTEL collector configuration. See the OpenTelemetry Protocol Specification for details.
- When using environment variables, you must set them in your shell/system, not in Cursor's settings.
- The JSON config file approach (recommended) avoids the need to set environment variables.
Usage
Once installed and configured, the hooks will automatically run whenever you use Cursor. The traces will be sent to your configured OTEL endpoint.
Span Attributes
This hook uses LangSmith/LangChain OpenTelemetry conventions for maximum compatibility with LLM observability platforms like LangSmith, Langfuse, and other OTLP-compatible systems.
Common Attributes (All Spans)
Session & Trace IDs (LangSmith convention):
langsmith.trace.session_id: Conversation identifier (from Cursor's conversation_id)langsmith.trace.id: OpenTelemetry trace ID (derived from span context, not generation_id)langsmith.span.id: OpenTelemetry span ID (derived from span context)langsmith.span.parent_id: Parent span ID when applicable (derived from span context)
Model Information (GenAI convention):
gen_ai.system: Provider name (anthropic, openai, cursor)gen_ai.request.model: AI model being used (e.g., "claude-sonnet-4-5")gen_ai.response.model: Model used in response
Operation Type:
gen_ai.operation.name: Operation type (chat, tool, chain, session)langsmith.span.kind: Span classification (llm, tool, chain)
Metadata:
langsmith.metadata.hook_event: Original Cursor hook event namelangsmith.metadata.generation_id: Cursor's generation identifier (preserved as metadata)langsmith.metadata.cursor_version: Cursor IDE versionlangsmith.metadata.user_email: User email (can be masked)langsmith.metadata.workspace_roots: Project directorieslangsmith.metadata.duration_ms: Event duration in milliseconds
Event-Specific Attributes
Prompts (GenAI convention):
gen_ai.prompt.0.role: Message role (typically "user")gen_ai.prompt.0.content: User prompt text (can be masked)
Tool Usage (GenAI convention):
gen_ai.tool.name: Tool name (e.g., "Read", "bash", "edit_file")gen_ai.tool.arguments: Tool input parameters (JSON)langsmith.metadata.tool_input: Detailed tool inputlangsmith.metadata.tool_output: Tool output (truncated if large)
Shell Execution (treated as tool):
gen_ai.tool.name: "bash"gen_ai.tool.arguments: Command in JSON formatlangsmith.metadata.shell_command: Command being executedlangsmith.metadata.shell_cwd: Working directorylangsmith.metadata.shell_exit_code: Command exit code
MCP Calls (treated as tool):
gen_ai.tool.name: Format: "{server}.{tool}"gen_ai.tool.arguments: MCP call parameters (JSON)langsmith.metadata.mcp_server: MCP server name
File Operations (treated as tool):
gen_ai.tool.name: "read_file" or "edit_file"gen_ai.tool.arguments: File path in JSON formatlangsmith.metadata.file_path: File being accessedlangsmith.metadata.edit_count: Number of edits in operation
Subagent Activities:
langsmith.span.kind: "chain"langsmith.metadata.subagent_type: Type of subagentlangsmith.metadata.subagent_task: Task description
Generation-based Span Batching
When using the http/json protocol, the hook automatically implements generation-based batching to improve trace coherence and reduce network overhead.
How It Works
-
Span Storage: As each hook event is processed, spans are converted to OTLP JSON format and stored in temporary files, grouped by
generation_id. -
Temporary Files: Spans are stored in
{temp_dir}/cursor_otel_spans/{generation_id}.jsonl, where each line is a JSON-formatted span. -
Batched Export: When a 'stop' hook event is received for a generation_id, all stored spans for that generation are:
- Read from the temporary file
- Combined into a single OTLP JSON payload
- Sent as one request to the OTEL receiver
- The temporary file is deleted after successful export
-
Automatic Cleanup: Temporary files older than 24 hours are automatically removed to prevent disk accumulation.
Parent-Child Span Relationships
The hook automatically maintains proper parent-child relationships between spans across process invocations:
Span Hierarchy:
- Root Spans:
sessionStart,beforeSubmitPrompt(start new trace contexts) - Session Children:
subagentStart, tool events (when not in subagent) - Subagent Children: Tool events during subagent execution
- Tool Children:
postToolUse,postToolUseFailure,afterShellExecution,afterMCPExecution,afterFileEdit(children of their corresponding start events)
Context Management:
Context is persisted across process invocations using temporary files ({temp_dir}/cursor_otel_context/{generation_id}_context.json):
- Tracks current session span, subagent span, and tool span
- Each hook event looks up its appropriate parent span
- Proper parent span_id is set when creating child spans
- Context is cleaned up after the 'stop' event
Example Trace Structure:
sessionStart (root)
├── subagentStart (child of session)
│ ├── preToolUse: Read (child of subagent)
│ │ └── postToolUse: Read (child of tool)
│ ├── preToolUse: Edit (child of subagent)
│ │ └── postToolUse: Edit (child of tool)
│ └── subagentStop (child of subagent)
└── stop (child of session)
Benefits
- Better Trace Coherence: All spans for a single generation are sent together, making it easier for trace backends to assemble complete traces
- Proper Parent-Child Relationships: Spans correctly reference their parent spans, even across separate process invocations
- Reduced Network Overhead: Instead of N individual requests (one per span), only one batched request is sent per generation
- Improved Reliability: If a span export fails, it doesn't affect the storage of other spans
- Correct ID Derivation: All spans maintain proper OpenTelemetry trace_id, span_id, and parent_span_id relationships
Requirements
- Only available when using
OTEL_EXPORTER_OTLP_PROTOCOL="http/json" - For other protocols (gRPC, http/protobuf), spans are sent immediately using standard BatchSpanProcessor (without cross-process parent-child relationships)
Privacy and Security
Data Masking
When CURSOR_OTEL_MASK_PROMPTS=true, the following fields are masked:
- User prompts and messages
- Tool inputs and outputs
- File paths (username components)
- Email addresses (partially masked)
- Command line arguments
What Gets Sent
By default, the hook sends:
- Timing information (durations, timestamps)
- Model and tool names
- Event types and status
- File paths and commands (unless masked)
- Conversation IDs, generation IDs (as metadata), and OpenTelemetry trace/span IDs
The hook never sends:
- API keys or authentication tokens (automatically filtered)
- File contents
- Raw code (only metadata)
OpenTelemetry Backends
This hook works with any OpenTelemetry-compliant backend using either gRPC or HTTP protocols.
For detailed OTLP protocol information, see:
Local Development with Jaeger
# Run Jaeger all-in-one (supports both gRPC and HTTP) docker run -d --name jaeger \ -p 4317:4317 \ -p 4318:4318 \ -p 16686:16686 \ jaegertracing/all-in-one:latest # Configure the hook (gRPC default) export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317" # Or use HTTP protocol export OTEL_EXPORTER_OTLP_PROTOCOL="http" export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318/v1/traces" # View traces at http://localhost:16686
Note: Check your backend's documentation for the correct endpoint URL and required headers. Each provider may have different requirements.
Hook Events Reference
| Event | When Triggered | Attributes |
|---|---|---|
sessionStart |
Agent session begins | session_id, composer_mode |
sessionEnd |
Agent session ends | session_id |
preToolUse |
Before tool execution | tool_name, tool_input |
postToolUse |
After tool execution | tool_name, tool_output |
postToolUseFailure |
Tool execution fails | tool_name, error |
beforeShellExecution |
Before shell command | command, cwd |
afterShellExecution |
After shell command | command, exit_code |
beforeMCPExecution |
Before MCP call | mcp_server, mcp_tool |
afterMCPExecution |
After MCP call | mcp_server, mcp_tool |
beforeReadFile |
Before file read | file_path |
afterFileEdit |
After file edit | file_path, edits |
beforeSubmitPrompt |
Before prompt submission | prompt |
stop |
Agent stops | status, loop_count |
subagentStart |
Subagent starts | subagent_type |
subagentStop |
Subagent stops | subagent_type |
Logging and Troubleshooting
Log Files
The hook automatically logs to ~/.cursor/hooks/cursor_otel_hook.log.
View logs:
# View recent entries tail -f ~/.cursor/hooks/cursor_otel_hook.log # Search for errors grep ERROR ~/.cursor/hooks/cursor_otel_hook.log # View all logs cat ~/.cursor/hooks/cursor_otel_hook.log
Enable debug logging:
Edit the wrapper script (~/.cursor/hooks/otel_hook.sh) to add --debug:
exec cursor-otel-hook --config "/path/to/otel_config.json" --debug "$@"
Debug mode features:
- Logs detailed DEBUG-level information to the log file
- Outputs logs to stderr (visible in Cursor)
- Preserves temporary OTLP JSON files for inspection (when using http/json protocol)
- Span files:
{temp_dir}/cursor_otel_spans/{generation_id}.jsonl - Context files:
{temp_dir}/cursor_otel_context/{generation_id}_context.json
- Span files:
Without debug mode:
- Only WARNING and ERROR messages are logged
- No stderr output
- Temporary files are automatically cleaned up after export
Common Issues
No traces appearing:
- Check log file for errors
- Verify OTEL endpoint is reachable:
curl http://localhost:4317 - Ensure collector is running:
docker ps | grep jaeger - Test manually:
echo '{"hook_event_name":"test"}' | cursor-otel-hook --config otel_config.json --debug
Hooks not firing:
- Check if log file is being created
- Verify
~/.cursor/hooks.jsonexists - Restart Cursor IDE
- Test wrapper script:
echo '{"hook_event_name":"test"}' | ~/.cursor/hooks/otel_hook.sh
Connection errors:
- For gRPC: Ensure port 4317 is accessible
- For HTTP: Ensure endpoint URL is correct
- Try switching protocols (gRPC ↔ HTTP)
Customization
Custom Hook Logic
To add custom logic (e.g., blocking certain operations), extend the CursorHookProcessor class:
from cursor_otel_hook.hook_receiver import CursorHookProcessor class CustomProcessor(CursorHookProcessor): def _generate_response(self, event, hook_data): # Block git commands if event == "beforeShellExecution": command = hook_data.get("command", "") if "git" in command: return { "permission": "deny", "user_message": "Git commands are blocked" } return super()._generate_response(event, hook_data)
Selective Hook Registration
Edit ~/.cursor/hooks.json to register hooks for only specific events:
{
"version": 1,
"hooks": {
"sessionStart": [{"command": "~/.cursor/hooks/otel_hook.sh", "timeout": 5}],
"sessionEnd": [{"command": "~/.cursor/hooks/otel_hook.sh", "timeout": 5}],
"preToolUse": [{"command": "~/.cursor/hooks/otel_hook.sh", "timeout": 5}],
"postToolUse": [{"command": "~/.cursor/hooks/otel_hook.sh", "timeout": 5}]
}
}Troubleshooting
Hooks Not Running
- Check if hooks are enabled in Cursor settings
- Verify the wrapper script is executable:
chmod +x ~/.cursor/hooks/otel_hook.sh - Check Cursor logs for hook errors
- Test manually:
echo '{"hook_event_name":"test"}' | ~/.cursor/hooks/otel_hook.sh
No Traces Appearing
- Verify OTEL endpoint is reachable:
curl http://localhost:4317 - Check if the collector is running
- Enable debug mode:
cursor-otel-hook --debug - Verify network connectivity and firewall rules
Performance Issues
- Reduce hook registrations (only essential events)
- Increase timeout values in
hooks.json - Use a local OTEL collector instead of remote endpoint
- Enable prompt masking to reduce payload size
Development
Running Tests
# Install dev dependencies pip install -e ".[dev]" # Run tests pytest tests/ # Format code black src/ # Type checking mypy src/
Project Structure
cursor_otel_hook/
├── src/
│ └── cursor_otel_hook/
│ ├── __init__.py
│ ├── __main__.py # CLI entry point
│ ├── batching_processor.py # Generation-based span batching
│ ├── config.py # Configuration management
│ ├── context_manager.py # Cross-process span context
│ ├── hook_receiver.py # Main hook processor
│ ├── json_exporter.py # Custom OTLP/JSON exporter
│ └── privacy.py # Data masking utilities
├── packaging/ # MDM/Enterprise packaging
│ ├── pyinstaller/ # PyInstaller build configs
│ │ ├── cursor_otel_hook.spec
│ │ ├── build_macos.sh
│ │ ├── build_windows.ps1
│ │ └── hooks/
│ ├── config/ # Configuration templates
│ │ ├── otel_config.template.json
│ │ └── hooks.template.json
│ ├── macos/ # macOS PKG packaging
│ │ ├── Distribution.xml
│ │ ├── build_pkg.sh
│ │ ├── scripts/
│ │ ├── launchagent/
│ │ └── resources/
│ ├── windows/ # Windows MSI packaging
│ │ ├── Product.wxs
│ │ ├── build_msi.ps1
│ │ └── scripts/
│ └── ci/ # GitHub Actions workflows
│ ├── build-macos.yml
│ └── build-windows.yml
├── setup.sh # Unix/macOS setup script
├── setup.ps1 # Windows setup script
├── pyproject.toml # Project metadata
├── requirements.txt # Dependencies
├── VERSION # Version for packaging
└── README.md # This file
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request
License
MIT License - see LICENSE file for details
Related Projects
- LangGuard - AI Control Plane
- Cursor IDE - AI-powered code editor
- OpenTelemetry - Observability framework
Support
For issues and questions:
- GitHub Issues: [Create an issue]
- Cursor Docs: https://cursor.com/docs
- OpenTelemetry Docs: https://opentelemetry.io/docs