Headless Vault CLI
Access Markdown notes on your personal computer from this VPS-hosted bot via SSH tunnel.
Terminology: "Local machine" = your personal computer (macOS or Linux) where your notes live. This skill runs on the VPS and connects to your machine via a reverse SSH tunnel.
Prerequisites
This is an instruction-only skill. Before using it, the user must complete a one-time setup on their local machine:
- 1. Install vaultctl on the local machine (see setup instructions)
- Configure SSH forced-command on the local machine's
~/.ssh/authorized_keys to restrict the VPS key to only run vaultctl (see Security Model below) - Start a reverse SSH tunnel from the local machine to the VPS, exposing INLINECODE2
- Set the environment variable
VAULT_SSH_USER to the local machine's username
Security Model
This skill connects to the local machine over a pre-configured reverse SSH tunnel. Access is restricted by design:
- - Forced-command restriction: The VPS SSH key is added to the local machine's
~/.ssh/authorized_keys with a forced-command wrapper, so the VPS can ONLY execute vaultctl — no interactive shell, no arbitrary commands (rm, curl, etc.) - Vault sandboxing:
vaultctl validates all file paths are inside VAULT_ROOT and rejects path traversal attempts (.., symlinks outside vault) - Non-destructive: Only
create (new files) and append (existing files) are supported — no delete, rename, move, or overwrite - No credentials stored: SSH authentication uses the VPS's existing SSH keypair; no additional secrets are stored by this skill
Example authorized_keys entry on the local machine:
CODEBLOCK0
This ensures the VPS can only run vaultctl commands, even if the tunnel is compromised.
Available Commands
You have access to these commands ONLY. Do not attempt commands not listed here (no rename, delete, move, or edit commands exist).
| Command | Description |
|---|
| INLINECODE15 | List vault directory structure |
| INLINECODE16 |
Find note by path or title |
|
info | Get file metadata (lines, bytes, sha256, mtime) |
|
read | Read note content |
|
create | Create a NEW note (fails if file exists) |
|
append | Append content to EXISTING note |
How to Run Commands
All commands are executed via SSH:
CODEBLOCK1
Always use -4 to force IPv4 (avoids IPv6 timeout issues).
Environment Variables
These must be set in the skill's runtime environment on the VPS:
| Variable | Required | Default | Description |
|---|
| INLINECODE22 | Yes | — | Local machine username for SSH tunnel |
| INLINECODE23 |
No |
2222 | SSH tunnel port on localhost |
|
VAULT_SSH_HOST | No |
localhost | SSH tunnel host |
Command Reference
tree - List vault structure
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree --depth 2
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree --all
Options:
- -
--depth N - Maximum depth to traverse - INLINECODE28 - Include all files, not just .md
resolve - Find note by path or title
ALWAYS use --base64 for path and title arguments to prevent shell injection:
CODEBLOCK3
info - Get file metadata
ALWAYS use --base64 for the path argument:
# echo -n "Projects/Plan.md" | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl info UHJvamVjdHMvUGxhbi5tZA== --base64
Returns JSON: INLINECODE31
read - Read note content
ALWAYS use --base64 for the path argument:
# echo -n "Projects/Plan.md" | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl read UHJvamVjdHMvUGxhbi5tZA== --base64
Returns JSON: INLINECODE33
create - Create a NEW note
IMPORTANT: Use
--base64 flag with BOTH path AND content base64 encoded. This is required for paths/content with spaces or special characters.
CODEBLOCK6
Example to create "Notes/Morning Brief.md" with content "# Hello\n\nWorld":
CODEBLOCK7
- - Creates parent directories automatically
- Fails if file already exists (use
append to add to existing files) - File must have
.md extension - NEVER duplicate the title as a heading inside the note content (e.g., for "My Note.md", don't start content with "# My Note")
append - Append to EXISTING note
CODEBLOCK8
- - Fails if file does not exist (use
create for new files)
What You CANNOT Do
These operations are NOT supported:
- - Rename files or folders
- Delete files or folders
- Move files between folders
- Edit specific parts of a file (only append to end)
- Create folders without a file (folders are created automatically with
create)
Tips
- - Always run
vaultctl tree first to see what notes exist - Use
vaultctl resolve --title <base64> --base64 to find a note by name - All output is JSON
- The local machine must be online with tunnel running
- ALWAYS use
--base64 for ALL path and content arguments — this is mandatory for security, not optional
Examples
Important: Always run tree first if you're unsure what notes exist. This prevents errors from wrong paths or duplicate names.
Example 1: User asks to read a note (check first)
User: "Show me my project plan"
Step 1 - Check what exists:
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree
Output:
CODEBLOCK10
Step 2 - Now read the correct path (always base64 encode):
# echo -n "Projects/Plan.md" | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl read UHJvamVjdHMvUGxhbi5tZA== --base64
Output:
CODEBLOCK12
Example 2: User asks to create a note (check first to avoid duplicates)
User: "Create a meeting notes file"
Step 1 - Check what already exists:
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree
Output:
CODEBLOCK14
Step 2 - No "Meeting Notes" exists, safe to create (do NOT duplicate title as heading):
# echo -n "Meeting Notes.md" | base64 → TWVldGluZyBOb3Rlcy5tZA==
# echo -n "## Agenda\n\n- Item 1\n- Item 2\n" | base64 → IyMgQWdlbmRhCgotIEl0ZW0gMQotIEl0ZW0gMgo=
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl create TWVldGluZyBOb3Rlcy5tZA== IyMgQWdlbmRhCgotIEl0ZW0gMQotIEl0ZW0gMgo= --base64
Output:
CODEBLOCK16
Example 3: User asks about vault contents
User: "What's in my notes?"
CODEBLOCK17
Output:
CODEBLOCK18
Then summarize for user: "You have a Projects folder with Plan.md, and an Ideas.md file at the root."
Example 4: Complex workflow with source and output notes
User: "According to the source note 'AI Digest Sources.md', browse the sources and output the digest to 'digest/2025-01-28-digest.md'"
Step 1 - Check what exists:
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl tree
Output:
CODEBLOCK20
Step 2 - Validate:
- - Source "AI Digest Sources.md" exists
- Output "digest/2025-01-28-digest.md" does NOT exist, will use INLINECODE43
(If source didn't exist: STOP and ask user "I couldn't find 'AI Digest Sources.md'. Did you mean one of these: [list alternatives]?")
(If output already existed: use append instead of create)
Step 3 - Read the source note (always base64 encode):
# echo -n "AI Digest Sources.md" | base64 → QUkgRGlnZXN0IFNvdXJjZXMubWQ=
ssh -4 -p 2222 ${VAULT_SSH_USER}@localhost vaultctl read QUkgRGlnZXN0IFNvdXJjZXMubWQ= --base64
Output:
CODEBLOCK22
Step 4 - Browse sources and generate digest content (done by bot outside this skill)
Step 5 - Write output to vault (do NOT duplicate title as heading):
CODEBLOCK23
(If output already existed, use append instead:)
CODEBLOCK24
Headless Vault CLI
通过SSH隧道,从此VPS托管的机器人访问个人电脑上的Markdown笔记。
术语:本地机器 = 你的个人电脑(macOS或Linux),笔记存储在此设备上。此技能运行在VPS上,通过反向SSH隧道连接到你的机器。
前置条件
这是一个纯指令技能。使用前,用户必须在本地机器上完成一次性设置:
- 1. 在本地机器上安装 vaultctl(参见设置说明)
- 在本地机器的 ~/.ssh/authorizedkeys 中配置SSH强制命令,限制VPS密钥仅能运行 vaultctl(参见下方安全模型)
- 从本地机器启动反向SSH隧道到VPS,暴露 localhost:2222
- 设置环境变量 VAULTSSHUSER 为本地机器的用户名
安全模型
此技能通过预先配置的反向SSH隧道连接到本地机器。访问权限通过设计受到限制:
- - 强制命令限制:VPS SSH密钥被添加到本地机器的 ~/.ssh/authorizedkeys 中,并带有强制命令包装器,因此VPS只能执行 vaultctl——没有交互式shell,没有任意命令(rm、curl等)
- Vault沙箱:vaultctl 验证所有文件路径均在 VAULTROOT 内,并拒绝路径遍历尝试(..、指向vault外部的符号链接)
- 非破坏性:仅支持 create(新建文件)和 append(追加到现有文件)——不支持删除、重命名、移动或覆盖
- 不存储凭据:SSH认证使用VPS现有的SSH密钥对;此技能不存储任何额外的密钥
本地机器上的 authorized_keys 条目示例:
command=/usr/local/bin/vaultctl-wrapper,no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA... vps-key
这确保了即使隧道被攻破,VPS也只能运行 vaultctl 命令。
可用命令
你只能访问以下命令。不要尝试未列出的命令(不存在重命名、删除、移动或编辑命令)。
| 命令 | 描述 |
|---|
| tree | 列出vault目录结构 |
| resolve |
按路径或标题查找笔记 |
| info | 获取文件元数据(行数、字节数、sha256、修改时间) |
| read | 读取笔记内容 |
| create | 创建新笔记(如果文件已存在则失败) |
| append | 向现有笔记追加内容 |
如何运行命令
所有命令通过SSH执行:
bash
ssh -4 -p ${VAULTSSHPORT:-2222} ${VAULTSSHUSER}@${VAULTSSHHOST:-localhost} vaultctl [args]
始终使用 -4 强制使用IPv4(避免IPv6超时问题)。
环境变量
这些必须在VPS上技能运行环境中设置:
| 变量 | 必需 | 默认值 | 描述 |
|---|
| VAULTSSHUSER | 是 | — | SSH隧道的本地机器用户名 |
| VAULTSSHPORT |
否 | 2222 | localhost上的SSH隧道端口 |
| VAULT
SSHHOST | 否 | localhost | SSH隧道主机 |
命令参考
tree - 列出vault结构
bash
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl tree
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl tree --depth 2
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl tree --all
选项:
- - --depth N - 最大遍历深度
- --all - 包含所有文件,不仅限于.md
resolve - 按路径或标题查找笔记
始终使用 --base64 处理路径和标题参数,防止shell注入:
bash
echo -n Projects/Plan.md | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl resolve --path UHJvamVjdHMvUGxhbi5tZA== --base64
echo -n Meeting Notes | base64 → TWVldGluZyBOb3Rlcw==
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl resolve --title TWVldGluZyBOb3Rlcw== --base64
info - 获取文件元数据
始终使用 --base64 处理路径参数:
bash
echo -n Projects/Plan.md | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl info UHJvamVjdHMvUGxhbi5tZA== --base64
返回JSON:{path: ..., lines: N, bytes: N, sha256: ..., mtime: N}
read - 读取笔记内容
始终使用 --base64 处理路径参数:
bash
echo -n Projects/Plan.md | base64 → UHJvamVjdHMvUGxhbi5tZA==
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl read UHJvamVjdHMvUGxhbi5tZA== --base64
返回JSON:{path: ..., content: ...}
create - 创建新笔记
重要:对路径和内容都使用 --base64 标志进行base64编码。对于包含空格或特殊字符的路径/内容,这是必需的。
bash
ssh -4 -p 2222 ${VAULTSSHUSER}@localhost vaultctl create path> content> --base64
创建 Notes/Morning Brief.md 并包含内容 # Hello\n\nWorld 的示例:
bash
编码路径:echo -n Notes/Morning Brief.md | base64 → Tm90ZXMvTW9ybmluZyBCcmllZi5tZA==
编码内容:echo -n # Hello\n\nWorld | base64 → IyBIZWxsbwoKV29ybGQ=
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl create Tm90ZXMvTW9ybmluZyBCcmllZi5tZA== IyBIZWxsbwoKV29ybGQ= --base64
- - 自动创建父目录
- 如果文件已存在则失败(使用 append 添加到现有文件)
- 文件必须有 .md 扩展名
- 切勿在笔记内容中重复标题作为标题(例如,对于My Note.md,不要以# My Note开头内容)
append - 追加到现有笔记
bash
ssh -4 -p 2222 ${VAULT
SSHUSER}@localhost vaultctl append
path> content> --base64
- - 如果文件不存在则失败(对于新文件使用 create)
你不能做的事情
以下操作不受支持:
- - 重命名文件或文件夹
- 删除文件或文件夹
- 移动文件到其他文件夹
- 编辑文件的特定部分(仅支持追加到末尾)
- 创建不带文件的文件夹(文件夹会随 create 自动创建)
提示
- - 始终先运行 vaultctl tree 查看存在哪些笔记
- 使用 vaultctl resolve --title --base64 按名称查找笔记
- 所有输出均为JSON格式
- 本地机器必须在线且隧道正在运行
- 始终对所有路径和内容参数使用 --base64——这是安全要求,不可省略
示例
重要:如果不确定存在哪些笔记,始终先运行 tree。这可以防止因路径错误或名称重复导致的错误。
示例1:用户要求读取笔记(先检查)
用户:显示我的项目计划
步骤1 - 检查存在的内容:
bash
ssh -4 -p 2222 ${VAULTSSHUSER}@localhost vaultctl tree
输出:
json
{tree: [{path: Projects, type: dir}, {path: Projects/Plan.md, type: file}]}
步骤2 - 现在读取正确的路径(始终base64编码):
bash
echo -n Projects/Plan.md