Crashvault is a lightweight, local-first crash/error vault with a simple CLI. Log errors, group them into issues, search, export/import, and keep a local history.
Contributions are welcome! Please read our CONTRIBUTING.md guide for:
- First-time contributor steps
- Development setup instructions
- Coding standards
- Pull request process
From source:
pip install -e .
Once installed, the crashvault command is available.
After installation, run the setup command to initialize your configuration:
crashvault setup
This creates ~/.crashvault/config.json with default settings for:
- User information (name, email, team)
- Notification preferences
- Storage configuration
crashvault help
crashvault list
crashvault add [ERROR]
crashvault kill
- Enriched event logging with levels, tags, and context:
crashvault add "Database timeout" --level=error --tag=db --tag=timeout --context service=orders --context region=us-east-1
- Search events by level, tag, and text:
crashvault search --level=error --tag=db --text="timeout"
- Show simple statistics:
crashvault stats
- Set status / reopen / rename:
crashvault set-status 12 resolved
crashvault reopen 12
crashvault set-title 12 "New clearer title"
- Purge a single issue and its events:
crashvault purge 12
- Garbage collect orphaned events:
crashvault gc
- Export/Import all data:
crashvault export --output backup.json
crashvault import backup.json --mode=merge
- Tail events live (with optional filters):
crashvault tail --level=error --tag=db --text=timeout
- List with filters/sorting:
crashvault list --status=open --sort=created_at --desc
- Add a quick note:
crashvault note "Shipped v0.2.0 to staging" --tag=release
- Create a small report:
crashvault report --title "Outage resolved" --body "Root cause: bad config" --tag=incident
- Attach a file:
crashvault attach ./screenshot.png --name ui/screenshot-2025-10-09.png
- Wrap any command and auto-log on failure:
crashvault wrap npm run build
- Install a Python exception hook (current process only):
python -c "import crashvault.cli as c; c.autolog.main([])"
# or from CLI spawn a Python process and autolog uncaught exceptions in that process
crashvault autolog
- Show code context from a stacktrace event:
crashvault diagnose <EVENT_ID>
- Generate reports in various formats:
# Markdown report (default)
crashvault generate-report --format markdown --output report.md
# HTML report with styling
crashvault generate-report --format html --output report.html
# JSON report for programmatic processing
crashvault generate-report --format json --output report.json
# Filter reports by status, level, or tags
crashvault generate-report --format html --status open --level error --output errors.html
- Send a desktop notification for an event:
crashvault notify <EVENT_ID>
CrashVault can receive errors from your applications in real-time via an HTTP server.
# Run in foreground
crashvault server start
# Run in background
crashvault server start --background
# Custom port
crashvault server start --port 9000
# Check status
crashvault server status
# Stop background server
crashvault server stop
# View logs
crashvault server logs -fThe server listens on http://localhost:5678 by default.
| Endpoint | Method | Description |
|---|---|---|
/api/v1/events |
POST | Submit an error event |
/api/v1/batch |
POST | Submit multiple events |
/api/v1/stats |
GET | Get error statistics |
/api/health |
GET | Health check |
{
"message": "TypeError: Cannot read property 'foo' of undefined",
"stacktrace": "Error: ...\n at foo.js:10:5\n at bar.js:20:3",
"level": "error",
"tags": ["frontend", "react"],
"context": {
"user_id": "123",
"browser": "Chrome 120"
},
"source": "https://myapp.com/dashboard",
"line": 42,
"column": 15
}Required fields: message
Optional fields:
stacktrace/stack- Full stack tracelevel- One of:debug,info,warning,error,critical(default:error)tags- Array of string tagscontext- Object with additional metadatasource/url- Source file or URLline/lineno- Line numbercolumn/colno- Column numberhost- Hostname (auto-detected from request IP if not provided)
Browser (JavaScript):
// Catch all uncaught errors
window.onerror = (message, source, line, column, error) => {
fetch('http://localhost:5678/api/v1/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: message,
stacktrace: error?.stack,
source: source,
line: line,
column: column,
level: 'error',
context: {
userAgent: navigator.userAgent,
url: window.location.href
}
})
}).catch(() => {}); // Don't throw if CrashVault is down
};
// Catch unhandled promise rejections
window.onunhandledrejection = (event) => {
fetch('http://localhost:5678/api/v1/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: event.reason?.message || String(event.reason),
stacktrace: event.reason?.stack,
level: 'error',
tags: ['unhandled-rejection']
})
}).catch(() => {});
};Node.js:
process.on('uncaughtException', (error) => {
fetch('http://localhost:5678/api/v1/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: error.message,
stacktrace: error.stack,
level: 'critical',
tags: ['uncaught-exception']
})
}).finally(() => process.exit(1));
});
process.on('unhandledRejection', (reason) => {
fetch('http://localhost:5678/api/v1/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: reason?.message || String(reason),
stacktrace: reason?.stack,
level: 'error',
tags: ['unhandled-rejection']
})
});
});Python:
import sys
import traceback
import requests
def crashvault_excepthook(exc_type, exc_value, exc_tb):
try:
requests.post('http://localhost:5678/api/v1/events', json={
'message': str(exc_value),
'stacktrace': ''.join(traceback.format_exception(exc_type, exc_value, exc_tb)),
'level': 'error',
'tags': [exc_type.__name__]
}, timeout=5)
except Exception:
pass
sys.__excepthook__(exc_type, exc_value, exc_tb)
sys.excepthook = crashvault_excepthookcURL (manual testing):
curl -X POST http://localhost:5678/api/v1/events \
-H "Content-Type: application/json" \
-d '{"message": "Test error", "level": "error", "tags": ["test"]}'Send notifications to external services when errors occur.
# Add a Slack webhook
crashvault webhook add slack --url="https://hooks.slack.com/services/T00/B00/xxx"
# Add a Discord webhook
crashvault webhook add discord --url="https://discord.com/api/webhooks/123/abc"
# Add a generic HTTP webhook with signing secret
crashvault webhook add http --url="https://myapp.com/webhooks/crashes" --secret="mysecret"
# Filter by severity (only error and critical)
crashvault webhook add slack --url="..." --events="error,critical"
# Give it a friendly name
crashvault webhook add slack --url="..." --name="prod-alerts"# List all webhooks
crashvault webhook list
# Show webhook details
crashvault webhook show <id>
# Test a webhook (sends a test notification)
crashvault webhook test <id>
# Disable/enable a webhook
crashvault webhook disable <id>
crashvault webhook enable <id>
# Remove a webhook
crashvault webhook remove <id>Slack uses Block Kit formatting with:
- Header with severity emoji
- Level and issue number fields
- Message text
- Stacktrace in code block (truncated)
- Host and tags in context
Discord uses rich embeds with:
- Color-coded by severity
- Fields for level, issue, host, tags
- Stacktrace in code block
HTTP sends raw JSON:
{
"type": "crashvault.event",
"data": {
"event_id": "abc123",
"issue_id": 1,
"message": "Error message",
"level": "error",
"stacktrace": "...",
"timestamp": "2025-02-10T12:00:00Z",
"tags": ["tag1"],
"context": {},
"host": "hostname"
}
}When you configure a secret, CrashVault signs the payload with HMAC-SHA256:
X-CrashVault-Signature: sha256=<hex-digest>
Verify in your webhook handler:
import hmac
import hashlib
def verify_signature(payload_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
payload_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)Webhooks are stored in ~/.crashvault/config.json:
{
"webhooks": [
{
"id": "abc123",
"type": "slack",
"url": "https://hooks.slack.com/...",
"name": "prod-alerts",
"events": ["error", "critical"],
"enabled": true
}
]
}- Run tests for your repo (with coverage if available):
crashvault test --coverage --path tests/
- Data directory: defaults to
~/.crashvault. Override with environment variableCRASHVAULT_HOMEor via config file:
crashvault config set root "C:/path/to/folder"
- View current path:
crashvault path
- Initialize folders (idempotent):
crashvault init
"Permission denied" when accessing vault
# Check vault directory permissions
ls -la ~/.crashvault
# Fix permissions if needed
chmod 700 ~/.crashvault
chmod 600 ~/.crashvault/*.json"Vault is encrypted" but you forgot the password
- There is no password recovery for encrypted vaults (by design for security)
- If you have a backup, restore from that
- Otherwise, you'll need to reset:
rm -rf ~/.crashvault && crashvault init
Server won't start / port already in use
# Check what's using the port
lsof -i :5678
# Use a different port
crashvault server start --port 9000
# Or kill the existing process
crashvault server stopWebhooks not firing
# Check webhook is enabled
crashvault webhook list
# Test the webhook manually
crashvault webhook test <webhook-id>
# Check logs for errors
tail -f ~/.crashvault/logs/app.logEvents not showing up after crashvault add
# Verify the event was created
crashvault list --status=all
# Check for issues with the vault
crashvault stats
# Look at recent events
crashvault tailImport fails with "invalid JSON"
- Ensure the file is valid JSON:
python -m json.tool backup.json - Check the file encoding (should be UTF-8)
- Try importing with
--mode=replaceif merge fails
Shell completion not working
# Regenerate completion scripts
crashvault completion bash > ~/.crashvault/completion.bash
source ~/.crashvault/completion.bash
# For zsh
crashvault completion zsh > ~/.zshrc.d/crashvault.zshEnable verbose logging for troubleshooting:
# Set log level via environment variable
export CRASHVAULT_LOG_LEVEL=DEBUG
crashvault <command>
# View logs
tail -f ~/.crashvault/logs/app.log- Run
crashvault helpfor command reference - Run
crashvault <command> --helpfor command-specific help - Check logs at
~/.crashvault/logs/app.log - File issues at the project repository
Thanks to Creeperkid2014 / AgentArk5