openmymemo 0.2.4__tar.gz
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.
- openmymemo-0.2.4/.agents/plugins/marketplace.json +12 -0
- openmymemo-0.2.4/.claude-plugin/marketplace.json +14 -0
- openmymemo-0.2.4/.claude-plugin/plugin.json +39 -0
- openmymemo-0.2.4/.github/dependabot.yml +11 -0
- openmymemo-0.2.4/.github/workflows/ci.yml +75 -0
- openmymemo-0.2.4/.github/workflows/release.yml +202 -0
- openmymemo-0.2.4/.gitignore +227 -0
- openmymemo-0.2.4/AGENTS.md +72 -0
- openmymemo-0.2.4/LICENSE +201 -0
- openmymemo-0.2.4/PKG-INFO +229 -0
- openmymemo-0.2.4/PRIVACY.md +97 -0
- openmymemo-0.2.4/README.md +194 -0
- openmymemo-0.2.4/SECURITY.md +26 -0
- openmymemo-0.2.4/desktop/package.json +14 -0
- openmymemo-0.2.4/desktop/pnpm-lock.yaml +135 -0
- openmymemo-0.2.4/desktop/splash/icon.png +0 -0
- openmymemo-0.2.4/desktop/splash/index.html +82 -0
- openmymemo-0.2.4/desktop/src-tauri/.gitignore +7 -0
- openmymemo-0.2.4/desktop/src-tauri/Cargo.lock +5200 -0
- openmymemo-0.2.4/desktop/src-tauri/Cargo.toml +33 -0
- openmymemo-0.2.4/desktop/src-tauri/build.rs +16 -0
- openmymemo-0.2.4/desktop/src-tauri/capabilities/default.json +17 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/128x128.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/128x128@2x.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/32x32.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/app-icon.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/icon.icns +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/icon.ico +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/icon.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/icons/tray.png +0 -0
- openmymemo-0.2.4/desktop/src-tauri/src/core.rs +898 -0
- openmymemo-0.2.4/desktop/src-tauri/src/install.rs +338 -0
- openmymemo-0.2.4/desktop/src-tauri/src/launcher.rs +386 -0
- openmymemo-0.2.4/desktop/src-tauri/src/main.rs +950 -0
- openmymemo-0.2.4/desktop/src-tauri/tauri.conf.json +33 -0
- openmymemo-0.2.4/docs/MEMORY_FORMAT.md +446 -0
- openmymemo-0.2.4/docs/distribution.md +52 -0
- openmymemo-0.2.4/docs/images/panel-changes.png +0 -0
- openmymemo-0.2.4/docs/images/panel-memories-dark.png +0 -0
- openmymemo-0.2.4/docs/images/panel-memories-light.png +0 -0
- openmymemo-0.2.4/docs/product-design.md +595 -0
- openmymemo-0.2.4/gemini-extension.json +26 -0
- openmymemo-0.2.4/integrations/claude-code/hooks/hooks.json +19 -0
- openmymemo-0.2.4/integrations/claude-desktop/.mcpbignore +7 -0
- openmymemo-0.2.4/integrations/claude-desktop/manifest.json +68 -0
- openmymemo-0.2.4/integrations/codex/setup.sh +10 -0
- openmymemo-0.2.4/integrations/gemini/GEMINI.md +20 -0
- openmymemo-0.2.4/integrations/hooks/session-start.sh +10 -0
- openmymemo-0.2.4/integrations/icons/icon-128.png +0 -0
- openmymemo-0.2.4/integrations/icons/icon-16.png +0 -0
- openmymemo-0.2.4/integrations/icons/icon-32.png +0 -0
- openmymemo-0.2.4/integrations/icons/icon-48.png +0 -0
- openmymemo-0.2.4/integrations/icons/icon-512.png +0 -0
- openmymemo-0.2.4/llms-install.md +40 -0
- openmymemo-0.2.4/mcp.json +11 -0
- openmymemo-0.2.4/plugin.json +31 -0
- openmymemo-0.2.4/pyproject.toml +72 -0
- openmymemo-0.2.4/scripts/build_mcpb.py +51 -0
- openmymemo-0.2.4/scripts/demo_vault.py +84 -0
- openmymemo-0.2.4/scripts/make_icons.py +68 -0
- openmymemo-0.2.4/scripts/stage_desktop.py +51 -0
- openmymemo-0.2.4/server.json +65 -0
- openmymemo-0.2.4/skills/codex-setup/SKILL.md +22 -0
- openmymemo-0.2.4/skills/memory/SKILL.md +14 -0
- openmymemo-0.2.4/skills/remember/SKILL.md +15 -0
- openmymemo-0.2.4/src/openmymemo/__init__.py +3 -0
- openmymemo-0.2.4/src/openmymemo/__main__.py +3 -0
- openmymemo-0.2.4/src/openmymemo/appfiles.py +87 -0
- openmymemo-0.2.4/src/openmymemo/cli.py +905 -0
- openmymemo-0.2.4/src/openmymemo/clients.py +1018 -0
- openmymemo-0.2.4/src/openmymemo/cloud.py +1382 -0
- openmymemo-0.2.4/src/openmymemo/codex.py +147 -0
- openmymemo-0.2.4/src/openmymemo/connectors.py +246 -0
- openmymemo-0.2.4/src/openmymemo/context.py +268 -0
- openmymemo-0.2.4/src/openmymemo/mcp_server.py +249 -0
- openmymemo-0.2.4/src/openmymemo/mdfile.py +371 -0
- openmymemo-0.2.4/src/openmymemo/proposals.py +474 -0
- openmymemo-0.2.4/src/openmymemo/snippets.py +93 -0
- openmymemo-0.2.4/src/openmymemo/static/assets/index-B3p4vYgC.js +2 -0
- openmymemo-0.2.4/src/openmymemo/static/assets/index-Bh2BAn9N.css +1 -0
- openmymemo-0.2.4/src/openmymemo/static/index.html +14 -0
- openmymemo-0.2.4/src/openmymemo/static/logo.png +0 -0
- openmymemo-0.2.4/src/openmymemo/textutil.py +130 -0
- openmymemo-0.2.4/src/openmymemo/topics.py +195 -0
- openmymemo-0.2.4/src/openmymemo/transfer.py +273 -0
- openmymemo-0.2.4/src/openmymemo/vault.py +875 -0
- openmymemo-0.2.4/src/openmymemo/web.py +666 -0
- openmymemo-0.2.4/tests/cloud_fake.py +277 -0
- openmymemo-0.2.4/tests/conftest.py +18 -0
- openmymemo-0.2.4/tests/fixtures/cloud/README.md +10 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/ack.json +5 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/bye.json +5 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/call.json +16 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/call_propose.json +20 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/close_codes.json +12 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/handshake.json +16 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/hello.json +306 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/item.json +12 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/ping.json +4 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/pong.json +4 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/result_error.json +8 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/result_ok.json +17 -0
- openmymemo-0.2.4/tests/fixtures/cloud/bridge/welcome.json +21 -0
- openmymemo-0.2.4/tests/fixtures/cloud/hpke_vector.json +32 -0
- openmymemo-0.2.4/tests/fixtures/cloud/link/authorize_url.json +4 -0
- openmymemo-0.2.4/tests/fixtures/cloud/link/request.json +8 -0
- openmymemo-0.2.4/tests/fixtures/cloud/link/response.json +13 -0
- openmymemo-0.2.4/tests/fixtures/cloud/link/unlink.json +10 -0
- openmymemo-0.2.4/tests/test_cli.py +323 -0
- openmymemo-0.2.4/tests/test_clients.py +875 -0
- openmymemo-0.2.4/tests/test_cloud.py +1168 -0
- openmymemo-0.2.4/tests/test_codex_setup.py +121 -0
- openmymemo-0.2.4/tests/test_format.py +270 -0
- openmymemo-0.2.4/tests/test_log.py +112 -0
- openmymemo-0.2.4/tests/test_mcp.py +185 -0
- openmymemo-0.2.4/tests/test_mdfile.py +105 -0
- openmymemo-0.2.4/tests/test_onboarded.py +83 -0
- openmymemo-0.2.4/tests/test_packaging.py +115 -0
- openmymemo-0.2.4/tests/test_proposals.py +366 -0
- openmymemo-0.2.4/tests/test_transfer_context.py +281 -0
- openmymemo-0.2.4/tests/test_vault.py +158 -0
- openmymemo-0.2.4/tests/test_vault_concurrency.py +39 -0
- openmymemo-0.2.4/tests/test_web.py +290 -0
- openmymemo-0.2.4/uv.lock +1194 -0
- openmymemo-0.2.4/web/index.html +13 -0
- openmymemo-0.2.4/web/package.json +27 -0
- openmymemo-0.2.4/web/pnpm-lock.yaml +1685 -0
- openmymemo-0.2.4/web/public/logo.png +0 -0
- openmymemo-0.2.4/web/src/App.test.ts +81 -0
- openmymemo-0.2.4/web/src/App.vue +245 -0
- openmymemo-0.2.4/web/src/api.ts +396 -0
- openmymemo-0.2.4/web/src/components/AppIcon.vue +23 -0
- openmymemo-0.2.4/web/src/components/AppToast.vue +21 -0
- openmymemo-0.2.4/web/src/components/ApprovalSwitch.vue +21 -0
- openmymemo-0.2.4/web/src/components/CloudRow.test.ts +221 -0
- openmymemo-0.2.4/web/src/components/CloudRow.vue +279 -0
- openmymemo-0.2.4/web/src/components/CloudSettings.test.ts +101 -0
- openmymemo-0.2.4/web/src/components/CloudSettings.vue +107 -0
- openmymemo-0.2.4/web/src/components/ConnectApps.test.ts +186 -0
- openmymemo-0.2.4/web/src/components/ConnectApps.vue +351 -0
- openmymemo-0.2.4/web/src/components/ConnectNote.vue +55 -0
- openmymemo-0.2.4/web/src/components/ConnectorPanel.vue +210 -0
- openmymemo-0.2.4/web/src/components/DesktopSidebar.vue +142 -0
- openmymemo-0.2.4/web/src/components/DesktopToolbar.vue +38 -0
- openmymemo-0.2.4/web/src/components/DigestRow.vue +136 -0
- openmymemo-0.2.4/web/src/components/DropMenu.vue +64 -0
- openmymemo-0.2.4/web/src/components/HistoryDialog.vue +48 -0
- openmymemo-0.2.4/web/src/components/ImportPaste.vue +83 -0
- openmymemo-0.2.4/web/src/components/MemoryInspector.test.ts +220 -0
- openmymemo-0.2.4/web/src/components/MemoryInspector.vue +262 -0
- openmymemo-0.2.4/web/src/components/MemoryRow.vue +146 -0
- openmymemo-0.2.4/web/src/components/ModalDialog.vue +44 -0
- openmymemo-0.2.4/web/src/components/NewTopicDialog.vue +45 -0
- openmymemo-0.2.4/web/src/components/PageHeader.vue +25 -0
- openmymemo-0.2.4/web/src/components/ProposalCard.vue +112 -0
- openmymemo-0.2.4/web/src/components/SettingsSheet.test.ts +19 -0
- openmymemo-0.2.4/web/src/components/SettingsSheet.vue +150 -0
- openmymemo-0.2.4/web/src/components/SnippetTabs.vue +44 -0
- openmymemo-0.2.4/web/src/components/SortDialog.vue +106 -0
- openmymemo-0.2.4/web/src/desktop.ts +76 -0
- openmymemo-0.2.4/web/src/i18n.ts +577 -0
- openmymemo-0.2.4/web/src/icons.ts +33 -0
- openmymemo-0.2.4/web/src/main.ts +8 -0
- openmymemo-0.2.4/web/src/memoryList.ts +87 -0
- openmymemo-0.2.4/web/src/memorySaves.ts +54 -0
- openmymemo-0.2.4/web/src/store.ts +107 -0
- openmymemo-0.2.4/web/src/style.css +218 -0
- openmymemo-0.2.4/web/src/views/ActivityView.vue +62 -0
- openmymemo-0.2.4/web/src/views/ChangesView.vue +135 -0
- openmymemo-0.2.4/web/src/views/ConnectorsView.test.ts +113 -0
- openmymemo-0.2.4/web/src/views/ConnectorsView.vue +59 -0
- openmymemo-0.2.4/web/src/views/ContextView.vue +51 -0
- openmymemo-0.2.4/web/src/views/ImportView.vue +103 -0
- openmymemo-0.2.4/web/src/views/MemoriesDesktopView.vue +304 -0
- openmymemo-0.2.4/web/src/views/MemoriesView.vue +276 -0
- openmymemo-0.2.4/web/src/views/WelcomeView.test.ts +328 -0
- openmymemo-0.2.4/web/src/views/WelcomeView.vue +409 -0
- openmymemo-0.2.4/web/tsconfig.json +17 -0
- openmymemo-0.2.4/web/vite.config.ts +31 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openmymemo",
|
|
3
|
+
"interface": { "displayName": "OpenMyMemo" },
|
|
4
|
+
"plugins": [
|
|
5
|
+
{
|
|
6
|
+
"name": "openmymemo",
|
|
7
|
+
"source": { "source": "local", "path": "./" },
|
|
8
|
+
"policy": { "installation": "AVAILABLE", "authentication": "ON_INSTALL" },
|
|
9
|
+
"category": "Productivity"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openmymemo",
|
|
3
|
+
"description": "OpenMyMemo: a local, user-owned AI memory for Claude Code.",
|
|
4
|
+
"owner": { "name": "MyMemo", "url": "https://github.com/MyMemoAI/openmymemo" },
|
|
5
|
+
"plugins": [
|
|
6
|
+
{
|
|
7
|
+
"name": "openmymemo",
|
|
8
|
+
"source": ".",
|
|
9
|
+
"description": "Start every session with your memory; what Claude writes shows up in a digest you can undo.",
|
|
10
|
+
"category": "productivity",
|
|
11
|
+
"tags": ["memory", "mcp", "local-first"]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "openmymemo",
|
|
3
|
+
"displayName": "OpenMyMemo",
|
|
4
|
+
"version": "0.2.4",
|
|
5
|
+
"description": "Your AI memory as a local folder you own. Claude starts each session with it and writes what it learns; you see every change and can undo it.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "MyMemo",
|
|
8
|
+
"url": "https://github.com/MyMemoAI/openmymemo"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/MyMemoAI/openmymemo",
|
|
11
|
+
"repository": "https://github.com/MyMemoAI/openmymemo",
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"memory",
|
|
15
|
+
"local-first",
|
|
16
|
+
"mcp",
|
|
17
|
+
"privacy"
|
|
18
|
+
],
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"openmymemo": {
|
|
21
|
+
"command": "uv",
|
|
22
|
+
"args": [
|
|
23
|
+
"run",
|
|
24
|
+
"--directory",
|
|
25
|
+
"${CLAUDE_PLUGIN_ROOT}",
|
|
26
|
+
"--frozen", "--no-dev",
|
|
27
|
+
"--quiet",
|
|
28
|
+
"openmymemo",
|
|
29
|
+
"mcp",
|
|
30
|
+
"--connector",
|
|
31
|
+
"claude-code",
|
|
32
|
+
"--init",
|
|
33
|
+
"--panel-port",
|
|
34
|
+
"8787"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"hooks": "./integrations/claude-code/hooks/hooks.json"
|
|
39
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security fixes for Python and panel dependencies come from Dependabot security updates (repo setting).
|
|
2
|
+
# This file only keeps the GitHub Actions used by the workflows up to date, in one monthly PR.
|
|
3
|
+
version: 2
|
|
4
|
+
updates:
|
|
5
|
+
- package-ecosystem: github-actions
|
|
6
|
+
directory: /
|
|
7
|
+
schedule:
|
|
8
|
+
interval: monthly
|
|
9
|
+
groups:
|
|
10
|
+
actions:
|
|
11
|
+
patterns: ["*"]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ci-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
# Three jobs, one per kind of runner: Linux tests the oldest and newest Python we support, macOS tests the
|
|
16
|
+
# middle one together with the Mac app, and the panel job checks the committed build and packs the extension.
|
|
17
|
+
jobs:
|
|
18
|
+
linux:
|
|
19
|
+
name: Python tests (Linux, 3.11 and 3.13)
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v7
|
|
23
|
+
- uses: astral-sh/setup-uv@v7
|
|
24
|
+
- run: uv run --frozen --python 3.13 ruff check src tests scripts
|
|
25
|
+
- name: Tests on Python 3.11
|
|
26
|
+
run: uv run --frozen --python 3.11 pytest
|
|
27
|
+
- name: Tests on Python 3.13
|
|
28
|
+
run: uv run --frozen --python 3.13 pytest
|
|
29
|
+
|
|
30
|
+
macos:
|
|
31
|
+
name: macOS tests and Mac app (Python 3.12)
|
|
32
|
+
runs-on: macos-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v7
|
|
35
|
+
- uses: astral-sh/setup-uv@v7
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
- run: uv run --frozen pytest
|
|
39
|
+
- run: python3 scripts/stage_desktop.py # the bundled core and uv, which the Tauri build checks for
|
|
40
|
+
- run: cargo test --locked
|
|
41
|
+
working-directory: desktop/src-tauri
|
|
42
|
+
|
|
43
|
+
panel:
|
|
44
|
+
name: Panel build and extension
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v7
|
|
48
|
+
- uses: pnpm/action-setup@v6
|
|
49
|
+
with:
|
|
50
|
+
version: 10
|
|
51
|
+
- uses: actions/setup-node@v7
|
|
52
|
+
with:
|
|
53
|
+
node-version: 22
|
|
54
|
+
cache: pnpm
|
|
55
|
+
cache-dependency-path: web/pnpm-lock.yaml
|
|
56
|
+
- uses: astral-sh/setup-uv@v7
|
|
57
|
+
- run: pnpm install --frozen-lockfile
|
|
58
|
+
working-directory: web
|
|
59
|
+
- run: pnpm build # type-checks with vue-tsc first
|
|
60
|
+
working-directory: web
|
|
61
|
+
- run: pnpm test
|
|
62
|
+
working-directory: web
|
|
63
|
+
- name: src/openmymemo/static matches web/
|
|
64
|
+
run: |
|
|
65
|
+
if [ -n "$(git status --porcelain src/openmymemo/static)" ]; then
|
|
66
|
+
git status --short src/openmymemo/static
|
|
67
|
+
echo "::error::The committed panel build is out of date. Run 'cd web && pnpm build' and commit src/openmymemo/static."
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
- run: uv run --frozen python scripts/build_mcpb.py # validates the manifest
|
|
71
|
+
- uses: actions/upload-artifact@v7
|
|
72
|
+
with:
|
|
73
|
+
name: openmymemo-mcpb
|
|
74
|
+
path: dist/*.mcpb
|
|
75
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Push a tag named after the version (v0.2.2) to publish the Mac app, the Claude Desktop extension and the
|
|
4
|
+
# Python package as a GitHub release, the Python package on PyPI, and server.json on the MCP Registry. The version
|
|
5
|
+
# must already be bumped everywhere (tests/test_packaging.py).
|
|
6
|
+
# The release is created once every file is built, so it never lacks the disk image; if a job fails, nothing
|
|
7
|
+
# is published and "Re-run failed jobs" picks up from there.
|
|
8
|
+
on:
|
|
9
|
+
push:
|
|
10
|
+
tags: ["v*"]
|
|
11
|
+
|
|
12
|
+
# Only the job that publishes can write; the Mac build runs many build scripts next to the signing secrets.
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
mac:
|
|
18
|
+
name: Mac app
|
|
19
|
+
# Builds OpenMyMemo-<version>-arm64.dmg. With these repository secrets the app is signed with a Developer
|
|
20
|
+
# ID and notarized; without them (a fork) it is signed ad hoc, and macOS asks once to open it (README).
|
|
21
|
+
# APPLE_CERTIFICATE the "Developer ID Application" certificate and its key as a .p12, base64
|
|
22
|
+
# APPLE_CERTIFICATE_PASSWORD the .p12's password
|
|
23
|
+
# APPLE_SIGNING_IDENTITY the certificate's name: "Developer ID Application: <Company> (<Team ID>)"
|
|
24
|
+
# APPLE_API_ISSUER notarization with an App Store Connect API key: the issuer id,
|
|
25
|
+
# APPLE_API_KEY_ID the key id,
|
|
26
|
+
# APPLE_API_PRIVATE_KEY and the text of the key's .p8 file
|
|
27
|
+
# APPLE_ID, APPLE_PASSWORD, APPLE_TEAM_ID
|
|
28
|
+
# optional: notarization with an Apple ID and an app-specific password,
|
|
29
|
+
# used only when the API key secrets are absent
|
|
30
|
+
# Tauri reads the APPLE_* variables itself (tauri-apps/tauri, crates/tauri-bundler/src/bundle/macos/sign.rs):
|
|
31
|
+
# it imports the certificate into a temporary keychain, and APPLE_SIGNING_IDENTITY overrides the ad hoc
|
|
32
|
+
# "signingIdentity": "-" in tauri.conf.json (crates/tauri-cli/src/interface/rust.rs).
|
|
33
|
+
runs-on: macos-latest
|
|
34
|
+
permissions:
|
|
35
|
+
contents: read
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
38
|
+
with:
|
|
39
|
+
persist-credentials: false
|
|
40
|
+
- name: The tag matches the version
|
|
41
|
+
run: |
|
|
42
|
+
version=$(sed -n 's/^version = "\(.*\)"$/\1/p' pyproject.toml | head -n 1)
|
|
43
|
+
if [ "$GITHUB_REF_NAME" != "v$version" ]; then
|
|
44
|
+
echo "::error::Tag $GITHUB_REF_NAME doesn't match version $version in pyproject.toml."
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
echo "VERSION=$version" >> "$GITHUB_ENV"
|
|
48
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7; stage_desktop.py bundles this uv
|
|
49
|
+
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
|
|
50
|
+
with:
|
|
51
|
+
version: 10
|
|
52
|
+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
|
|
53
|
+
with:
|
|
54
|
+
node-version: 22
|
|
55
|
+
cache: pnpm
|
|
56
|
+
cache-dependency-path: desktop/pnpm-lock.yaml
|
|
57
|
+
- run: pnpm install --frozen-lockfile
|
|
58
|
+
working-directory: desktop
|
|
59
|
+
- name: Build the app and the disk image
|
|
60
|
+
working-directory: desktop
|
|
61
|
+
env:
|
|
62
|
+
# CI=true also makes Tauri skip the Finder scripting that lays out the disk image window.
|
|
63
|
+
CI: "true"
|
|
64
|
+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
65
|
+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
66
|
+
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
67
|
+
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
|
|
68
|
+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY_ID }}
|
|
69
|
+
APPLE_API_PRIVATE_KEY: ${{ secrets.APPLE_API_PRIVATE_KEY }}
|
|
70
|
+
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
71
|
+
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
72
|
+
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
73
|
+
run: |
|
|
74
|
+
# A missing secret arrives as an empty variable, which Tauri would take as set.
|
|
75
|
+
for name in APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_API_ISSUER \
|
|
76
|
+
APPLE_API_KEY APPLE_API_PRIVATE_KEY APPLE_ID APPLE_PASSWORD APPLE_TEAM_ID; do
|
|
77
|
+
if [ -z "${!name}" ]; then unset "$name"; fi
|
|
78
|
+
done
|
|
79
|
+
if [ -z "${APPLE_CERTIFICATE:-}" ] || [ -z "${APPLE_CERTIFICATE_PASSWORD:-}" ] || [ -z "${APPLE_SIGNING_IDENTITY:-}" ]; then
|
|
80
|
+
echo "::warning::No Developer ID certificate in the secrets: the app is signed ad hoc and not notarized."
|
|
81
|
+
unset APPLE_CERTIFICATE APPLE_CERTIFICATE_PASSWORD APPLE_SIGNING_IDENTITY APPLE_API_ISSUER APPLE_API_KEY \
|
|
82
|
+
APPLE_ID APPLE_PASSWORD APPLE_TEAM_ID
|
|
83
|
+
elif [ -n "${APPLE_API_PRIVATE_KEY:-}" ] && [ -n "${APPLE_API_KEY:-}" ] && [ -n "${APPLE_API_ISSUER:-}" ]; then
|
|
84
|
+
# Tauri would use APPLE_ID first if it were set; the API key is the one to use.
|
|
85
|
+
unset APPLE_ID APPLE_PASSWORD
|
|
86
|
+
export APPLE_API_KEY_PATH="$RUNNER_TEMP/AuthKey_$APPLE_API_KEY.p8"
|
|
87
|
+
( umask 077 && printf '%s\n' "$APPLE_API_PRIVATE_KEY" > "$APPLE_API_KEY_PATH" )
|
|
88
|
+
elif [ -z "${APPLE_ID:-}" ] || [ -z "${APPLE_PASSWORD:-}" ] || [ -z "${APPLE_TEAM_ID:-}" ]; then
|
|
89
|
+
echo "::warning::No notarization credentials in the secrets: the app is signed but not notarized."
|
|
90
|
+
unset APPLE_ID APPLE_PASSWORD APPLE_API_ISSUER APPLE_API_KEY
|
|
91
|
+
fi
|
|
92
|
+
unset APPLE_API_PRIVATE_KEY
|
|
93
|
+
pnpm tauri build --bundles app,dmg
|
|
94
|
+
- name: Check the signature and name the disk image
|
|
95
|
+
run: |
|
|
96
|
+
bundle=desktop/src-tauri/target/release/bundle
|
|
97
|
+
codesign --verify --deep --strict --verbose=2 "$bundle/macos/OpenMyMemo.app"
|
|
98
|
+
codesign -dv "$bundle/macos/OpenMyMemo.app" 2>&1 | grep -E '^(Authority|Signature|TeamIdentifier)=' || true
|
|
99
|
+
mkdir -p dist
|
|
100
|
+
cp "$bundle/dmg/OpenMyMemo_${VERSION}_aarch64.dmg" "dist/OpenMyMemo-${VERSION}-arm64.dmg"
|
|
101
|
+
hdiutil verify "dist/OpenMyMemo-${VERSION}-arm64.dmg"
|
|
102
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
103
|
+
with:
|
|
104
|
+
name: openmymemo-dmg
|
|
105
|
+
path: dist/*.dmg
|
|
106
|
+
if-no-files-found: error
|
|
107
|
+
|
|
108
|
+
release:
|
|
109
|
+
needs: mac
|
|
110
|
+
runs-on: ubuntu-latest
|
|
111
|
+
permissions:
|
|
112
|
+
contents: write # gh release create
|
|
113
|
+
steps:
|
|
114
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
115
|
+
with:
|
|
116
|
+
persist-credentials: false
|
|
117
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
|
|
118
|
+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7
|
|
119
|
+
with:
|
|
120
|
+
node-version: 22
|
|
121
|
+
- name: The tag matches the version
|
|
122
|
+
run: |
|
|
123
|
+
version=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
124
|
+
if [ "$GITHUB_REF_NAME" != "v$version" ]; then
|
|
125
|
+
echo "::error::Tag $GITHUB_REF_NAME doesn't match version $version in pyproject.toml."
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
- run: uv sync --frozen
|
|
129
|
+
- run: uv run pytest
|
|
130
|
+
- run: uv run python scripts/build_mcpb.py
|
|
131
|
+
- run: uv build
|
|
132
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
133
|
+
with:
|
|
134
|
+
name: openmymemo-dmg
|
|
135
|
+
path: dist
|
|
136
|
+
- name: Publish the release
|
|
137
|
+
env:
|
|
138
|
+
GH_TOKEN: ${{ github.token }}
|
|
139
|
+
run: |
|
|
140
|
+
gh release create "$GITHUB_REF_NAME" dist/*.dmg dist/*.mcpb dist/*.whl dist/*.tar.gz \
|
|
141
|
+
--title "OpenMyMemo ${GITHUB_REF_NAME#v}" --generate-notes
|
|
142
|
+
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7
|
|
143
|
+
with:
|
|
144
|
+
name: openmymemo-python
|
|
145
|
+
path: |
|
|
146
|
+
dist/*.whl
|
|
147
|
+
dist/*.tar.gz
|
|
148
|
+
if-no-files-found: error
|
|
149
|
+
|
|
150
|
+
pypi:
|
|
151
|
+
# The same wheel and sdist as the GitHub release, uploaded with PyPI's trusted publishing: PyPI accepts this
|
|
152
|
+
# job's OIDC token, so there is no API token in the secrets. One-time setup on pypi.org: a trusted publisher
|
|
153
|
+
# for MyMemoAI/openmymemo, workflow release.yml, environment pypi. If it fails after the GitHub release is
|
|
154
|
+
# out, "Re-run failed jobs" runs only this job. PyPI never takes the same version twice.
|
|
155
|
+
needs: release
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
environment:
|
|
158
|
+
name: pypi
|
|
159
|
+
url: https://pypi.org/project/openmymemo/
|
|
160
|
+
permissions:
|
|
161
|
+
id-token: write
|
|
162
|
+
steps:
|
|
163
|
+
- uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7
|
|
164
|
+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
165
|
+
with:
|
|
166
|
+
name: openmymemo-python
|
|
167
|
+
path: dist
|
|
168
|
+
- run: uv publish --trusted-publishing always dist/*
|
|
169
|
+
|
|
170
|
+
mcp-registry:
|
|
171
|
+
# Lists this version on the official MCP Registry (registry.modelcontextprotocol.io), which MCP clients and
|
|
172
|
+
# other directories read. The registry stores only server.json: it checks that the PyPI package of that
|
|
173
|
+
# version exists and that its README names this server ("mcp-name:" near the top of README.md), so it runs
|
|
174
|
+
# after PyPI. GitHub OIDC proves the namespace io.github.MyMemoAI, so there is no token in the secrets.
|
|
175
|
+
needs: pypi
|
|
176
|
+
runs-on: ubuntu-latest
|
|
177
|
+
permissions:
|
|
178
|
+
contents: read
|
|
179
|
+
id-token: write
|
|
180
|
+
steps:
|
|
181
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
182
|
+
with:
|
|
183
|
+
persist-credentials: false
|
|
184
|
+
- name: Install mcp-publisher
|
|
185
|
+
env:
|
|
186
|
+
VERSION: v1.8.1
|
|
187
|
+
SHA256: a06c9096dcb9727c13555b6be26c7effa707b01f06a4c561ba7a3635443cf2cc
|
|
188
|
+
run: |
|
|
189
|
+
curl -fsSL -o mcp-publisher.tar.gz \
|
|
190
|
+
"https://github.com/modelcontextprotocol/registry/releases/download/$VERSION/mcp-publisher_linux_amd64.tar.gz"
|
|
191
|
+
echo "$SHA256 mcp-publisher.tar.gz" | sha256sum --check
|
|
192
|
+
tar xzf mcp-publisher.tar.gz mcp-publisher
|
|
193
|
+
- run: ./mcp-publisher validate
|
|
194
|
+
- run: ./mcp-publisher login github-oidc
|
|
195
|
+
- name: Publish server.json
|
|
196
|
+
run: |
|
|
197
|
+
# PyPI can take a minute to serve a version it has just accepted.
|
|
198
|
+
for wait in 0 30 60 120; do
|
|
199
|
+
sleep "$wait"
|
|
200
|
+
if ./mcp-publisher publish; then exit 0; fi
|
|
201
|
+
done
|
|
202
|
+
exit 1
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
/build/
|
|
12
|
+
/develop-eggs/
|
|
13
|
+
/dist/
|
|
14
|
+
/downloads/
|
|
15
|
+
/eggs/
|
|
16
|
+
/.eggs/
|
|
17
|
+
/lib/
|
|
18
|
+
/lib64/
|
|
19
|
+
/parts/
|
|
20
|
+
/sdist/
|
|
21
|
+
/var/
|
|
22
|
+
/wheels/
|
|
23
|
+
/share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
*.lcov
|
|
51
|
+
.hypothesis/
|
|
52
|
+
.pytest_cache/
|
|
53
|
+
cover/
|
|
54
|
+
|
|
55
|
+
# Translations
|
|
56
|
+
*.mo
|
|
57
|
+
*.pot
|
|
58
|
+
|
|
59
|
+
# Django stuff:
|
|
60
|
+
*.log
|
|
61
|
+
local_settings.py
|
|
62
|
+
db.sqlite3
|
|
63
|
+
db.sqlite3-journal
|
|
64
|
+
|
|
65
|
+
# Flask stuff:
|
|
66
|
+
instance/
|
|
67
|
+
.webassets-cache
|
|
68
|
+
|
|
69
|
+
# Scrapy stuff:
|
|
70
|
+
.scrapy
|
|
71
|
+
|
|
72
|
+
# Sphinx documentation
|
|
73
|
+
docs/_build/
|
|
74
|
+
|
|
75
|
+
# PyBuilder
|
|
76
|
+
.pybuilder/
|
|
77
|
+
target/
|
|
78
|
+
|
|
79
|
+
# Jupyter Notebook
|
|
80
|
+
.ipynb_checkpoints
|
|
81
|
+
|
|
82
|
+
# IPython
|
|
83
|
+
profile_default/
|
|
84
|
+
ipython_config.py
|
|
85
|
+
|
|
86
|
+
# pyenv
|
|
87
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
88
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
89
|
+
# .python-version
|
|
90
|
+
|
|
91
|
+
# pipenv
|
|
92
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
93
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
94
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
95
|
+
# install all needed dependencies.
|
|
96
|
+
# Pipfile.lock
|
|
97
|
+
|
|
98
|
+
# uv
|
|
99
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
100
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
101
|
+
# commonly ignored for libraries.
|
|
102
|
+
# uv.lock
|
|
103
|
+
|
|
104
|
+
# poetry
|
|
105
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
106
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
107
|
+
# commonly ignored for libraries.
|
|
108
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
109
|
+
# poetry.lock
|
|
110
|
+
# poetry.toml
|
|
111
|
+
|
|
112
|
+
# pdm
|
|
113
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
114
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
115
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
116
|
+
# pdm.lock
|
|
117
|
+
# pdm.toml
|
|
118
|
+
.pdm-python
|
|
119
|
+
.pdm-build/
|
|
120
|
+
|
|
121
|
+
# pixi
|
|
122
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
123
|
+
# pixi.lock
|
|
124
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
125
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
126
|
+
.pixi/*
|
|
127
|
+
!.pixi/config.toml
|
|
128
|
+
|
|
129
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
130
|
+
__pypackages__/
|
|
131
|
+
|
|
132
|
+
# Celery stuff
|
|
133
|
+
celerybeat-schedule*
|
|
134
|
+
celerybeat.pid
|
|
135
|
+
|
|
136
|
+
# Redis
|
|
137
|
+
*.rdb
|
|
138
|
+
*.aof
|
|
139
|
+
*.pid
|
|
140
|
+
|
|
141
|
+
# RabbitMQ
|
|
142
|
+
mnesia/
|
|
143
|
+
rabbitmq/
|
|
144
|
+
rabbitmq-data/
|
|
145
|
+
|
|
146
|
+
# ActiveMQ
|
|
147
|
+
activemq-data/
|
|
148
|
+
|
|
149
|
+
# SageMath parsed files
|
|
150
|
+
*.sage.py
|
|
151
|
+
|
|
152
|
+
# Environments
|
|
153
|
+
.env
|
|
154
|
+
.envrc
|
|
155
|
+
.venv
|
|
156
|
+
env/
|
|
157
|
+
venv/
|
|
158
|
+
ENV/
|
|
159
|
+
env.bak/
|
|
160
|
+
venv.bak/
|
|
161
|
+
|
|
162
|
+
# Spyder project settings
|
|
163
|
+
.spyderproject
|
|
164
|
+
.spyproject
|
|
165
|
+
|
|
166
|
+
# Rope project settings
|
|
167
|
+
.ropeproject
|
|
168
|
+
|
|
169
|
+
# mkdocs/Zensical documentation
|
|
170
|
+
/site
|
|
171
|
+
|
|
172
|
+
# mypy
|
|
173
|
+
.mypy_cache/
|
|
174
|
+
.dmypy.json
|
|
175
|
+
dmypy.json
|
|
176
|
+
|
|
177
|
+
# Pyre type checker
|
|
178
|
+
.pyre/
|
|
179
|
+
|
|
180
|
+
# pytype static type analyzer
|
|
181
|
+
.pytype/
|
|
182
|
+
|
|
183
|
+
# Cython debug symbols
|
|
184
|
+
cython_debug/
|
|
185
|
+
|
|
186
|
+
# PyCharm
|
|
187
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
188
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
189
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
190
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
191
|
+
# .idea/
|
|
192
|
+
|
|
193
|
+
# Abstra
|
|
194
|
+
# Abstra is an AI-powered process automation framework.
|
|
195
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
196
|
+
# Learn more at https://abstra.io/docs
|
|
197
|
+
.abstra/
|
|
198
|
+
|
|
199
|
+
# Visual Studio Code
|
|
200
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore that
|
|
201
|
+
# can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
202
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer, you
|
|
203
|
+
# could uncomment the following to ignore the entire vscode folder
|
|
204
|
+
# .vscode/
|
|
205
|
+
# Temporary file for partial code execution
|
|
206
|
+
tempCodeRunnerFile.py
|
|
207
|
+
|
|
208
|
+
# Ruff stuff:
|
|
209
|
+
.ruff_cache/
|
|
210
|
+
|
|
211
|
+
# PyPI configuration file
|
|
212
|
+
.pypirc
|
|
213
|
+
|
|
214
|
+
# Marimo
|
|
215
|
+
marimo/_static/
|
|
216
|
+
marimo/_lsp/
|
|
217
|
+
__marimo__/
|
|
218
|
+
|
|
219
|
+
# Streamlit
|
|
220
|
+
.streamlit/secrets.toml
|
|
221
|
+
|
|
222
|
+
# OpenMyMemo
|
|
223
|
+
node_modules/
|
|
224
|
+
web/.vite/
|
|
225
|
+
|
|
226
|
+
# Agent worktrees created by Claude Code sessions
|
|
227
|
+
.claude/worktrees/
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# OpenMyMemo — agent guide
|
|
2
|
+
|
|
3
|
+
A local-first, open-source AI memory folder with an approval panel. [docs/product-design.md](./docs/product-design.md) is the product definition; if an implementation would contradict it, update the design doc first (§12 and §13 record where v0.1 and v0.2 differ from earlier plans).
|
|
4
|
+
|
|
5
|
+
## Non-negotiables
|
|
6
|
+
|
|
7
|
+
- Local only: no cloud storage, sync, accounts or telemetry, except the optional MyMemo Cloud connector (product-design.md §16), which does nothing until the person signs in and never holds memory in readable form at rest. The server listens on `127.0.0.1` only.
|
|
8
|
+
- All user data is plain text: `memories/*.md` is the source of truth for memory content; metadata, history, activity, proposals and settings under `.openmymemo/` are plain text too. Don't introduce a database.
|
|
9
|
+
- Every AI write goes through a proposal (`proposals.py`) and never edits files directly. A change that applies without the user (the default, or a connector set to `auto`) must stay undoable, must never write into a private topic, and must never silently change a memory the user wrote last (`last_actor`); the table in product-design.md §5.5 is normative.
|
|
10
|
+
- Works with zero external dependencies: anything that needs a model endpoint is optional and degrades instead of failing.
|
|
11
|
+
- No dependency on MyMemo services, accounts or databases. The MyMemo Cloud connector is the one optional piece that talks to MyMemo; everything else works without it, and removing it changes nothing else. Code and UI patterns may be borrowed from MyMemo's own apps; other runtime coupling may not.
|
|
12
|
+
- Don't weaken the panel API guard (`guard` in `web.py`: Host, Origin, `X-OpenMyMemo` header) or the `/mcp` token check.
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv sync
|
|
18
|
+
uv run pytest # all tests, including MCP end to end over stdio and real HTTP
|
|
19
|
+
uv run ruff check src tests scripts
|
|
20
|
+
uv run openmymemo --vault /tmp/v init # CLI
|
|
21
|
+
uv run python scripts/demo_vault.py /tmp/d # demo data
|
|
22
|
+
cd web && pnpm install && pnpm build # panel → src/openmymemo/static/ (commit the build output)
|
|
23
|
+
cd web && pnpm test # panel tests (vitest)
|
|
24
|
+
cd desktop && pnpm install && pnpm tauri dev # Mac app (needs Rust); `pnpm tauri build` for the .app
|
|
25
|
+
python3 scripts/stage_desktop.py && (cd desktop/src-tauri && cargo test) # Mac app tests
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Code map
|
|
29
|
+
|
|
30
|
+
| File | Responsibility |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `src/openmymemo/mdfile.py` | Parse and rewrite topic files (frontmatter, sections, memory lines; format-1 header migration); untouched lines must survive byte for byte |
|
|
33
|
+
| `src/openmymemo/vault.py` | The vault: sync (editor edits → meta/history), add/update/archive/restore/rollback, settings, locking |
|
|
34
|
+
| `src/openmymemo/topics.py` | The 14 default topics, groups, classification keywords |
|
|
35
|
+
| `docs/MEMORY_FORMAT.md` | The folder format; change it before changing what the code reads or writes |
|
|
36
|
+
| `docs/distribution.md`, `llms-install.md` | Where OpenMyMemo is published and listed, the shared listing details, and the setup guide AI agents such as Cline follow |
|
|
37
|
+
| `src/openmymemo/textutil.py` | Similarity, search scoring, rule-based classification |
|
|
38
|
+
| `src/openmymemo/connectors.py` | Connector permissions, tokens, revocation tombstones |
|
|
39
|
+
| `src/openmymemo/clients.py` | The catalog of AI apps (product-design.md §15.1): detection, status, one-click connect and disconnect by editing an app's MCP config (JSON or Codex TOML) or running its `mcp add`, and the manual snippets |
|
|
40
|
+
| `src/openmymemo/appfiles.py` | Writing other apps' files (their MCP configs, Codex's `hooks.json`): atomic, permissions kept from the first byte, through symlinks, with a one-time `<file>.openmymemo-backup` |
|
|
41
|
+
| `src/openmymemo/proposals.py` | Proposal lifecycle, dedupe, auto-apply and undo |
|
|
42
|
+
| `src/openmymemo/context.py` | Compiles what an AI sees, MEMORY.md, log.md, search |
|
|
43
|
+
| `src/openmymemo/transfer.py` | Import (ChatGPT / Claude / Markdown / JSON) and export |
|
|
44
|
+
| `src/openmymemo/mcp_server.py` | MCP tools (mcp SDK 2.x `MCPServer`); `relayed=` builds the MyMemo Cloud variant |
|
|
45
|
+
| `src/openmymemo/web.py` | Panel API, `/mcp` and `/cloud/callback` combined into one ASGI app; `panel_server()` is the uvicorn server that starts MyMemo Cloud once its port is bound |
|
|
46
|
+
| `src/openmymemo/cloud.py` | MyMemo Cloud (product-design.md §16): the per-computer link (`cloud.json`, never in the folder), linking with PKCE and a loopback callback, and the bridge: one outbound WebSocket that answers relayed tool calls as `cloud-<slug>` connectors and files the offline queue (HPKE-sealed proposals) through `proposals.py`. The wire format is pinned by `tests/fixtures/cloud/` (the MyMemo service tests against the same files); `tests/cloud_fake.py` is a fake service built from it |
|
|
47
|
+
| `src/openmymemo/cli.py` | Typer CLI |
|
|
48
|
+
| `src/openmymemo/codex.py` | Codex session hook: merges it into `~/.codex/hooks.json` and takes it out again (Codex doesn't run plugin hooks) |
|
|
49
|
+
| `web/` | Vue 3 + Tailwind v4 panel source; all copy lives in `web/src/i18n.ts` |
|
|
50
|
+
| `web/src/components/ConnectApps.vue` | The app list with Connect / Disconnect / Set up, used by the Connectors page and the first-run guide; `ConnectNote` shows what's left to do, `ConnectorPanel` a connected app's permissions, `CloudRow` the MyMemo Cloud row (sign-in, status, setup for ChatGPT and claude.ai, its web apps) |
|
|
51
|
+
| `web/src/desktop.ts` | The Mac layout switch (`?desktop=1`), the shell's commands and shortcuts; `MemoriesDesktopView`, `MemoryInspector`, `DesktopSidebar`, `DesktopToolbar` are its screens; `memorySaves.ts` queues the inspector's saves per memory. `PageHeader` becomes the window toolbar there |
|
|
52
|
+
| `desktop/` | Mac app (Tauri 2, product-design.md §14, §15.2): `src-tauri/src/core.rs` installs the core (non-editable) and finds or starts the server for the folder, `launcher.rs` writes the `openmymemo` launcher AI apps run, `install.rs` moves the app from the disk image to Applications, `main.rs` has the window, menus, menu-bar item, notifications, settings and link handling; `scripts/stage_desktop.py` stages the core and `uv` before each build |
|
|
53
|
+
| `.claude-plugin/` | Claude Code plugin manifest and marketplace (the repo root is the plugin) |
|
|
54
|
+
| `plugin.json`, `mcp.json`, `.agents/plugins/` | Codex plugin (Agent Plugins format) and its marketplace |
|
|
55
|
+
| `skills/` | Skills shared by the Claude Code and Codex plugins |
|
|
56
|
+
| `integrations/hooks/` | Session-start hook script shared by Claude Code (plugin hook in `integrations/claude-code/hooks/hooks.json`) and Codex (user-level hook installed by `setup codex`; `integrations/codex/setup.sh` runs it from the installed plugin) |
|
|
57
|
+
| `integrations/claude-desktop/` | `.mcpb` manifest; build with `scripts/build_mcpb.py` |
|
|
58
|
+
| `integrations/icons/`, `web/public/logo.png` | The MyMemo logo at each size, rendered from MyMemo's app icon by `scripts/make_icons.py` |
|
|
59
|
+
|
|
60
|
+
## Conventions
|
|
61
|
+
|
|
62
|
+
- Everything user-facing is English: docs, panel copy, CLI output, MCP tool names and descriptions. Chinese belongs only in data handling (classifier keywords, parsing pasted pages, test fixtures), because users' memories may be in Chinese.
|
|
63
|
+
- File formats (`memories/*.md`, `connectors.yaml`, `.openmymemo/*`) are a public contract specified in [docs/MEMORY_FORMAT.md](./docs/MEMORY_FORMAT.md): change the spec first and keep reading older files.
|
|
64
|
+
- Topic slugs are the file names; titles come from the files.
|
|
65
|
+
- All writes go through `Vault` methods, which lock, re-read from disk, write atomically and update meta and history.
|
|
66
|
+
- The mcp SDK is 2.x: `from mcp.server.mcpserver import MCPServer, Context`; static resources can't take a `Context`.
|
|
67
|
+
- Plugins run `uv run` from the installed copy of this repo, so anything the package needs at runtime must be inside the repo (and inside the `.mcpb` staging list in `scripts/build_mcpb.py`). Keep the version in `pyproject.toml`, `src/openmymemo/__init__.py`, both `plugin.json` files, `server.json` (the MCP Registry entry, both of its versions), the `.mcpb` manifest, `web/package.json` and the Mac app (`desktop/package.json`, `desktop/src-tauri/tauri.conf.json`, `desktop/src-tauri/Cargo.toml`) in sync (`tests/test_packaging.py` checks), and run `uv lock` after a bump.
|
|
68
|
+
- CI (`.github/workflows/ci.yml`) is three jobs, one per runner: the Python tests and lint on Linux (Python 3.11 and 3.13), the Python tests and the Mac app's tests on macOS (Python 3.12), and the panel (its tests, and that the committed build matches `web/`) with packing the `.mcpb`. The `main` ruleset requires these three checks by name, so renaming a job means updating it. To release: bump the version, merge, then push a tag `v<version>`; `.github/workflows/release.yml` publishes the `.mcpb`, wheel and sdist as a GitHub release, the wheel and sdist on PyPI (trusted publishing, environment `pypi`), and then `server.json` on the MCP Registry (GitHub OIDC; the registry checks the `mcp-name:` line in `README.md`, so keep it).
|
|
69
|
+
- Don't add a root `.mcp.json`: Claude Code would treat it as project config for everyone working on this repo. The Claude Code MCP server is declared inline in `.claude-plugin/plugin.json`.
|
|
70
|
+
- Commit messages are imperative English; one topic per PR.
|
|
71
|
+
- MyMemo Cloud is hidden until turned on in Settings (or `openmymemo cloud settings --show`), and listed while linked (product-design.md §16.11). It reads `OPENMYMEMO_CLOUD_URL` (the service; overrides the one chosen in Settings, default `https://api.mymemo.ai`) and `OPENMYMEMO_CLOUD_DIR` (the folder of `cloud.json` and `settings.json`). `tests/conftest.py` gives every test its own HOME, cloud folder and a local URL; set both yourself before trying `openmymemo cloud …` or the panel's sign-in by hand, so nothing touches your real link or MyMemo.
|
|
72
|
+
- The Mac app adds nothing to the panel's API: it is the same panel in another layout. New panel features go into the web screens; give the Mac layout its own version only where the design has one. A native command the panel calls must be listed in `desktop/src-tauri/build.rs` and granted in `capabilities/default.json`, because the panel is a remote origin to Tauri.
|