webobsidian
Read, write, search, and manage notes in a WebObsidian vault through its Agent REST API (/api/v1). Use whenever the user asks to find, read, create, update, append to, or delete notes in their WebObsidian / Obsidian vault, list tags, get backlinks, or run a vault search. Credentials (base URL + API key) are stored in ~/.webobsidian/credentials.json; if missing, ask the user for them and save them before making requests.
- License 许可
- Apache-2.0
- 最近更新
- 2026-11-15
- Stars
- ★ 1
- Forks
- 0
01 前言 Front Matter
- name
- webobsidian
- description
- Read, write, search, and manage notes in a WebObsidian vault through its Agent REST API (/api/v1). Use whenever the user asks to find, read, create, update, append to, or delete notes in their WebObsidian / Obsidian vault, list tags, get backlinks, or run a vault search. Credentials (base URL + API key) are stored in ~/.webobsidian/credentials.json; if missing, ask the user for them and save them before making requests.
03 SKILL.md 正文
WebObsidian Agent skill
Operate a WebObsidian vault over its Agent REST
API at /api/v1. Everything is a plain HTTP call authenticated with an API key.
Credentials (read these first, every session)
Credentials live in ~/.webobsidian/credentials.json:
{ "baseUrl": "https://your-webobsidian.example.com", "apiKey": "wok_xxxxxxxx" }
Before the first request in a session, load them into shell variables:
BASE=$(python3 -c 'import json,os;print(json.load(open(os.path.expanduser("~/.webobsidian/credentials.json")))["baseUrl"].rstrip("/"))')
KEY=$(python3 -c 'import json,os;print(json.load(open(os.path.expanduser("~/.webobsidian/credentials.json")))["apiKey"])')
If ~/.webobsidian/credentials.json does not exist or a call returns 401:
- Ask the user for their WebObsidian base URL (e.g.
https://notes.example.comorhttp://host:8787) and their API key. They create the key in the app at Settings → API Keys (choose scopesread/write/search). Keys look likewok_…. - Save it (never echo the key back):
mkdir -p ~/.webobsidian && chmod 700 ~/.webobsidian cat > ~/.webobsidian/credentials.json <<JSON { "baseUrl": "<BASE_URL>", "apiKey": "<API_KEY>" } JSON chmod 600 ~/.webobsidian/credentials.json - Verify with the health + an authenticated call, then proceed.
Security rules: never print, log, or commit the API key. Never write it into vault notes. If a command would expose it, redact it.
Sanity check
curl -s "$BASE/api/v1/health" # liveness, no auth
curl -s -H "X-API-Key: $KEY" "$BASE/api/v1/tags" | head # confirms the key works
Authentication
Send the key as a header on every /api/v1 request (either form works):
X-API-Key: wok_xxx
Authorization: Bearer wok_xxx
Scopes per key: read, write, search. A call outside the key's scope returns 403.
Rate-limited (default 120 req/min/key) → 429 when exceeded; back off and retry.
Endpoint reference
All {path} values are vault-relative and must be URL-encoded (curl -G --data-urlencode
for queries; encode /-containing paths in the URL path, e.g. Notes/Ideas.md →
Notes%2FIdeas.md is accepted, plain Notes/Ideas.md also works).
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/health |
– | Liveness check |
| GET | /api/v1/notes?offset=&limit= |
read | List markdown notes (paginated) |
| GET | /api/v1/notes/{path} |
read | Read a note + parsed metadata |
| PUT | /api/v1/notes/{path} |
write | Create / overwrite a note — body {"content":"..."} |
| PATCH | /api/v1/notes/{path} |
write | Append — body {"append":"..."} |
| DELETE | /api/v1/notes/{path} |
write | Move note to trash |
| GET | /api/v1/search?q=&limit= |
search | QMD search (fielded: tag:, path:, title:) |
| GET | /api/v1/backlinks?path= |
read | Notes linking to a path |
| GET | /api/v1/tags |
read | All tags with counts |
Recipes
# List 10 notes
curl -s -H "X-API-Key: $KEY" "$BASE/api/v1/notes?limit=10"
# Read a note (URL-encode the path's query value if it has spaces/slashes)
curl -s -H "X-API-Key: $KEY" "$BASE/api/v1/notes/Welcome.md"
# Create or overwrite a note
curl -s -X PUT -H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{"content":"# Title\n\nBody written by the agent."}' \
"$BASE/api/v1/notes/Agent/Generated.md"
# Append to a note (creates it if missing)
curl -s -X PATCH -H "X-API-Key: $KEY" -H 'Content-Type: application/json' \
-d '{"append":"\n- another bullet"}' \
"$BASE/api/v1/notes/Agent/Generated.md"
# Delete a note (→ trash)
curl -s -X DELETE -H "X-API-Key: $KEY" "$BASE/api/v1/notes/Agent/Generated.md"
# Full-text search (fielded queries supported)
curl -s -G -H "X-API-Key: $KEY" "$BASE/api/v1/search" \
--data-urlencode "q=tag:idea graph" --data-urlencode "limit=5"
# Backlinks for a note
curl -s -G -H "X-API-Key: $KEY" "$BASE/api/v1/backlinks" --data-urlencode "path=Welcome.md"
# All tags with counts
curl -s -H "X-API-Key: $KEY" "$BASE/api/v1/tags"
Response shapes
// GET /api/v1/notes/{path}
{ "path": "Welcome.md", "content": "...", "title": "Welcome",
"frontmatter": { "tags": ["welcome"] }, "tags": ["welcome"], "links": ["Notes/Ideas"] }
// GET /api/v1/search
{ "query": "graph", "hits": [
{ "path": "Notes/Ideas.md", "title": "Ideas", "score": 4.2, "tags": ["idea"], "snippet": "…" } ] }
Obsidian Flavored Markdown (write notes in this dialect)
The vault is a real Obsidian vault — the user also opens these files in the Obsidian app,
so write Obsidian Flavored Markdown, not plain Markdown. Use [[wikilinks]] for links
between vault notes (Obsidian tracks renames); use [text](url) only for external URLs.
Properties (YAML frontmatter)
At the very top of the note, between --- fences. Default keys: tags, aliases,
cssclasses. Preserve existing frontmatter on overwrite.
---
title: My Note
date: 2024-01-15
tags:
- project
- active
aliases:
- Alternative Name
---
Wikilinks (internal links)
[[Note Name]] Link to a note
[[Note Name|Display Text]] Custom display text
[[Note Name#Heading]] Link to a heading
[[Note Name#^block-id]] Link to a block
[[#Heading in same note]] Same-note link
Block references
Append ^block-id to a paragraph; for lists/quotes put the id on its own line after the block.
This paragraph can be linked to. ^my-block-id
Embeds / transclusion (prefix a wikilink with !)
![[Note Name]] Embed a whole note
![[Note Name#Heading]] Embed one section
![[image.png]] Embed an image
![[image.png|300]] Embed with width
![[document.pdf#page=3]] Embed a PDF page
Callouts
> [!note]
> Basic callout.
> [!warning] Custom Title
> Callout with a custom title.
> [!faq]- Collapsed by default
> Foldable callout (`-` starts collapsed, `+` starts expanded).
Common types: note, tip, info, warning, danger, success, failure, question,
example, quote, bug, abstract, todo.
Tags
#tag inline tag
#nested/tag hierarchical tag
Letters, digits (not first char), _, -, /. Tags also go in frontmatter tags:.
Tasks
- [ ] Pending task
- [x] Completed task
Other syntax
==highlight== **bold** *italic*
Footnote[^1]. [^1]: Footnote text. Inline footnote.^[Inline text.]
Visible %%hidden inline comment%% text. $e^{i\pi}+1=0$ (inline math)
$$\frac{a}{b} = c$$ (block math, KaTeX)
```mermaid
graph TD
A --> B
```
Editing rules
- Prefer
PATCHappend overPUTwhen only adding content, so you don't clobber a note. - Read before you overwrite an existing note unless the user explicitly wants a fresh replace; preserve its frontmatter and formatting.
- Paths are case-sensitive and notes must include the
.mdextension. - When you reference another note, link it (
[[Other Note]]) instead of writing a bare name — it keeps the graph and backlinks intact.
Troubleshooting
401→ key missing/invalid → re-run the credentials flow above.403→ the key lacks the required scope → ask the user to create a key with the needed scope (read/write/search).404on a note → wrong path/casing, or it's in.trash.429→ rate limited → wait and retry.- Connection refused / TLS error → confirm the base URL and that the server is reachable.
04 同仓库更多 Skills
jev
Ask typed System One judgments (noul / choice / score) against Allternit's LOCAL System One server instead of prompting a chat model to "return JSON". Use when classifying, routing, scoring, or screening something and code needs a probability it can branch on, or when the user runs /jev. Official TypeSafe Jev is an optional, explicit remote lane.
jev-route
Route with local System One answers — map Choice + confidence to act / confirm / human lanes, or pick a model tier by Choice label. Also documents the separate `route-model` helper for OpenRouter's typesafe/jev-router (a chat-model router, NOT System One). Use for confidence routing, model-tier routing, or when the user runs /jev-route.
jev-guardrail
Screen text or agent tool calls with a battery of local System One Noul hazards plus a Score, with policy in code — and the Claude Code PreToolUse guard (hooks/pretooluse-guard) that puts deterministic hard rules first and lets Jev only raise friction. Use for injection/secret/destructive-action screening or when the user runs /jev-guardrail.
jev-fanout
Ask every independent System One question over the same state in ONE POST /v1/systemone to the local server (speculative fan-out). Use for parallel judgments, compound commands, one-call turn assessment, or when the user runs /jev-fanout. Do not fire one HTTP call per question.
memory-drive
Read and write the user's Allternit Memory Drive, a git repo of markdown memories in the open Agent Memory Repo format. Use at the start of a session to load what the user's agents remember (MEMORY.md), when the user says "remember this", when you learn a durable fact about the user or their work, and before answering questions that depend on past sessions.
agent-orchestrator
Orchestrate external CLI agents (kimi, codex, agy, claude, grok, gizzi) through the Allternit Factory (gizzi agents / orchestration / workspace / workflows). Use when the user asks to delegate, offload, or farm out implementation work to another CLI agent / terminal session, or to run work outside this session to save tokens. Part of Allternit Agents / Bot Agents — not a separate product.