ainote Sync API
The sync API from ainote — 10 operation(s) for sync.
The sync API from ainote — 10 operation(s) for sync.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/ainote-dev:ainote-dev-sync-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: ainote MCP — OpenAPI mirror Sync API
version: 1.3.0
description: OpenAPI 3.1 surface auto-generated from ainote's MCP tool registry. Use this with OpenAI Custom GPT Actions, LangChain remote tools, AutoGen, or any HTTP-first agent runtime that consumes OpenAPI. The native MCP (JSON-RPC) endpoint at POST /api/mcp remains the recommended path for Claude/Cursor/Windsurf. Tool semantics (annotations, idempotency, destructiveness) are identical across both surfaces — see x-mcp-annotations.
contact:
name: ainote
url: https://docs.ainote.dev
license:
name: MIT
servers:
- url: https://api.ainote.dev
security:
- McpKeyAuth: []
tags:
- name: Sync
paths:
/api/mcp/tools/sync_push:
post:
operationId: tool_sync_push
summary: Push a markdown file into the primary vault.
description: 'Push a markdown file into the primary vault. Optional CAS via base_sha to detect concurrent multi-PC writes (Layer 3 of multi-PC sync plan). WAF-bypass tip: large bodies (~10KB+) that get false-positive blocked at Cloudflare can be sent via `content_b64` (base64-encoded) OR `content` prefixed with `__B64__:` instead. When the push CREATES a new .md file, the response may carry `dedup_candidates` — existing memory files that look similar (keyword + title similarity, no LLM). It is an advisory, not a rejection: YOU decide to merge into one of them (re-push that path), drop this write as a duplicate (skip), or keep it as a new memory (store).'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: false
destructiveHint: true
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Relative file path (e.g., 'global/MEMORY.md', 'launchcrew/firebase.md'). No leading slash, no '..'.
content:
type: string
description: Full file content (markdown text). Alternatively prefix with '__B64__:' followed by base64 payload for WAF bypass.
content_b64:
type: string
description: 'Optional: base64-encoded file content (use INSTEAD of `content`). For WAF-bypass on large bodies. Server decodes before storing. If both supplied, content_b64 wins.'
base_sha:
type: string
description: 'Optional: git_sha the client last observed for this path. When present, server compares with current git_sha and returns -32009 conflict on mismatch (with current content for 3-way diff). Omit for legacy LWW behavior (response will include a `warning` field nudging clients to upgrade).'
device_id:
type: string
description: 'Optional: client device identifier (e.g., from ~/.claude/ainote-sync/device.id). Stored on FileIndex so future conflict responses can report which device last wrote the path.'
force:
type: boolean
description: 'Optional: when true, skip CAS check even if base_sha is supplied. Use only for intentional overwrites; presence is auditable via warning logs.'
resolves_conflict_id:
type: string
description: 'Optional: UUID of a vault_conflicts row this push resolves. When supplied, server validates ownership/unresolved/path/sha and atomically marks the conflict as resolution=clean inside the same transaction as the file_indices write. Validation failure rolls back the whole push and returns -32009 stale_conflict_id.'
supports_superseded:
type: boolean
description: Optional capability opt-in. When true AND resolves_conflict_id points at an already-resolved conflict whose (path, remote_sha) matches this push, the server returns a NORMAL 200 with resource_data {status:'superseded', reason:'resolved_elsewhere', applied:false, git_sha:<current remote>} instead of a -32009 error, so the client pulls to converge. Omit (default) to keep the legacy -32009 contract.
required:
- path
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_push_batch:
post:
operationId: tool_sync_push_batch
summary: Push MANY files into the primary vault in ONE call.
description: 'Push MANY files into the primary vault in ONE call. Use this instead of looping sync_push whenever you have more than a couple of changed paths — the cost of sync_push is round trips, not bytes. Per-item semantics are identical to sync_push (Layer 3 base_sha CAS, superseded contract, content_b64 WAF fallback). Partial success is normal and returns HTTP 200: read `results[]` and match entries by `path`, NOT by position. A conflict result always carries `remote_sha` + `conflict_reason` so you can go straight to sync_merge. Request-level failures (duplicate paths in one batch, idempotency key reused with a different payload, >200 items, >4MB) return 4xx and apply NOTHING. Each item MUST carry `content_sha` (SHA1 hex of the decoded body, same algorithm as git_sha) — it powers both the integrity check and the retry-safe `skipped_identical` result. Newly created .md items may carry `dedup_candidates` (same merge/skip/store advisory as sync_push); a batch creating more than 10 new files skips the check entirely and reports `dedup_skipped: "bulk"`.'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: false
destructiveHint: true
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
items:
type: array
description: Up to 200 push items, 4MB total, one entry per unique path. Duplicate paths reject the whole batch.
items:
type: object
properties:
path:
type: string
description: Relative file path. No leading slash, no '..'.
content:
type: string
description: Full file content. May use the '__B64__:' prefix like sync_push.
content_b64:
type: string
description: Optional base64 body (use INSTEAD of content) for WAF bypass. Wins over content if both are present.
content_sha:
type: string
description: REQUIRED. SHA1 hex of the decoded content. Mismatch fails this item only (status 'error'); equality with the current remote git_sha yields 'skipped_identical' instead of a conflict, which is what makes a crashed batch safe to retry.
base_sha:
type: string
description: 'Same tri-state semantics as sync_push: omit for legacy LWW, null to assert the path does not exist yet, or the last observed git_sha for CAS.'
resolves_conflict_id:
type: string
description: Optional vault_conflicts UUID this item closes. Requires a non-null base_sha and force=false.
force:
type: boolean
description: Optional per-item CAS bypass (audited). Suppresses the skipped_identical short-circuit.
device_id:
type: string
description: Optional per-item device id; falls back to the batch-level device_id.
required:
- path
- content_sha
idempotency_key:
type: string
description: 'REQUIRED. Opaque client-generated UUID, one per batch ATTEMPT-SET: reuse the same key when retrying the same items after a timeout (the server replays the stored results instead of re-applying), and generate a NEW key whenever the items change. Reusing a key with a different payload is a 400 collision, never a silent replay. Do not derive it from paths or content.'
device_id:
type: string
description: Optional batch-level device identifier; per-item device_id overrides it.
supports_superseded:
type: boolean
description: Same capability opt-in as sync_push, applied to every item in the batch.
required:
- items
- idempotency_key
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_pull:
post:
operationId: tool_sync_pull
summary: Legacy alias for pulling files from the primary vault.
description: 'Legacy alias for pulling files from the primary vault. Paginated: default 25 files per call, follow `next_cursor` for the rest. To fetch specific files, pass `paths` (up to 100 exact paths in one call) instead of pulling their whole directory.'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
since:
type: string
description: ISO 8601 timestamp. Only return files updated after this time. Omit to start from the first page. Deletions are not reported.
path:
type: string
description: 'Optional filter: a directory (everything under it, e.g. ''global'') or an exact file path (e.g. ''global/MEMORY.md''). A trailing slash is ignored.'
paths:
type: array
items:
type: string
description: Up to 100 exact file paths fetched in ONE call. Absent paths are listed in `missing`. Cannot be combined with path/since/cursor.
limit:
type: integer
description: Max files per page. Default 25, max 100.
cursor:
type: string
description: Pass `next_cursor` from the previous response to fetch the next page.
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_list:
post:
operationId: tool_sync_list
summary: Legacy alias for listing files in the primary vault.
description: 'Legacy alias for listing files in the primary vault. Paginated: default 200 entries per call, follow `next_cursor` for the rest.'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: A directory to list (everything under it, e.g. 'global') or an exact file path (e.g. 'global/MEMORY.md'). A trailing slash is ignored. Omit to list from the first page.
since:
type: string
description: ISO 8601 timestamp. Only list files updated strictly after this time. Deletions are not reported — diff a full list against your local copy to find them.
limit:
type: integer
description: Max entries per page. Default 200, max 1000.
cursor:
type: string
description: Pass `next_cursor` from the previous response to fetch the next page.
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_changes:
post:
operationId: tool_sync_changes
summary: Read changes from the primary vault in sequence order, including deletions.
description: Read changes from the primary vault in sequence order, including deletions. Start with since_seq=0 for a full listing; then pass next_seq and feed_epoch on each page. Default limit 500, max 1000. On reset_required, discard the cursor and restart from 0 without an epoch. On feed_unavailable, fall back to sync_list. Fetch changed content with sync_pull(paths:).
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
since_seq:
type: integer
minimum: 0
default: 0
description: Last applied sequence; 0 starts a full listing.
feed_epoch:
type: string
description: Epoch from the previous response; a mismatch requires a full reset.
limit:
type: integer
minimum: 1
maximum: 1000
default: 500
description: Max combined file and deletion entries per page.
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_delete:
post:
operationId: tool_sync_delete
summary: Delete a file from the primary vault.
description: 'Delete a file from the primary vault. Optional CAS via base_sha to detect concurrent multi-PC writes. Protected paths (global/memory/, global/skills/, global/planning/, global/intent/, global/claude-config/, handoffs/) require base_sha or explicit force:true (audited). Idempotent: deleting a non-existent path returns success with deleted:false.'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: false
destructiveHint: true
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Relative file path to delete (e.g., 'global/_waf_probe.md'). No leading slash, no '..'.
base_sha:
type: string
description: 'Optional: git_sha the client last observed for this path. When present, server compares with current git_sha and returns -32009 conflict on mismatch (with current content for 3-way diff).'
device_id:
type: string
description: 'Optional: client device identifier for audit log (e.g., from ~/.claude/ainote-sync/device.id).'
force:
type: boolean
description: 'Optional: when true, skip CAS check even if base_sha is supplied. Use only for intentional overwrites; presence is auditable via warning logs.'
required:
- path
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_merge:
post:
operationId: tool_sync_merge
summary: Compute a stateless 3-way merge for a vault file.
description: Compute a stateless 3-way merge for a vault file. Server runs `git merge-file --diff3 --stdout` over (base_text, local_text, current remote from file_indices) and returns the merged text plus the exact remote_sha it merged against. NO database mutation — to commit the result, follow up with sync_push(content=merged_text, base_sha=merged_against.remote_sha, resolves_conflict_id=conflict_id).
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Relative vault path (e.g., 'global/MEMORY.md').
base_text:
type: string
description: 'Common ancestor text — what the client had cached when it started editing. Source: client state.json baseline. Required.'
base_sha:
type: string
description: 'Optional: git_sha the client believes is the merge base. When supplied, server verifies (informational; merge still runs).'
local_text:
type: string
description: Current local text on the client (post-edit). Required.
device_id:
type: string
description: 'Optional: client device identifier. Recorded on any vault_conflict row created downstream.'
required:
- path
- base_text
- local_text
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_diff:
post:
operationId: tool_sync_diff
summary: Return the unified diff (and raw remote text) of a vault file.
description: Return the unified diff (and raw remote text) of a vault file. Useful for surfacing what `sync_merge` would conflict on, or for the client to render a `git diff` view before pushing. NO database mutation. Server has no history — base_text must be supplied by the caller if a 3-way view is needed; otherwise this returns remote_text only.
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Relative vault path.
local_text:
type: string
description: 'Optional: client''s current text. When supplied, response includes unified diff (remote → local).'
base_text:
type: string
description: 'Optional: client''s baseline (last-known remote). When supplied along with local_text, response includes both diffs (base → remote, base → local) so the client can render a 3-way view.'
required:
- path
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_pending_conflicts:
post:
operationId: tool_sync_pending_conflicts
summary: List unresolved vault_conflicts rows for the authenticated user's primary vault.
description: List unresolved vault_conflicts rows for the authenticated user's primary vault. Used by clients (e.g. SessionStart hook) to surface conflicts that need merge attention. Returns up to `limit` rows ordered by most recent first.
tags:
- Sync
x-mcp-annotations:
readOnlyHint: true
destructiveHint: false
idempotentHint: true
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
limit:
type: integer
description: 'Optional: max rows to return (default 50, max 200).'
path:
type: string
description: 'Optional: filter to a specific path.'
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
/api/mcp/tools/sync_audit_layer5:
post:
operationId: tool_sync_audit_layer5
summary: Record the result of a client-side Layer 5 codex review (sync.py merge gate) as…
description: 'Record the result of a client-side Layer 5 codex review (sync.py merge gate) as a vault_events row. Body of the review is NOT stored — only an HMAC digest of the summary so operators can correlate without exposing review content. Opt-in: server skips writes (still returns success) unless ENV[''AINOTE_LAYER5_AUDIT'']=''on'' AND a versioned HMAC secret is configured. Used by the sync.py SessionStart hook + merge command to surface ''why was this blocked?'' across multi-PC sessions.'
tags:
- Sync
x-mcp-annotations:
readOnlyHint: false
destructiveHint: false
idempotentHint: false
openWorldHint: false
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
path:
type: string
description: Vault path the review covered.
verdict:
type: string
description: 'One of: pass, flag, block, error.'
summary:
type: string
description: Free-form codex output summary. Server HMACs this; raw text is NEVER stored.
chunk_count:
type: integer
description: 'Optional: number of diff chunks the client fed to codex.'
duration_ms:
type: integer
description: 'Optional: wall-clock time of the codex review on the client.'
required:
- path
- verdict
responses:
'200':
description: Tool executed successfully
content:
application/json:
schema:
$ref: '#/components/schemas/ToolSuccessResponse'
'400':
description: Invalid arguments or business-rule violation
content:
application/json:
schema:
$ref: '#/components/schemas/ToolErrorResponse'
'401':
description: Missing or invalid McpKey
components:
schemas:
ToolSuccessResponse:
type: object
description: 'Successful tool invocation. `content` mirrors the MCP `tools/call` result shape: an array of content blocks (text and optionally a structured resource payload).'
properties:
content:
type: array
items:
type: object
properties:
type:
type: string
enum:
- text
- resource
text:
type: string
ToolErrorResponse:
type: object
description: Uniform error shape emitted by ainote MCP tool handlers.
properties:
error:
type: object
properties:
code:
type: integer
description: JSON-RPC error code (-32xxx range)
message:
type: string
required:
- code
- message
securitySchemes:
McpKeyAuth:
type: apiKey
in: header
name: Authorization
description: Send `McpKey <YOUR_MCP_KEY>`. Issue an MCP key at /settings/mcp or via `npx @ainote/mcp signup`.
x-ainote-meta:
generator: Api::Mcp::OpenapiController
generated_at: '2026-11-01T14:35:55Z'
tools_count: 56
native_mcp_endpoint: https://api.ainote.dev/api/mcp
agent_compatibility_doc: https://github.com/ainote-dev/ainote-mcp#agent-compatibility