@notilens/notilens
v0.5.4
Published
NotiLens — send alerts to NotiLens from Node.js scripts, apps, and AI agents
Downloads
168
Maintainers
Readme
NotiLens
Send alerts to NotiLens from Node.js scripts, apps, and AI agents.
Two ways to use it — pick one or both:
- CLI — for shell scripts, bash pipelines, Claude Code hooks, any terminal workflow
- SDK — for Node.js/TypeScript projects (import and call directly in code)
Installation
npm install -g @notilens/notilensOr per-project:
npm install @notilens/notilensCLI
1. Setup
Get your token and secret from the NotiLens dashboard.
notilens init --name my-app --token YOUR_TOKEN --secret YOUR_SECRETThis saves credentials to ~/.notilens_config.json. All future commands read from there — no need to pass token/secret again.
Multiple sources (each notifies a different topic):
notilens init --name scraper --token TOKEN_A --secret SECRET_A
notilens init --name mailer --token TOKEN_B --secret SECRET_BList / remove:
notilens sources
notilens remove-source my-app2. Notify
The simplest way to send a notification — no task or run context needed:
notilens notify order.placed "Order #1234" --name my-app
notilens notify disk.space.full "Only 1GB left" --name my-app --type warning
notilens notify report.ready "Report is ready" --name my-app --download_url https://example.com/report.pdf3. Commands
--task is a semantic label (e.g. email, report). Each task.start creates an isolated run internally — concurrent executions of the same label never conflict.
Task Lifecycle
notilens queue --name my-app --task email
notilens start --name my-app --task email
notilens progress "Fetching data" --name my-app --task email
notilens loop "Step 3 of 10" --name my-app --task email
notilens retry --name my-app --task email
notilens pause "Rate limited" --name my-app --task email
notilens resume "Resuming" --name my-app --task email
notilens wait "Awaiting tool" --name my-app --task email
notilens stop --name my-app --task email
notilens complete "All done" --name my-app --task email
notilens error "Step 3 failed" --name my-app --task email
notilens fail "Unrecoverable" --name my-app --task email
notilens timeout "Took too long" --name my-app --task email
notilens cancel "User cancelled" --name my-app --task email
notilens terminate "Out of memory" --name my-app --task emailtask.start prints the internal run_id to stdout. You can capture it if needed — but for sequential scripts, just use --task LABEL and the SDK handles the rest automatically.
Output Events
notilens output.generate "Report ready" --name my-app --task email
notilens output.fail "Model unavailable" --name my-app --task emailInput / Human-in-the-loop
notilens input.required "Please confirm the output" --name my-app --task email
notilens input.approve "Confirmed" --name my-app --task email
notilens input.reject "Rejected" --name my-app --task emailGeneric Event
notilens track order.placed "Order #1234" --name my-app --meta amount=99.99
notilens track disk.space.full "Only 1GB remaining" --name my-app --type warningMetrics
Pass any key=value pairs — numeric values accumulate across calls:
notilens metric tokens=512 cost=0.003 --name my-app --task email
notilens metric records=1500 --name my-app --task email
# Reset one metric
notilens metric.reset tokens --name my-app --task email
# Reset all metrics
notilens metric.reset --name my-app --task email4. Claude Code Hooks Example
{
"hooks": {
"PreToolUse": [{
"matcher": "Task",
"hooks": [{
"type": "command",
"command": "notilens start --name claude --task $TASK_ID"
}]
}],
"PostToolUse": [{
"matcher": "Task",
"hooks": [{
"type": "command",
"command": "notilens complete \"Task done\" --name claude --task $TASK_ID"
}]
}],
"Stop": [{
"hooks": [{
"type": "command",
"command": "notilens complete \"Session ended\" --name claude --task session"
}]
}],
"Notification": [{
"hooks": [{
"type": "command",
"command": "notilens input.required \"Claude needs input\" --name claude --task session"
}]
}]
}
}Options
| Flag | Description |
|------|-------------|
| --name <name> | Name identifying the source (required) |
| --task <label> | Task label (e.g. email, report) |
| --type | Override type: info success warning urgent |
| --meta key=value | Custom metadata (repeatable) |
| --image_url <url> | Attach an image |
| --open_url <url> | Link to open |
| --download_url <url> | Link to download |
| --tags "tag1,tag2" | Comma-separated tags |
| --is_actionable true\|false | Override actionable flag |
| --force_send true\|false | Bypass ML filtering. Default true for notify, fail, timeout, terminate, input.required, output.* |
force_send (CLI)
By default NotiLens routes notifications through ML-based filtering. Use --force_send true to bypass ML and deliver immediately, or --force_send false to force ML routing even on high-signal commands.
| Command | Default |
|---------|---------|
| notilens notify | true |
| notilens fail | true |
| notilens timeout | true |
| notilens terminate | true |
| notilens input.required | true |
| notilens output.generate | true |
| notilens output.fail | true |
| Everything else | false |
# Override to route through ML
notilens fail "Error" --name my-app --task email --force_send false
# Override to bypass ML
notilens progress "Critical step" --name my-app --task email --force_send trueFull CLI Example
notilens init --name summarizer --token MY_TOKEN --secret MY_SECRET
notilens start --name summarizer --task report
notilens metric tokens=1024 cost=0.004 --name summarizer --task report
notilens complete "Summary ready" --name summarizer --task report \
--meta input_file=report.pdf \
--open_url https://example.com/summary.pdfSDK
Use the SDK to send notifications directly from your Node.js or TypeScript code.
1. Setup
import { NotiLens } from '@notilens/notilens';
// Option A — pass credentials directly
const nl = NotiLens.init('my-app', { token: 'YOUR_TOKEN', secret: 'YOUR_SECRET' });
// Option B — read from environment variables
// NOTILENS_TOKEN=xxx NOTILENS_SECRET=yyy
const nl = NotiLens.init('my-app');
// Option C — read from saved CLI config (~/.notilens_config.json)
const nl = NotiLens.init('my-app');All init options:
const nl = NotiLens.init('my-app', {
token: 'YOUR_TOKEN', // required (or env var)
secret: 'YOUR_SECRET', // required (or env var)
stateTtl: 86400, // optional — orphaned state TTL in seconds (default: 86400 / 24h)
});2. Notify
The simplest way to send a notification — no task or run context needed:
nl.notify('order.placed', 'Order #1234');
nl.notify('disk.space.full', 'Only 1GB left', { level: 'warning' });
nl.notify('report.ready', 'Your report is ready', {
downloadUrl: 'https://example.com/report.pdf',
tags: 'report,weekly',
});
// Also available on a run
run.notify('deploy.done', 'Deployed to production', {
openUrl: 'https://example.com/deploy/123',
});3. Task Lifecycle
nl.task(label) creates a Run — an isolated execution context with its own state. Multiple concurrent runs of the same label never conflict.
const run = nl.task('email'); // create a run for the "email" task
run.queue(); // optional — pre-start signal
run.start(); // begin the run
run.progress('Fetching records');
run.loop('Processing batch 2');
run.retry();
run.pause('Waiting for rate limit'); // non-terminal warning
run.resume('Resuming work'); // non-terminal info
run.wait('Waiting for tool response'); // non-terminal warning
run.error('Non-fatal error'); // task continues
run.complete('All done'); // terminal — clears state
run.fail('Unrecoverable'); // terminal
run.timeout('Exceeded 30s'); // terminal
run.cancel('User cancelled'); // terminal
run.terminate('OOM'); // terminal
run.stop();4. Input / Human-in-the-loop
run.inputRequired('Please confirm the output');
run.inputApproved('User confirmed');
run.inputRejected('User rejected');5. Output Events
run.outputGenerated('Summary ready');
run.outputFailed('Model timeout');6. Metrics
Track any numeric or string values per run — accumulated automatically and included in every notification.
run.metric('tokens', 350); // set
run.metric('tokens', 210); // now 560 (numeric values accumulate)
run.metric('cost', 0.0012);
run.metric('model', 'gpt-4'); // strings are replaced, not accumulated
run.resetMetrics('tokens'); // reset one metric
run.resetMetrics(); // reset all metricsAutomatic Timing
NotiLens automatically tracks task timing. These fields are included in every notification's meta payload when non-zero:
| Field | Description |
|-------|-------------|
| total_duration_ms | Wall-clock time since start |
| queue_ms | Time between queue and start |
| pause_ms | Cumulative time spent paused |
| wait_ms | Cumulative time spent waiting |
| active_ms | Active time (total − pause − wait) |
7. Custom Events
run.track('order.placed', 'Order #1234', { meta: { amount: 99.99 } });
run.track('disk.space.full', 'Only 1GB remaining', { level: 'warning' });
nl.track('user.registered', 'New signup', { meta: { plan: 'pro' } });force_send (SDK)
By default NotiLens routes notifications through ML-based filtering. Pass forceSend: true (or as a positional param) to bypass ML and deliver immediately.
| Method | Default |
|--------|---------|
| notify() | true |
| fail() | true |
| timeout() | true |
| terminate() | true |
| inputRequired() | true |
| outputGenerated() | true |
| outputFailed() | true |
| Everything else | false |
All methods accept forceSend as an overridable param:
// Override a default-true method to go through ML
run.fail('Error', false);
run.timeout('Slow', false);
// Override a default-false method to bypass ML
run.progress('Critical step', true);
run.complete('Done', true);
// Via options for notify/track
nl.notify('low.priority', 'FYI', { forceSend: false });
run.track('custom.event', 'msg', { forceSend: true });Full SDK Example
import { NotiLens } from '@notilens/notilens';
const nl = NotiLens.init('summarizer', { token: 'TOKEN', secret: 'SECRET' });
const run = nl.task('report');
run.start();
try {
run.progress('Fetching PDF');
const result = await llm.complete(prompt);
run.metric('tokens', result.usage.totalTokens);
run.metric('cost', result.usage.cost);
run.outputGenerated('Summary ready');
run.complete('All done');
} catch (err) {
run.fail((err as Error).message);
}Requirements
- Node.js >= 18.0.0
License
MIT — notilens.com
