Skip to main content

NotiLens — unified SDK + CLI for AI agent notifications

Project description

NotiLens

Send notifications from AI agents and any Python project to NotiLens.

Two ways to use it — pick one or both:

  • CLI — for shell scripts, Claude Code hooks, bash pipelines
  • SDK — for Python projects, with optional AI framework auto-patching

Installation

pip install notilens

With AI framework auto-patching:

pip install notilens[openai]       # OpenAI
pip install notilens[anthropic]    # Anthropic
pip install notilens[langchain]    # LangChain
pip install notilens[all]          # all frameworks


CLI

Use the CLI in shell scripts, Claude Code hooks, or any terminal workflow.

1. Setup (required, one time)

Get your token and secret from the NotiLens dashboard.

notilens init --agent my-agent --token YOUR_TOKEN --secret YOUR_SECRET

This saves credentials to ~/.notilens_config.json. All future commands for this agent read from there — no need to pass token/secret again.

Multiple agents (each agent notifies a different topic):

notilens init --agent scraper --token TOKEN_A --secret SECRET_A
notilens init --agent mailer  --token TOKEN_B --secret SECRET_B

2. Commands

Task Lifecycle

# required: --agent
# optional: --task (auto-generated if omitted)

notilens task.start    --agent my-agent --task job_001
notilens task.progress "Fetching data"  --agent my-agent --task job_001
notilens task.loop     "Step 3 of 10"   --agent my-agent --task job_001
notilens task.retry    --agent my-agent --task job_001
notilens task.stop     --agent my-agent --task job_001
notilens task.complete "All done"       --agent my-agent --task job_001
notilens task.error    "Step 3 failed"  --agent my-agent --task job_001
notilens task.fail     "Unrecoverable"  --agent my-agent --task job_001
notilens task.timeout  "Took too long"  --agent my-agent --task job_001
notilens task.cancel   "User cancelled" --agent my-agent --task job_001
notilens task.terminate "Out of memory" --agent my-agent --task job_001

Input / Human-in-the-loop

notilens input.required "Please confirm the output" --agent my-agent --task job_001
notilens input.approve  "Confirmed"                 --agent my-agent --task job_001
notilens input.reject   "Rejected by user"          --agent my-agent --task job_001

Output Events

notilens output.generate "Report ready"     --agent my-agent --task job_001
notilens output.fail     "Model unavailable" --agent my-agent --task job_001

Metrics

Pass any key=value pairs — numeric values accumulate across calls:

notilens metric tokens=512 cost=0.003 --agent my-agent --task job_001
notilens metric records=1500          --agent my-agent --task job_001

# Reset one metric
notilens metric.reset tokens --agent my-agent --task job_001

# Reset all metrics
notilens metric.reset --agent my-agent --task job_001

Custom Events

Works for any project — AI or not:

notilens emit user.registered "New signup"      --agent my-agent
notilens emit disk.space.full "Only 2GB left"   --agent my-agent
notilens emit order.placed    "Order #1234"      --agent my-agent

3. Full CLI Example

# Register once
notilens init --agent summarizer --token my_token --secret my_secret

# Run a job
notilens task.start --agent summarizer --task job_42

notilens metric tokens=1024 --agent summarizer --task job_42
notilens metric cost=0.004  --agent summarizer --task job_42

notilens task.complete "Summary ready" \
  --agent summarizer \
  --task job_42 \
  --open_url https://example.com/summary.pdf \
  --meta pages=12

4. Claude Code Hooks Example

Register the agent once:

notilens init --agent claude-code --token YOUR_TOKEN --secret YOUR_SECRET

Then in ~/.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "",
      "hooks": [{
        "type": "command",
        "command": "notilens task.progress \"Using tool: $CLAUDE_TOOL_NAME\" --agent claude-code --task $CLAUDE_SESSION_ID"
      }]
    }],
    "Stop": [{
      "matcher": "",
      "hooks": [{
        "type": "command",
        "command": "notilens task.complete \"Session ended\" --agent claude-code --task $CLAUDE_SESSION_ID"
      }]
    }]
  }
}

CLI Options

Flag Required Description
--agent NAME Yes Agent name
--task ID No Task ID — auto-generated if omitted
--level No Override level: debug info warning error
--meta key=value No Custom metadata (repeatable)
--image_url URL No Attach an image
--open_url URL No Link to open
--download_url URL No Link to download
--tags "tag1,tag2" No Comma-separated tags
--is_actionable true|false No Override actionable flag


SDK

Use the SDK in Python projects. Supports manual task lifecycle calls and optional auto-patching of AI frameworks.

1. Setup (required)

import notilens

# required: agent, token, secret
# token/secret can also come from NOTILENS_TOKEN / NOTILENS_SECRET env vars
agent = notilens.init(
    agent="my-agent",    # required — agent name
    token="YOUR_TOKEN",  # required — or set NOTILENS_TOKEN env var
    secret="YOUR_SECRET" # required — or set NOTILENS_SECRET env var
)

Via environment variables:

export NOTILENS_TOKEN=your_token
export NOTILENS_SECRET=your_secret
agent = notilens.init(agent="my-agent")  # reads token+secret from env

All init options:

agent = notilens.init(
    agent="my-agent",      # required
    token="...",           # required (or env var)
    secret="...",          # required (or env var)
    patch=False,           # optional — auto-patch AI frameworks (default: False)
    min_level="info",      # optional — minimum event level to send (default: "info")
    loop_threshold=10,     # optional — AI calls before loop alert (default: 10)
    loop_window=60.0,      # optional — loop detection window in seconds (default: 60)
    call_timeout=30.0,     # optional — alert if AI call exceeds N seconds (default: 30)
    silent=False,          # optional — suppress SDK log output (default: False)
    debug=False,           # optional — verbose logging (default: False)
)

2. Task Lifecycle

# task_id is optional — auto-generated if omitted
# task_start returns the task_id so you can reference it later
task_id = agent.task_start(task_id="job_001")  # task_id optional

agent.task_progress("Step 2 of 5", task_id=task_id)   # optional mid-run update
agent.task_loop("Processing item 42", task_id=task_id) # optional loop marker
agent.task_retry(task_id=task_id)                      # optional retry signal

# Terminal events — pick one to end the task
agent.task_complete("All done", task_id=task_id)
agent.task_fail("Unrecoverable error", task_id=task_id)
agent.task_timeout("Exceeded time limit", task_id=task_id)
agent.task_cancel("User cancelled", task_id=task_id)
agent.task_terminate("OOM", task_id=task_id)
agent.task_stop(task_id=task_id)

# Non-terminal error (task continues)
agent.task_error("Step 3 failed, retrying", task_id=task_id)

3. Input / Human-in-the-loop

agent.input_required("Confirm before proceeding", task_id=task_id)
agent.input_approved("User confirmed", task_id=task_id)
agent.input_rejected("User rejected", task_id=task_id)

4. Output Events

# Use for any kind of generated output — AI response, report, file, API result
agent.output_generated("Summary ready", task_id=task_id)
agent.output_failed("Model unavailable", task_id=task_id)

5. Metrics

Track any numeric or string values — accumulated automatically and included in every notification.

agent.metric("tokens", 350)    # set
agent.metric("tokens", 210)    # now 560 (numeric values accumulate)
agent.metric("cost", 0.0012)
agent.metric("records", 1500)
agent.metric("model", "gpt-4") # strings are replaced, not accumulated

agent.reset_metrics("tokens")  # reset one metric
agent.reset_metrics()           # reset all metrics

6. Custom Events

Works for any project — AI or not:

agent.emit("user.registered", "New signup", meta={"plan": "pro"})  # meta optional
agent.emit("disk.space.full", "Only 2GB left", level="warning")    # level optional
agent.emit("order.placed", "Order #1234", meta={"amount": 99.99})

7. Auto-patching AI Frameworks

Add patch=True to init() — no other changes needed. NotiLens will automatically track every AI call.

import notilens
import openai  # or anthropic, langchain, crewai, pydantic-ai

agent = notilens.init(
    agent="my-agent",
    token="YOUR_TOKEN",
    secret="YOUR_SECRET",
    patch=True,           # required to enable auto-patching
    call_timeout=30.0,    # optional — alert if any AI call takes longer than 30s
    loop_threshold=10,    # optional — alert if 10+ AI calls happen within loop_window
)

# From here, use OpenAI / Anthropic etc. normally.
# NotiLens fires ai.call.start, ai.call.complete, task.error, task.timeout, task.loop automatically.
response = openai.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Summarise this..."}],
)

Multiple agents — only one can own patching:

scraper = notilens.init(agent="scraper", token="TOKEN_A", secret="SECRET_A", patch=True)
mailer  = notilens.init(agent="mailer",  token="TOKEN_B", secret="SECRET_B")
# patch=True on a second agent raises RuntimeError

8. Full SDK Example

import notilens

agent   = notilens.init("summarizer", token="my_token", secret="my_secret")
task_id = agent.task_start()

try:
    agent.task_progress("Fetching PDF", task_id=task_id)

    result = llm.complete(prompt)
    agent.metric("tokens", result.usage.total_tokens)
    agent.metric("cost", result.usage.cost)

    agent.output_generated("Summary ready", task_id=task_id)
    agent.task_complete("All done", task_id=task_id)

except Exception as e:
    agent.task_fail(str(e), task_id=task_id)


Events Reference

Event Default Type Description
task.started info Task began
task.progress info Mid-run update
task.loop warning Loop iteration
task.retry warning Retry attempt
task.completed success Task finished successfully
task.stopped info Manually stopped
task.failed urgent Task failed
task.error urgent Non-fatal error
task.timeout urgent Exceeded time limit
task.cancelled warning Task cancelled
task.terminated urgent Force-terminated
output.generated success Output produced (AI response, report, file, etc.)
output.failed urgent Output generation failed
input.required warning Waiting for human input
input.approved success Input approved
input.rejected warning Input rejected

Requirements

  • Python >= 3.9

License

MIT — notilens.com

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

notilens-0.3.0.tar.gz (25.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

notilens-0.3.0-py3-none-any.whl (22.7 kB view details)

Uploaded Python 3

File details

Details for the file notilens-0.3.0.tar.gz.

File metadata

  • Download URL: notilens-0.3.0.tar.gz
  • Upload date:
  • Size: 25.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for notilens-0.3.0.tar.gz
Algorithm Hash digest
SHA256 dab42389dd017612b624f848764e6c44c1841c419569f84a591e173adf2f8eb2
MD5 838c23ff4fba6b008cec52797c83762c
BLAKE2b-256 fe097bc286520bc268cd3f7d3a7e19ea392ba3692b55bc99a1444eb4842aa150

See more details on using hashes here.

File details

Details for the file notilens-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: notilens-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 22.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for notilens-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 be2df0927eb922510f37d298f03f009bf1a7b0d44220a9a371f3696fed2e2c3c
MD5 8e004f1d5fb4cfe3e1c71d100a40fbc4
BLAKE2b-256 1b0aa1ec21fe8d4c8379f131ede0895f07b8956cbbfd1ba26e99c24bf6665619

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page