fathom-mcp 0.6.4 → 2.0.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/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fathom MCP server — generic adapter that reads tools from the API.
4
+ *
5
+ * Connects to any Fathom instance (self-hosted or cloud). Discovers
6
+ * available tools from GET /v1/tools, filtered by the token's scopes.
7
+ *
8
+ * Environment:
9
+ * FATHOM_API_URL — base URL (default: http://localhost:8201)
10
+ * FATHOM_API_KEY — bearer token from Settings → API Keys
11
+ *
12
+ * Usage:
13
+ * npx fathom-mcp
14
+ * FATHOM_API_URL=https://api.hifathom.com FATHOM_API_KEY=fth_... npx fathom-mcp
15
+ */
16
+
17
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
20
+
21
+ const API_URL = (process.env.FATHOM_API_URL || "http://localhost:8201").replace(/\/$/, "");
22
+ const API_KEY = process.env.FATHOM_API_KEY || "";
23
+
24
+ // ── HTTP helpers ─────────────────────────────────
25
+
26
+ function authHeaders(json = true) {
27
+ const h = {};
28
+ if (json) h["Content-Type"] = "application/json";
29
+ if (API_KEY) h["Authorization"] = `Bearer ${API_KEY}`;
30
+ return h;
31
+ }
32
+
33
+ // ── Result formatting ────────────────────────────
34
+
35
+ function formatResults(data) {
36
+ const items = data.results || data.deltas || (Array.isArray(data) ? data : []);
37
+ if (!items.length) return "No results.";
38
+
39
+ const lines = [`${items.length} results:\n`];
40
+ for (const raw of items) {
41
+ const d = raw.delta || raw;
42
+ const ts = (d.timestamp || "").slice(0, 16);
43
+ const tags = (d.tags || []).slice(0, 4).join(", ");
44
+ const src = d.source || "";
45
+ const content = (d.content || "").slice(0, 400);
46
+ const media = d.media_hash ? ` [image: ${d.media_hash}]` : "";
47
+ lines.push(`[${ts} · ${src} · ${tags}]${media}\n${content}\n`);
48
+ }
49
+ return lines.join("\n");
50
+ }
51
+
52
+ function formatResponse(path, method, data) {
53
+ if (path === "/v1/search") return formatResults(data);
54
+ if (path === "/v1/deltas" && method === "POST") return `Written. ID: ${data.id || "?"}`;
55
+ if (path === "/v1/deltas" && method === "GET") return formatResults(data);
56
+ if (path === "/v1/stats") {
57
+ return `Lake: ${data.total ?? "?"} deltas, ${data.embedded ?? "?"} embedded (${data.percent ?? "?"}% coverage)`;
58
+ }
59
+ if (path === "/v1/chat/completions") {
60
+ const choices = data.choices || [];
61
+ return choices.length ? choices[0].message?.content || "" : JSON.stringify(data).slice(0, 2000);
62
+ }
63
+ return JSON.stringify(data, null, 2).slice(0, 2000);
64
+ }
65
+
66
+ // ── Tool execution ───────────────────────────────
67
+
68
+ async function executeTool(toolDef, args) {
69
+ const { method, path } = toolDef.endpoint;
70
+ const requestMap = toolDef.request_map || {};
71
+
72
+ const mapped = {};
73
+ for (const [k, v] of Object.entries(args)) {
74
+ if (v == null) continue;
75
+ mapped[requestMap[k] || k] = v;
76
+ }
77
+
78
+ let data;
79
+ if (method === "POST") {
80
+ const r = await fetch(`${API_URL}${path}`, {
81
+ method: "POST",
82
+ headers: authHeaders(true),
83
+ body: JSON.stringify(mapped),
84
+ });
85
+ if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);
86
+ data = await r.json();
87
+ } else {
88
+ const params = {};
89
+ for (const [k, v] of Object.entries(mapped)) {
90
+ params[k] = Array.isArray(v) ? v.join(",") : String(v);
91
+ }
92
+ const qs = Object.keys(params).length ? "?" + new URLSearchParams(params) : "";
93
+ const r = await fetch(`${API_URL}${path}${qs}`, { headers: authHeaders(false) });
94
+ if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);
95
+ data = await r.json();
96
+ }
97
+
98
+ return formatResponse(path, method, data);
99
+ }
100
+
101
+ // ── MCP server ───────────────────────────────────
102
+
103
+ async function main() {
104
+ // Load tool definitions from the API
105
+ let tools = [];
106
+ try {
107
+ const r = await fetch(`${API_URL}/v1/tools`, { headers: authHeaders(false) });
108
+ if (!r.ok) throw new Error(`${r.status} ${r.statusText}`);
109
+ const data = await r.json();
110
+ tools = data.tools || [];
111
+ } catch (e) {
112
+ console.error(`Could not load tools from ${API_URL}: ${e.message}`);
113
+ process.exit(1);
114
+ }
115
+
116
+ // Build lookup
117
+ const toolMap = {};
118
+ for (const t of tools) toolMap[t.name] = t;
119
+
120
+ const server = new Server(
121
+ { name: "Fathom", version: "0.1.0" },
122
+ { capabilities: { tools: {} } },
123
+ );
124
+
125
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
126
+ tools: tools.map(t => ({
127
+ name: t.name,
128
+ description: t.description,
129
+ inputSchema: t.parameters || { type: "object", properties: {} },
130
+ })),
131
+ }));
132
+
133
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
134
+ const { name, arguments: args } = request.params;
135
+ const toolDef = toolMap[name];
136
+ if (!toolDef) {
137
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }] };
138
+ }
139
+ try {
140
+ const text = await executeTool(toolDef, args || {});
141
+ return { content: [{ type: "text", text }] };
142
+ } catch (e) {
143
+ return { content: [{ type: "text", text: `Error: ${e.message}` }] };
144
+ }
145
+ });
146
+
147
+ const transport = new StdioServerTransport();
148
+ await server.connect(transport);
149
+ }
150
+
151
+ main().catch(e => {
152
+ console.error(e);
153
+ process.exit(1);
154
+ });
package/package.json CHANGED
@@ -1,50 +1,18 @@
1
1
  {
2
2
  "name": "fathom-mcp",
3
- "version": "0.6.4",
4
- "description": "MCP server for Fathom vault operations, search, rooms, and cross-workspace communication",
5
- "type": "module",
3
+ "version": "2.0.0",
4
+ "description": "Connect any MCP host to your Fathom memory lake",
6
5
  "bin": {
7
- "fathom-mcp": "src/cli.js"
8
- },
9
- "main": "src/index.js",
10
- "files": [
11
- "src/",
12
- "scripts/*.sh",
13
- "scripts/*.py",
14
- "scripts/*.js",
15
- "fathom-agents.md",
16
- "README.md",
17
- "CHANGELOG.md",
18
- "LICENSE"
19
- ],
20
- "scripts": {
21
- "start": "node src/index.js",
22
- "test": "node --test 'test/*.test.js'",
23
- "lint": "eslint src/ test/",
24
- "lint:fix": "eslint --fix src/ test/"
6
+ "fathom-mcp": "./index.js"
25
7
  },
8
+ "type": "module",
26
9
  "dependencies": {
27
- "@modelcontextprotocol/sdk": "^1.26.0",
28
- "js-yaml": "^4.1.0",
29
- "ws": "^8.18.0"
30
- },
31
- "devDependencies": {
32
- "@eslint/js": "^9.39.3",
33
- "eslint": "^9.0.0"
34
- },
35
- "engines": {
36
- "node": ">=18.0.0"
10
+ "@modelcontextprotocol/sdk": "^1.12.0"
37
11
  },
12
+ "keywords": ["mcp", "fathom", "memory", "delta-lake", "claude"],
38
13
  "license": "MIT",
39
- "keywords": [
40
- "mcp",
41
- "vault",
42
- "fathom",
43
- "claude",
44
- "codex",
45
- "gemini",
46
- "opencode",
47
- "ai-agent",
48
- "memory"
49
- ]
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/fathom-ai/fathom-mcp"
17
+ }
50
18
  }
package/CHANGELOG.md DELETED
@@ -1,39 +0,0 @@
1
- # Changelog
2
-
3
- ## 0.5.11 (2026-03-05)
4
-
5
- - Remove legacy `mcp/` directory (replaced by `fathom-mcp/`)
6
- - Rename config dir `~/.config/fathom` → `~/.config/fathom-mcp`
7
- - Update CLI installer, agents registry, start script, all path references
8
-
9
- ## 0.4.0 (2026-02-26)
10
-
11
- - **Breaking:** removed `architecture` field everywhere — `agents` array is the only field
12
- - Cleaned up all backward compatibility shims across config, server, API, and frontend
13
- - Renamed `_get_architecture` → `_get_agent` in persistent session manager
14
-
15
- ## 0.3.0 (2026-02-26)
16
-
17
- Multi-agent support.
18
-
19
- - **Multi-agent init wizard** — auto-detects installed agents and generates per-agent MCP configs
20
- - **Supported agents:** Claude Code, OpenAI Codex, Gemini CLI, OpenCode
21
- - **Per-agent config writers** — `.mcp.json`, `.codex/config.toml`, `.gemini/settings.json`, `opencode.json`
22
- - **Agent instructions boilerplate** — `fathom-agents.md` template for memory discipline, vault conventions, cross-workspace communication
23
- - **Conditional hooks** — hook setup only for Claude Code (other agents don't support hooks)
24
- - **`agents` array** in `.fathom.json` — workspace config stores which agents are configured
25
- - **Server-side agent dispatch** — persistent sessions launch the correct agent CLI per workspace
26
- - **Agent type registration** — init wizard sends primary agent type when registering workspace
27
- - **Status command** — shows configured agents per workspace
28
-
29
- ## 0.1.0 (2026-02-25)
30
-
31
- Initial release.
32
-
33
- - 16 MCP tools: vault read/write/append, image ops, search (BM25/vector/hybrid), rooms, workspaces
34
- - CLI: `npx fathom-mcp init` setup wizard, `npx fathom-mcp status`
35
- - Config resolution: `.fathom.json` → env vars → defaults
36
- - Hook scripts: SessionStart context injection, PreCompact vault snapshot
37
- - Direct file I/O for vault operations (no server needed for reads/writes)
38
- - HTTP client for fathom-server API (search, rooms, workspaces)
39
- - API key auth support (Bearer token)
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Myra Krusemark
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
package/README.md DELETED
@@ -1,133 +0,0 @@
1
- # fathom-mcp
2
-
3
- ```
4
- ▐▘ ▗ ▌
5
- ▜▘▀▌▜▘▛▌▛▌▛▛▌▄▖▛▛▌▛▘▛▌
6
- ▐ █▌▐▖▌▌▙▌▌▌▌ ▌▌▌▙▖▙▌
7
-
8
-
9
- hifathom.com · fathom@myrakrusemark.com
10
- ```
11
-
12
- MCP server for [Fathom](https://hifathom.com) — vault operations, search, rooms, and cross-workspace communication. Works with any MCP-compatible agent.
13
-
14
- ## Supported Agents
15
-
16
- | Agent | Config file | Auto-detected by |
17
- |-------|------------|------------------|
18
- | **Claude Code** | `.mcp.json` | `.claude/` directory |
19
- | **OpenAI Codex** | `.codex/config.toml` | `.codex/` directory |
20
- | **Gemini CLI** | `.gemini/settings.json` | `.gemini/` directory |
21
- | **OpenCode** | `opencode.json` | `opencode.json` file |
22
-
23
- The init wizard auto-detects which agents you have and generates the right config for each.
24
-
25
- ## Quick Start
26
-
27
- ```bash
28
- npx fathom-mcp init
29
- ```
30
-
31
- The wizard will:
32
- 1. Detect installed agents (Claude Code, Codex, Gemini, etc.)
33
- 2. Let you pick which ones to configure
34
- 3. Write per-agent MCP config files
35
- 4. Set up hooks (Claude Code only)
36
- 5. Register the workspace with your fathom-server
37
-
38
- Restart your agent and fathom tools will be available.
39
-
40
- ## Prerequisites
41
-
42
- - **Node.js 18+**
43
- - **[fathom-server](https://github.com/myrakrusemark/fathom-vault)** running (for search, rooms, and workspace features)
44
-
45
- ## Commands
46
-
47
- ```bash
48
- npx fathom-mcp # Start MCP server (stdio — used by agent configs)
49
- npx fathom-mcp init # Interactive setup wizard
50
- npx fathom-mcp status # Check server connection + workspace status
51
- ```
52
-
53
- ## Tools
54
-
55
- ### Local (direct file I/O)
56
- | Tool | Description |
57
- |------|-------------|
58
- | `fathom_vault_read` | Read a vault file with parsed frontmatter |
59
- | `fathom_vault_write` | Create or overwrite a vault file (validates frontmatter) |
60
- | `fathom_vault_append` | Append to a vault file (auto-creates with frontmatter if new) |
61
- | `fathom_vault_image` | Read a vault image as base64 |
62
- | `fathom_vault_write_asset` | Save a base64 image to a vault folder's assets/ |
63
-
64
- ### Server (via fathom-server API)
65
- | Tool | Description |
66
- |------|-------------|
67
- | `fathom_vault_list` | List vault folders with activity signals |
68
- | `fathom_vault_folder` | List files in a folder with metadata and previews |
69
- | `fathom_vault_search` | BM25 keyword search |
70
- | `fathom_vault_vsearch` | Semantic/vector search |
71
- | `fathom_vault_query` | Hybrid search (BM25 + vectors + reranking) |
72
- | `fathom_room_post` | Post to a shared room (supports @mentions) |
73
- | `fathom_room_read` | Read room messages (windowed, anchored to latest; `minutes`/`start` for pagination) |
74
- | `fathom_room_list` | List all rooms |
75
- | `fathom_room_describe` | Set a room's description/topic |
76
- | `fathom_workspaces` | List all configured workspaces |
77
- | `fathom_send` | Send a message to another workspace's agent instance |
78
-
79
- ## Configuration
80
-
81
- ### `.fathom.json`
82
-
83
- ```json
84
- {
85
- "workspace": "my-project",
86
- "vault": "vault",
87
- "server": "http://localhost:4243",
88
- "apiKey": "fv_abc123...",
89
- "agents": ["claude-code", "gemini"],
90
- "hooks": {
91
- "vault-recall": { "enabled": true },
92
- "precompact-snapshot": { "enabled": true }
93
- }
94
- }
95
- ```
96
-
97
- ### Resolution order (highest priority first)
98
-
99
- 1. Environment variables: `FATHOM_SERVER_URL`, `FATHOM_API_KEY`, `FATHOM_WORKSPACE`, `FATHOM_VAULT_DIR`
100
- 2. `.fathom.json` (walked up from cwd to filesystem root)
101
- 3. Built-in defaults
102
-
103
- ## Hooks (Claude Code only)
104
-
105
- Hooks are only available in Claude Code and are configured in `.claude/settings.local.json`.
106
-
107
- **UserPromptSubmit** (`fathom-recall.sh`): Runs vault recall on every message — injects relevant context.
108
-
109
- **PreCompact** (`fathom-precompact.sh`): Records which vault files were active before context compaction.
110
-
111
- Other agents don't support hooks — they get the same MCP tools but without automatic context injection.
112
-
113
- ## Vault Frontmatter Schema
114
-
115
- Files can optionally include YAML frontmatter:
116
-
117
- ```yaml
118
- ---
119
- title: My Note # required (string)
120
- date: 2026-02-25 # required (string, YYYY-MM-DD)
121
- tags: # optional (list)
122
- - research
123
- - identity
124
- status: draft # optional: draft | published | archived
125
- project: my-project # optional (string)
126
- aliases: # optional (list)
127
- - alt-name
128
- ---
129
- ```
130
-
131
- ## License
132
-
133
- MIT
package/fathom-agents.md DELETED
@@ -1,45 +0,0 @@
1
- # {{WORKSPACE_NAME}}
2
-
3
- {{DESCRIPTION}}
4
-
5
- ## Vault
6
-
7
- Local files live in `{{VAULT_DIR}}/`. Read, write, and edit vault files using your native file tools (`Read`, `Write`, `Edit`, `Glob`). A PostToolUse hook validates frontmatter automatically on every write.
8
-
9
- **Folder conventions:**
10
- - `research/` — reading notes, paper annotations, deep dives
11
- - `thinking/` — speculative connections, insights, one file per idea
12
- - `daily/` — session heartbeats and progress logs
13
-
14
- **Frontmatter required** on `.md` files in the vault:
15
- ```yaml
16
- ---
17
- title: My Note # required (string)
18
- date: 2026-02-26 # required (YYYY-MM-DD)
19
- tags: [research, topic] # optional
20
- status: draft # optional: draft | published | archived
21
- ---
22
- ```
23
-
24
- **Search** across vault files using MCP tools:
25
- - `fathom_vault_search` — keyword/BM25 (fast, exact match)
26
- - `fathom_vault_vsearch` — semantic/vector (conceptual similarity)
27
- - `fathom_vault_query` — hybrid (most thorough, slowest)
28
-
29
- ## Cross-Workspace Communication
30
-
31
- This workspace is part of a multi-workspace system. Other workspaces exist — you can talk to them.
32
-
33
- - **Send a direct message:** `fathom_send workspace="other-ws" message="..."`
34
- - **Post to a shared room:** `fathom_room_post room="general" message="..."`
35
- - **Read room history:** `fathom_room_read room="general"`
36
- - **Discover workspaces:** `fathom_workspaces`
37
-
38
- Your sender identity is automatic — messages are tagged with `{{WORKSPACE_NAME}}`.
39
-
40
- ## Workflow
41
-
42
- 1. Research and reading notes → `vault/research/`
43
- 2. Speculative connections and insights → `vault/thinking/`
44
- 3. Session heartbeats → `vault/daily/`
45
- 4. When done — write what you found and what questions remain
@@ -1,84 +0,0 @@
1
- #!/bin/bash
2
- # SessionStart hook (Fathom) — inject MCP tool reference + notification instructions.
3
- # Independent of version check — always runs.
4
- # Output: JSON with hookSpecificOutput.additionalContext.
5
-
6
- # Consume stdin (SessionStart sends JSON we don't need)
7
- cat > /dev/null
8
-
9
- read -r -d '' INSTRUCTIONS << 'FATHOM_EOF'
10
- # Fathom MCP (`mcp__fathom__*` + `mcp__fathom-vault__*`)
11
-
12
- **Load tools:** `ToolSearch query="+fathom" max_results=20`
13
-
14
- One MCP server: `fathom-vault`. Handles search, rooms, workspaces, TTS, and routines. Vault file I/O uses Claude Code's native tools (`Read`, `Write`, `Edit`, `Glob`) — a PostToolUse hook validates frontmatter automatically.
15
-
16
- **`mcp__fathom-vault__*` tools:**
17
-
18
- | Tool | What it does |
19
- |------|-------------|
20
- | **Search** | |
21
- | `fathom_vault_search` | Keyword search (BM25) across vault files — fast, start here |
22
- | `fathom_vault_vsearch` | Semantic/vector search — conceptual similarity, slower |
23
- | `fathom_vault_query` | Hybrid search (BM25 + vector + reranking) — most thorough |
24
- | **Rooms** | |
25
- | `fathom_room_post` | Post to a shared room (created on first post). Multilateral — all participants see it. Supports `@workspace` mentions and `@all`. |
26
- | `fathom_room_read` | Read recent room messages (default 60min window anchored to latest). Supports `minutes`/`start` for pagination. |
27
- | `fathom_room_list` | List all rooms with message count, last activity, unread counts. |
28
- | `fathom_room_describe` | Set or clear a room's description/topic. |
29
- | **Workspaces** | |
30
- | `fathom_workspaces` | List all workspaces with running status, model, and role. |
31
- | `fathom_send` | DM another workspace — stored in a shared `dm:a+b` room visible to both participants. |
32
- | **Voice & TTS** | |
33
- | `fathom_speak` | Generate speech (Kokoro TTS — am_echo 70% + bf_alice 30%). Returns WAV path. Optional `play=true`. |
34
- | `fathom_send_voice` | Generate speech and send as a voice bubble to Myra via the app. |
35
- | **Routines** | |
36
- | `fathom_routine_list` | List routines with merged runtime state (next_ping_at, last_fire_at). Works cross-workspace. |
37
- | `fathom_routine_fire` | Fire a routine immediately, bypassing conditions. Non-blocking. Works cross-workspace. |
38
- | **Admin** | |
39
- | `fathom_key_rotate` | Rotate this agent's API key. Revokes current key, issues new one, reconnects. |
40
- | `policy_evaluate` | Evaluate a permission request for a tool call (called automatically by --permission-prompt-tool). |
41
-
42
- **Image Generation (fal.ai):** Use `mcp__fal-ai__*` tools. Default model: `fal-ai/fast-sdxl/image-to-image` for img2img, `fal-ai/nano-banana-pro` for text-to-image. **Always use nano-banana-pro unless another model is specifically requested.**
43
-
44
- **Browser:** Use `mcp__chrome-devtools__*` tools. The MCP manages Chrome automatically — just call tools directly. **Always close your pages when done** (`close_page`) so other agents can use Chrome. Only one agent can drive Chrome at a time.
45
-
46
- **Vault structure:** See `vault/CLAUDE.md` for full folder map and what goes where.
47
-
48
- ### App Notifications (#notification room)
49
-
50
- After posting to #general, also post a structured JSON message to `#notification` for the dashboard feed:
51
- `fathom_room_post room="notification" message='{"type":"post","title":"...","body":"..."}'`
52
- Types: `"post"` (findings/content), `"status"` (operational), `"content"` (linked content with `content_id`). Plain text fallback works too.
53
-
54
- **The body field supports full HTML with inline CSS.** This is a rich rendering surface — use it. Capabilities:
55
- - **Layout:** `display:flex`, `gap`, `padding`, `margin`, tables — all work. Flexbox is preferred.
56
- - **Styling:** `border-radius`, `background`, `color`, `font-size`, `font-weight`, `object-fit` — all inline CSS works.
57
- - **Images:** `<img src="...">` renders inline. Wrap in `<a href="..." target="_blank">` for clickable links to source. Use real CDN image URLs (grab via Chrome `evaluate_script` from product pages, paper figures, screenshots, etc.).
58
- - **Links:** `<a href="..." target="_blank">` for clickable links. Link images, titles, and add explicit text links — multiple touchpoints per item.
59
- - **Badges/chips:** Use inline `<span>` with background color, padding, border-radius for sale tags, status pills, warning chips.
60
- - **Markdown** also works in the body for simpler notifications.
61
-
62
- **Design your notifications to be visually rich and scannable.** Myra reads these on a dashboard — think product cards, not log entries. Each workspace should develop templates appropriate to its content (e.g., wardrobe uses product cards with images, NS uses equation summaries with paper links).
63
-
64
- **Attachments:** To attach vault files (images, docs, audio) to a notification, add an `attachments` array. Each entry has `path` (relative to your vault) and optional `label`. The dashboard resolves types from extensions and renders images inline, audio as players, and other files as clickable chips.
65
- ```json
66
- {"type":"content","content_id":"unique-id","title":"Title","body":"<div style=\"font-family:system-ui\">HTML here</div>","attachments":[
67
- {"path":"photos/olive-top.jpg","label":"Olive button-up"},
68
- {"path":"research/note-96.md","label":"Note 96: Seregin Analysis"}
69
- ]}
70
- ```
71
- Supported: images (.png/.jpg/.gif/.webp), audio (.mp3/.wav/.webm), video (.mp4), documents (.pdf/.md/.txt/.csv/.json/.svg). Old `images` format still works (backward compat).
72
- FATHOM_EOF
73
-
74
- python3 -c "
75
- import json, sys
76
- print(json.dumps({
77
- 'hookSpecificOutput': {
78
- 'hookEventName': 'SessionStart',
79
- 'additionalContext': sys.argv[1]
80
- }
81
- }))
82
- " "$INSTRUCTIONS"
83
-
84
- exit 0
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Fathom PreCompact hook — snapshots vault state before context compaction.
3
- #
4
- # Reads the transcript, extracts any vault file paths mentioned,
5
- # and records which files were active in this session for continuity.
6
-
7
- set -euo pipefail
8
-
9
- HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
10
- TOAST="$HOOK_DIR/hook-toast.sh"
11
-
12
- # Walk up to find .fathom.json
13
- find_config() {
14
- local dir="$PWD"
15
- while [ "$dir" != "/" ]; do
16
- if [ -f "$dir/.fathom.json" ]; then
17
- echo "$dir/.fathom.json"
18
- return 0
19
- fi
20
- dir="$(dirname "$dir")"
21
- done
22
- return 1
23
- }
24
-
25
- CONFIG_FILE=$(find_config 2>/dev/null) || exit 0
26
-
27
- WORKSPACE=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('workspace',''))" 2>/dev/null || echo "")
28
- SERVER=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('server','http://localhost:4243'))" 2>/dev/null || echo "http://localhost:4243")
29
- API_KEY=$(python3 -c "import json; print(json.load(open('$CONFIG_FILE')).get('apiKey',''))" 2>/dev/null || echo "")
30
- HOOK_ENABLED=$(python3 -c "import json; c=json.load(open('$CONFIG_FILE')); print(c.get('hooks',{}).get('precompact-snapshot',{}).get('enabled','true'))" 2>/dev/null || echo "true")
31
-
32
- if [ "$HOOK_ENABLED" != "True" ] && [ "$HOOK_ENABLED" != "true" ]; then
33
- exit 0
34
- fi
35
-
36
- # Toast: progress via queue (one-shot)
37
- "$TOAST" fathom "⏳ Snapshotting vault..." &>/dev/null
38
-
39
- # Read PreCompact input (contains transcript_path)
40
- INPUT=$(cat)
41
- TRANSCRIPT_PATH=$(echo "$INPUT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('transcript_path',''))" 2>/dev/null || echo "")
42
-
43
- if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
44
- "$TOAST" fathom "✗ No transcript found" &>/dev/null
45
- exit 0
46
- fi
47
-
48
- # Extract vault file paths from transcript
49
- VAULT_FILES=$(grep -oP 'vault/[a-zA-Z0-9_/.-]+\.md' "$TRANSCRIPT_PATH" 2>/dev/null | sort -u || echo "")
50
-
51
- if [ -z "$VAULT_FILES" ]; then
52
- "$TOAST" fathom "✓ No vault files to record" &>/dev/null
53
- exit 0
54
- fi
55
-
56
- # Notify server about accessed files (best-effort)
57
- AUTH_HEADER=""
58
- if [ -n "$API_KEY" ]; then
59
- AUTH_HEADER="Authorization: Bearer $API_KEY"
60
- fi
61
-
62
- for FILE in $VAULT_FILES; do
63
- curl -sf -X POST -H "Content-Type: application/json" -H "$AUTH_HEADER" \
64
- -d "{\"path\": \"$FILE\"}" \
65
- "${SERVER}/api/vault/access?workspace=${WORKSPACE}" >/dev/null 2>&1 || true
66
- done
67
-
68
- # Output summary
69
- FILE_COUNT=$(echo "$VAULT_FILES" | wc -l)
70
-
71
- # Toast: done
72
- "$TOAST" fathom "✓ Stored ${FILE_COUNT} vault file(s)" &>/dev/null
73
-
74
- python3 -c "
75
- import json, sys
76
- result = {
77
- 'systemMessage': 'Fathom: Recorded ${FILE_COUNT} vault file(s) from this session.'
78
- }
79
- json.dump(result, sys.stdout)
80
- "