8.6 KiB
ECHO — Obsidian Local REST API Reference
Server: https://echoapi.alwisp.com (reverse proxy → backend Obsidian Local REST API)
Auth header: Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab
The endpoint has a valid TLS certificate — -k is not required. Paths address the vault at its root.
Prefer
scripts/echo.shover the raw recipes below. It wraps every verb with auth, status checking, retry, idempotent append, and frontmatter patches. The recipes here are the underlying mechanics and the fallback. If you callcurldirectly, check the HTTP status — add-o /dev/null -w "%{http_code}"and branch on it. APATCHto a non-existent heading returns400 invalid-target(errorCode 40080) and the write is silently lost; a barecurlthat ignores status will report success anyway.GETreturns404for a missing file. Treat any>= 400as a failed operation, surface it, and do not continue as if it succeeded.
Reading Files
# Read any file by vault path
curl -s \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
"https://echoapi.alwisp.com/vault/_agent/context/current-context.md"
Returns raw file content (text/markdown). On 404, the file does not exist.
# Read a specific heading's content only
curl -s \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
"https://echoapi.alwisp.com/vault/_agent/memory/semantic/operator-preferences.md/heading/Operator"
Nested headings: separate levels with :: (URL-encode spaces as %20):
/vault/path/to/note.md/heading/Work%3A%3AMeetings
Listing Directories
# List contents of a directory (trailing slash required)
curl -s \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
"https://echoapi.alwisp.com/vault/_agent/sessions/"
Returns JSON: { "files": [...], "folders": [...] }.
Appending Content (POST)
POST appends to the end of an existing file. Creates the file if it doesn't exist.
cat > /tmp/obs_entry.md << 'OBSEOF'
- 2026-06-05: your entry here
OBSEOF
curl -s -X POST \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_entry.md \
"https://echoapi.alwisp.com/vault/inbox/captures/inbox.md"
Creating or Overwriting Files (PUT)
PUT creates a new file or fully overwrites an existing one. Intermediate directories are created automatically.
cat > /tmp/obs_file.md << 'OBSEOF'
---
type: session-log
status: complete
created: 2026-06-05
updated: 2026-06-05
tags: [agent, session]
agent_written: true
source_notes: []
---
# content here
## Related
- [[projects/active/some-project]]
OBSEOF
curl -s -X PUT \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_file.md \
"https://echoapi.alwisp.com/vault/_agent/sessions/2026-06-05-1430-my-session.md"
Patching a Specific Section (PATCH)
PATCH edits inside a file without rewriting it. Target and operation are set via headers.
Append under a heading
Heading targets must be the FULL heading path, ::-delimited from the top-level heading. A bare subheading name returns 400 invalid-target (errorCode 40080). Example: ## Fact / Pattern nested under # Operator Preferences → Target: Operator Preferences::Fact / Pattern. Percent-encode non-ASCII characters (e.g. H%C3%A9llo); spaces are fine.
cat > /tmp/obs_patch.md << 'OBSEOF'
Jason prefers concise status updates — lead with the decision.
OBSEOF
curl -s -X PATCH \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
-H "Operation: append" \
-H "Target-Type: heading" \
-H "Target: Operator Preferences::Fact / Pattern" \
-H "Content-Type: text/markdown" \
--data-binary @/tmp/obs_patch.md \
"https://echoapi.alwisp.com/vault/_agent/memory/semantic/operator-preferences.md"
Discover heading / block / frontmatter targets
When unsure of the exact heading path, GET the note with the document-map Accept header:
curl -s \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
-H "Accept: application/vnd.olrapi.document-map+json" \
"https://echoapi.alwisp.com/vault/_agent/memory/semantic/operator-preferences.md"
Returns { "headings": [...], "blocks": [...], "frontmatterFields": [...] }. Copy the heading string verbatim into Target.
Replace a heading's content entirely
Same call with Operation: replace — e.g. to refresh a project's Project Name::Status.
Prepend under a heading
Same call with Operation: prepend.
Patch a frontmatter field
curl -s -X PATCH \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
-H "Operation: replace" \
-H "Target-Type: frontmatter" \
-H "Target: updated" \
-H "Content-Type: application/json" \
--data '"2026-06-05"' \
"https://echoapi.alwisp.com/vault/projects/active/vault-foundation.md"
Searching
curl -s -X POST \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
"https://echoapi.alwisp.com/search/simple/?query=weekly+review"
Returns an array of { filename, score, matches: [{ context, match }] }.
Deleting Files
curl -s -X DELETE \
-H "Authorization: Bearer 241265fbe6830934a9a4ad3e69335f64a42153b663aa5b0017cb1ea1217b2bab" \
"https://echoapi.alwisp.com/vault/inbox/imports/old-note.md"
Only on explicit operator request. Deletion is destructive.
URL-Encoding Notes
- Path separators (
/) in the vault path are literal — do not encode them. - Spaces in filenames or heading targets in a URL: use
%20. - Nested heading levels in a URL path: use
%3A%3Afor::. - Heading text in the
Target:header: the full heading path joined by::(e.g.Operator Preferences::Fact / Pattern), no#; spaces are fine; percent-encode non-ASCII.
Memory Routing Map
| Situation | Vault path | Method |
|---|---|---|
| Quick capture / unsorted | inbox/captures/inbox.md (date-prefixed line) |
POST |
| Raw imported material | inbox/imports/ |
PUT |
| Operator preference / durable fact | _agent/memory/semantic/operator-preferences.md |
PATCH |
| Other durable facts, patterns | _agent/memory/semantic/<slug>.md |
PUT |
| Event record (what happened) | _agent/memory/episodic/<slug>.md |
PUT |
| Short-lived, time-boxed state | _agent/memory/working/<slug>.md |
PUT |
| Task-scoped context / focus | _agent/context/current-context.md |
PATCH / PUT |
| Working-session log | _agent/sessions/YYYY-MM-DD-HHMM-<slug>.md |
PUT |
| Long-running project state | projects/<lifecycle>/<slug>.md (lifecycle: incubating → active → on-hold/archived; folder and status: MUST agree) |
PUT + PATCH |
| Ongoing area of responsibility (standing domain, no end state) | areas/<domain>/<slug>.md (<domain>: business/personal/learning/systems) |
PUT |
| Non-obvious decision (ADR) | decisions/by-date/YYYY-MM-DD-<slug>.md (mirror only into an existing project note's ## Key Decisions; otherwise skip) |
PUT |
| Person context | resources/people/<name>.md |
PUT / PATCH |
| Company / organization context | resources/companies/<slug>.md |
PUT / PATCH |
| Concept / reference note | resources/concepts/ or resources/references/ |
PUT |
| Meeting notes / call recap | resources/meetings/YYYY-MM-DD-<slug>.md |
PUT |
| Skill / plugin capability entry (catalog, not build work) | _agent/skills/active/<slug>.md (→ archived/ when retired) |
PUT |
| Daily activity / Agent Log | journal/daily/YYYY-MM-DD.md |
POST / PATCH |
| Journal rollup | journal/{weekly/YYYY-Www,monthly/YYYY-MM,quarterly/YYYY-Qn,annual/YYYY}.md (weekly = opt-in on first session of a new ISO week; monthly = offered with Vault Health; quarterly/annual = manual) |
PUT |
| Vault-health audit (agent self-maintenance) | _agent/health/YYYY-MM-vault-health.md (monthly; NOT a journal entry) |
PUT |
| Session-end orientation pointer | _agent/heartbeat/last-session.md (one line, overwritten each session end) |
PUT |
| Bootstrap marker (plugin-owned) | _agent/echo-vault.md (schema_version, bootstrap date) — the "is this vault set up?" probe |
GET / PUT |
Slug rules: kebab-case, ASCII, ~40 chars max. Every file carries canonical frontmatter (see vault-layout.md).