A command-line knowledge base with built-in AI agent integration via MCP.
- Overview
- Features
- Installation
- Environment Variables
- Usage
- Storing Data
- Retrieving Data
- Running Commands
- Searching
- Aliases
- Copying Data
- Renaming
- Editing Data
- Removing Data
- Context (Knowledge Summary)
- Run Confirmation
- Interpolation
- Encryption
- Configuration
- Project-Scoped Data
- Data Management
- Staleness Detection
- Schema Validation
- Shell Wrapper
- Shell Tab-Completion
- Scripting Tips
- Debugging
- Command Reference
- MCP Server (AI Agent Integration)
- Documentation
- Development
- License
CodexCLI is a command-line tool and AI agent knowledge base. It stores structured information using hierarchical dot notation (similar to JSON) and exposes it to AI agents via MCP. The goal: make AI agents more effective by giving them persistent, shared project context across sessions.
- Hierarchical Data Storage: Store data using intuitive dot notation paths (e.g.,
server.production.ip) - Command Runner: Execute stored shell commands with dry-run, composition (
:) and chaining (&&), and optional per-entry confirmation - Interpolation: Reference stored values with
${key}, execute stored commands with$(key), and use conditional defaults${key:-fallback}— all resolved at read time - Aliases: Create shortcuts to frequently accessed paths
- Encryption: Password-protect sensitive values
- Search: Find entries by searching keys or values
- Tree Visualization: Display nested data in a tree-like structure
- Clipboard Integration: Copy values directly to clipboard (macOS, Linux, Windows)
- Inline Editing: Open entries in
$EDITOR/$VISUALfor quick edits - JSON Output: Machine-readable
--jsonflag ongetandfindfor scripting - Stdin Piping: Pipe values into
setfrom other commands - Project-Scoped Data: Opt-in
.codexcli/per project — project entries take precedence, fall through to global - Smart Init:
ccli initscans your codebase, populates.codexcli/with project/commands/files/deps/conventions/context entries, generatesCLAUDE.md, and seeds the three-file knowledge convention - Auto-Backup: Automatic timestamped backups with configurable rotation (
max_backupssetting) - File Locking: Advisory locking prevents data corruption from concurrent access
- Shell Tab-Completion: Full tab-completion for Bash and Zsh (commands, flags, keys, aliases)
- Staleness Detection: Track when entries were last updated, find stale knowledge (
ccli stale), inline[untracked]/[Nd]warnings ongetandcontextoutput - Schema Validation: Check entries against recommended namespaces (
ccli lint), customizable via_schema.namespaces - MCP Server: 19 tools for any MCP-compatible AI agent (Claude Code, Copilot, ChatGPT, etc.) via the Model Context Protocol
- Telemetry & Audit: Track usage patterns with scope-aware telemetry (
ccli stats) and full audit log with before/after diffs, hit/miss tracking, and per-entry metrics (ccli audit --detailed). Includes net token savings with self-calibrating exploration cost estimates, miss-path tracking, and per-agent breakdown.
brew tap seabeardev/ccli
brew install ccliDownload the latest release for your platform from GitHub Releases.
# macOS (Apple Silicon)
curl -fsSL https://github.com/seabearDEV/codexCLI/releases/latest/download/ccli-macos-arm64 -o ccli
chmod +x ccli && sudo mv ccli /usr/local/bin/
# macOS (Intel)
curl -fsSL https://github.com/seabearDEV/codexCLI/releases/latest/download/ccli-macos-x64 -o ccli
chmod +x ccli && sudo mv ccli /usr/local/bin/
# Linux (x64)
curl -fsSL https://github.com/seabearDEV/codexCLI/releases/latest/download/ccli-linux-x64 -o ccli
chmod +x ccli && sudo mv ccli /usr/local/bin/
# Linux (ARM64)
curl -fsSL https://github.com/seabearDEV/codexCLI/releases/latest/download/ccli-linux-arm64 -o ccli
chmod +x ccli && sudo mv ccli /usr/local/bin/
# Windows (x64) — download from:
# https://github.com/seabearDEV/codexCLI/releases/latest/download/ccli-win-x64.exe
# First run will prompt to install shell completions
ccliNote: Installing from source registers the development binary
cclid(notccli). All examples in this README useccli, but substitutecclidif you installed from source. The productioncclibinary is available via Homebrew or the GitHub Releases download above.
Ensure npm's global binaries are in your PATH by adding the following to your shell profile (.bashrc, .zshrc, or equivalent):
export PATH="$(npm config get prefix)/bin:$PATH"git clone https://github.com/seabearDEV/codexCLI.git
cd codexCLI
npm install
npm run build
npm install -g .If cclid is not found after installing, verify that npm's global bin directory is in your PATH:
echo $PATH | grep -o "$(npm config get prefix)/bin"CodexCLI honors a small set of environment variables for deployment-time configuration. All are optional — sensible defaults work for most users. (For interactive UI preferences like color and pager, see Configuration under Usage.)
| Variable | Purpose | Default |
|---|---|---|
CODEX_DATA_DIR |
Override the global data directory. Must be an absolute path. All global state lives here: the entry store (store/), config, audit log, telemetry. |
~/.codexcli |
CODEX_PROJECT |
Explicit path to a .codexcli/ directory, a legacy .codexcli.json file, or a containing directory. Fails closed if the path doesn't resolve — no cwd walk-up fallback. |
unset (walk up from cwd) |
CODEX_PROJECT_DIR |
MCP-server launcher hint — the directory the server should treat as the project root. Equivalent to passing --cwd <dir>. Applied via setProjectRootOverride (no process.chdir), so it works whether the server is run as a binary or imported. |
unset |
CODEX_NO_PROJECT |
Disable project-file lookup entirely. Set to any non-empty value (e.g. 1) and findProjectFile() returns null regardless of cwd or CODEX_PROJECT. |
unset |
CODEX_AGENT_NAME |
Identifier recorded in the audit and telemetry logs for the calling agent. Used by ccli stats and ccli audit to break down activity per agent (Claude, Cursor, Copilot, etc.). |
unset |
CODEX_DISABLE_LOCKING |
Test-only. When set to 1, withFileLock falls back to running its closure without acquiring the file lock if lock acquisition fails. The default (production) behavior since v1.11 is to fail closed and propagate the lock error. Production code should never set this — there are no known production environments where lock acquisition is expected to fail. Tests that intentionally exercise contended-lock scenarios use this opt-out instead. |
unset |
CODEX_DATA_DIRmust be absolute. Relative paths (./mydata,~/foo) are rejected with a hard error rather than silently resolved againstprocess.cwd(). Pass an expanded absolute path.- Verify your data directory at any time with
ccli info— theDataline shows the resolved path and is annotated with(CODEX_DATA_DIR)when the env var is set. - Pin the project root for the MCP server in
.claude.jsonby setting"env": { "CODEX_PROJECT": "<repo path>" }in the codexcli MCP block. This is more deterministic than relying oncwdwalk-up.
# Set a simple entry
ccli set mykey "my value"
# Set a nested entry using dot notation
ccli set server.production.ip 192.168.1.100
# Set with an alias
ccli set server.production.ip 192.168.1.100 -a ip
# Overwrite without confirmation
ccli set server.production.ip 10.0.0.1 -f
# Read value interactively (avoids shell expansion of $, !, etc.)
ccli set secret.token -p
# Same, but with visible input
ccli set secret.token -p --show
# Encrypt a value
ccli set api.key sk-secret-123 -e
# Mark an entry as requiring confirmation before running
ccli set commands.deploy "./deploy.sh" --confirm
# Remove the confirmation requirement from an entry
ccli set commands.deploy --no-confirm
# Batch set multiple key=value pairs
ccli set a=1 b=2 c=3
# Pipe a value from stdin
echo "my value" | ccli set mykey
# Pipe from another command
curl -s https://api.example.com/token | ccli set api.tokenAfter setting an entry, you'll be asked interactively whether it should require confirmation to run. Use --confirm or --no-confirm to skip the prompt.
When inside a project directory (one with a .codexcli/ store), get shows project entries by default. Use -G for global entries or -A for both. Outside a project, get shows global entries. Looking up a specific key always falls through from project to global automatically.
# List keys in the current scope
ccli get
# List keys with values
ccli get -v
# Get a specific entry (leaf values always show their value)
ccli get server.production.ip
# List keys in a namespace
ccli get server
# List keys in a namespace with values
ccli get server -v
# Show global entries only (when inside a project)
ccli get -G
# Show entries from all scopes with section headers
ccli get -A
# Limit key depth (1 = top-level, 2 = two levels, etc.)
ccli get -k 1
ccli get -k 2 -v # two levels with values
# Display as a tree structure (keys only by default)
ccli get --tree
ccli get --tree --values # tree with values
ccli get --tree -k 2 # tree limited to 2 levels
# Output plain text without colors (for scripting)
ccli get server.production.ip -p
# Show stored value before interpolation
ccli get paths.myproject --source
# Decrypt an encrypted value
ccli get api.key -d
# Copy value to clipboard
ccli get server.ip -c
# Output as JSON (for scripting)
ccli get server --json
# List all aliases
ccli alias listCommands run immediately by default. Entries marked with --confirm at set time will prompt before executing. Use -y to skip the prompt.
# Execute a stored command (runs immediately unless marked --confirm)
ccli run deploy.cmd
# Skip the confirmation prompt (for entries marked --confirm)
ccli run deploy.cmd -y
# Dry run (print without executing)
ccli run deploy.cmd --dry
# Chain multiple commands with &&
ccli run nav.project commands.list -y
# → cd /path/to/project && ls -l
# Compose a command from fragments using :
ccli run commands.cd:paths.project -y
# → cd /path/to/project
# Combine composition and chaining
ccli run commands.cd:paths.project commands.list -y
# → cd /path/to/project && ls -l
# Multiple colon-separated segments
ccli run commands.scp:files.config:targets.prod -y
# → scp ./config.yml admin@prod:/etc/app/
# Decrypt and run an encrypted command
ccli run secret.script -d -y
# Capture output for piping (instead of inheriting stdio)
ccli run cmd.echo --capture | tr a-z A-Z
# Stored command chain (macro) — value is space-separated key refs
ccli set macros.deploy "commands.build commands.test commands.deploy"
ccli run macros.deploy --chain -y
# → npm run build && npm test && ./deploy.sh# Search keys and values
ccli find 192.168
# Search data entries only (skip aliases)
ccli find prod -e
# Search aliases only
ccli find ip -a
# Show results as a tree
ccli find server -t
# Output as JSON (for scripting)
ccli find prod --json
# Search with regex
ccli find "prod.*ip" --regex
# Search keys only (skip value matching)
ccli find "server" --keys
# Search values only (skip key matching)
ccli find "10.0" --valuesAliases are shortcuts to frequently used key paths. Managed via the alias subcommand:
# Create an alias
ccli alias set ip server.production.ip
# List all aliases
ccli alias list
# Remove an alias
ccli alias remove ip
# Rename an alias
ccli alias rename ip sip
# Use an alias anywhere you'd use a key
ccli get ip
ccli run ip
# Create an alias inline when setting an entry
ccli set server.production.ip 192.168.1.100 -a ip
# Remove an entry and its alias
ccli remove server.production.ipCopy an entry (or an entire subtree) to a new key:
# Copy a single entry
ccli copy server.ip server.ip.backup
# Copy an entire subtree
ccli copy server server.backup
# Overwrite destination without confirmation
ccli cp server.ip server.ip.backup -fRename entry keys or aliases without re-creating them:
# Rename an entry key (moves the value, updates aliases)
ccli rename server.old server.new
# Rename an alias
ccli alias rename oldalias newalias
# Rename a key and set a new alias on it
ccli rename server.old server.new --set-alias snOpen a stored value in your $EDITOR (or $VISUAL) for inline editing:
# Edit an entry in your default editor
ccli edit server.production.ip
# Edit an encrypted entry (decrypts before editing, re-encrypts on save)
ccli edit api.key --decryptRemoving an entry prompts for confirmation. Use -f to skip.
# Remove an entry (prompts for confirmation)
ccli remove server.old
# Remove without confirmation
ccli remove server.old -f
# Remove an alias only (keep the entry)
ccli alias remove myaliasReference stored values inside other values with ${key} syntax. References are resolved at read time.
# Store a base path
ccli set paths.github "/Users/me/Projects/github.com"
# Reference it in another entry
ccli set paths.myproject 'cd ${paths.github}/myproject'
# Resolves at read time
ccli get paths.myproject
# → cd /Users/me/Projects/github.com/myproject
# Works with run too
ccli run paths.myproject -y
# Use --source to see the raw stored value
ccli get paths.myproject --source
# Use --prompt (-p) when setting to avoid shell expansion of ${}
ccli set paths.myproject -pUse bash-style modifiers for fallback values and required-key checks:
# Default value — use fallback when key is not found
ccli set greeting 'Hello, ${user.name:-stranger}!'
ccli get greeting
# → Hello, stranger! (if user.name doesn't exist)
# → Hello, Alice! (if user.name is "Alice")
# Required value — throw a custom error when key is not found
ccli set deploy.cmd 'ssh ${deploy.host:?deploy.host must be set first}'
ccli run deploy.cmd
# → Error: deploy.host must be set first
# Nested defaults — the fallback can itself contain ${} references
ccli set url '${api.url:-${api.default_url}}/endpoint'
# Empty default — resolves to empty string when key is missing
ccli set optional '${maybe.key:-}'Use $(key) to execute a stored command and substitute its stdout. The key must reference a stored string value containing a shell command.
# Store a command
ccli set system.user "whoami"
# Reference it with $(key) — executes the command and substitutes the output
ccli set paths.home '/Users/$(system.user)'
ccli get paths.home
# → /Users/kh
# See the raw value without executing
ccli get paths.home --source
# → /Users/$(system.user)
# Aliases work too
ccli set system.user -a user
ccli set paths.home '/Users/$(user)'Exec interpolation supports:
- Recursion: stored commands can contain
${key}or$(key)references that resolve before execution - Caching: the same key is only executed once per interpolation pass
- Circular detection:
$(a)→$(b)→$(a)throws an error - Timeout: commands are killed after 10 seconds
- Cross-type references:
${key}values can contain$(key)and vice versa
# Encrypt a value (prompts for password twice)
ccli set api.key sk-secret-123 -e
# Encrypted values show as [encrypted]
ccli get api.key
# → api.key: [encrypted]
# Decrypt to view
ccli get api.key -d
# Decrypt and copy to clipboard
ccli get api.key -d -c
# Decrypt and run
ccli run secret.deploy -d -y
# Clear terminal after setting sensitive data
ccli set api.key -p -e -c# Show all settings
ccli config
# Get a specific setting
ccli config get theme
# Change a setting
ccli config set theme dark
ccli config set colors false
# Show version, stats, and storage paths
ccli info
# Show usage examples
ccli config examplesAvailable settings:
| Setting | Values | Description |
|---|---|---|
colors |
true / false |
Enable/disable colored output |
theme |
default / dark / light |
UI theme |
max_backups |
integer (default: 10) |
Number of auto-backups to keep (0 to disable) |
CodexCLI supports per-project knowledge stores that live alongside your code. The .codexcli/ directory is designed to be committed to version control, creating a shared knowledge base that persists across sessions, team members, and AI agents. As of v1.10.0, each entry is its own JSON file inside the directory (.codexcli/arch.storage.json, .codexcli/commands.build.json, etc.) — this eliminates merge conflict churn when multiple devs add different entries on parallel branches. Use CLI or MCP tools to edit; hand-editing the wrapper files is unsupported.
# Initialize a project — scans codebase, creates .codexcli/ and CLAUDE.md
ccli init
# Preview what init would create
ccli init --dry-run
# Init without CLAUDE.md generation
ccli init --no-claude
# Init without codebase scan (empty .codexcli/)
ccli init --no-scan
# Store project knowledge
ccli set commands.build "npm run build"
ccli set commands.test "npm test"
ccli set arch.api "REST endpoints in src/routes/, validated by Zod schemas"
ccli set conventions.errors "Always use AppError class from src/utils/errors.ts"
ccli set context.auth "JWT tokens expire after 1h, refresh via /api/refresh"
# get shows project entries only (when inside a project)
ccli get
# Single-key lookups fall through to global transparently
ccli get paths.github # not in project → found in global
# Use -G to see global entries only
ccli get -G
# Use -A to see both scopes with section headers
ccli get -A
# Use -G to explicitly write to global while inside a project
ccli set server.ip 192.168.1.100 -G
# Remove the project store
ccli init --removeScope flags: The -G / --global flag is available on set, get, run, find, copy, edit, rename, and remove. Data management commands (export, import, reset) also support -P / --project.
Deep dive: See the Schema Guide for the full rationale behind the file structure, what makes a good entry, and a walkthrough of the codexCLI project's own
.codexcli/as a reference implementation.
When using CodexCLI as a project knowledge base (especially with AI agents via MCP), we recommend organizing entries under these namespaces:
| Namespace | Purpose | Examples |
|---|---|---|
project.* |
Basic metadata | project.name, project.stack, project.description |
commands.* |
Build, test, deploy commands | commands.build, commands.test, commands.deploy.staging |
arch.* |
Architecture and design decisions | arch.storage, arch.api, arch.auth |
conventions.* |
Coding patterns, naming, style | conventions.types, conventions.errors, conventions.testing |
context.* |
Non-obvious gotchas, edge cases | context.migration, context.legacy, context.performance |
files.* |
Key file paths and their roles | files.entry, files.config, files.routes |
deps.* |
Notable dependencies and why | deps.commander, deps.vitest, deps.zod |
Keep values concise — one sentence or a short command. Use multiple keys under the same namespace for detail. Don't store things easily derived from package.json or the code itself; store insights, decisions, and context that would otherwise be lost.
When an AI agent connects via MCP, the recommended workflow is:
- Call
codex_contextas your first tool call to bootstrap session knowledge. Pick the right tier for the task:tier:"essential"— answering questions, small fixes, single-file edits- omit /
tier:"standard"— multi-file changes, bug fixes, new features (default) tier:"full"— refactoring subsystems, changing architecture, onboarding to the codebase
- Check relevant namespaces (
arch,conventions,context,files) before exploring the codebase - Record non-obvious discoveries with
codex_setas you work - Update stale entries when you find they no longer match the code
Agent usage is tracked automatically — run ccli stats to see bootstrap rate, write-back rate, and namespace coverage trends.
Every AI session has the same problem: the agent starts from zero, spends thousands of tokens exploring the codebase, and all that understanding vanishes when the session ends. CodexCLI turns that into a compounding asset.
Here's how it works in practice:
-
You run
ccli initin a new project. The CLI scans the codebase in milliseconds and creates a skeleton.codexcli/with project metadata, commands, file paths, dependencies, and conventions it can detect from the filesystem. -
First AI session begins. The agent calls
codex_context, sees the skeleton, and recognizes it's a fresh project (context.initialized: scaffold). Before starting your task, it reads the actual source code — entry points, core modules, config files — and populates the deep knowledge: architecture decisions inarch.*, non-obvious gotchas incontext.*, and rich file descriptions infiles.*. This deep analysis runs once. -
Every session after that — whether it's Claude, Copilot, Cursor, ChatGPT, or any other MCP-compatible agent — bootstraps the full knowledge base in a single
codex_contextcall. No re-exploration. No wasted tokens. -
The flywheel accelerates. Agent A discovers a database migration gotcha on Monday and stores it in
context.migration. Agent B (different tool, different session) hits the same area on Tuesday and benefits immediately — it already knows about the gotcha. Agent B discovers an API pattern and stores it inarch.api. Agent C benefits on Wednesday.
The knowledge base grows with every session. The token cost per session drops. ccli stats shows you the trend: bootstrap rate, hit rate, estimated tokens saved, per-namespace coverage. The more you use it, the more efficient every agent becomes.
Because the knowledge lives in .codexcli/ (plain JSON files committed to your repo), it works across machines, across team members, and across AI tools. No vendor lock-in, no cloud dependency, no API keys. Just files that get smarter over time.
All data (entries, aliases, confirm metadata) is stored in a directory with one JSON file per entry plus _aliases.json and _confirm.json sidecars — ~/.codexcli/store/ for global data, .codexcli/ for project-scoped data. Pre-v1.10.0 unified .codexcli.json / data.json files are automatically migrated on first access and the old file is renamed to .backup.
# Export data to a timestamped file
ccli data export entries
# Export to a specific file
ccli data export aliases -o my-aliases.json
# Export with pretty-printed JSON
ccli data export entries --pretty
# Export confirm metadata
ccli data export confirm
# Export everything (entries, aliases, confirm metadata)
ccli data export all
# Export only global data (when a project file exists)
ccli data export entries -G
# Import data from a file (replaces existing)
ccli data import entries backup.json
# Import and merge with existing data
ccli data import entries backup.json --merge
# Preview changes without importing
ccli data import entries backup.json --merge --preview
# Reset data to empty state (prompts first)
ccli data reset entries
# Reset without confirmation
ccli data reset all -fAuto-backup: Before destructive operations (
data reset, non-mergedata import), CodexCLI automatically creates a timestamped backup in~/.codexcli/.backups/. The last 10 backups are kept by default — configure withccli config set max_backups <n>(set to0to disable rotation).
Get a compact summary of stored project knowledge — the same view AI agents get via codex_context:
# Show project knowledge (standard tier — excludes arch.*)
ccli context
# Show only essential entries (project/commands/conventions)
ccli context --tier essential
# Show everything
ccli context --tier full
# Output as JSON
ccli context --json
# Plain text without colors
ccli context -pMark commands that should prompt before executing:
# Require confirmation before running
ccli confirm set commands.deploy
# List keys requiring confirmation
ccli confirm list
# Remove confirmation requirement
ccli confirm remove commands.deploy
# Skip confirmation at run time with -y
ccli run commands.deploy -yTrack when entries were last updated and find stale knowledge that may need refreshing.
# Show entries not updated in 30 days (default)
ccli stale
# Show entries not updated in 7 days
ccli stale 7
# Output as JSON
ccli stale --jsonTimestamps are tracked automatically when entries are set, copied, or renamed.
Staleness is also surfaced inline — ccli get and codex_context (MCP) append tags to stale or untracked entries:
[untracked]— entry has no update timestamp (predates staleness tracking). Most suspect.[47d]— entry hasn't been updated in 47 days. Verify before trusting version numbers, URLs, or commands.
The CLI get command prints a yellow warning for stale/untracked entries. Fresh entries show no tag.
Check entries against the recommended namespace schema to keep your knowledge base organized.
# Check for entries outside recommended namespaces
ccli lint
# Output as JSON
ccli lint --json
# Check global store only
ccli lint -GDefault namespaces: project, commands, arch, conventions, context, files, deps, system. Add custom namespaces in .codexcli/:
{
"_schema": { "namespaces": ["myapp", "infra"] }
}By default, ccli run executes commands in a child process. This means shell builtins like cd, export, and alias have no effect on your current shell.
After running ccli config completions install, a shell wrapper function is added to your shell profile that fixes this. When you use ccli run (or ccli r), the wrapper:
- Calls the real
cclibinary with--source, which outputs the raw command to stdout instead of executing it - Captures that output and
evals it in your current shell
All other ccli commands pass through to the binary unchanged.
# Store a navigation command
ccli set paths.myproject 'cd ~/Projects/my-project'
# This actually changes your directory (with the wrapper installed)
ccli r paths.myproject -y
# Without the wrapper, cd would run in a child process and have no effectThe wrapper is installed automatically by ccli config completions install. If you already have completions installed, run it again to add the wrapper, then source your shell profile.
CodexCLI supports tab-completion for Bash and Zsh, including commands, flags, stored keys, alias names, and more.
ccli config completions installThis appends a completion loader and shell wrapper to your ~/.zshrc or ~/.bashrc and tells you to restart your shell (or source the file).
If you prefer to set it up yourself:
# Zsh - add to ~/.zshrc
eval "$(ccli config completions zsh)"
# Bash - add to ~/.bashrc or ~/.bash_profile
eval "$(ccli config completions bash)"| Context | Completions |
|---|---|
ccli <TAB> |
All commands (set, get, run, find, edit, copy, remove, rename, alias, confirm, context, info, init, stale, lint, stats, audit, config, data) |
ccli get <TAB> |
Flags + stored data keys + aliases + namespace prefixes |
ccli run <TAB> |
Flags + stored data keys + aliases |
ccli run cd:<TAB> |
Data keys + aliases (completes the segment after :) |
ccli set <TAB> |
Flags + namespace prefixes (one level at a time) |
ccli alias <TAB> |
Subcommands (set, remove, list, rename) |
ccli confirm <TAB> |
Subcommands (set, remove, list) |
ccli config <TAB> |
Subcommands (set, get, info, examples, completions) |
ccli config set <TAB> |
Config keys (colors, theme, max_backups) |
ccli data <TAB> |
Subcommands (export, import, reset) |
ccli data export <TAB> |
entries, aliases, confirm, all |
# Use raw output in other commands
ssh $(ccli get server.ip -r)
# Decrypt and copy to c