CLI
The Obris CLI keeps a local directory in two-way sync with an Obris topic. Pull every item in a topic down to disk, push your local edits back, and bulk-upload new files in one command. The same CLI is what the Claude and Codex plugins shell out to.
The CLI is one of several ways to add knowledge to Obris. You can also sync from Google Drive or Notion, save web content with the Chrome extension, or upload files in the dashboard.
Install
Requires Python 3.10+.
pip install obris-cli
obris --version
Or run directly with uv without installing:
uvx --from obris-cli obris --help
The PyPI package is obris-cli; the installed command is obris.
Authenticate
Authentication is browser-based. No API keys to copy or paste.
obris auth login
Opens your browser, you authorize the CLI, and the command finishes. Tokens are stored locally per environment.
From inside an AI agent (two-step)
If something else is driving the CLI (a plugin, an agent), use the two-step variant so the caller doesn't block on a polling loop:
obris auth login --no-wait # prints a URL and exits immediately
obris auth complete # finalizes once the user has authorized
Check status
obris auth status
Reports whether the active environment is authenticated. Read-only.
Log out
obris auth logout
Sync
obris sync is the headline workflow. It links a local directory to one or more Obris root topics and keeps them in sync.
First sync: link a topic to a directory
obris sync -p <directory> -t <topic-id>
Pulls every item in the topic (and its subtopics) down into the directory. Subtopics become subdirectories. The CLI stores its tracking metadata in <directory>/.obris/ so you never have to repeat the topic ID on later runs.
If you omit -t, the CLI creates a new root topic named after the directory and links it. Pass --no-create if you'd rather it error than create a topic.
Link multiple topics to the same directory
You can link more than one root topic to a single directory. Run obris sync -t <topic-id> again with a different topic ID and the CLI sets up another sync alongside the first.
obris sync -p <directory> -t <topic-id-1> # link the first topic
obris sync -p <directory> -t <topic-id-2> # link a second topic alongside it
obris sync -p <directory> # syncs every linked topic in one pass
Each topic gets its own .obris/<topic-id>.json state file, and files are tracked independently. A file you add to topic A does not show up under topic B unless you explicitly add it there too. To add new files in a multi-topic directory, route them with obris sync add <file> -t <topic-id> so the right topic gets the file.
Bootstrap a directory full of files
If the directory already has files you want in the topic, add --add-all on the first sync. The CLI walks the directory, uploads every untracked file in one bulk request, and creates subtopics on the server to mirror local subdir structure:
obris sync -p <directory> -t <topic-id> --add-all
--add-all is idempotent. Re-running picks up newly-added local files without touching the ones already tracked.
Ongoing sync
obris sync -p <directory>
No flags. The CLI auto-detects the linked topic from .obris/, picks up remote changes (pulls), pushes local edits, and reports new untracked files without uploading them.
Dry-run preview
obris sync -p <directory> --dry-run
obris sync -p <directory> --dry-run --add-all
--dry-run never mutates server or disk state. Combined with --add-all, it shows exactly which files would be uploaded before you commit. If the directory has no linked topic yet, the dry-run shows what topic name and subtopic structure would be created without actually creating them.
Common flags
- Name
-p, --path- Type
- string
- Description
Local directory. Defaults to the current directory.
- Name
-t, --topic- Type
- string
- Description
Root topic ID. Required for the first sync of a new directory unless you want a topic created automatically.
- Name
-i, --item- Type
- string
- Description
Sync only specific item IDs. Repeatable.
- Name
--include- Type
- string
- Description
Subtopic name-path glob. Repeatable; patterns OR together. See Subtopic filtering.
- Name
--add-all- Type
- flag
- Description
Upload every untracked file under the synced directory.
- Name
--no-subtopics- Type
- flag
- Description
With
--add-all, skip files in subdirs instead of creating matching subtopics.
- Name
--no-create- Type
- flag
- Description
Error instead of creating a root topic when the directory has no sync state.
- Name
--dry-run- Type
- flag
- Description
Preview without making changes.
- Name
-v, --verbose- Type
- flag
- Description
List every untracked, excluded, or symlink path.
Sync configuration
Excluding files
obris sync exclude <pattern> -p <directory>
Stops syncing files that match the pattern. Examples:
obris sync exclude scratch/ # an entire folder
obris sync exclude notes.draft.md # a specific file
obris sync exclude '*.draft.md' # all drafts
Including files (overriding exclusions)
obris sync include <pattern> -p <directory>
Forces a file or pattern to sync, overriding any exclusion. Works whether the exclusion is a built-in default or one you added previously. Use this whenever obris sync says a file is being skipped and you actually want it.
obris sync include .env.example # sync the example even though .env.* is excluded
obris sync include .DS_Store # override a built-in default
obris sync include scratch/draft # un-exclude a file in an excluded folder
exclude and include are strict inverses. Last call wins. Toggling the same pattern back and forth cancels the previous entry rather than stacking; if you include a pattern that wasn't excluded in the first place, the CLI prints a "no-effect" warning so you can see the action did nothing.
Listing current settings
obris sync exclude --list -p <directory>
Shows every pattern currently excluded or included for the directory.
Default exclusions
--add-all and obris sync skip a sensible default set so secrets and tooling cruft never land in the knowledge base:
- VCS:
.git/,.svn/,.hg/ - Dependencies:
node_modules/,.venv/,venv/,__pycache__/ - OS cruft:
.DS_Store,Thumbs.db - Credentials:
.env,.env.*,.envrc,.netrc,.npmrc,.pypirc,.aws/,.gnupg/,.ssh/ - Sync metadata:
.obris/(the CLI's own state directory)
Common AI tool config dirs (.claude/, .cursor/, .github/) are not skipped. They're treated as content. Override any default with obris sync include <pattern>.
Subtopic filtering
Sync only matching subtopics with --include:
obris sync -p <directory> --include 'Projects/**' --include '**/skill-*'
--include scopes every operation in the sync: pulls of new items, push and pull of tracked items, conflict detection, remote-deleted detection, and --add-all bulk uploads. Files outside the include scope are surfaced separately so you know they were skipped on purpose:
Skipped 2 untracked file(s) outside --include scope:
Misc/random.md
README.md
Patterns OR together; supports ** (zero or more segments), *, ?, [abc]. Case-insensitive.
Per-file sync operations
sync add
Add a single local file to a synced topic.
obris sync add <filepath>
obris sync add <filepath> -t <topic-id>
If the directory is synced to exactly one topic, -t is optional. Pass -t to target a specific subtopic.
obris sync add bypasses the exclusion list since you've explicitly named the file. That makes it the right way to sync a file that matches a default exclusion.
sync link
Relink a renamed file to its remote item.
obris sync link <filepath> -i <item-id>
obris sync link <filepath> -i <item-id> -t <topic-id>
When you rename a synced file, the next sync unlinks it. sync link reattaches the new filename to the existing remote item so future syncs pick up your edits instead of treating the file as new.
sync unlink
Break the local-to-remote sync link without deleting either side.
obris sync unlink <id-or-filename>
obris sync unlink notes.md draft.md # multiple at once
Both the local file and the remote item stay in place; subsequent obris sync calls will not re-pull these items. Re-link later with obris sync link or obris sync add. To permanently delete the remote item, use obris knowledge delete <id>.
sync conflicts
When the same item changed on both sides between syncs, the CLI flags it conflicted and skips it for both push and pull. Other items sync normally; the conflict is opt-in to resolve.
obris sync conflicts list -p <directory>
obris sync conflicts resolve <filename> --keep-local -p <directory>
obris sync conflicts resolve <filename> --keep-remote -p <directory>
--keep-local pushes the local copy up. --keep-remote pulls the remote copy down and saves the local copy as a sibling <name> (conflict YYYY-MM-DD).<ext> file so nothing is lost.
Where state lives
The CLI stores tracking metadata at <directory>/.obris/: one JSON file per linked topic, plus a .gitignore so the directory self-excludes from any git/svn checkout your project might be inside. The engine ignores .obris/ when scanning for files to sync.
rm -rf <directory> cleans up tracking state along with the local files. No global state is left orphaned.
JSON output
The top-level --json flag on obris itself (not on the subcommand) makes commands emit a structured JSON summary instead of human-readable lines. Useful when relaying outcomes to other tools or counting exactly what moved.
obris --json sync -p <directory>
Sync JSON fields: path, pulled, pushed, conflicts, errors, untracked, excluded_count, symlinks, conflicts_pending, missing_local, skipped_by_include.
--json works on every command. obris --json topic list, obris --json knowledge view <id>, and so on.
Other commands
topic
obris topic list # root topics
obris topic list --all # every topic, hierarchical
obris topic list --parent <id> # children of a topic
obris topic tree <topic-id> # subtree as a table
obris topic view <topic-id> # subtopics + items
knowledge
obris knowledge view <id>
obris knowledge move <id> --topic <id>
obris knowledge delete <id>
save
Save a file or screenshot to a topic. --screenshot requires macOS or Linux.
obris save photo.png # upload a file to Scratch
obris save photo.png --topic <id> # upload to a specific topic
obris save --screenshot # take a screenshot, upload to Scratch
obris save --screenshot --name "diagram" # name it explicitly
obris save --screenshot --prompt # open a name dialog before capturing
- Name
filepath- Type
- string
- Description
Path to a file. Optional if
--screenshotis set.
- Name
--screenshot- Type
- flag
- Description
Take an interactive screenshot and upload it. macOS or Linux only.
- Name
--name- Type
- string
- Description
Display name for the saved item.
- Name
--prompt- Type
- flag
- Description
Open a dialog to enter a name before capturing.
- Name
--topic- Type
- string
- Description
Topic ID to upload to. Defaults to your Scratch topic.
Environments
obris env manages multiple environments (e.g. prod, dev, local, a self-hosted instance).
obris env list # all environments
obris env view # show the active one
obris env use dev # set the default environment
obris env add staging --url https://obris.staging.example.com
obris env remove staging
Use --env <name> on any command to override for a single invocation, without changing the default:
obris --env dev sync -p <directory>
obris --env local auth login --no-wait
Each environment keeps its own auth tokens.
Hotkeys
Bind keyboard shortcuts to obris save --screenshot using any automation tool: Alfred, Raycast, Keyboard Maestro, macOS Shortcuts, etc.
Example: Alfred
Create a workflow with a Hotkey trigger connected to a Run Script action (language: /bin/zsh):
Quick capture:
/full/path/to/obris save --screenshot
Capture with name prompt:
/full/path/to/obris save --screenshot --prompt
Use the full path to the obris binary since Alfred does not load your shell
profile. Run which obris to find it.
Platform support
| Platform | Sync | Save (file) | Save (screenshot) |
|---|---|---|---|
| macOS | Yes | Yes | Yes |
| Linux | Yes | Yes | Yes |
| Windows | Yes | Yes | No |