2ndbrain 2026.1.30 → 2026.1.31

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.
@@ -0,0 +1,165 @@
1
+ # Skill: knowledge
2
+
3
+ ## Description
4
+
5
+ Manage a personal knowledge graph with nodes and edges. Nodes represent concepts, people, places, ideas, or anything worth tracking. Edges represent named, directed relationships between nodes (e.g., "works at", "related to", "depends on"). Use this skill to build, query, and traverse the user's personal knowledge graph.
6
+
7
+ ## When to Activate
8
+
9
+ Activate this skill when any of the following conditions are met:
10
+
11
+ - The user's message begins with `/knowledge`
12
+ - The user mentions entities and wants them tracked (e.g., "remember that Alice works at Acme Corp", "Bob is my dentist")
13
+ - The user asks about relationships between things (e.g., "how is X related to Y", "what do I know about X", "who works at Y")
14
+ - The user wants to create, update, or explore connections between concepts
15
+ - The user asks to list or browse known entities
16
+
17
+ ## Available Tools
18
+
19
+ - `mcp__pg__query` -- Execute SQL queries against the PostgreSQL database.
20
+
21
+ No other tools are permitted for this skill.
22
+
23
+ ## Database Tables
24
+
25
+ ### `knowledge_nodes`
26
+
27
+ | Column | Type | Description |
28
+ |--------|------|-------------|
29
+ | `id` | SERIAL PRIMARY KEY | Auto-incrementing identifier |
30
+ | `created_at` | TIMESTAMPTZ | Timestamp of creation |
31
+ | `updated_at` | TIMESTAMPTZ | Timestamp of last update |
32
+ | `name` | TEXT NOT NULL | Name of the entity (person, concept, place, etc.) |
33
+ | `note` | TEXT | Optional descriptive note about the entity |
34
+
35
+ ### `knowledge_edges`
36
+
37
+ | Column | Type | Description |
38
+ |--------|------|-------------|
39
+ | `id` | SERIAL PRIMARY KEY | Auto-incrementing identifier |
40
+ | `created_at` | TIMESTAMPTZ | Timestamp of creation |
41
+ | `updated_at` | TIMESTAMPTZ | Timestamp of last update |
42
+ | `source_id` | INTEGER NOT NULL | FK to `knowledge_nodes.id` (the "from" node) |
43
+ | `target_id` | INTEGER NOT NULL | FK to `knowledge_nodes.id` (the "to" node) |
44
+ | `name` | TEXT NOT NULL | Relationship label (e.g., "works at", "is friend of") |
45
+
46
+ There is a unique constraint on `(source_id, target_id, name)` to prevent duplicate edges.
47
+
48
+ ### `embeddings` (for post-create embedding queue only)
49
+
50
+ | Column | Type | Description |
51
+ |--------|------|-------------|
52
+ | `entity_type` | TEXT NOT NULL | Type of entity (use `'node'` for knowledge nodes) |
53
+ | `entity_id` | INTEGER NOT NULL | The `id` of the knowledge node |
54
+
55
+ ## Operations
56
+
57
+ ### Create a Node
58
+
59
+ When the user mentions a new concept, person, place, or idea to track.
60
+
61
+ ```sql
62
+ INSERT INTO knowledge_nodes (name, note)
63
+ VALUES ('Alice', 'Friend from university, works in data science')
64
+ RETURNING id, name;
65
+ ```
66
+
67
+ Before creating a node, check if one with the same name already exists to avoid duplicates:
68
+
69
+ ```sql
70
+ SELECT id, name, note FROM knowledge_nodes WHERE name ILIKE 'Alice';
71
+ ```
72
+
73
+ If a match exists, ask the user whether to update the existing node or create a new one.
74
+
75
+ ### Create an Edge
76
+
77
+ When the user describes a relationship between two entities.
78
+
79
+ ```sql
80
+ INSERT INTO knowledge_edges (source_id, target_id, name)
81
+ VALUES (1, 2, 'works at')
82
+ ON CONFLICT (source_id, target_id, name) DO NOTHING;
83
+ ```
84
+
85
+ Both the source and target nodes must exist before creating an edge. If either does not exist, create the missing node(s) first (with user confirmation if the intent is ambiguous).
86
+
87
+ ### Query a Node by Name
88
+
89
+ When the user asks "what do I know about X" or mentions an entity by name.
90
+
91
+ ```sql
92
+ SELECT id, name, note, created_at
93
+ FROM knowledge_nodes
94
+ WHERE name ILIKE '%' || 'search term' || '%';
95
+ ```
96
+
97
+ ### Traverse Edges from a Node
98
+
99
+ When the user asks about relationships or connections (e.g., "how is X connected", "what is related to X").
100
+
101
+ Outgoing relationships (what does X relate to):
102
+
103
+ ```sql
104
+ SELECT kn.name AS target, ke.name AS relationship
105
+ FROM knowledge_edges ke
106
+ JOIN knowledge_nodes kn ON kn.id = ke.target_id
107
+ WHERE ke.source_id = <node_id>;
108
+ ```
109
+
110
+ Incoming relationships (what relates to X):
111
+
112
+ ```sql
113
+ SELECT kn.name AS source, ke.name AS relationship
114
+ FROM knowledge_edges ke
115
+ JOIN knowledge_nodes kn ON kn.id = ke.source_id
116
+ WHERE ke.target_id = <node_id>;
117
+ ```
118
+
119
+ For a complete picture, run both queries and present all connections.
120
+
121
+ ### Full-Text Search
122
+
123
+ Search across both the `name` and `note` fields of knowledge nodes.
124
+
125
+ ```sql
126
+ SELECT id, name, note, created_at
127
+ FROM knowledge_nodes
128
+ WHERE name ILIKE '%' || 'search term' || '%'
129
+ OR note ILIKE '%' || 'search term' || '%'
130
+ ORDER BY updated_at DESC
131
+ LIMIT 10;
132
+ ```
133
+
134
+ ### Update a Node
135
+
136
+ When the user wants to add or change information about an existing entity.
137
+
138
+ ```sql
139
+ UPDATE knowledge_nodes
140
+ SET note = 'Updated information here',
141
+ updated_at = NOW()
142
+ WHERE id = <node_id>;
143
+ ```
144
+
145
+ ### Post-Create: Queue for Embedding
146
+
147
+ After successfully creating a knowledge node, attempt to queue it for embedding generation.
148
+
149
+ ```sql
150
+ INSERT INTO embeddings (entity_type, entity_id)
151
+ VALUES ('node', <new_node_id>)
152
+ ON CONFLICT DO NOTHING;
153
+ ```
154
+
155
+ **Important:** The `embeddings` table only exists when the embeddings engine is enabled. If this query fails because the table does not exist, silently ignore the error and proceed normally. The knowledge node is already saved -- embedding is optional. Do not report the embedding queue failure to the user.
156
+
157
+ ## Restrictions and Notes
158
+
159
+ - Always use `mcp__pg__query` for database operations. Do not use any other tool.
160
+ - Edges are directed: "Alice works at Acme" means Alice is the source and Acme is the target. Choose direction to reflect the natural reading of the relationship.
161
+ - Before creating nodes, always check for existing nodes with similar names to prevent duplicates.
162
+ - When presenting graph data to the user, format it clearly -- list relationships in a readable way rather than dumping raw SQL results.
163
+ - If the user describes multiple entities and relationships in one message, process them all (create nodes first, then edges).
164
+ - Never delete nodes or edges unless the user explicitly requests it. Deleting a node cascades to all its edges.
165
+ - When searching, if no exact match is found, try broader partial matches and present the closest results.
@@ -0,0 +1,216 @@
1
+ # Skill: project-manage
2
+
3
+ ## Description
4
+
5
+ Manage projects, specifications, and issues. Use this skill to create projects, add tasks and issues, write specifications, track progress, mark items complete, and get project status summaries. Supports hierarchical sub-tasks and nested specifications.
6
+
7
+ ## When to Activate
8
+
9
+ Activate this skill when any of the following conditions are met:
10
+
11
+ - The user's message begins with `/project`
12
+ - The user mentions tasks, projects, or work items (e.g., "I need to do X", "add a task for Y", "create a project for Z")
13
+ - The user asks about project status (e.g., "what's the status of project Z", "what tasks are open", "what's left to do")
14
+ - The user wants to track issues, bugs, or blockers
15
+ - The user wants to document a specification, requirement, or architecture decision
16
+ - The user marks something as done or complete
17
+
18
+ ## Available Tools
19
+
20
+ - `mcp__pg__query` -- Execute SQL queries against the PostgreSQL database.
21
+
22
+ No other tools are permitted for this skill.
23
+
24
+ ## Database Tables
25
+
26
+ ### `projects`
27
+
28
+ | Column | Type | Description |
29
+ |--------|------|-------------|
30
+ | `id` | SERIAL PRIMARY KEY | Auto-incrementing identifier |
31
+ | `created_at` | TIMESTAMPTZ | Timestamp of creation |
32
+ | `updated_at` | TIMESTAMPTZ | Timestamp of last update |
33
+ | `name` | TEXT NOT NULL | Name of the project |
34
+
35
+ ### `issues`
36
+
37
+ | Column | Type | Description |
38
+ |--------|------|-------------|
39
+ | `id` | SERIAL PRIMARY KEY | Auto-incrementing identifier |
40
+ | `created_at` | TIMESTAMPTZ | Timestamp of creation |
41
+ | `updated_at` | TIMESTAMPTZ | Timestamp of last update |
42
+ | `project_id` | INTEGER | FK to `projects.id` (nullable -- issues can exist without a project) |
43
+ | `parent_id` | INTEGER | FK to `issues.id` (nullable -- for sub-task hierarchy) |
44
+ | `note` | TEXT NOT NULL | Description of the issue or task |
45
+ | `completed` | BOOLEAN NOT NULL DEFAULT FALSE | Whether the issue is resolved |
46
+
47
+ ### `specifications`
48
+
49
+ | Column | Type | Description |
50
+ |--------|------|-------------|
51
+ | `id` | SERIAL PRIMARY KEY | Auto-incrementing identifier |
52
+ | `created_at` | TIMESTAMPTZ | Timestamp of creation |
53
+ | `updated_at` | TIMESTAMPTZ | Timestamp of last update |
54
+ | `project_id` | INTEGER NOT NULL | FK to `projects.id` |
55
+ | `parent_id` | INTEGER | FK to `specifications.id` (nullable -- for nested specs) |
56
+ | `note` | TEXT NOT NULL | Specification content |
57
+
58
+ ## Operations
59
+
60
+ ### Create a Project
61
+
62
+ When the user wants to start tracking a new project.
63
+
64
+ ```sql
65
+ INSERT INTO projects (name)
66
+ VALUES ('My New Project')
67
+ RETURNING id, name, created_at;
68
+ ```
69
+
70
+ Before creating, check if a project with the same name already exists:
71
+
72
+ ```sql
73
+ SELECT id, name FROM projects WHERE name ILIKE 'My New Project';
74
+ ```
75
+
76
+ ### Create an Issue or Task
77
+
78
+ When the user wants to add a task, bug, blocker, or to-do item.
79
+
80
+ ```sql
81
+ INSERT INTO issues (project_id, note)
82
+ VALUES (<project_id>, 'Description of the task')
83
+ RETURNING id, note, created_at;
84
+ ```
85
+
86
+ If the user does not specify a project, either ask which project it belongs to, or create the issue without a project (`project_id = NULL`).
87
+
88
+ ### Create a Sub-Task
89
+
90
+ Issues support hierarchical nesting via `parent_id`. When the user wants to break a task into smaller pieces.
91
+
92
+ ```sql
93
+ INSERT INTO issues (project_id, parent_id, note)
94
+ VALUES (<project_id>, <parent_issue_id>, 'Sub-task description')
95
+ RETURNING id, note, created_at;
96
+ ```
97
+
98
+ ### Create a Specification
99
+
100
+ When the user wants to document a requirement, architecture decision, or design note for a project.
101
+
102
+ ```sql
103
+ INSERT INTO specifications (project_id, note)
104
+ VALUES (<project_id>, 'Specification content here')
105
+ RETURNING id, note, created_at;
106
+ ```
107
+
108
+ Specifications also support nesting via `parent_id` for hierarchical documentation:
109
+
110
+ ```sql
111
+ INSERT INTO specifications (project_id, parent_id, note)
112
+ VALUES (<project_id>, <parent_spec_id>, 'Child specification detail')
113
+ RETURNING id, note, created_at;
114
+ ```
115
+
116
+ ### Mark an Issue as Complete
117
+
118
+ When the user says something is done, finished, or complete.
119
+
120
+ ```sql
121
+ UPDATE issues
122
+ SET completed = TRUE, updated_at = NOW()
123
+ WHERE id = <issue_id>;
124
+ ```
125
+
126
+ To reopen an issue:
127
+
128
+ ```sql
129
+ UPDATE issues
130
+ SET completed = FALSE, updated_at = NOW()
131
+ WHERE id = <issue_id>;
132
+ ```
133
+
134
+ ### Project Status Summary
135
+
136
+ When the user asks for an overview of a project or all projects. Show counts of open and closed issues.
137
+
138
+ For a single project:
139
+
140
+ ```sql
141
+ SELECT
142
+ p.name AS project,
143
+ COUNT(i.id) FILTER (WHERE NOT i.completed) AS open_issues,
144
+ COUNT(i.id) FILTER (WHERE i.completed) AS closed_issues,
145
+ COUNT(i.id) AS total_issues
146
+ FROM projects p
147
+ LEFT JOIN issues i ON i.project_id = p.id
148
+ WHERE p.id = <project_id>
149
+ GROUP BY p.id, p.name;
150
+ ```
151
+
152
+ For all projects:
153
+
154
+ ```sql
155
+ SELECT
156
+ p.name AS project,
157
+ COUNT(i.id) FILTER (WHERE NOT i.completed) AS open_issues,
158
+ COUNT(i.id) FILTER (WHERE i.completed) AS closed_issues,
159
+ COUNT(i.id) AS total_issues
160
+ FROM projects p
161
+ LEFT JOIN issues i ON i.project_id = p.id
162
+ GROUP BY p.id, p.name
163
+ ORDER BY p.name;
164
+ ```
165
+
166
+ ### List Open Issues for a Project
167
+
168
+ ```sql
169
+ SELECT id, note, created_at, parent_id
170
+ FROM issues
171
+ WHERE project_id = <project_id>
172
+ AND completed = FALSE
173
+ ORDER BY created_at ASC;
174
+ ```
175
+
176
+ ### View Sub-Task Hierarchy
177
+
178
+ To display an issue with its sub-tasks:
179
+
180
+ ```sql
181
+ SELECT id, note, completed, parent_id, created_at
182
+ FROM issues
183
+ WHERE parent_id = <parent_issue_id>
184
+ ORDER BY created_at ASC;
185
+ ```
186
+
187
+ ### List Specifications for a Project
188
+
189
+ ```sql
190
+ SELECT id, note, parent_id, created_at
191
+ FROM specifications
192
+ WHERE project_id = <project_id>
193
+ ORDER BY created_at ASC;
194
+ ```
195
+
196
+ ### Search Across Issues
197
+
198
+ ```sql
199
+ SELECT i.id, i.note, i.completed, p.name AS project
200
+ FROM issues i
201
+ LEFT JOIN projects p ON p.id = i.project_id
202
+ WHERE i.note ILIKE '%' || 'search term' || '%'
203
+ ORDER BY i.created_at DESC
204
+ LIMIT 10;
205
+ ```
206
+
207
+ ## Restrictions and Notes
208
+
209
+ - Always use `mcp__pg__query` for database operations. Do not use any other tool.
210
+ - When the user mentions a project by name, look it up first. If multiple projects match, list them and ask the user to clarify.
211
+ - When marking items complete, confirm which specific issue is being completed. If the user says "mark it done" ambiguously, ask which task they mean.
212
+ - Present project status in a clear, concise format. Use counts and lists, not raw SQL output.
213
+ - Issues can exist without a project (`project_id = NULL`). These are standalone tasks.
214
+ - When showing sub-tasks, indicate the hierarchy clearly (e.g., indent or label parent/child relationships).
215
+ - Never delete projects, issues, or specifications unless the user explicitly asks for deletion.
216
+ - When a project has many issues, summarize by status (open vs. closed) rather than listing every single one, unless the user asks for a full list.
@@ -0,0 +1,182 @@
1
+ # Skill: recall
2
+
3
+ ## Description
4
+
5
+ Search across all personal data using natural language. This skill provides unified search over journal entries, knowledge graph nodes, project issues, specifications, and conversation history. It uses semantic vector search when embeddings are available, and falls back to text-based search otherwise.
6
+
7
+ ## When to Activate
8
+
9
+ Activate this skill automatically when the user expresses search or recall intent. Common triggers include:
10
+
11
+ - "Find..." or "Search for..."
12
+ - "Remember when..." or "What was that thing about..."
13
+ - "What did I say about..."
14
+ - "Do I have anything on..."
15
+ - "Look up..." or "Can you find..."
16
+ - Any question that requires searching across the user's stored data
17
+
18
+ This skill does not require a slash command prefix. It activates whenever the user appears to be searching their personal data.
19
+
20
+ ## Available Tools
21
+
22
+ - `mcp__pg__query` -- Execute SQL queries against the PostgreSQL database.
23
+ - `embed_query` -- Convert a text string into a vector embedding for semantic search. Accepts `{ text: "search query" }` and returns `{ vector: [...], dimensions: N }`.
24
+
25
+ ## Database Tables
26
+
27
+ ### `embedding_config` (read-only, check availability)
28
+
29
+ | Column | Type | Description |
30
+ |--------|------|-------------|
31
+ | `id` | INTEGER | Always 1 (single-row table) |
32
+ | `provider` | TEXT | Embedding provider name |
33
+ | `model` | TEXT | Embedding model name |
34
+ | `dimensions` | INTEGER | Vector dimensions |
35
+
36
+ ### `embeddings` (for semantic search)
37
+
38
+ | Column | Type | Description |
39
+ |--------|------|-------------|
40
+ | `entity_type` | TEXT | Type: `'journal'`, `'node'`, `'issue'`, `'message'`, etc. |
41
+ | `entity_id` | INTEGER | ID in the source entity table |
42
+ | `vector` | VECTOR | Embedding vector |
43
+
44
+ ### Entity Tables (joined for full content)
45
+
46
+ - `journal` -- `id`, `note`, `created_at`
47
+ - `knowledge_nodes` -- `id`, `name`, `note`, `created_at`
48
+ - `issues` -- `id`, `note`, `completed`, `project_id`, `created_at`
49
+ - `specifications` -- `id`, `note`, `project_id`, `created_at`
50
+ - `conversation_messages` -- `id`, `content`, `role`, `created_at`
51
+
52
+ ## Operations
53
+
54
+ ### Step 1: Check Semantic Search Availability
55
+
56
+ Before attempting semantic search, check whether the embeddings engine is configured.
57
+
58
+ ```sql
59
+ SELECT dimensions FROM embedding_config WHERE id = 1;
60
+ ```
61
+
62
+ - If this query **succeeds and returns a row**, semantic search is available. Proceed to Step 2a.
63
+ - If this query **fails** (table does not exist) or **returns no rows**, semantic search is unavailable. Skip to Step 2b (text fallback).
64
+
65
+ ### Step 2a: Semantic Search (preferred)
66
+
67
+ When semantic search is available, use the `embed_query` tool to vectorize the user's search query, then find the nearest matches.
68
+
69
+ 1. Call `embed_query` with the user's search text:
70
+
71
+ ```
72
+ embed_query({ text: "the user's search query" })
73
+ ```
74
+
75
+ This returns `{ vector: [0.123, ...], dimensions: 1536 }`.
76
+
77
+ 2. If `embed_query` succeeds, search for nearest neighbors using cosine distance:
78
+
79
+ ```sql
80
+ SELECT entity_type, entity_id,
81
+ 1 - (vector <=> '<vector_string>'::vector) AS similarity
82
+ FROM embeddings
83
+ WHERE vector IS NOT NULL
84
+ ORDER BY vector <=> '<vector_string>'::vector
85
+ LIMIT 10;
86
+ ```
87
+
88
+ Replace `<vector_string>` with the vector array returned by `embed_query`, formatted as a string (e.g., `'[0.123, 0.456, ...]'`).
89
+
90
+ 3. Join the results back to their source tables to retrieve the full content. Use the `entity_type` to determine which table to join:
91
+
92
+ For journal entries (`entity_type = 'journal'`):
93
+ ```sql
94
+ SELECT j.id, j.note, j.created_at
95
+ FROM journal j WHERE j.id = <entity_id>;
96
+ ```
97
+
98
+ For knowledge nodes (`entity_type = 'node'`):
99
+ ```sql
100
+ SELECT kn.id, kn.name, kn.note, kn.created_at
101
+ FROM knowledge_nodes kn WHERE kn.id = <entity_id>;
102
+ ```
103
+
104
+ For issues (`entity_type = 'issue'`):
105
+ ```sql
106
+ SELECT i.id, i.note, i.completed, p.name AS project_name, i.created_at
107
+ FROM issues i
108
+ LEFT JOIN projects p ON p.id = i.project_id
109
+ WHERE i.id = <entity_id>;
110
+ ```
111
+
112
+ For specifications (`entity_type = 'spec'`):
113
+ ```sql
114
+ SELECT s.id, s.note, p.name AS project_name, s.created_at
115
+ FROM specifications s
116
+ LEFT JOIN projects p ON p.id = s.project_id
117
+ WHERE s.id = <entity_id>;
118
+ ```
119
+
120
+ 4. If `embed_query` fails (returns an error), fall through to Step 2b.
121
+
122
+ ### Step 2b: Text Fallback Search
123
+
124
+ When semantic search is unavailable or `embed_query` fails, search across all entity tables using case-insensitive text matching.
125
+
126
+ **Important:** When using this fallback, inform the user: "Using text search (semantic search is not available)."
127
+
128
+ Search each table independently and combine results:
129
+
130
+ ```sql
131
+ -- Journal entries
132
+ SELECT 'journal' AS source, id, note AS content, created_at
133
+ FROM journal
134
+ WHERE note ILIKE '%' || 'search term' || '%'
135
+ ORDER BY created_at DESC
136
+ LIMIT 5;
137
+
138
+ -- Knowledge nodes
139
+ SELECT 'knowledge' AS source, id, name || ': ' || COALESCE(note, '') AS content, created_at
140
+ FROM knowledge_nodes
141
+ WHERE name ILIKE '%' || 'search term' || '%'
142
+ OR note ILIKE '%' || 'search term' || '%'
143
+ ORDER BY created_at DESC
144
+ LIMIT 5;
145
+
146
+ -- Issues
147
+ SELECT 'issue' AS source, id, note AS content, created_at
148
+ FROM issues
149
+ WHERE note ILIKE '%' || 'search term' || '%'
150
+ ORDER BY created_at DESC
151
+ LIMIT 5;
152
+
153
+ -- Specifications
154
+ SELECT 'spec' AS source, id, note AS content, created_at
155
+ FROM specifications
156
+ WHERE note ILIKE '%' || 'search term' || '%'
157
+ ORDER BY created_at DESC
158
+ LIMIT 5;
159
+ ```
160
+
161
+ ### Step 3: Source Attribution
162
+
163
+ Always present results with clear attribution to their source. The user should know where each result came from.
164
+
165
+ Format examples:
166
+ - "From your journal on Jan 15: ..."
167
+ - "From your knowledge graph -- Alice: works at Acme Corp"
168
+ - "From project X, issue #3: ..."
169
+ - "From a specification in project Y: ..."
170
+
171
+ Include dates and context to help the user identify the result they are looking for.
172
+
173
+ ## Restrictions and Notes
174
+
175
+ - Always try semantic search first when available. It produces better results for natural language queries.
176
+ - If semantic search is unavailable, always use the text fallback. Never tell the user that search is impossible.
177
+ - Always attribute results to their source table and include timestamps.
178
+ - If no results are found across any table, say so clearly and suggest alternative search terms or phrasing.
179
+ - Do not modify any data during recall operations. This skill is read-only -- it only searches.
180
+ - When presenting multiple results, rank them by relevance (similarity score for semantic, or recency for text fallback).
181
+ - If the user's query seems to target a specific data type (e.g., "my journal entries about X"), you may search only the relevant table rather than all tables.
182
+ - Keep the result presentation concise. Summarize long entries rather than dumping full content, unless the user asks for detail.