Viewert CLI
Authenticate with your Viewert account, sync Vellums to and from your local filesystem as plain Markdown, and run a local MCP server — all without leaving your terminal.
What Is the Viewert CLI?
The Viewert CLI is a standalone command-line tool for working with your Vellums outside the browser. Pull a Vellum down as a Markdown file, edit it in your favorite editor, push it back — or keep a whole folder in sync automatically. It also runs a local MCP server, so any MCP-compatible AI client can read and write your Vellums directly, authenticated as you.
Install — macOS & Linux (Homebrew)
The easiest path on macOS or Linux is Homebrew. Installing gives you two identical binaries — `viewert` and the shorter `v` — so every command below works with either name.
brew tap viewert/viewert
brew install viewertTrusting the Tap (First Install Only)
brew trust viewert/viewert
brew install viewertInstall — Linux (.deb / .rpm)
Prefer your distro's package manager over Homebrew? Every release also publishes .deb and .rpm packages for amd64 and arm64. Grab the one matching your distro from the GitHub Releases page and install it directly.
# Debian/Ubuntu
sudo dpkg -i viewert_<version>_linux_amd64.deb
# Fedora/RHEL
sudo rpm -i viewert_<version>_linux_amd64.rpmInstall — Windows
Authenticate
Log in once per machine. No password ever touches the CLI — it uses the same OAuth device flow as connecting a third-party AI client.
Run the login command
v login A short code and a URL are printed to your terminal.
Approve in your browser
Open the URL, enter the code if prompted, and approve the request with your Viewert account.
You're in
The CLI stores your session in your OS keyring — macOS Keychain, Linux libsecret, or Windows Credential Manager — never as a plaintext file. It refreshes automatically, so you won't need to log in again on this machine.
Checking Who You're Logged In As
v me (alias v user) is your identity check — analogous to `gh auth status` or `whoami`. It shows who you're logged in as, when your session expires, and which scopes it has. Logging out is a top-level command now too, no `auth` prefix.
v me
Shows the logged-in username, token expiry, and scopes. v user is an identical alias — use whichever reads better in your muscle memory.
v logout
Removes your stored credentials from this machine's keyring.
v status: A Local, Offline Health Check
v status is the git-status equivalent for a folder of Vellum Markdown files — purely local, no network call, so it's always fast and works offline. It recursively scans a folder (current directory by default) for *.md files and buckets each one into untracked, modified locally since the last push/sync, or up to date, based only on the file itself plus the local .viewert-sync.json state.
v status
v status ~/my-vellumsstatus vs. sync --dry-run
Listing and Pulling Vellums
Browse your library and bring individual Vellums down to disk as Markdown, with a YAML frontmatter block carrying the tracking ID and title.
v ls
Lists your Vellums with their ID, title, and last-updated date. Add --libram <id> to filter to a single Libram, or --tag <tag> (repeatable) to filter by tag.
v pull <vellum-id>
Downloads a single Vellum as a Markdown file named after its title (or pass --output/-o to choose the path). The file's frontmatter v_id is what push and sync use to know which Vellum a file corresponds to.
Pulling by Tag
Rather than pulling one Vellum at a time, pull every Vellum matching a tag straight into a folder — handy for bringing a whole tagged collection onto disk at once.
viewert pull --tag project:skills -o ~/my-vellums
# require ALL tags, not just any
viewert pull --tag skills --tag adam --match-all -o ~/my-vellums
# preview first, write nothing
viewert pull --tag skills --dry-runPulling by Tag: Matching Rules
Pushing Local Changes
Push a single Markdown file, or point push at a whole folder to recursively push every *.md file found in it — --tag is always required. Most files in an existing notes/skills repo won't have Viewert's own frontmatter (or will carry foreign frontmatter from another tool entirely), so the tag is the explicit signal that a file belongs in Viewert rather than push guessing from its shape.
viewert push notes.md --tag project:skills
viewert push . --tag project:skills
viewert push ~/repos/my-skills --tag skills --tag adamHow Push Decides Create vs. Update
A file with a v_id already in its frontmatter is updated in place; everything else is created as a new Vellum, with v_id written back into the file afterward. Title comes from frontmatter if present, otherwise the first "# Heading" line in the file, otherwise the filename. Tags are merged with whatever a Vellum already has (up to the account limit of 4) — pushing never silently drops existing tags. Directories named .git, node_modules, vendor, or starting with a dot are skipped during a folder push.
Frontmatter Is Preserved, Not Overwritten
Files from other tools — Obsidian aliases/tags, Jekyll layout/date, anything else — keep their existing frontmatter fields when Viewert writes v_id, slug, title, tagline, and updated_at into the file. A bare id: field from before this change is still honored as the tracking ID, but only when it's shaped like a real Viewert ID; a foreign id: field from another tool is left alone untouched.
---
v_id: 01JABCXYZ...
title: Backend Architecture Notes
tags: [architecture, backend]
aliases: [DB Notes]
---
## Database schema
Everything lives in Postgres...Bidirectional Sync
For a whole folder of Vellums, sync keeps everything up to date in both directions — pulling remote changes down and pushing local edits up, matched by each file's frontmatter v_id.
v sync ~/my-vellums # sync once, both directions
v sync ~/my-vellums --watch # keep syncing as you edit locally
v sync ~/my-vellums --direction pull # pull only
v sync ~/my-vellums --dry-run # preview without writing anythingConflict Handling
MCP Server for Claude
v mcp starts a local Model Context Protocol server over stdio, giving Claude direct read/write access to your Vellums and Librams — authenticated with the same login you already used for v login, no separate API key required.
{
"mcpServers": {
"viewert": {
"command": "viewert",
"args": ["mcp"]
}
}
}Exposed MCP Tools
Once connected, Claude has access to five tools covering your whole library:
list_vellums
Lists your Vellums.
get_vellum
Fetches a single Vellum's full content.
create_vellum
Creates a new Vellum.
update_vellum
Updates an existing Vellum.
list_librams
Lists your Librams.
Prefer a Remote Connection?
CI/CD & Non-Interactive Use
v login needs a browser and a human to approve the device-flow prompt — not something a CI runner can do. For scripts, GitHub Actions, cron jobs, or any other non-interactive context, set VIEWERT_TOKEN to an API key instead. When it's set, every command uses it directly and skips login/keyring entirely — no browser, no human, no session to refresh.
export VIEWERT_TOKEN=vwt_your_api_key_here
viewert ls --tag project:skillsCreating an API Key
GitHub Actions Example
Store the key as a repository secret, then reference it as an environment variable in the workflow step that runs the CLI:
- name: Sync Vellums
env:
VIEWERT_TOKEN: ${{ secrets.VIEWERT_TOKEN }}
run: |
viewert push ./docs --tag ci-syncedWhy VIEWERT_TOKEN Matters on Headless Linux
This isn't just convenience — v login normally stores credentials in an OS keyring (macOS Keychain, Windows Credential Manager, or libsecret on Linux), and most headless CI containers don't run a libsecret daemon at all. That means v login often wouldn't work reliably in CI even if a human were there to click "approve." VIEWERT_TOKEN sidesteps the keyring completely, so it works the same in every container regardless of what's installed.
Configuration
Settings live at ~/.config/viewert/config.json (created automatically on first login). To point the CLI at a different backend — a self-hosted or staging instance — override the API base for a single command with --api, or persistently with the VIEWERT_API environment variable. For authentication, VIEWERT_TOKEN (an API key) always takes priority over any keyring-stored login, on every command, for as long as it's set in the shell.