agentrem 1.3.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,37 +1,27 @@
1
- # 🧠 agentrem — Reminders for AI Agents
1
+ # 🔔 agentrem
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/agentrem)](https://www.npmjs.com/package/agentrem)
4
+ [![Tests](https://img.shields.io/badge/tests-392%20passing-brightgreen)](https://github.com/fraction12/agentrem)
4
5
  [![CI](https://github.com/fraction12/agentrem/actions/workflows/ci.yml/badge.svg)](https://github.com/fraction12/agentrem/actions/workflows/ci.yml)
5
- [![Tests](https://img.shields.io/badge/tests-292%20passing-brightgreen)](https://github.com/fraction12/agentrem)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
  [![Node.js](https://img.shields.io/node/v/agentrem)](https://nodejs.org)
8
8
  [![MCP](https://img.shields.io/badge/MCP-compatible-blue)](https://modelcontextprotocol.io)
9
9
 
10
- Structured reminders CLI + MCP server that gives AI agents persistent, priority-aware memory with triggers, recurrence, dependencies, and full-text search.
10
+ Structured reminders for AI agents. Persistent, searchable, works across sessions.
11
11
 
12
- **Why?** AI agents forget between sessions. agentrem gives them a reminder system that persists across sessions, triggers on time/keywords/conditions, and fits within token budgets.
13
-
14
- ## Install
12
+ ## Instant Start
15
13
 
16
14
  ```bash
17
- npm install -g agentrem
18
- agentrem init
15
+ npx agentrem add "Deploy to prod" --due tomorrow --priority 2
16
+ npx agentrem check
17
+ npx agentrem list
19
18
  ```
20
19
 
21
- ## Connect to Your AI Tool
20
+ ---
22
21
 
23
- ### Claude Code (Recommended)
22
+ ## For AI Agents
24
23
 
25
- Claude Code has shell access, so it works out of the box no MCP config needed.
26
-
27
- **1. Install globally:**
28
-
29
- ```bash
30
- npm install -g agentrem
31
- agentrem init
32
- ```
33
-
34
- **2. Add to your `CLAUDE.md`:**
24
+ Copy this into your `CLAUDE.md` / `AGENTS.md` (or run `agentrem setup` to generate it):
35
25
 
36
26
  ```markdown
37
27
  ## Reminders
@@ -53,19 +43,11 @@ agentrem add "<content>" --due "<when>" --priority <1-5> --tags "<tags>"
53
43
  - `agentrem --help` — full reference
54
44
  ```
55
45
 
56
- **3. That's it.** Next time you tell Claude Code "remind me to deploy tomorrow at 9am", it runs:
57
-
58
- ```bash
59
- agentrem add "Deploy to production" --due "tomorrow 9am" --priority 2
60
- ```
61
-
62
- Next session, `agentrem check` surfaces it automatically.
46
+ ---
63
47
 
64
- ### Claude Desktop (MCP)
65
-
66
- For Claude Desktop (the chat app), use the MCP server:
48
+ ## MCP Server
67
49
 
68
- Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
50
+ For Claude Desktop and any MCP client — add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
69
51
 
70
52
  ```json
71
53
  {
@@ -78,7 +60,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
78
60
  }
79
61
  ```
80
62
 
81
- Or without global install:
63
+ No global install? Use `npx`:
82
64
 
83
65
  ```json
84
66
  {
@@ -91,148 +73,141 @@ Or without global install:
91
73
  }
92
74
  ```
93
75
 
94
- Restart Claude Desktop. You'll see agentrem tools available (add, check, list, search, complete, snooze, etc.).
95
-
96
- ### Cursor / Windsurf / Any MCP Client
97
-
98
- Same MCP pattern — point your config to `agentrem-mcp` or `npx agentrem mcp`.
76
+ Run `agentrem setup --mcp` to print this config. MCP tools: `add_reminder` · `check_reminders` · `list_reminders` · `search_reminders` · `complete_reminder` · `snooze_reminder` · `edit_reminder` · `delete_reminder` · `get_stats` · `undo_change` · `export_reminders` · `import_reminders`
77
+
78
+ ---
79
+
80
+ ## All Commands
81
+
82
+ | Command | Key Flags | Example |
83
+ |---------|-----------|---------|
84
+ | `add <content>` | `--due` `--priority` `--tags` `--trigger` `--recur` `--agent` `--dry-run` | `agentrem add "PR review" --due "+4h" --priority 2` |
85
+ | `check` | `--type` `--text` `--budget` `--format` `--json` `--escalate` `--agent` | `agentrem check --type time,session --budget 800 --json` |
86
+ | `list` | `--status` `--priority` `--tag` `--due` `--limit` `--json` `--all` `--agent` | `agentrem list --priority 1,2 --json` |
87
+ | `search <query>` | `--status` `--limit` `--json` | `agentrem search "deploy staging" --json` |
88
+ | `complete <id>` | `--notes` | `agentrem complete abc12345` |
89
+ | `snooze <id>` | `--until` `--for` | `agentrem snooze abc12345 --for 2h` |
90
+ | `edit <id>` | `--content` `--due` `--priority` `--tags` `--add-tags` `--remove-tags` | `agentrem edit abc12345 --priority 1` |
91
+ | `delete [id]` | `--permanent` `--status` `--older-than` | `agentrem delete abc12345 --permanent` |
92
+ | `stats` | `--json` | `agentrem stats --json` |
93
+ | `history [id]` | `--limit` `--json` | `agentrem history --limit 20 --json` |
94
+ | `undo <history_id>` | — | `agentrem undo 42` |
95
+ | `gc` | `--older-than` `--dry-run` | `agentrem gc --older-than 30` |
96
+ | `export` | `--out` `--status` | `agentrem export --out backup.json` |
97
+ | `import <file>` | `--merge` `--replace` `--dry-run` | `agentrem import backup.json --merge` |
98
+ | `watch` | `--interval` `--once` `--verbose` `--install` `--uninstall` `--status` `--agent` | `agentrem watch --install` |
99
+ | `setup` | `--mcp` | `agentrem setup` / `agentrem setup --mcp` |
100
+ | `doctor` | `--json` | `agentrem doctor` |
101
+ | `init` | `--force` | `agentrem init` |
102
+ | `quickstart` | — | `agentrem quickstart` |
103
+ | `schema` | — | `agentrem schema` |
104
+
105
+ **`--json` is available on `check`, `list`, `search`, `stats`, `history`, `doctor` — use it for structured output in your agent.**
106
+
107
+ ### Trigger Types
99
108
 
100
- ### OpenClaw
101
-
102
- agentrem works as a CLI tool that OpenClaw agents call directly:
109
+ | Type | Fires when... | Key flags |
110
+ |------|--------------|-----------|
111
+ | `time` | Due datetime is reached | `--due` |
112
+ | `keyword` | Message text matches | `--keywords`, `--match any\|all\|regex` |
113
+ | `condition` | Shell command output matches | `--check`, `--expect` |
114
+ | `session` | Every session start check | — |
115
+ | `heartbeat` | Every heartbeat check | — |
116
+ | `manual` | Explicit `check` only | — |
103
117
 
104
- ```bash
105
- # Session start hook
106
- agentrem check --type time,session --budget 800
118
+ ### Priority Levels
107
119
 
108
- # Keyword scanning on messages
109
- agentrem check --type keyword --text "user message here"
120
+ | Level | Label | Behavior |
121
+ |-------|-------|----------|
122
+ | 1 | 🔴 Critical | Always surfaced |
123
+ | 2 | 🟡 High | Surfaced within 60% budget |
124
+ | 3 | 🔵 Normal | Surfaced within 85% budget |
125
+ | 4 | ⚪ Low | Counted but not surfaced |
126
+ | 5 | 💤 Someday | Skipped entirely |
110
127
 
111
- # Periodic maintenance
112
- agentrem check --escalate && agentrem gc --days 30
113
- ```
128
+ ---
114
129
 
115
- ### Any Agent with Shell Access
130
+ ## Natural Language Dates
116
131
 
117
- If your agent can run shell commands, it can use agentrem directly:
132
+ `--due`, `--until`, and `--decay` all accept natural language:
118
133
 
119
134
  ```bash
120
- agentrem add "Follow up on PR review" --due "+4h" --priority 2
121
- agentrem check
122
- agentrem complete <id>
135
+ --due "now" # Immediately
136
+ --due "today" # Today at 23:59
137
+ --due "tomorrow" # Tomorrow at 09:00
138
+ --due "in 5 minutes"
139
+ --due "in 2 hours"
140
+ --due "in 3 days"
141
+ --due "in 1 week"
142
+ --due "+5m" # Short relative
143
+ --due "+2h"
144
+ --due "+3d"
145
+ --due "+1w"
146
+ --due "2026-04-01T09:00:00" # ISO datetime
147
+ --due "2026-04-01" # ISO date
123
148
  ```
124
149
 
125
- ## Quick Start
126
-
127
- ```bash
128
- # Time-triggered reminder
129
- agentrem add "Deploy v2.1 to staging" --due "+2h" --priority 2 --tags "deploy,staging"
130
-
131
- # Keyword-triggered (fires when text matches)
132
- agentrem add "Review security checklist" --trigger keyword --keywords "deploy,release" --match any
133
-
134
- # Session reminder (fires every session start)
135
- agentrem add "Check CI pipeline status" --trigger session
150
+ ---
136
151
 
137
- # Recurring weekly reminder
138
- agentrem add "Weekly sync prep" --due "monday 9am" --recur 1w
152
+ ## Background Watcher
139
153
 
140
- # Check what's triggered
141
- agentrem check
154
+ `agentrem watch` polls for due reminders and fires native OS notifications.
142
155
 
143
- # List all active
144
- agentrem list
145
-
146
- # Full-text search
147
- agentrem search "deploy staging"
148
-
149
- # Complete
150
- agentrem complete <id>
156
+ ```bash
157
+ agentrem watch # Poll every 30s (foreground)
158
+ agentrem watch --interval 60 # Custom interval
159
+ agentrem watch --once # Single check and exit
160
+ agentrem watch --agent jarvis # Watch for a specific agent
161
+ agentrem watch --verbose # Show poll log
162
+
163
+ # Install as OS service (auto-start on boot)
164
+ agentrem watch --install
165
+ agentrem watch --install --interval 60
166
+ agentrem watch --status
167
+ agentrem watch --uninstall
151
168
  ```
152
169
 
153
- ## CLI Commands
154
-
155
- | Command | Description |
156
- |---------|-------------|
157
- | `init` | Initialize database (`--force` to recreate with backup) |
158
- | `add <content>` | Create a reminder |
159
- | `check` | Check for triggered reminders |
160
- | `list` | List reminders with filters |
161
- | `search <query>` | Full-text search across all fields |
162
- | `complete <id>` | Mark done (auto-creates next if recurring) |
163
- | `snooze <id>` | Snooze (`--until` or `--for`) |
164
- | `edit <id>` | Edit reminder fields |
165
- | `delete [id]` | Soft-delete (`--permanent` for hard delete) |
166
- | `stats` | Show statistics |
167
- | `gc` | Garbage collect old reminders |
168
- | `history [id]` | View audit trail |
169
- | `undo <history_id>` | Revert a change |
170
- | `export` | Export to JSON |
171
- | `import <file>` | Import from JSON |
172
- | `schema` | Show database schema |
173
-
174
- ## Trigger Types
170
+ **Service files:** macOS → `~/Library/LaunchAgents/com.agentrem.watch.plist` · Linux → `~/.config/systemd/user/agentrem-watch.service` · Logs → `~/.agentrem/logs/watch.log`
175
171
 
176
- | Type | Fires when... | Key flags |
177
- |------|--------------|-----------|
178
- | `time` | Due datetime is reached | `--due` |
179
- | `keyword` | Text matches keywords | `--keywords`, `--match` |
180
- | `condition` | Shell command matches expected output | `--check`, `--expect` |
181
- | `session` | Every session check | — |
182
- | `heartbeat` | Every heartbeat check | — |
183
- | `manual` | Only via explicit check | — |
172
+ ---
184
173
 
185
- ## Priority Levels
174
+ ## Native Notifications 🔔
186
175
 
187
- | Level | Label | Behavior |
188
- |-------|-------|----------|
189
- | 1 | 🔴 Critical | Always surfaced |
190
- | 2 | 🟡 High | Surfaced within 60% budget |
191
- | 3 | 🔵 Normal | Surfaced within 85% budget |
192
- | 4 | ⚪ Low | Counted but not surfaced |
193
- | 5 | 💤 Someday | Skipped entirely |
176
+ On macOS, agentrem ships a bundled Swift app (`Agentrem.app`) so notifications appear with a bell icon — not a terminal icon.
194
177
 
195
- ## Features
178
+ | Priority | Sound |
179
+ |----------|-------|
180
+ | P1 🔴 Critical | Hero |
181
+ | P2 🟡 High | Ping |
182
+ | P3 🔵 Normal | Pop |
196
183
 
197
- - **Recurrence** `--recur 1d/2w/1m` auto-creates next instance on completion
198
- - **Dependencies** — `--depends-on <id>` blocks until dependency is completed
199
- - **Decay** — `--decay <datetime>` auto-expires after a date
200
- - **Max fires** — `--max-fires <n>` auto-completes after N triggers
201
- - **Escalation** — `check --escalate` promotes overdue (P3→P2 after 48h, P2→P1 after 24h)
202
- - **Token budget** — `check --budget <n>` limits output to fit context windows
203
- - **Full-text search** — FTS5 across content, context, tags, notes
204
- - **Undo** — revert any change via audit history
205
- - **Multi-agent** — `--agent <name>` isolates reminders per agent
206
- - **Export/Import** — JSON backup with merge and replace modes
184
+ **Backend fallback order:** `Agentrem.app` → `terminal-notifier` `osascript` `console`
207
185
 
208
- ## MCP Server
186
+ Notifications include a **Complete** button and cheeky overdue messages. To rebuild the Swift app: `npm run build:notify`
209
187
 
210
- The MCP server exposes all functionality as tools, resources, and prompts for AI clients.
188
+ ---
211
189
 
212
- ### Tools
213
- `add_reminder` · `check_reminders` · `list_reminders` · `search_reminders` · `complete_reminder` · `snooze_reminder` · `edit_reminder` · `delete_reminder` · `get_stats` · `get_history` · `undo_change` · `garbage_collect` · `export_reminders` · `import_reminders`
190
+ ## Why agentrem?
214
191
 
215
- ### Resources
216
- - `agentrem://reminders/active` all active reminders
217
- - `agentrem://reminders/overdue` overdue reminders
218
- - `agentrem://stats` — statistics
219
- - `agentrem://schema` — database schema
192
+ ```
193
+ # vs flat files / memory.md
194
+ agentrem check --json # structured output your agent can parse; memory.md can't do that
195
+ ```
220
196
 
221
- ### Prompts
222
- - `triage` review and prioritize active reminders
223
- - `guided-creation`interactive reminder creation
224
- - `session-briefing`session start briefing
197
+ - **Persistent across sessions** — SQLite-backed, survives restarts, not just in-context notes
198
+ - **Priority-aware + token budgets** — `check --budget 800` fits within any context window without overflow
199
+ - **Triggerable**time, keyword, condition, session, heartbeat triggers; not just static lists
200
+ - **Agent-native**`--json` everywhere, `--agent` namespacing, MCP server for chat clients
225
201
 
226
- ## Development
202
+ ---
203
+
204
+ ## Install
227
205
 
228
206
  ```bash
229
- git clone https://github.com/fraction12/agentrem.git
230
- cd agentrem
231
- npm install
232
- npm run build
233
- npm test # 292 tests
207
+ npm install -g agentrem
208
+ agentrem init
234
209
  ```
235
210
 
236
- ## License
211
+ Then run `agentrem setup` to get your `CLAUDE.md` snippet, or `agentrem setup --mcp` for Claude Desktop.
237
212
 
238
- MIT
213
+ MIT License
@@ -14,5 +14,16 @@
14
14
  <string>APPL</string>
15
15
  <key>LSUIElement</key>
16
16
  <true/>
17
+ <key>CFBundleURLTypes</key>
18
+ <array>
19
+ <dict>
20
+ <key>CFBundleURLSchemes</key>
21
+ <array>
22
+ <string>agentrem</string>
23
+ </array>
24
+ <key>CFBundleURLName</key>
25
+ <string>com.agentrem.notifier</string>
26
+ </dict>
27
+ </array>
17
28
  </dict>
18
29
  </plist>
@@ -8,6 +8,7 @@ struct NotifyPayload: Decodable {
8
8
  let subtitle: String?
9
9
  let message: String
10
10
  let sound: String?
11
+ let reminderId: String?
11
12
  }
12
13
 
13
14
  // ── Read JSON file from argv[1] or process args ──────────────────────────────
@@ -23,49 +24,118 @@ for i in 1..<args.count {
23
24
  }
24
25
  }
25
26
 
26
- guard let path = jsonPath else {
27
- fputs("agentrem-notify: usage: open -a Agentrem.app --args <json-file>\n", stderr)
28
- exit(1)
29
- }
30
-
31
- guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: path)),
32
- let payload = try? JSONDecoder().decode(NotifyPayload.self, from: fileData) else {
33
- fputs("agentrem-notify: failed to read or decode \(path)\n", stderr)
34
- exit(1)
27
+ // Parse payload if a JSON path was provided (nil when relaunched for action handling)
28
+ var parsedPayload: NotifyPayload? = nil
29
+ if let path = jsonPath {
30
+ if let fileData = try? Data(contentsOf: URL(fileURLWithPath: path)),
31
+ let decoded = try? JSONDecoder().decode(NotifyPayload.self, from: fileData) {
32
+ parsedPayload = decoded
33
+ } else {
34
+ fputs("agentrem-notify: failed to read or decode \(path)\n", stderr)
35
+ exit(1)
36
+ }
35
37
  }
36
38
 
37
39
  // ── Set up as proper NSApplication (required for UNUserNotificationCenter) ───
38
40
 
39
41
  class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDelegate {
40
- let payload: NotifyPayload
41
-
42
- init(payload: NotifyPayload) {
42
+ let payload: NotifyPayload?
43
+ var timeoutWorkItem: DispatchWorkItem?
44
+
45
+ init(payload: NotifyPayload?) {
43
46
  self.payload = payload
44
47
  super.init()
45
48
  }
46
-
49
+
50
+ // ── Shared logging ────────────────────────────────────────────────────────
51
+
52
+ func log(_ msg: String) {
53
+ let logPath = NSHomeDirectory() + "/.agentrem/logs/notify-actions.log"
54
+ let ts = ISO8601DateFormatter().string(from: Date())
55
+ let line = "[\(ts)] \(msg)\n"
56
+ if let fh = FileHandle(forWritingAtPath: logPath) {
57
+ fh.seekToEndOfFile()
58
+ fh.write(line.data(using: .utf8)!)
59
+ fh.closeFile()
60
+ } else {
61
+ // Create parent dirs if needed
62
+ try? FileManager.default.createDirectory(
63
+ atPath: NSHomeDirectory() + "/.agentrem/logs",
64
+ withIntermediateDirectories: true)
65
+ FileManager.default.createFile(atPath: logPath, contents: line.data(using: .utf8))
66
+ }
67
+ }
68
+
69
+ // ── Run `agentrem complete <reminderId>` ──────────────────────────────────
70
+
71
+ func runComplete(reminderId: String) {
72
+ log("Running: agentrem complete \(reminderId)")
73
+ let proc = Process()
74
+ proc.executableURL = URL(fileURLWithPath: "/opt/homebrew/bin/node")
75
+ proc.arguments = ["/opt/homebrew/lib/node_modules/agentrem/dist/index.js", "complete", reminderId]
76
+ proc.environment = ["HOME": NSHomeDirectory(), "PATH": "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"]
77
+ do {
78
+ try proc.run()
79
+ proc.waitUntilExit()
80
+ log("Complete exited with code \(proc.terminationStatus)")
81
+ } catch {
82
+ log("ERROR running complete: \(error.localizedDescription)")
83
+ }
84
+ }
85
+
47
86
  func applicationDidFinishLaunching(_ notification: Notification) {
48
87
  let center = UNUserNotificationCenter.current()
49
88
  center.delegate = self
50
-
51
- center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
52
- if let error = error {
53
- fputs("agentrem-notify: auth error: \(error.localizedDescription)\n", stderr)
54
- NSApp.terminate(nil)
55
- return
56
- }
57
-
58
- guard granted else {
59
- fputs("agentrem-notify: notification permission not granted\n", stderr)
60
- NSApp.terminate(nil)
61
- return
89
+
90
+ // Register the "Complete ✅" action category so macOS shows the button.
91
+ // .foreground ensures the app is brought to foreground on tap, making
92
+ // the didReceive callback fire reliably even after relaunch.
93
+ let completeAction = UNNotificationAction(
94
+ identifier: "COMPLETE_REMINDER",
95
+ title: "Complete ✅",
96
+ options: []
97
+ )
98
+ let category = UNNotificationCategory(
99
+ identifier: "AGENTREM_REMINDER",
100
+ actions: [completeAction],
101
+ intentIdentifiers: [],
102
+ options: []
103
+ )
104
+ center.setNotificationCategories([category])
105
+
106
+ if payload != nil {
107
+ // Normal launch: request permission then fire the notification
108
+ center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
109
+ if let error = error {
110
+ fputs("agentrem-notify: auth error: \(error.localizedDescription)\n", stderr)
111
+ NSApp.terminate(nil)
112
+ return
113
+ }
114
+ guard granted else {
115
+ fputs("agentrem-notify: notification permission not granted\n", stderr)
116
+ NSApp.terminate(nil)
117
+ return
118
+ }
119
+ self.postNotification()
62
120
  }
63
-
64
- self.postNotification()
65
121
  }
122
+ // else: relaunched to handle an action or URL — wait for the delegate callback
123
+
124
+ // Terminate after 10 s whether or not we handle an action
125
+ scheduleTimeout(seconds: 10.0)
126
+ }
127
+
128
+ func scheduleTimeout(seconds: Double) {
129
+ let work = DispatchWorkItem {
130
+ NSApp.terminate(nil)
131
+ }
132
+ timeoutWorkItem = work
133
+ DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: work)
66
134
  }
67
-
135
+
68
136
  func postNotification() {
137
+ guard let payload = payload else { return }
138
+
69
139
  let content = UNMutableNotificationContent()
70
140
  content.title = payload.title
71
141
  content.body = payload.message
@@ -75,24 +145,78 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
75
145
  } else {
76
146
  content.sound = .default
77
147
  }
78
-
148
+
149
+ // Attach category so the "Complete ✅" button appears
150
+ content.categoryIdentifier = "AGENTREM_REMINDER"
151
+
152
+ // Pass reminderId (and URL scheme backup) so we can call `agentrem complete`
153
+ if let reminderId = payload.reminderId {
154
+ content.userInfo = [
155
+ "reminderId": reminderId,
156
+ "url": "agentrem://complete/\(reminderId)"
157
+ ]
158
+ }
159
+
79
160
  let request = UNNotificationRequest(
80
161
  identifier: UUID().uuidString,
81
162
  content: content,
82
163
  trigger: nil
83
164
  )
84
-
165
+
85
166
  UNUserNotificationCenter.current().add(request) { error in
86
167
  if let error = error {
87
168
  fputs("agentrem-notify: post error: \(error.localizedDescription)\n", stderr)
88
- }
89
- // Give the notification a moment to display
90
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
91
169
  NSApp.terminate(nil)
92
170
  }
171
+ // Stay alive for 10 s to handle an immediate action tap;
172
+ // the timeout scheduled in applicationDidFinishLaunching covers this.
173
+ }
174
+ }
175
+
176
+ // ── URL scheme handler (agentrem://complete/<reminderId>) ─────────────────
177
+
178
+ func application(_ application: NSApplication, open urls: [URL]) {
179
+ for url in urls {
180
+ log("application:open URL=\(url.absoluteString)")
181
+ guard url.scheme == "agentrem",
182
+ url.host == "complete" else {
183
+ log("Unrecognised URL, ignoring: \(url.absoluteString)")
184
+ continue
185
+ }
186
+ // Path is "/<reminderId>" — strip leading slash
187
+ let reminderId = url.path.hasPrefix("/")
188
+ ? String(url.path.dropFirst())
189
+ : url.path
190
+ guard !reminderId.isEmpty else {
191
+ log("URL missing reminderId: \(url.absoluteString)")
192
+ continue
193
+ }
194
+ runComplete(reminderId: reminderId)
195
+ }
196
+ timeoutWorkItem?.cancel()
197
+ NSApp.terminate(nil)
198
+ }
199
+
200
+ // ── Action handler ────────────────────────────────────────────────────────
201
+
202
+ func userNotificationCenter(_ center: UNUserNotificationCenter,
203
+ didReceive response: UNNotificationResponse,
204
+ withCompletionHandler completionHandler: @escaping () -> Void) {
205
+ log("didReceive action=\(response.actionIdentifier) userInfo=\(response.notification.request.content.userInfo)")
206
+
207
+ if response.actionIdentifier == "COMPLETE_REMINDER" {
208
+ if let reminderId = response.notification.request.content.userInfo["reminderId"] as? String,
209
+ !reminderId.isEmpty {
210
+ runComplete(reminderId: reminderId)
211
+ } else {
212
+ log("No reminderId in userInfo")
213
+ }
93
214
  }
215
+ completionHandler()
216
+ timeoutWorkItem?.cancel()
217
+ NSApp.terminate(nil)
94
218
  }
95
-
219
+
96
220
  // Show notification even when app is in foreground
97
221
  func userNotificationCenter(_ center: UNUserNotificationCenter,
98
222
  willPresent notification: UNNotification,
@@ -103,6 +227,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
103
227
 
104
228
  let app = NSApplication.shared
105
229
  app.setActivationPolicy(.accessory) // No dock icon
106
- let delegate = AppDelegate(payload: payload)
230
+ let delegate = AppDelegate(payload: parsedPayload)
107
231
  app.delegate = delegate
108
232
  app.run()
package/dist/api.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ import { type StatsResult } from './core.js';
2
+ import type { Reminder } from './types.js';
3
+ export type { Reminder } from './types.js';
4
+ export type { StatsResult } from './core.js';
5
+ export interface CheckResult {
6
+ /** Reminders that fired and fit within the token budget */
7
+ included: Reminder[];
8
+ /** Count of reminders not returned per priority level due to budget */
9
+ overflowCounts: Record<number, number>;
10
+ /** Total number of reminders that triggered (before budget trim) */
11
+ totalTriggered: number;
12
+ }
13
+ /** Reset the internal DB singleton (useful for testing with custom DB paths). */
14
+ export declare function _resetDb(): void;
15
+ export interface AddOptions {
16
+ due?: string;
17
+ priority?: number;
18
+ tags?: string;
19
+ agent?: string;
20
+ context?: string;
21
+ trigger?: string;
22
+ category?: string;
23
+ keywords?: string;
24
+ recur?: string;
25
+ }
26
+ /**
27
+ * Add a new reminder.
28
+ * @example
29
+ * const rem = await add('Review PR', { due: 'tomorrow', priority: 2 });
30
+ */
31
+ export declare function add(content: string, opts?: AddOptions): Promise<Reminder>;
32
+ export interface CheckOptions {
33
+ type?: string;
34
+ budget?: number;
35
+ agent?: string;
36
+ format?: 'text' | 'json';
37
+ }
38
+ /**
39
+ * Check for triggered reminders. Returns all reminders that are currently
40
+ * due/active within the given token budget.
41
+ * @example
42
+ * const { included } = await check({ budget: 500 });
43
+ */
44
+ export declare function check(opts?: CheckOptions): Promise<CheckResult>;
45
+ export interface ListOptions {
46
+ filter?: string;
47
+ agent?: string;
48
+ limit?: number;
49
+ status?: string;
50
+ priority?: string;
51
+ tag?: string;
52
+ }
53
+ /**
54
+ * List reminders.
55
+ * @example
56
+ * const reminders = await list({ limit: 10 });
57
+ */
58
+ export declare function list(opts?: ListOptions): Promise<Reminder[]>;
59
+ /**
60
+ * Mark a reminder as completed.
61
+ * @example
62
+ * const done = await complete('abc123');
63
+ */
64
+ export declare function complete(id: string, notes?: string): Promise<Reminder>;
65
+ export interface SnoozeOptions {
66
+ for: string;
67
+ }
68
+ /**
69
+ * Snooze a reminder for a duration.
70
+ * @example
71
+ * const snoozed = await snooze('abc123', { for: '2h' });
72
+ */
73
+ export declare function snooze(id: string, opts: SnoozeOptions): Promise<Reminder>;
74
+ export interface SearchOptions {
75
+ limit?: number;
76
+ agent?: string;
77
+ }
78
+ /**
79
+ * Full-text search reminders.
80
+ * @example
81
+ * const results = await search('PR review');
82
+ */
83
+ export declare function search(query: string, opts?: SearchOptions): Promise<Reminder[]>;
84
+ /**
85
+ * Get reminder statistics.
86
+ * @example
87
+ * const s = await stats();
88
+ * console.log(s.totalActive);
89
+ */
90
+ export declare function stats(opts?: {
91
+ agent?: string;
92
+ }): Promise<StatsResult>;
93
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAMA,OAAO,EAQL,KAAK,WAAW,EACjB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAI7C,MAAM,WAAW,WAAW;IAC1B,2DAA2D;IAC3D,QAAQ,EAAE,QAAQ,EAAE,CAAC;IACrB,uEAAuE;IACvE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,oEAAoE;IACpE,cAAc,EAAE,MAAM,CAAC;CACxB;AAeD,iFAAiF;AACjF,wBAAgB,QAAQ,IAAI,IAAI,CAK/B;AAID,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAc/E;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAMrE;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,IAAI,CAAC,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAQlE;AAED;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAG5E;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE/E;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAKrF;AAED;;;;;GAKG;AACH,wBAAsB,KAAK,CAAC,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAG3E"}
package/dist/api.js ADDED
@@ -0,0 +1,111 @@
1
+ // ── Programmatic JavaScript API ───────────────────────────────────────────
2
+ // Clean async wrappers for use by agents and scripts.
3
+ // import { add, check, list, complete, search } from 'agentrem'
4
+ import { initDb, getDb } from './db.js';
5
+ import { coreAdd, coreCheck, coreList, coreSearch, coreComplete, coreSnooze, coreStats, } from './core.js';
6
+ // ── Lazy DB singleton ──────────────────────────────────────────────────────
7
+ let _db = null;
8
+ function db() {
9
+ if (!_db) {
10
+ // Auto-init on first call so `import { add } from 'agentrem'` just works
11
+ initDb(false);
12
+ _db = getDb();
13
+ }
14
+ return _db;
15
+ }
16
+ /** Reset the internal DB singleton (useful for testing with custom DB paths). */
17
+ export function _resetDb() {
18
+ if (_db) {
19
+ try {
20
+ _db.close();
21
+ }
22
+ catch { /* ignore */ }
23
+ _db = null;
24
+ }
25
+ }
26
+ /**
27
+ * Add a new reminder.
28
+ * @example
29
+ * const rem = await add('Review PR', { due: 'tomorrow', priority: 2 });
30
+ */
31
+ export async function add(content, opts) {
32
+ const result = coreAdd(db(), {
33
+ content,
34
+ due: opts?.due,
35
+ priority: opts?.priority,
36
+ tags: opts?.tags,
37
+ agent: opts?.agent,
38
+ context: opts?.context,
39
+ trigger: opts?.trigger,
40
+ category: opts?.category,
41
+ keywords: opts?.keywords,
42
+ recur: opts?.recur,
43
+ });
44
+ return result;
45
+ }
46
+ /**
47
+ * Check for triggered reminders. Returns all reminders that are currently
48
+ * due/active within the given token budget.
49
+ * @example
50
+ * const { included } = await check({ budget: 500 });
51
+ */
52
+ export async function check(opts) {
53
+ return coreCheck(db(), {
54
+ type: opts?.type,
55
+ budget: opts?.budget,
56
+ agent: opts?.agent,
57
+ });
58
+ }
59
+ /**
60
+ * List reminders.
61
+ * @example
62
+ * const reminders = await list({ limit: 10 });
63
+ */
64
+ export async function list(opts) {
65
+ return coreList(db(), {
66
+ agent: opts?.agent,
67
+ limit: opts?.limit,
68
+ status: opts?.status,
69
+ priority: opts?.priority,
70
+ tag: opts?.tag ?? opts?.filter,
71
+ });
72
+ }
73
+ /**
74
+ * Mark a reminder as completed.
75
+ * @example
76
+ * const done = await complete('abc123');
77
+ */
78
+ export async function complete(id, notes) {
79
+ const { completed } = coreComplete(db(), id, notes);
80
+ return completed;
81
+ }
82
+ /**
83
+ * Snooze a reminder for a duration.
84
+ * @example
85
+ * const snoozed = await snooze('abc123', { for: '2h' });
86
+ */
87
+ export async function snooze(id, opts) {
88
+ return coreSnooze(db(), id, undefined, opts.for);
89
+ }
90
+ /**
91
+ * Full-text search reminders.
92
+ * @example
93
+ * const results = await search('PR review');
94
+ */
95
+ export async function search(query, opts) {
96
+ return coreSearch(db(), {
97
+ query,
98
+ limit: opts?.limit,
99
+ });
100
+ }
101
+ /**
102
+ * Get reminder statistics.
103
+ * @example
104
+ * const s = await stats();
105
+ * console.log(s.totalActive);
106
+ */
107
+ export async function stats(opts) {
108
+ void opts; // agent filter not currently in coreStats; included for API compat
109
+ return coreStats(db());
110
+ }
111
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ export interface NotifyOpts {
5
5
  message: string;
6
6
  sound?: string;
7
7
  group?: string;
8
+ reminderId?: string;
8
9
  }
9
10
  export type NotifierBackend = 'agentrem-app' | 'terminal-notifier' | 'osascript' | 'console';
10
11
  /** Reset the cached backend (for testing). */
@@ -1 +1 @@
1
- {"version":3,"file":"notifier.d.ts","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,mBAAmB,GAAG,WAAW,GAAG,SAAS,CAAC;AAM7F,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wEAAwE;AACxE,wBAAgB,cAAc,IAAI,eAAe,CA2BhD;AAkBD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,GAAE,MAAmB,GAAG,UAAU,CAgBnF;AA4BD,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAiBvD;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3C"}
1
+ {"version":3,"file":"notifier.d.ts","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,mBAAmB,GAAG,WAAW,GAAG,SAAS,CAAC;AAM7F,8CAA8C;AAC9C,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wEAAwE;AACxE,wBAAgB,cAAc,IAAI,eAAe,CA2BhD;AAkBD,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,GAAE,MAAmB,GAAG,UAAU,CAgBnF;AA4BD,0DAA0D;AAC1D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAiBvD;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE3C"}
package/dist/notifier.js CHANGED
@@ -86,7 +86,7 @@ export function buildNotifyOpts(rem, now = Date.now()) {
86
86
  }
87
87
  const message = truncate(rem.content, 80);
88
88
  const sound = PRIORITY_SOUNDS[rem.priority]; // undefined for P4/P5
89
- return { title, subtitle, message, sound, group: 'com.agentrem.watch' };
89
+ return { title, subtitle, message, sound, group: 'com.agentrem.watch', reminderId: rem.id };
90
90
  }
91
91
  // ── Path helpers ─────────────────────────────────────────────────────────────
92
92
  /** Resolve the bundled .app bundle path. Returns undefined if it doesn't exist. */
@@ -148,6 +148,7 @@ function sendViaAgentremApp(opts) {
148
148
  subtitle: opts.subtitle,
149
149
  message: opts.message,
150
150
  sound: opts.sound,
151
+ reminderId: opts.reminderId,
151
152
  });
152
153
  writeFileSync(tmpPath, payload, 'utf8');
153
154
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"notifier.js","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"notifier.js","sourceRoot":"","sources":["../src/notifier.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export declare const SCHEMA_VERSION = 1;
2
- export declare const VERSION = "1.3.1";
2
+ export declare const VERSION = "1.5.0";
3
3
  export declare const PRIORITY_LABELS: Record<number, string>;
4
4
  export declare const PRIORITY_COLORS: Record<number, string>;
5
5
  export declare const VALID_TRIGGERS: Set<string>;
package/dist/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // ── Types ──────────────────────────────────────────────────────────────────
2
2
  export const SCHEMA_VERSION = 1;
3
- export const VERSION = '1.3.1';
3
+ export const VERSION = '1.5.0';
4
4
  export const PRIORITY_LABELS = {
5
5
  1: '🔴 Critical',
6
6
  2: '🟡 High',
package/llms-full.txt CHANGED
@@ -28,7 +28,7 @@ Create a reminder.
28
28
 
29
29
  | Flag | Description | Example |
30
30
  |------|-------------|---------|
31
- | `--due, -d <datetime>` | Due datetime (relative or absolute) | `--due "+2h"`, `--due "tomorrow 9am"`, `--due "2026-03-01"` |
31
+ | `--due, -d <datetime>` | Due datetime (natural language or ISO) | `--due "+2h"`, `--due "tomorrow"`, `--due "in 5 minutes"` |
32
32
  | `--trigger, -t <type>` | Trigger type: time/keyword/condition/session/heartbeat/manual | `--trigger keyword` |
33
33
  | `--priority, -p <n>` | Priority 1-5 (default: 3) | `--priority 1` |
34
34
  | `--tags <tags>` | Comma-separated tags | `--tags "deploy,urgent"` |
@@ -50,6 +50,10 @@ Create a reminder.
50
50
  # Time reminder
51
51
  agentrem add "Deploy v2" --due "+2h" --priority 2 --tags "deploy"
52
52
 
53
+ # Natural language due date
54
+ agentrem add "Team standup" --due "tomorrow" --priority 3
55
+ agentrem add "Send report" --due "in 30 minutes"
56
+
53
57
  # Keyword trigger
54
58
  agentrem add "Review security" --trigger keyword --keywords "deploy,release" --match any
55
59
 
@@ -57,7 +61,7 @@ agentrem add "Review security" --trigger keyword --keywords "deploy,release" --m
57
61
  agentrem add "Check CI" --trigger session
58
62
 
59
63
  # Recurring weekly
60
- agentrem add "Team sync prep" --due "monday 9am" --recur 1w
64
+ agentrem add "Team sync prep" --due "2026-02-24T09:00:00" --recur 1w
61
65
 
62
66
  # With dependency
63
67
  agentrem add "Deploy" --due "+4h" --depends-on abc12345
@@ -175,7 +179,7 @@ Snooze a reminder.
175
179
 
176
180
  ```bash
177
181
  agentrem snooze abc12345 --for 2h
178
- agentrem snooze abc12345 --until "tomorrow 9am"
182
+ agentrem snooze abc12345 --until "tomorrow"
179
183
  ```
180
184
 
181
185
  ### agentrem edit <id>
@@ -187,7 +191,7 @@ Edit reminder fields.
187
191
  | `--content <text>` | New content |
188
192
  | `--context <ctx>` | New context |
189
193
  | `--priority, -p <n>` | New priority |
190
- | `--due, -d <datetime>` | New due date |
194
+ | `--due, -d <datetime>` | New due date (natural language or ISO) |
191
195
  | `--tags <tags>` | Replace all tags |
192
196
  | `--add-tags <tags>` | Add tags |
193
197
  | `--remove-tags <tags>` | Remove tags |
@@ -200,6 +204,7 @@ Edit reminder fields.
200
204
  ```bash
201
205
  agentrem edit abc12345 --priority 1
202
206
  agentrem edit abc12345 --due "+4h" --add-tags "urgent"
207
+ agentrem edit abc12345 --due "in 2 hours"
203
208
  ```
204
209
 
205
210
  ### agentrem delete [id]
@@ -307,17 +312,218 @@ agentrem setup # Print CLAUDE.md snippet
307
312
  agentrem setup --mcp # Print Claude Desktop MCP config
308
313
  ```
309
314
 
310
- ### agentrem schema
315
+ ### agentrem doctor
311
316
 
312
- Print the database schema (useful for debugging).
317
+ Self-diagnostic command. Checks that the database exists and is healthy, schema is valid, and warns about overdue reminders or large DB size.
318
+
319
+ | Flag | Description |
320
+ |------|-------------|
321
+ | `--json` | Output structured JSON |
322
+
323
+ ```bash
324
+ agentrem doctor
325
+ agentrem doctor --json
326
+ ```
327
+
328
+ Output:
329
+ ```
330
+ 🩺 agentrem doctor
331
+
332
+ ✅ Database exists: /Users/you/.agentrem/reminders.db
333
+ ✅ Schema valid: Tables: reminders, history, reminders_fts
334
+ ⚠️ Active reminders: 0 active reminders. Add one: agentrem add "Test" --due "+1h"
335
+ ✅ Database size: 64 KB
336
+
337
+ 🟡 Some issues found.
338
+ ```
339
+
340
+ JSON output example:
341
+ ```json
342
+ {
343
+ "healthy": false,
344
+ "checks": [
345
+ { "check": "Database exists", "status": "ok", "detail": "/Users/you/.agentrem/reminders.db" },
346
+ { "check": "Schema valid", "status": "ok", "detail": "Tables: reminders, history, reminders_fts" },
347
+ { "check": "Active reminders", "status": "warn", "detail": "No active reminders. Add one: agentrem add \"Test\" --due \"+1h\"" },
348
+ { "check": "Database size", "status": "ok", "detail": "64 KB" }
349
+ ]
350
+ }
351
+ ```
352
+
353
+ ### agentrem quickstart
354
+
355
+ Interactive first-run walkthrough. Initializes the database (if needed), creates a sample reminder, runs a check, and cleans up — confirming everything works.
356
+
357
+ ```bash
358
+ agentrem quickstart
359
+ ```
360
+
361
+ Output:
362
+ ```
363
+ 📦 Step 1/4: Initializing database...
364
+ 📝 Step 2/4: Creating a sample reminder...
365
+ 🔔 Step 3/4: Checking triggered reminders...
366
+ ✅ Step 4/4: Completing the test reminder...
367
+
368
+ 🎉 Quickstart complete! agentrem is working.
369
+
370
+ Next steps:
371
+ agentrem add "My first real reminder" --due "+1h" --priority 2
372
+ agentrem check
373
+ agentrem setup # Get your CLAUDE.md snippet
374
+ agentrem doctor # Run diagnostics anytime
375
+ ```
376
+
377
+ ### agentrem watch
378
+
379
+ Background daemon that polls for due reminders and fires native OS notifications. Runs until interrupted (SIGINT/SIGTERM).
380
+
381
+ | Flag | Description |
382
+ |------|-------------|
383
+ | `--interval <seconds>` | Poll interval in seconds (default: 30) |
384
+ | `--agent, -a <name>` | Agent name to check for (default: main) |
385
+ | `--once` | Run a single check and exit |
386
+ | `--verbose` | Show poll log output |
387
+ | `--install` | Install as OS background service (launchd on macOS, systemd on Linux) |
388
+ | `--uninstall` | Remove the background service |
389
+ | `--status` | Show service status |
390
+
391
+ ```bash
392
+ # Run in foreground
393
+ agentrem watch # Poll every 30s (default)
394
+ agentrem watch --interval 60 # Poll every 60s
395
+ agentrem watch --agent jarvis # Check reminders for agent "jarvis"
396
+ agentrem watch --once # Single check then exit
397
+ agentrem watch --verbose # Verbose logging
398
+
399
+ # Service management (auto-start on boot)
400
+ agentrem watch --install # Install and start service
401
+ agentrem watch --install --interval 60 # Install with custom interval
402
+ agentrem watch --uninstall # Stop and remove service
403
+ agentrem watch --status # Show installed/running status
404
+ ```
405
+
406
+ #### How polling works
407
+
408
+ - Runs `coreCheck` with types `time,heartbeat,session,condition` and `--escalate` on every tick
409
+ - Per-reminder **dedup cooldown**: once a reminder is notified, it won't fire again for 5 minutes
410
+ - Handles SIGINT/SIGTERM for clean shutdown
411
+ - First check runs immediately on start
412
+
413
+ #### Service management
414
+
415
+ **macOS (launchd):**
416
+ - Writes a LaunchAgent plist to `~/Library/LaunchAgents/com.agentrem.watch.plist`
417
+ - Logs to `~/.agentrem/logs/watch.log` and `watch.error.log`
418
+ - Service label: `com.agentrem.watch`
419
+ - `KeepAlive: true` — restarts automatically on crash
420
+
421
+ **Linux (systemd):**
422
+ - Writes a user unit to `~/.config/systemd/user/agentrem-watch.service`
423
+ - Enabled with `systemctl --user enable --now`
424
+ - Logs to `~/.agentrem/logs/watch.log` and `watch.error.log`
425
+
426
+ #### watch --status output
427
+
428
+ ```
429
+ ✅ Installed: true
430
+ 🟢 Running: true
431
+ Platform: darwin
432
+ File: /Users/you/Library/LaunchAgents/com.agentrem.watch.plist
433
+ Detail: launchctl: ...
434
+ ```
435
+
436
+ #### watch --once (single check)
437
+
438
+ Useful in scripts or cron jobs to check once and exit. Combine with `--verbose` to see what fired:
439
+
440
+ ```bash
441
+ agentrem watch --once --verbose
442
+ # [agentrem watch] started — interval=30s agent=main
443
+ # [agentrem watch] 🔔 [8f103c9c] Deploy v2
444
+ # [agentrem watch] checked at 2026-02-22T09:00:00.000Z — 1 triggered, 1 notified
445
+ ```
446
+
447
+ ---
448
+
449
+ ## Native Notifications
450
+
451
+ agentrem ships a custom Swift app (`Agentrem.app`) bundled in `assets/`. When present, it is preferred over all other backends.
452
+
453
+ ### Notification Backends (priority order)
454
+
455
+ | Backend | When used | Notes |
456
+ |---------|-----------|-------|
457
+ | `agentrem-app` | `Agentrem.app` found in `assets/` | Preferred. Shows "agentrem" as app name with 🔔 bell icon |
458
+ | `terminal-notifier` | `terminal-notifier` on PATH | Fallback if app missing |
459
+ | `osascript` | macOS, no terminal-notifier | Native AppleScript notifications |
460
+ | `console` | Linux / no other option | Prints to stdout |
461
+
462
+ ### Priority-Based Sounds
463
+
464
+ | Priority | Sound |
465
+ |----------|-------|
466
+ | P1 Critical | Hero |
467
+ | P2 High | Ping |
468
+ | P3 Normal | Pop |
469
+ | P4–P5 | (no sound) |
470
+
471
+ ### Overdue Messages
472
+
473
+ The notification subtitle changes based on how overdue a reminder is:
474
+
475
+ | Overdue duration | Subtitle |
476
+ |-----------------|----------|
477
+ | < 2 min | "just now" |
478
+ | < 30 min | "X min ago" |
479
+ | < 1 hour | "about an hour, no biggie" |
480
+ | < 3 hours | "been a couple hours..." |
481
+ | < 6 hours | "this has been waiting a while" |
482
+ | < 24 hours | "so... you forgot about this one 😅" |
483
+ | < 48 hours | "it's been a whole day, dude" |
484
+ | 2+ days | "I've been here for N days. just saying." |
485
+
486
+ ### Rebuilding Agentrem.app
487
+
488
+ ```bash
489
+ npm run build:notify # Recompile Swift source in assets/notify-src/
490
+ ```
313
491
 
314
492
  ---
315
493
 
316
494
  ## Date/Time Formats
317
495
 
318
- Relative: `+1h`, `+2d`, `+1w`, `+30m`
319
- Named: `tomorrow`, `tomorrow 9am`, `monday`, `next friday 2pm`
320
- Absolute: `2026-03-01`, `2026-03-01T09:00:00`
496
+ All date inputs (`--due`, `--until`, `--decay`, etc.) accept:
497
+
498
+ ### Natural language
499
+ ```
500
+ now # Immediately
501
+ today # Today at 23:59
502
+ tomorrow # Tomorrow at 09:00
503
+ in 5 minutes
504
+ in 2 hours
505
+ in 3 days
506
+ in 1 week
507
+ ```
508
+
509
+ ### Relative shortcuts
510
+ ```
511
+ +5m # 5 minutes from now
512
+ +2h # 2 hours from now
513
+ +3d # 3 days from now
514
+ +1w # 1 week from now
515
+ ```
516
+
517
+ ### ISO 8601
518
+ ```
519
+ 2026-02-22T09:00:00 # Full datetime
520
+ 2026-02-22T09:00 # Without seconds
521
+ 2026-02-22 09:00:00 # Space separator
522
+ 2026-02-22 09:00 # Space, no seconds
523
+ 2026-02-22 # Date only (00:00:00)
524
+ ```
525
+
526
+ ---
321
527
 
322
528
  ## Environment Variables
323
529
 
@@ -326,6 +532,8 @@ Absolute: `2026-03-01`, `2026-03-01T09:00:00`
326
532
  | `AGENTREM_DB` | Database file path | `~/.agentrem/reminders.db` |
327
533
  | `AGENTREM_DIR` | Data directory | `~/.agentrem` |
328
534
 
535
+ ---
536
+
329
537
  ## MCP Server
330
538
 
331
539
  ```bash
@@ -334,3 +542,26 @@ npx agentrem mcp # Without global install
334
542
  ```
335
543
 
336
544
  14 tools, 4 resources, 3 prompts. See README.md for full MCP reference.
545
+
546
+ ### Claude Desktop Config
547
+
548
+ ```json
549
+ {
550
+ "mcpServers": {
551
+ "agentrem": {
552
+ "command": "agentrem-mcp",
553
+ "args": []
554
+ }
555
+ }
556
+ }
557
+ ```
558
+
559
+ ---
560
+
561
+ ## agentrem schema
562
+
563
+ Print the database schema (useful for debugging).
564
+
565
+ ```bash
566
+ agentrem schema
567
+ ```
package/llms.txt CHANGED
@@ -14,7 +14,7 @@ npm install -g agentrem && agentrem init
14
14
  agentrem check --type time,session --budget 800
15
15
 
16
16
  # 3. When your human says "remind me" — save it
17
- agentrem add "Deploy to prod" --due "tomorrow 9am" --priority 2
17
+ agentrem add "Deploy to prod" --due "+2h" --priority 2
18
18
  ```
19
19
 
20
20
  Add `agentrem setup` output to your CLAUDE.md for automatic integration.
@@ -30,6 +30,9 @@ agentrem complete <id> # Mark done (auto-creates next if recurring)
30
30
  agentrem snooze <id> --for 2h # Snooze by duration or --until datetime
31
31
  agentrem edit <id> # Modify fields
32
32
  agentrem stats # Overview (--json for structured output)
33
+ agentrem watch # Background daemon: poll + fire OS notifications
34
+ agentrem doctor # Self-diagnostic check
35
+ agentrem quickstart # Interactive first-run walkthrough
33
36
  agentrem setup # Print CLAUDE.md snippet (--mcp for MCP config)
34
37
  ```
35
38
 
@@ -37,7 +40,7 @@ agentrem setup # Print CLAUDE.md snippet (--mcp for MCP config)
37
40
 
38
41
  | Type | Use when... | Example |
39
42
  |------|------------|---------|
40
- | `time` | Something is due at a specific time | `--due "tomorrow 9am"` |
43
+ | `time` | Something is due at a specific time | `--due "+2h"` |
41
44
  | `keyword` | You should react when certain words appear | `--trigger keyword --keywords "deploy,release"` |
42
45
  | `session` | You need to check every session start | `--trigger session` |
43
46
  | `heartbeat` | You need to check every heartbeat | `--trigger heartbeat` |
@@ -47,6 +50,26 @@ agentrem setup # Print CLAUDE.md snippet (--mcp for MCP config)
47
50
 
48
51
  1=Critical (always surfaced), 2=High, 3=Normal, 4=Low (counted not shown), 5=Someday (skipped)
49
52
 
53
+ ## Natural Language Dates
54
+
55
+ `--due` accepts many formats:
56
+
57
+ ```bash
58
+ --due "now" # Immediately
59
+ --due "today" # Today at 23:59
60
+ --due "tomorrow" # Tomorrow at 09:00
61
+ --due "in 5 minutes"
62
+ --due "in 2 hours"
63
+ --due "in 3 days"
64
+ --due "in 1 week"
65
+ --due "+5m" # 5 minutes from now
66
+ --due "+2h" # 2 hours from now
67
+ --due "+3d" # 3 days from now
68
+ --due "+1w" # 1 week from now
69
+ --due "2026-02-22T09:00:00"
70
+ --due "2026-02-22"
71
+ ```
72
+
50
73
  ## Agent Integration Patterns
51
74
 
52
75
  ```bash
@@ -65,6 +88,23 @@ agentrem list --json
65
88
  agentrem stats --json
66
89
  ```
67
90
 
91
+ ## Background Watcher (watch)
92
+
93
+ `agentrem watch` runs a daemon that polls for due reminders and fires native OS notifications.
94
+
95
+ ```bash
96
+ agentrem watch # Start daemon (Ctrl+C to stop)
97
+ agentrem watch --interval 60 # Poll every 60s (default: 30s)
98
+ agentrem watch --agent jarvis # Check for specific agent
99
+ agentrem watch --once # Single check, then exit
100
+ agentrem watch --verbose # Show poll log
101
+
102
+ # Service management (auto-start on boot)
103
+ agentrem watch --install # Install as launchd/systemd service
104
+ agentrem watch --uninstall # Remove service
105
+ agentrem watch --status # Show service status
106
+ ```
107
+
68
108
  ## Key Features
69
109
 
70
110
  - **Recurrence**: `--recur 1d|2w|1m` — auto-creates next on completion
@@ -74,6 +114,7 @@ agentrem stats --json
74
114
  - **Multi-agent**: `--agent <name>` isolates per agent
75
115
  - **Full-text search**: FTS5 across content, context, tags, notes
76
116
  - **JSON output**: `--json` on check, list, search, stats, history
117
+ - **Native notifications**: macOS Agentrem.app with bell icon + priority sounds
77
118
  - **MCP server**: `agentrem-mcp` for Claude Desktop / MCP clients
78
119
  - **Zero config**: SQLite database, no external services
79
120
 
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "agentrem",
3
- "version": "1.3.1",
3
+ "version": "1.5.0",
4
4
  "description": "Structured reminders CLI for AI agents with MCP server",
5
5
  "type": "module",
6
- "main": "dist/index.js",
6
+ "main": "dist/api.js",
7
+ "types": "dist/api.d.ts",
8
+ "exports": {
9
+ ".": "./dist/api.js",
10
+ "./mcp": "./dist/mcp/server.js"
11
+ },
7
12
  "bin": {
8
13
  "agentrem": "dist/index.js",
9
14
  "agentrem-mcp": "dist/mcp/server.js"
@@ -18,6 +23,7 @@
18
23
  ],
19
24
  "scripts": {
20
25
  "build": "tsc",
26
+ "postbuild": "chmod +x dist/index.js dist/mcp/server.js",
21
27
  "build:notify": "bash scripts/build-notify.sh",
22
28
  "dev": "tsc --watch",
23
29
  "test": "vitest run",