notionmemory 0.1.0__py3-none-any.whl
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.
- notionmemory/__init__.py +0 -0
- notionmemory/agent_skills/calendar/SKILL.md +65 -0
- notionmemory/agent_skills/library/SKILL.md +48 -0
- notionmemory/agent_skills/memory/SKILL.md +60 -0
- notionmemory/agent_skills/settings/SKILL.md +42 -0
- notionmemory/agent_skills/templates/SKILL.md +286 -0
- notionmemory/app.py +24 -0
- notionmemory/cli.py +1082 -0
- notionmemory/core/__init__.py +0 -0
- notionmemory/core/agent_runtime.py +99 -0
- notionmemory/core/config.py +88 -0
- notionmemory/core/detection.py +105 -0
- notionmemory/core/i18n.py +18 -0
- notionmemory/core/install/__init__.py +0 -0
- notionmemory/core/install/codex.py +163 -0
- notionmemory/core/install/handlers.py +399 -0
- notionmemory/core/install/manifest.py +121 -0
- notionmemory/core/install/receipt.py +31 -0
- notionmemory/core/install/runner.py +94 -0
- notionmemory/core/install/spec.py +20 -0
- notionmemory/core/install/teardown.py +245 -0
- notionmemory/core/integrations.py +127 -0
- notionmemory/core/messages.py +159 -0
- notionmemory/core/notion_auth.py +92 -0
- notionmemory/core/notion_client.py +51 -0
- notionmemory/core/notion_markdown.py +263 -0
- notionmemory/core/paths.py +54 -0
- notionmemory/core/registry.py +53 -0
- notionmemory/core/skill_assets.py +19 -0
- notionmemory/core/skill_base.py +81 -0
- notionmemory/hooks/__init__.py +0 -0
- notionmemory/hooks/common.py +19 -0
- notionmemory/hooks/save_reminder.py +53 -0
- notionmemory/hooks/session_start.py +216 -0
- notionmemory/skills/__init__.py +0 -0
- notionmemory/skills/calendar/__init__.py +0 -0
- notionmemory/skills/calendar/notion_db.py +137 -0
- notionmemory/skills/calendar/routing.py +100 -0
- notionmemory/skills/calendar/skill.py +40 -0
- notionmemory/skills/calendar/store.py +275 -0
- notionmemory/skills/git/__init__.py +0 -0
- notionmemory/skills/git/flusher.py +139 -0
- notionmemory/skills/git/hooks.py +123 -0
- notionmemory/skills/git/queue.py +98 -0
- notionmemory/skills/git/skill.py +34 -0
- notionmemory/skills/library/__init__.py +0 -0
- notionmemory/skills/library/crawl.py +110 -0
- notionmemory/skills/library/index.py +113 -0
- notionmemory/skills/library/retrieve.py +32 -0
- notionmemory/skills/library/skill.py +43 -0
- notionmemory/skills/memory/__init__.py +0 -0
- notionmemory/skills/memory/notion_db.py +213 -0
- notionmemory/skills/memory/skill.py +44 -0
- notionmemory/skills/memory/store.py +176 -0
- notionmemory/skills/templates/__init__.py +0 -0
- notionmemory/skills/templates/coerce.py +235 -0
- notionmemory/skills/templates/document.py +256 -0
- notionmemory/skills/templates/filters.py +363 -0
- notionmemory/skills/templates/introspect.py +624 -0
- notionmemory/skills/templates/profile.py +151 -0
- notionmemory/skills/templates/render.py +140 -0
- notionmemory/skills/templates/skill.py +61 -0
- notionmemory/skills/templates/store.py +288 -0
- notionmemory/skills/templates/types.py +85 -0
- notionmemory/web/__init__.py +0 -0
- notionmemory/web/assets/app.js +451 -0
- notionmemory/web/assets/design.css +119 -0
- notionmemory/web/assets/i18n.json +156 -0
- notionmemory/web/assets/index.html +32 -0
- notionmemory/web/assets/styles.css +617 -0
- notionmemory/web/jobs.py +41 -0
- notionmemory/web/server.py +244 -0
- notionmemory-0.1.0.dist-info/METADATA +106 -0
- notionmemory-0.1.0.dist-info/RECORD +78 -0
- notionmemory-0.1.0.dist-info/WHEEL +5 -0
- notionmemory-0.1.0.dist-info/entry_points.txt +2 -0
- notionmemory-0.1.0.dist-info/licenses/LICENSE +21 -0
- notionmemory-0.1.0.dist-info/top_level.txt +1 -0
notionmemory/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: calendar
|
|
3
|
+
description: List, add, update, and cancel my events in the Notion Calendar DB. Use when the user says things like "what's on tomorrow/this week", "schedule a meeting/add an event", or "move/cancel an event". Searching past decisions or memories is the memory skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# calendar — list / add / update / cancel
|
|
7
|
+
|
|
8
|
+
Command to run (the `notionmemory` command is registered on PATH at install time — run it as-is from any project):
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
notionmemory calendar list [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--days N]
|
|
12
|
+
notionmemory calendar add "<title>" --start "YYYY-MM-DD HH:MM" [--end "YYYY-MM-DD HH:MM"] [--location "<location>"] [--link <url>] [--notes "<notes>"] [--source claude|codex]
|
|
13
|
+
notionmemory calendar update <event_id> [--title "..."] [--start "..."] [--end "..."] [--location "..."] [--link <url>] [--status Scheduled|Done|Canceled]
|
|
14
|
+
notionmemory calendar cancel <event_id>
|
|
15
|
+
notionmemory calendar setup
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Conventions
|
|
19
|
+
|
|
20
|
+
1. Relative time expressions ("tomorrow at 3pm", "next Monday") must be **converted by the agent to `YYYY-MM-DD HH:MM` based on the current date** before being passed in. A date with no time produces an all-day event.
|
|
21
|
+
2. Before update/cancel, always run `list` first to find the target, show it to the user, and get **explicit confirmation**.
|
|
22
|
+
3. After add/update, echo the printed event_id back to the user.
|
|
23
|
+
4. Indicate the saving actor: `--source claude` for a Claude Code session, `--source codex` for Codex.
|
|
24
|
+
5. **Do not copy event text verbatim into the Second Brain.** Only save decisions or facts that arose from an event via the memory skill, linking the Notion page URL that `add` printed via memory's `--link`.
|
|
25
|
+
6. `cancel` records Status=Canceled and then sends the page to the Notion trash (it also disappears from the calendar app, recoverable within 30 days) — tell the user this happened.
|
|
26
|
+
7. If the CLI prints Notion Calendar app connection instructions (on first DB creation), relay them to the user verbatim. If the user asks "it's not showing up in the app / how do I connect it", run `calendar setup` to show the instructions — app setup has no API, so it can't be applied automatically.
|
|
27
|
+
|
|
28
|
+
## Where to write — different from reading
|
|
29
|
+
|
|
30
|
+
Reading can merge multiple sources, but writing must **pick exactly one**. When
|
|
31
|
+
`notionmemory calendar add` returns exit 2 with a list of candidates, that means "where to
|
|
32
|
+
write hasn't been decided." **Don't pick arbitrarily — ask the user.**
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Where should I add this?
|
|
36
|
+
1. Calendar DB (built-in)
|
|
37
|
+
2. Tasks DB in the my-planner template
|
|
38
|
+
→ just this time / going forward
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Translate the answer into a command:
|
|
42
|
+
|
|
43
|
+
| User's answer | What to run |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Just this time · Calendar DB | `notionmemory calendar add ... --here` |
|
|
46
|
+
| Just this time · template | Check properties with `notionmemory templates show <slug>` → `notionmemory templates add <slug> <db-key> --set ...` |
|
|
47
|
+
| Going forward · Calendar DB | `notionmemory calendar target calendar`, then `calendar add` again |
|
|
48
|
+
| Going forward · template | `notionmemory calendar target template:<slug>/<db-key>` |
|
|
49
|
+
|
|
50
|
+
**Only use `calendar target` when the user explicitly says "going forward."** Promoting a
|
|
51
|
+
one-off answer to a permanent default means the user won't be able to trace "why does this
|
|
52
|
+
go here?" weeks later.
|
|
53
|
+
|
|
54
|
+
If the write target is set to a template, `calendar add` will tell you which command to run
|
|
55
|
+
and refuse — calendar does **not** write to another template's database. Follow the guidance
|
|
56
|
+
it gives and use the `templates` commands instead. Always confirm property names with
|
|
57
|
+
`templates show <slug>` — never guess them.
|
|
58
|
+
|
|
59
|
+
## Find content with library
|
|
60
|
+
|
|
61
|
+
Finding things **by content** — "where did I file this / how did I do X before" — is not
|
|
62
|
+
this skill's job but `library`'s: `notionmemory library search "<query>"`. It searches
|
|
63
|
+
across your Second Brain, registered templates, and general documents, attaching the
|
|
64
|
+
source to every hit. Don't conclude "nothing here" from a single source.
|
|
65
|
+
(Date/status **filter** queries are still this skill's job — library only searches text content.)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: library
|
|
3
|
+
description: Use this to find where something is organized in my Notion. When the user's own Notion content (pages, documents, Second Brain) needs to be found by content — "where did I organize this", "how did I handle X before", "let's reuse that paper summary elsewhere" — run the notionmemory CLI with this skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# library
|
|
7
|
+
|
|
8
|
+
Finds **"what something is about"** across my entire Notion. Whether it's a page, a document,
|
|
9
|
+
or a Second Brain entry, and regardless of whether it's a template or a plain document, it finds
|
|
10
|
+
it by content in one shot.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
notionmemory library search "<query>" [--limit N] # ranked pointers (source · title · section · id)
|
|
14
|
+
notionmemory library read <page-id> # live-read the found page's body (block ids inline)
|
|
15
|
+
notionmemory library refresh [--full] # refresh the index (--full for a full crawl)
|
|
16
|
+
notionmemory library status # index age · count
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`search` returns **pointers, not body content** — `content · [page-id] title > section`,
|
|
20
|
+
`memory · [mem-id] title`. Each pointer carries its source.
|
|
21
|
+
|
|
22
|
+
## Three usage modes
|
|
23
|
+
|
|
24
|
+
- **locate** — Just show the pointers from `search`. Do not read the body.
|
|
25
|
+
- **pull** — Live-read only the top 1–2 candidates with `library read <page-id>` and use that.
|
|
26
|
+
The read output has block ids inline, so if you need to revisit a specific part, use those.
|
|
27
|
+
Do not bulk-read every candidate (delegate below if 3+ sources).
|
|
28
|
+
- **sweep** — When you need to sweep 3+ sources and synthesize, **delegate to a subagent**.
|
|
29
|
+
Have the subagent read the candidates and return **only the answer + sources (ids)**, so the
|
|
30
|
+
raw body content doesn't flood the main context. (Delegation conditions: 3+ sources, synthesis
|
|
31
|
+
needed, read-only. Source pointers must always be returned.)
|
|
32
|
+
|
|
33
|
+
## If the index is empty or stale
|
|
34
|
+
|
|
35
|
+
If session start injects "library index: none" or a stale age, the index doesn't exist yet or is
|
|
36
|
+
out of date. **Tell the user you're building the search index**, then run `library refresh --full`
|
|
37
|
+
before searching (this crawls the whole workspace and takes time, so don't do it silently). For
|
|
38
|
+
queries where recency matters, like "what did I write today," also `refresh` first.
|
|
39
|
+
|
|
40
|
+
## Limits
|
|
41
|
+
|
|
42
|
+
- **The index only knows titles and headings.** A page whose relevant content lives only in the
|
|
43
|
+
body, not in the title or headings, may not be found — try broadening the query with synonyms
|
|
44
|
+
(e.g., "container orchestration" → "Kubernetes"), or ask the user which page they mean.
|
|
45
|
+
- Search reflects the current index, so **a page you just created may not show up until you
|
|
46
|
+
refresh.**
|
|
47
|
+
- **Date/status filters** ("tomorrow's schedule", "incomplete todos") belong to calendar/templates'
|
|
48
|
+
structured queries, not library. library only finds things by "what they're about" (text).
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: memory
|
|
3
|
+
description: Saves, searches, and deletes long-term memories in a Notion Second Brain. Use when the user says "remember this / save this / note that", when you've learned a decision, pattern, or preference with lasting value, or when past context would help ("did we ever" do this before).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# memory — remember / recall / forget
|
|
7
|
+
|
|
8
|
+
Executable commands (the `notionmemory` command is registered on PATH at install time — run it as-is from any project):
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
notionmemory remember "<content>" --type <t> --concepts "a,b,c" [--files "x.py,y.ts"] [--project <p>] [--source claude|codex] [--related <mem_id>] [--link <notion_page_url>] [--supersedes <mem_id>] [--auto]
|
|
12
|
+
notionmemory recall "<query>" [--type <t>] [--project <p>] [--top N]
|
|
13
|
+
notionmemory recall --get <mem_id>
|
|
14
|
+
notionmemory forget <mem_id>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## remember conventions
|
|
18
|
+
|
|
19
|
+
1. Preserve the user's own wording in content — no reinterpreting or over-summarizing.
|
|
20
|
+
2. concepts should be **2-5 items, lowercase, specific**: `jwt-refresh-rotation` correct / `auth` wrong.
|
|
21
|
+
3. If there are referenced file paths, record them in `--files` (real paths only, never guess).
|
|
22
|
+
4. Choose `--type`: pattern (a recurring code pattern) / preference (a user preference) / architecture (a structural decision) / bug (a bug and its fix) / workflow (a work procedure) / fact (anything else).
|
|
23
|
+
5. Indicate who is saving: `--source claude` for a Claude Code session, `--source codex` for Codex.
|
|
24
|
+
6. **When the agent decides on its own to save something, always attach `--auto`.** Saves the user explicitly requested go without `--auto`. If it exits 2 ("auto-save is off"), give up on saving and move on quietly.
|
|
25
|
+
7. When replacing an existing memory, use `--supersedes <mem_id>` (the original is preserved as Superseded); use `--related <mem_id>` for related memories and `--link <url>` for a related Notion page.
|
|
26
|
+
8. After saving, echo the printed mem_id and concepts back to the user verbatim — those are the future search terms.
|
|
27
|
+
|
|
28
|
+
## recall conventions
|
|
29
|
+
|
|
30
|
+
- Use the user's own wording as the query as-is. Narrow with `--project`/`--type` when a project or topic is mentioned.
|
|
31
|
+
- **Never fabricate results**: report exactly what comes back, and if it falls back to "no results," say so plainly and suggest 2-3 alternative search terms. Never make things up.
|
|
32
|
+
- Use `recall --get <mem_id>` when the full content is needed.
|
|
33
|
+
|
|
34
|
+
## forget conventions
|
|
35
|
+
|
|
36
|
+
- Before deleting, always use recall to find the target, show it to the user, and get **explicit confirmation**.
|
|
37
|
+
- Tell the user this sets Status=Forgotten (not a hard delete).
|
|
38
|
+
|
|
39
|
+
## Anti-patterns
|
|
40
|
+
|
|
41
|
+
WRONG: `--concepts "stuff, code, notes"` — unfindable later.
|
|
42
|
+
RIGHT: `--concepts "jwt-refresh-rotation, token-revocation"` — specific and searchable.
|
|
43
|
+
|
|
44
|
+
WRONG: recall returns nothing, so you answer with a guess like "it was probably discussed last week."
|
|
45
|
+
RIGHT: "No matching memories. Should I try searching for `refresh token` or `session expiry` instead?"
|
|
46
|
+
|
|
47
|
+
## Checklist
|
|
48
|
+
|
|
49
|
+
- content preserves the user's own wording.
|
|
50
|
+
- concepts: 2-5 items, lowercase, specific.
|
|
51
|
+
- `--auto` is attached when the agent decided to save on its own.
|
|
52
|
+
- recall results were reported exactly as returned.
|
|
53
|
+
|
|
54
|
+
## Find content with library
|
|
55
|
+
|
|
56
|
+
Finding things **by content** — "where did I file this / how did I do X before" — is not
|
|
57
|
+
this skill's job but `library`'s: `notionmemory library search "<query>"`. It searches
|
|
58
|
+
across your Second Brain, registered templates, and general documents, attaching the
|
|
59
|
+
source to every hit. Don't conclude "nothing here" from a single source.
|
|
60
|
+
(Date/status **filter** queries are still this skill's job — library only searches text content.)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: settings
|
|
3
|
+
description: Opens the notionmemory web settings dashboard. Use this skill when the user says something like "open notionmemory settings" or "show me the connections/settings screen" — it (re)starts the local settings server if needed and opens the browser.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# settings
|
|
7
|
+
|
|
8
|
+
When the user wants to open notionmemory's settings screen (connections, skill options), follow the steps below in order.
|
|
9
|
+
|
|
10
|
+
## 1. Check if it's already running
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
curl -s -o /dev/null -w "%{http_code}" http://localhost:8765/api/skills
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
- If the response is `200`, the server is already running — don't start a new one, skip ahead to step 3.
|
|
17
|
+
|
|
18
|
+
## 2. If it's not running, start it in the background
|
|
19
|
+
|
|
20
|
+
Use the `notionmemory` command (registered on PATH at install time).
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
nohup notionmemory serve >/tmp/notionmemory-serve.log 2>&1 &
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- Wait about 1 second, then re-run the `curl` from step 1 to confirm you get `200`. If it doesn't come up, check `/tmp/notionmemory-serve.log` and report the cause to the user.
|
|
27
|
+
|
|
28
|
+
## 3. Open the browser
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
open http://localhost:8765
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 4. Tell the user
|
|
35
|
+
|
|
36
|
+
- URL: `http://localhost:8765`
|
|
37
|
+
- This screen is **settings-only** — it stores connections (Notion PAT, etc.), skill option defaults, and **per-template prompts** (how and in what tone to fill each template). The actual work of reading material and authoring/organizing it into Notion is done by the `templates` skill (`templates create-page` to create the structure → `templates block`/`templates image` to author content).
|
|
38
|
+
- To stop the server: `pkill -f "notionmemory serve"`
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- The port is fixed at `8765`. The server keeps running in the background, so let the user know to stop it with the `pkill` command above once they're done.
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: templates
|
|
3
|
+
description: Use to look up, add, update, or author against a registered Notion template/database. If the user mentions their own Notion templates or DBs — like "add this to my reading list", "show application status", "register this template" — run the notionmemory CLI with this skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# templates
|
|
7
|
+
|
|
8
|
+
Register an arbitrary Notion template, then CRUD it according to its schema. Unlike the DBs
|
|
9
|
+
we built ourselves (calendar, second brain), **the code doesn't know the schema** — so every
|
|
10
|
+
time, read the profile first and use the names in it verbatim.
|
|
11
|
+
|
|
12
|
+
## 3-step protocol — follow the order
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
1. notionmemory templates list # which templates are registered
|
|
16
|
+
2. notionmemory templates show <slug> # DB key · property names · types
|
|
17
|
+
3. add / query / update using the exact names seen in step 2
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Don't skip step 2 and guess property names or options.** The value-enforcement layer
|
|
21
|
+
blocks it anyway, but it costs an extra round trip. The rejection message includes the full
|
|
22
|
+
allow-list, so read it and retry with the correction.
|
|
23
|
+
|
|
24
|
+
If you also need to see options/relation targets, use `templates show <slug> --full`.
|
|
25
|
+
|
|
26
|
+
## Query
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
notionmemory templates query <slug> <db>
|
|
30
|
+
--where "property operator value" # multiple = AND
|
|
31
|
+
--search "free text" # token AND × text-property OR
|
|
32
|
+
--sort "property asc|desc"
|
|
33
|
+
--limit N | --all
|
|
34
|
+
--fields "A,B,C" | --count | --json
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Operators: `=` `!=` `>` `<` `>=` `<=` `contains` `!contains` `starts` `ends` `in` `empty` `!empty`
|
|
38
|
+
|
|
39
|
+
- **If you use `--limit`, also give `--sort`.** Truncating without sorting gives the first N
|
|
40
|
+
rows in an arbitrary order — if the user asked for "the last 5", you get any 5. If output
|
|
41
|
+
was truncated, that fact appears on the last line.
|
|
42
|
+
- **Pass dates as absolute dates, computed by you.** `--where "Due >= 2026-07-22"`. This CLI
|
|
43
|
+
does not interpret relative expressions.
|
|
44
|
+
- `in` is the only surface for OR: `--where "Status in Todo,Doing"`.
|
|
45
|
+
- Write relations by name: `--where "Company contains Acme"` — no need to look up the id.
|
|
46
|
+
- The real row id in results is always the `id` key. If the target DB has a user-created
|
|
47
|
+
property literally named `id`/`url`, that value isn't dropped — it's moved to the
|
|
48
|
+
`"id (property)"` / `"url (property)"` key and preserved — if you requested a property
|
|
49
|
+
with that name, look for it there in the result.
|
|
50
|
+
|
|
51
|
+
## Add · update · archive
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
notionmemory templates add <slug> <db> --set "property=value" [--set ...] [--notes "markdown"]
|
|
55
|
+
notionmemory templates update <slug> <db> <row-id> --set "property=value"
|
|
56
|
+
notionmemory templates archive <slug> <db> <row-id>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `<row-id>` is the first column of `query` output. Don't try to update without querying first.
|
|
60
|
+
- Values not in the option list are rejected. Attach `--allow-new-option` **only when the
|
|
61
|
+
user explicitly asked you to create a new option** — attaching it by default lets typo'd
|
|
62
|
+
options accumulate in the user's workspace.
|
|
63
|
+
- There is no hard delete. `archive` moves to trash, which Notion can restore from within 30 days.
|
|
64
|
+
|
|
65
|
+
## Register · refresh · remove
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
notionmemory templates register <page URL | page ID | name> # re-register with --slug
|
|
69
|
+
notionmemory templates refresh <slug> # when the user changed the schema in Notion
|
|
70
|
+
notionmemory templates refresh <slug> --refresh-notes # regenerate schema + usage notes (body) too — slow
|
|
71
|
+
notionmemory templates remove <slug> # deletes only the profile, doesn't touch Notion
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- Before registering, confirm that **the page has been shared with the integration**
|
|
75
|
+
(the most common failure): page top-right ••• → Connections → notionmemory.
|
|
76
|
+
- If registering by name matches multiple candidates, it exits 2 with a list — ask the user
|
|
77
|
+
which one they mean.
|
|
78
|
+
- If you hit a "property not found" error, the user renamed it in Notion. Run `refresh` first.
|
|
79
|
+
|
|
80
|
+
**If you need a new DB** — notionmemory has **no DB-creation command (by design)**. Schema
|
|
81
|
+
authoring is your job: call the Notion API directly via `NotionSession` to create a DB with
|
|
82
|
+
the schema you want, then bring its URL in with `register` to CRUD it. Property types/options
|
|
83
|
+
aren't boxed in by our CLI, so this gives full freedom.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from notionmemory.core.notion_client import NotionSession
|
|
87
|
+
NotionSession().request("POST", "/databases", json={
|
|
88
|
+
"parent": {"page_id": "<parent page id>"},
|
|
89
|
+
"title": [{"type": "text", "text": {"content": "<DB name>"}}],
|
|
90
|
+
"properties": { "Name": {"title": {}}, "Status": {"select": {"options": [...]}} }})
|
|
91
|
+
# → bring the id/url from the response in with `notionmemory templates register <url>`
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Document editing — working with body content, no DB involved
|
|
95
|
+
|
|
96
|
+
Templates aren't only databases. Pages whose content is **body text (paragraphs, headings,
|
|
97
|
+
sections)** — CVs, portfolios, paper notes — get registered too. The `Structure:` list in
|
|
98
|
+
`show <slug>` gives each page's heading outline and page-id.
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
templates read <slug> <page-id> # live body → markdown + block-id
|
|
102
|
+
templates block add <page-id> [--after <block-id>] --markdown "..." # append (free)
|
|
103
|
+
templates page add <parent-page-id> --title "..." [--markdown "..."] # create subpage (free)
|
|
104
|
+
templates block set <block-id> --markdown "..." [--yes] # replace content (needs confirmation)
|
|
105
|
+
templates block remove <block-id> [--yes] # delete = trash (needs confirmation)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
If body content contains **backticks (code fences), quotes, or `$()`**, don't pass it via
|
|
109
|
+
`--markdown "..."` straight to the shell — use `--markdown-file <path>` (or
|
|
110
|
+
`--markdown-file -` for stdin) instead, to avoid the shell mistaking backticks for command
|
|
111
|
+
substitution. The same applies to `prompt --set-file` and `new-prompt --prompt-file`
|
|
112
|
+
(prompts commonly contain backticks). Writing the markdown to a file first and passing that
|
|
113
|
+
path is the safe route.
|
|
114
|
+
|
|
115
|
+
`read` output is `[<block-id>] <markdown>`; `[db: id]` is an embedded DB (→ handle it with
|
|
116
|
+
`query`), `[page: id]` is a subpage (→ `read` it separately).
|
|
117
|
+
|
|
118
|
+
**A row body is also a document.** Each row in a DB is itself a page. "Add a paper and write
|
|
119
|
+
a summary" means: use `add` to create the row and get **the row id**, then use `block add`
|
|
120
|
+
on that id to fill in the body — a combination of CRUD (row) + document editing (body).
|
|
121
|
+
|
|
122
|
+
### Three rules
|
|
123
|
+
|
|
124
|
+
1. **Never guess a block-id without `read`.** Before editing or deleting, always `read` the
|
|
125
|
+
page first to get live block-ids. The cached outline (`show`) only tells you the
|
|
126
|
+
structure — editing needs a live id.
|
|
127
|
+
2. **`--yes` is not a shortcut.** Calling `block set`/`remove` without `--yes` returns a
|
|
128
|
+
preview (before → after) and exits 2. **Show that preview to the user and only re-run
|
|
129
|
+
with `--yes` after getting their approval.** Don't attach `--yes` on your own to skip
|
|
130
|
+
confirmation. Adds/creates are free to do without asking.
|
|
131
|
+
3. **New items should imitate an existing sibling.** When creating a new subpage or row
|
|
132
|
+
body, first `read` an existing sibling to see its section structure, then write in the
|
|
133
|
+
same shape (Notion database templates can't be triggered via the API).
|
|
134
|
+
|
|
135
|
+
`read` only the one page you're editing (not the whole tree). You already know the section
|
|
136
|
+
structure from `show`'s cached outline.
|
|
137
|
+
|
|
138
|
+
## Content authoring — filling in a template
|
|
139
|
+
|
|
140
|
+
Each template can have an **attached prompt** (`templates show` displays it if present) —
|
|
141
|
+
"fill this template like this, in this tone." Read it and follow it before authoring.
|
|
142
|
+
|
|
143
|
+
- If you need a new structure, create and register a page with `templates create-page
|
|
144
|
+
--parent <id> --title <t> --slug <s>`, then attach a prompt with `templates prompt <s>
|
|
145
|
+
--set "<instructions/tone>"`.
|
|
146
|
+
- Fill in the body with `templates block`/`templates page` (document editing);
|
|
147
|
+
**insert images with `templates image <page-id> <local-image> [--caption ...]`** (this
|
|
148
|
+
command handles the Notion upload).
|
|
149
|
+
- Read files (PDF/code/HTML) and crop figures **with your own tools** — notionmemory does
|
|
150
|
+
not read. Just pass the path of the image file you produced to `templates image`.
|
|
151
|
+
|
|
152
|
+
### Example — lecture notes / paper notes
|
|
153
|
+
"Organize this folder of lecture material for me": (1) you read the PDFs/images in the
|
|
154
|
+
folder yourself (reading and figure-cropping are your own tools' job — install PyMuPDF/
|
|
155
|
+
poppler etc., or ask the user if missing; notionmemory only handles writing to Notion),
|
|
156
|
+
(2) create a notes page with `templates page add <parent>`, (3) following that template's
|
|
157
|
+
prompt, fill the body with `templates block` and insert cropped figures with `templates
|
|
158
|
+
image`. Paper notes work the same way — structure/tone come from the template/prompt,
|
|
159
|
+
reading/cropping is on you.
|
|
160
|
+
|
|
161
|
+
`templates create-page` **registers** the page it creates as a template — use it only when
|
|
162
|
+
creating a single, ongoing edit-target page (an instance). Notes stamped repeatedly from a
|
|
163
|
+
blueprint should not be registered (registry pollution) — use `templates page add` for
|
|
164
|
+
those instead.
|
|
165
|
+
|
|
166
|
+
## Prompt-only templates (blueprints) — repeated generation
|
|
167
|
+
|
|
168
|
+
A template with a prompt but no `page_id` is a **blueprint** — if `templates show` displays
|
|
169
|
+
it as "prompt-only," that means it isn't one page, it's **a definition that stamps out a
|
|
170
|
+
new page each time**.
|
|
171
|
+
|
|
172
|
+
- Create: `templates new-prompt <slug> --name "Lecture Notes" --prompt "<instructions/tone>"`
|
|
173
|
+
(no location fixed yet).
|
|
174
|
+
- **Using it**: "organize this lecture material (as lecture notes)" → read that template's
|
|
175
|
+
prompt, **agree with the user on a location**, create a new page with `templates page add
|
|
176
|
+
<parent>`, then fill it per the prompt using `templates block`/`image` (don't register
|
|
177
|
+
it). Repeat per subject — each note you make exists independently, and finding it later
|
|
178
|
+
is `library`'s job.
|
|
179
|
+
- **Promoting it**: once it becomes "let's collect these notes into one DB," `templates
|
|
180
|
+
register` that DB **under the same slug** to turn it into an instance-DB (the prompt is
|
|
181
|
+
preserved), and from then on add one row per subject to that DB.
|
|
182
|
+
- Prompt-only templates have no `query`/`add`/`refresh` (DB/structure operations) — those
|
|
183
|
+
commands are blocked with guidance.
|
|
184
|
+
|
|
185
|
+
### Seed — lecture notes
|
|
186
|
+
The retired note-capture skill is revived as this blueprint. Set it up once and reuse it
|
|
187
|
+
per subject. Create it with `templates new-prompt lecture-notes --name "Lecture Notes"
|
|
188
|
+
--prompt "<prompt below>"`, putting the full text below (distilled from the old
|
|
189
|
+
note-capture rules) into the prompt verbatim. The tone lives inside the prompt too (a
|
|
190
|
+
template = structure + attached prompt, tone included):
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
Read lecture, paper, or study material (PDF/image/slides) and turn it into a personal
|
|
194
|
+
knowledge note that is still useful when you look at it again months later. Don't pretend
|
|
195
|
+
to know information that isn't in the source. Write the notes in the SAME LANGUAGE as the
|
|
196
|
+
source material.
|
|
197
|
+
|
|
198
|
+
[authority/evidence] The source material is the only ground truth — don't add background
|
|
199
|
+
knowledge, examples, quotes, numbers, or claims about the author's intent from your own
|
|
200
|
+
memory. Restructure and paraphrase boldly for clarity, but preserve the source's
|
|
201
|
+
conditions, exceptions, uncertainty, formulas, terminology, and comparison direction. If a
|
|
202
|
+
reading is uncertain, don't guess to fill it in — omit it or mark it as uncertain.
|
|
203
|
+
|
|
204
|
+
[terminology] When the source uses non-English technical vocabulary, annotate the original
|
|
205
|
+
term with a brief gloss on first use — pair the source-language term with a short
|
|
206
|
+
explanatory gloss the first time a key term or definition appears. Preserve casing and math
|
|
207
|
+
notation. Don't invent forced translations — keep the original term/abbreviation if there's
|
|
208
|
+
no natural equivalent.
|
|
209
|
+
|
|
210
|
+
[structure] Infer the material type from the source and use the matching frame: lecture →
|
|
211
|
+
scope → prerequisite concepts → key concepts and their relations → examples present in the
|
|
212
|
+
source → limitations/points of confusion → synthesis; paper → citation → question →
|
|
213
|
+
motivation → method → setup → results → limitations; experiment/assignment/project → goal
|
|
214
|
+
→ setup → procedure → results → interpretation → next steps. Open with a 2–4 sentence
|
|
215
|
+
overview stating the scope and the key question. Reorganize by concept/argument structure,
|
|
216
|
+
not slide order. Include examples only when they're present in the source.
|
|
217
|
+
|
|
218
|
+
[style] Describe the subject directly rather than reviewing the material itself — ban
|
|
219
|
+
phrasing like "this lecture..." / "the slide says..." (write "X is defined as..." instead).
|
|
220
|
+
Default to a plain, dispassionate textbook register — no addressing the reader, no
|
|
221
|
+
exclamations. Each paragraph carries one role only — roughly 1–2 sentences and about 220
|
|
222
|
+
characters at most — and breaks with a blank line when moving from definition → implication
|
|
223
|
+
or condition → example.
|
|
224
|
+
|
|
225
|
+
[format] Keep key definitions/theorems in short paragraphs, bold only the key terms (don't
|
|
226
|
+
overuse a "Definition —" prefix or blockquotes). Use inline LaTeX for short expressions,
|
|
227
|
+
standalone `$$...$$` for long derivations. Use tables for comparisons, numbered lists for
|
|
228
|
+
procedures, bullets for parallel items, language-tagged code blocks for code, and checkboxes
|
|
229
|
+
for to-dos.
|
|
230
|
+
|
|
231
|
+
[figures] Crop important figures/diagrams and place each right after the paragraph that
|
|
232
|
+
interprets it — don't dump them all at the end. Skip decorative logos, tables of contents,
|
|
233
|
+
and pages that duplicate body text. Fold handwriting into the relevant sentence; omit it if
|
|
234
|
+
illegible.
|
|
235
|
+
|
|
236
|
+
[Notion syntax] Don't use `[[wikilinks]]` (connect concepts through prose instead). Headings
|
|
237
|
+
go up to three levels (`#`–`###`), list nesting up to one level. No slash commands or HTML
|
|
238
|
+
tags — write tables and code in markdown syntax.
|
|
239
|
+
|
|
240
|
+
[title] Pull the title from the cover page or first title in the source, not from the
|
|
241
|
+
filename or an invented summary. If a lecture number and topic are visible, use
|
|
242
|
+
`Lecture N — original title`; never invent a missing number or title.
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Relationship to other skills — parallel sources
|
|
246
|
+
|
|
247
|
+
Built-in skills (calendar / memory / git) and registered templates are **not competitors.**
|
|
248
|
+
Users don't tell you where their data lives.
|
|
249
|
+
|
|
250
|
+
1. Before answering, check the `notionmemory templates:` list injected at session start.
|
|
251
|
+
2. If a template overlaps the request's domain, **query both and merge with sources
|
|
252
|
+
attached** — e.g. "2 from calendar · 1 from todo-list".
|
|
253
|
+
3. **Never conclude "nothing" from checking only one source.** A silent omission is the only
|
|
254
|
+
real failure here.
|
|
255
|
+
4. Narrow down only once the user names a specific template.
|
|
256
|
+
|
|
257
|
+
**Writing is different.** If something overlaps a built-in like calendar — a schedule/
|
|
258
|
+
deadline — and the user says "add it," you must pick one place. If `notionmemory calendar
|
|
259
|
+
add` exits 2 with a list of candidates, ask the user, and if they say they want this
|
|
260
|
+
template going forward, lock it in with `notionmemory calendar target
|
|
261
|
+
template:<slug>/<db-key>`. To revert, use `notionmemory calendar target calendar`.
|
|
262
|
+
|
|
263
|
+
## Limits — know these up front
|
|
264
|
+
|
|
265
|
+
- **Page body is not searchable.** Notion API DB filters only look at properties. Content
|
|
266
|
+
put into `--notes` cannot be found by any condition. Guide the user to put anything they'll
|
|
267
|
+
need to search for into a property instead.
|
|
268
|
+
- View/filter/sort settings and automatic creation of the relation's counterpart row are not
|
|
269
|
+
supported.
|
|
270
|
+
|
|
271
|
+
## Delegating to a subagent
|
|
272
|
+
|
|
273
|
+
Delegate **only when all three conditions are true.**
|
|
274
|
+
|
|
275
|
+
1. **3 or more** sources to sweep
|
|
276
|
+
2. What's needed is **synthesis**, not raw rows
|
|
277
|
+
3. **Read-only**, with no follow-up edit expected
|
|
278
|
+
|
|
279
|
+
(3) is the key one — a subagent returns only a summary, so **the row ids are lost**, which
|
|
280
|
+
makes any subsequent `update`/`archive` impossible and forces the user to re-query.
|
|
281
|
+
|
|
282
|
+
- Delegate: "What did I do this quarter?" (git + memory + 2 templates, synthesis, read-only)
|
|
283
|
+
- Inline: "Show application status" (1 source, raw rows needed, likely follow-up edit)
|
|
284
|
+
|
|
285
|
+
Reduce output first with `--fields`/`--count`/`--limit`. Delegation is a fallback for what's
|
|
286
|
+
left after that — not the first line of defense.
|
notionmemory/app.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from flask import Flask
|
|
3
|
+
from notionmemory.core.config import Config
|
|
4
|
+
from notionmemory.core.integrations import build_integrations
|
|
5
|
+
from notionmemory.core.registry import Registry
|
|
6
|
+
from notionmemory.core.skill_base import Skill
|
|
7
|
+
from notionmemory.skills.calendar.skill import CalendarSkill
|
|
8
|
+
from notionmemory.skills.git.skill import GitCaptureSkill
|
|
9
|
+
from notionmemory.skills.library.skill import LibrarySkill
|
|
10
|
+
from notionmemory.skills.memory.skill import MemorySkill
|
|
11
|
+
from notionmemory.skills.templates.skill import TemplatesSkill
|
|
12
|
+
from notionmemory.web.server import create_app
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def build_registry(config_path: str, skills: list[Skill] | None = None) -> Registry:
|
|
16
|
+
config = Config.load(config_path)
|
|
17
|
+
resolved = skills if skills is not None else [
|
|
18
|
+
MemorySkill(config), GitCaptureSkill(config),
|
|
19
|
+
CalendarSkill(config), TemplatesSkill(config), LibrarySkill(config)]
|
|
20
|
+
return Registry(resolved, build_integrations(config), config)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def build_app(config_path: str, skills: list[Skill] | None = None) -> Flask:
|
|
24
|
+
return create_app(build_registry(config_path, skills))
|