Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ Guidance for Claude Code when working in this repository.

- **Config** — `settings.ts` (pure model mirroring memory-core `vaults.json`), `settings-tab.ts` (the page: Connect · Setup sync · Expose local/remote MCP · MCP address · config file), `vaults-config.ts` (merge-preserving `~/.agentage/vaults.json` writer; desktop, atomic).
- **Auth** (`auth/`) — `pkce.ts` (S256), `oauth.ts` (DCR + token exchange/refresh/revoke; public PKCE client), `discovery.ts` (`/.well-known/oauth-authorization-server`), `token-store.ts` (`app.secretStorage` + the `auth.json` mirror), `auth-json.ts` (desktop `~/.agentage/auth.json`, atomic 0600, CLI shape), `auth-flow.ts` (DI orchestration: startSignIn/handleCallback/getValidToken-with-refresh/disconnect/isSignedIn). AS = Better Auth at `auth.agentage.io`; custom-scheme redirect `obsidian://agentage-memory-cb`.
- **Git** (`git/`) — `git-client.ts` (DI clone/fetch/pull/push/merge; full single-branch, token-in-header, **never force**), `merge-note.ts` (split-YAML field-LWW + diff3 body), `backup-ref.ts`, `http-requesturl.ts` (requestUrl `HttpClient`), `vault-fs.ts` (mobile `vault.adapter` fs-shim — built, not yet wired), `stream-utils.ts`, `git-test-server.ts` (test-only `git-http-backend`).
- **Git** (`git/`) — `git-client.ts` (DI clone/fetch/pull/push/merge; full single-branch, token-in-header, **never force**), `merge-note.ts` (split-YAML field-LWW + diff3 body), `backup-ref.ts`, `http-requesturl.ts` (requestUrl `HttpClient`), `vault-fs.ts` (`vault.adapter` fs-shim — **wired as the git fs on every platform**; no `node:fs` on the sync path), `stream-utils.ts`, `git-test-server.ts` (test-only `git-http-backend`).
- **Sync** — `resolve-host.ts` (`/.well-known/agentage-sync` + 1h cache), `sync-controller.ts` (single-flight lifecycle: ensure repo → commit-before-pull → merge → conflict note → push).
- **Entry** — `main.ts` (wires Obsidian adapters: secretStorage, requestUrl, node fs on desktop, the ribbon/status-bar/command). Obsidian-coupled files are coverage-excluded; the rest is unit/integration-tested.
- **Entry** — `main.ts` (wires Obsidian adapters: secretStorage, requestUrl, `VaultFs` for git, node fs only for the desktop `~/.agentage` config, the ribbon/status-bar/command). Obsidian-coupled files are coverage-excluded; the rest is unit/integration-tested.

## Key invariants
- **Client owns history.** The server is plain git (force-push allowed, no fast-forward-only), so the plugin **never force-pushes**; it commits-before-pull, 3-way merges, and surfaces conflicts (markers + a `conflict:true` note). Never silent-drop.
- **Tokens** live in `app.secretStorage` + `~/.agentage/auth.json` (0600) — **never** `vaults.json`/`data.json`.
- **isomorphic-git gotchas:** token via `onAuth` header only (never the URL, #1942); full single-branch clone (no `depth` — shallow breaks push, #682); no gc (re-clone on bloat — mobile, future).
- **Merge:** split YAML frontmatter before diff3 (markers inside `---` corrupt the note).
- **Desktop** uses node fs (the tested path); mobile (`vault.adapter` via `vault-fs.ts`) is a later milestone.
- **Git fs is `VaultFs` (vault adapter) on every platform** — the only `node:fs/os/path` use is the desktop `~/.agentage` config mirror (lazy, `isDesktop`-guarded). **Mobile is deferred** (`isDesktopOnly: true`): the git layer is mobile-safe, but sign-in (the `obsidian://` deep-link round-trip) and first-sync `.git` detection are not device-verified — re-enable only after a mobile smoke passes.

## Development

Expand All @@ -39,4 +39,4 @@ npm version <x.y.z> # bump manifest.json + versions.json (release prep)
App-level e2e (Playwright-Electron + the live `sync`/`auth` wire) lives in **`agentage/e2e`** (`tests/obsidian`, `tests/sync`), not this repo.

## Conventions
Node 22+, TypeScript strict (ES2024, ESM), esbuild → CommonJS `main.js`. Named exports only (the sole default export is the `Plugin` subclass in `main.ts`). Vitest. ESLint + Prettier (incl. `eslint-plugin-obsidianmd` store rules). `minAppVersion 1.11.4` (secretStorage), `isDesktopOnly: false`. `normalizePath()` on vault paths; **no client-side telemetry**; the README must disclose network hosts + account/payment requirements (enforced by `check:docs`/`check:hosts`). Conventional commits. Inherits the global Agentage standards (`~/projects/CLAUDE.md`).
Node 22+, TypeScript strict (ES2024, ESM), esbuild → CommonJS `main.js`. Named exports only (the sole default export is the `Plugin` subclass in `main.ts`). Vitest. ESLint + Prettier (incl. `eslint-plugin-obsidianmd` store rules). `minAppVersion 1.11.4` (secretStorage), `isDesktopOnly: true` (desktop-only; mobile deferred). `normalizePath()` on vault paths; **no client-side telemetry**; the README must disclose network hosts + account/payment requirements (enforced by `check:docs`/`check:hosts`). Conventional commits. Inherits the global Agentage standards (`~/projects/CLAUDE.md`).
14 changes: 6 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Two-way **Git** sync between your Obsidian vault and your private [Agentage Memory](https://agentage.io) — the shared memory layer for every AI. Your notes stay plain Markdown that you own, and Claude, ChatGPT, Cursor, and any MCP client read and write the *same* files.

> ⚠️ **Status:** desktop git sync + Agentage sign-in (OAuth 2.1 / PKCE) work today. Mobile is wired but experimental (not yet device-verified). Background auto-sync is next.
> ⚠️ **Status:** **desktop only** today (`isDesktopOnly`). Desktop git sync + Agentage sign-in (OAuth 2.1 / PKCE) work. Mobile is planned (see [Mobile](#mobile-planned)); background auto-sync is next.

## Features

Expand All @@ -13,7 +13,7 @@ Two-way **Git** sync between your Obsidian vault and your private [Agentage Memo
- 🤝 **Shared with every AI over MCP** — the same memory is exposed at `memory.agentage.io`, so Claude / ChatGPT / Cursor read and write the same notes. [How to connect →](https://agentage.io/connect)
- 🔐 **Sign in once** — OAuth 2.1 / PKCE; the token is kept in Obsidian's encrypted secret storage, never in your notes or config.
- 🧩 **Plain Markdown, safe merges** — notes stay `.md`; concurrent edits reconcile with a 3-way merge (per-field frontmatter + diff3 body), and conflicts surface as markers + a note — never a silent drop.
- 📊 **Status at a glance** — on desktop, a status-bar dot (green / red / gray) with a click menu: Sync now, Open dashboard, settings. On mobile (no status bar), the same actions open from the ribbon icon and the command palette.
- 📊 **Status at a glance** — a status-bar dot (green / red / gray) with a click menu: Sync now, Open dashboard, settings. The same actions are in the command palette and the ribbon.

## Installation

Expand All @@ -32,8 +32,8 @@ From the [latest release](https://github.com/agentage/obsidian-sync/releases/lat
## Getting started

1. **Settings → Agentage Sync → Start sync with agentage** — sign in. A browser window opens once; no password is stored by the plugin.
2. **Choose a memory** — open the actions (desktop: click the status-bar dot; mobile: tap the ribbon icon, or run **Agentage Sync: Open menu** from the command palette) → **Choose memory…** → pick an existing memory or **Create a new** one. (A fresh memory makes the cleanest first sync.)
3. **Sync now** — from the same actions menu or the command palette (**Agentage Sync: Sync now**). Your notes are committed and pushed.
2. **Choose a memory** — click the status-bar dot (or run **Agentage Sync: Choose memory** from the command palette) → **Choose memory…** → pick an existing memory or **Create a new** one. (A fresh memory makes the cleanest first sync.)
3. **Sync now** — from the dot menu or the command palette (**Agentage Sync: Sync now**). Your notes are committed and pushed.
4. **Connect your AI apps** — point Claude / ChatGPT / Cursor at your memory over MCP. [See how to connect →](https://agentage.io/connect)

## Settings
Expand All @@ -48,11 +48,9 @@ From the [latest release](https://github.com/agentage/obsidian-sync/releases/lat
- **Sync** runs a real git client (vendored [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git)) over Obsidian's network layer, authenticated with your sign-in token (sent only as an `Authorization` header, never in the URL). It never force-pushes — it commits before pulling and 3-way merges.
- The same repo is what AI apps read and write over MCP — one memory, every AI.

## Mobile support (⚠️ experimental)
## Mobile (planned)

The plugin is `isDesktopOnly: false` and runs its git engine over Obsidian's vault adapter on mobile too, but mobile sync is **not yet device-verified**. Try it on a throwaway vault first. Desktop is the supported path today.

Mobile has no status bar, so the actions (Sign in, Choose memory, Sync now, Open dashboard) open from the **ribbon icon** (in the left drawer) or the **command palette** (search *Agentage Sync*). Everything else works the same as desktop.
This release is **desktop only** (`isDesktopOnly: true`), so Obsidian won't offer it on phones yet. The git engine already runs over Obsidian's vault adapter (no Node APIs on the sync path), so the groundwork is in place — what's left is verifying sign-in and first sync on real iOS/Android. Mobile will be re-enabled once that's solid.

## Privacy & network use

Expand Down
4 changes: 2 additions & 2 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"id": "agentage-memory",
"name": "Agentage Sync",
"version": "0.1.5",
"version": "0.1.6",
"minAppVersion": "1.11.4",
"description": "Sync your vault to a private memory that any AI reads and writes over MCP: Claude, ChatGPT, Cursor, and any MCP client share the same Markdown you own.",
"author": "agentage",
"authorUrl": "https://agentage.io",
"isDesktopOnly": false
"isDesktopOnly": true
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-sync",
"version": "0.1.5",
"version": "0.1.6",
"description": "Agentage Memory — Obsidian plugin. One memory, every AI, owned by you.",
"private": true,
"type": "module",
Expand Down
6 changes: 3 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ export default class AgentageMemoryPlugin extends Plugin implements SettingsHost
void this.auth.handleCallback(params).then(() => this.onAuthChanged());
});

// Ribbon shows on mobile (the status bar does NOT). It opens a modal action-picker
// (not a Menu — those don't render from a tap on mobile), so Sync now / Choose memory
// / dashboard are reachable on phones.
// Ribbon + command open a modal action-picker (Sync now / Choose memory / dashboard).
// Kept alongside the status-bar dot so the same actions survive when there's no status
// bar (the mobile case, once mobile is re-enabled — desktop-only for now).
this.addRibbonIcon('refresh-cw', 'Agentage Sync', () => this.openActions());
const sb = this.addStatusBarItem();
this.statusBar = sb;
Expand Down
3 changes: 2 additions & 1 deletion versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"0.1.2": "1.11.4",
"0.1.3": "1.11.4",
"0.1.4": "1.11.4",
"0.1.5": "1.11.4"
"0.1.5": "1.11.4",
"0.1.6": "1.11.4"
}