Skip to content

tee8z/via

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

via

crates.io docs.rs

via is a secure CLI for running commands and API requests with credentials from your secret provider without exposing secrets to your shell.

Define services in a config file, store only op:// secret references, and let via resolve credentials at runtime. 1Password is supported today; more providers can be added behind the same config-driven model.

Status

via is early and currently focuses on 1Password-backed credentials.

The first provider backend is the 1Password CLI. via uses the official local CLI instead of an unofficial Rust SDK wrapper so the core CLI stays small, portable, and compatible with normal 1Password desktop/CLI auth flows.

The crates.io package is via-cli; the installed binary is via.

Install via

Download and install the latest prebuilt release binary:

curl -fsSL https://raw.githubusercontent.com/tee8z/via/master/scripts/install-release.sh | bash

To pin a specific release:

curl -fsSL https://raw.githubusercontent.com/tee8z/via/master/scripts/install-release.sh | VERSION=v0.2.0 bash

The installer selects the macOS or Linux asset for your machine, installs via to ${INSTALL_DIR:-$HOME/.local/bin}, and prints a PATH update if that directory is not already available in your shell. Releases built with verification metadata are checked against SHA256SUMS; signed checksum verification can be required with VERIFY=required. See docs/release-signing.md.

To install manually, open the latest release and download the asset for your platform:

  • Linux x86_64: via-linux-x86_64.tar.gz
  • Linux arm64: via-linux-arm64.tar.gz
  • macOS Intel: via-macos-x86_64.tar.gz
  • macOS Apple Silicon: via-macos-arm64.tar.gz
  • Windows x86_64: via-windows-x86_64.zip
  • Windows arm64: via-windows-arm64.zip

Extract the archive and place via or via.exe in a directory on your PATH. Then verify the install:

via --help

If you already have Rust installed, you can also install from crates.io:

cargo install via-cli

Human Setup Requirements

  • 1Password CLI installed.
  • Provider authentication handled through via login.
  • Secrets stored in 1Password and referenced by op://... URIs.

Install 1Password CLI:

# macOS CLI
brew install --cask 1password-cli

# Windows CLI
winget install -e --id AgileBits.1Password.CLI

For Linux, follow the official 1Password CLI install guide for APT, YUM, Alpine, NixOS, or manual installation: https://developer.1password.com/docs/cli/get-started/.

Install the 1Password desktop app if it is not already installed:

# macOS desktop app
brew install --cask 1password

# Windows desktop app
winget install -e --id AgileBits.1Password

For Linux desktop app setup, follow the official 1Password Linux install guide: https://support.1password.com/install-linux/.

Then verify:

op --version

Open and unlock the 1Password desktop app, add your account if needed, then enable the CLI integration in Settings > Developer > Integrate with 1Password CLI.

Sign in through via:

via login
via config doctor

via login runs the configured provider's official login flow with an interactive terminal. For 1Password, it delegates to op signin and passes the configured account when [providers.onepassword] account = "..." is set.

If 1Password lists multiple accounts, choose the account that contains the configured vault. To see which accounts the CLI can access:

op account list

If needed, pin via to a specific account:

[providers.onepassword]
type = "1password"
cache = "daemon"
account = "<account-id-or-sign-in-address>"

Run the guided setup:

via config

via config creates a generic service config from values you type in. It does not assume GitHub or any other specific service.

Run:

via config doctor

to check that the secret provider, configured secret references, and any delegated tools are available. via config doctor verifies that secrets are readable by via, but never prints secret values.

Security Model

via has two execution modes:

rest

via makes the HTTP request itself. The resolved secret stays inside the via process and is not passed to a shell, child process, environment variable, argv, or temp file. This is the preferred mode for AI agents.

delegated

via runs a configured trusted binary, injects configured secrets only into that child process, captures stdout/stderr, redacts known secret values, and then forwards the sanitized output. This is higher risk than rest: the child binary receives the secret and must be trusted not to write it elsewhere, transform it before printing, send it over the network, or spawn other processes with it.

Use delegated capabilities only when the binary's native behavior is required. Prefer REST APIs when practical.

via never invokes configured commands through a shell.

Usage

The command shape is:

via <service> <capability> [args...]

For example, with the config below:

via github api /user
via github api GET /repos/OWNER/REPO/issues --query state=open
via github api POST /repos/OWNER/REPO/pulls --json @pull-request.json

If the configured capability delegates to a trusted CLI, everything after the capability name is passed to that binary:

via github gh issue list --repo OWNER/REPO --state open --limit 10 --json number,title,url

Discover what is configured:

via config path
via login
via config doctor
via capabilities
via capabilities --json
via skill print

via skill print emits concise instructions an AI agent can use for the current config.

Example Config

Create via.toml:

version = 1

[providers.onepassword]
type = "1password"
cache = "daemon"

[services.github]
description = "GitHub REST API access through a GitHub App installation"
hint = "via github api /user"
provider = "onepassword"

[services.github.secrets]
app = "op://Private/Example GitHub App/metadata"
private_key = "op://Private/Example GitHub App/github-app.private-key.pem"

[services.github.commands.api]
description = "Call the GitHub REST API. Prefer this for agents."
mode = "rest"
base_url = "https://api.github.com"
method_default = "GET"

[services.github.commands.api.auth]
type = "github_app"
credential = "app"
private_key = "private_key"

[services.github.commands.api.headers]
Accept = "application/vnd.github+json"
X-GitHub-Api-Version = "2022-11-28"

REST capabilities accept paths, not arbitrary absolute URLs. The configured base_url is the trust boundary for that service.

Service-level hint values are optional example commands shown by via capabilities and via skill print. They should demonstrate a safe, minimal call for the configured service without embedding secrets.

cache = "daemon" is the default on macOS and Linux. via auto-starts a per-user local daemon that owns op read calls and caches resolved 1Password secrets in memory for a short TTL. There is no separate service to install or manage for normal use. Use via daemon status, via daemon clear, and via daemon stop to inspect, clear, or stop it; the next command auto-starts it again. Set cache = "off" to always call op read directly. See docs/daemon-architecture.md for the daemon flow, commands, and verification steps.

Config changes do not require a daemon reload. Each via invocation reads the config file again and registers the current allowed secret references with the daemon. Discovery commands such as via capabilities and via skill print show config-only changes immediately. If you changed a secret value in 1Password or want to drop cached OAuth/token state, run via daemon clear; use via daemon stop to restart the daemon completely on the next command.

On Windows, the cache currently defaults to off because the daemon needs a named-pipe backend that is not implemented yet. The config shape is already feature-ready: once Windows daemon support exists, cache = "daemon" can use the same provider setting.

For GitHub App installation-token auth, store the app metadata and private key as separate 1Password secrets and use:

[services.github.secrets]
app = "op://Private/Example GitHub App/metadata"
private_key = "op://Private/Example GitHub App/github-app.private-key.pem"

[services.github.commands.api.auth]
type = "github_app"
credential = "app"
private_key = "private_key"

See docs/github-app-setup.md for the full GitHub App setup flow.

The GitHub App metadata field must be valid JSON with type, numeric app_id, and installation_id. Store the PEM as a 1Password file attachment so it does not need JSON escaping.

For OAuth-backed REST capabilities, store the OAuth credential bundle in 1Password and use:

[services.service.secrets]
oauth = "op://Private/OAuth/credential"

[services.service.commands.api.auth]
type = "oauth"
credential = "oauth"

OAuth credential bundles use type = "service_oauth", the service's REST OAuth token_url, and the grant fields needed by that service. Prefer client_credentials for bot, agent, service-account, or app-actor connections whenever the OAuth service supports it. For Linear:

{
  "type": "service_oauth",
  "token_url": "https://api.linear.app/oauth/token",
  "grant_type": "client_credentials",
  "client_id": "client_id",
  "client_secret": "client_secret",
  "scope": "read,issues:create"
}

via asks the local daemon to mint OAuth access tokens through the provider's REST token endpoint, keeps access tokens and refresh-token state only in daemon memory while the daemon is running, and sends API requests with a bearer token. Nothing from the OAuth token exchange is written to disk. Use refresh_token only for services that need user-actor OAuth and cannot issue bot/app credentials. See docs/linear-oauth-setup.md for the Linear app-actor setup flow.

For APIs that need one or more secret-backed headers:

[services.example.secrets]
api_key = "op://Private/Example/api-key"
tenant = "op://Private/Example/tenant"

[services.example.commands.api.auth]
type = "headers"

[services.example.commands.api.auth.headers.Authorization]
secret = "api_key"
prefix = "Token "

[services.example.commands.api.auth.headers.X-Tenant]
secret = "tenant"

Agent Rules

Agents using via should:

  • Start with via capabilities --json.
  • Prefer configured rest capabilities.
  • Use delegated capabilities only when the configured binary is needed.
  • Never ask the user for tokens or passwords.
  • Never call the underlying secret provider directly.
  • Never print environment variables or credentials.
  • Run via config doctor <service> when a service fails.

About

via is a secure CLI for running commands and API requests with credentials from your secret provider without exposing secrets to your shell.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors