Documentation Index
Fetch the complete documentation index at: https://onecli.sh/docs/llms.txt
Use this file to discover all available pages before exploring further.
This page describes the protocol between oc (the core CLI) and plugins (standalone binaries). If you’re using oc to call plugins, this explains what happens under the hood. If you’re building a plugin, this is the contract you need to implement.
Discovery
Plugins are executable binaries stored in ~/.onecli/plugins/ with the naming convention oc-{name}. When you run oc google calendar list-events, oc looks for a binary at ~/.onecli/plugins/oc-google.
The plugin directory can be overridden with ONECLI_PLUGIN_DIR.
Manifest
Every plugin must respond to the manifest subcommand with a JSON object describing its capabilities:
{
"name": "google",
"version": "v1.0.1",
"description": "Gmail, Calendar, Drive...",
"auth": {
"required": true,
"local_flow": "oauth",
"scopes": ["calendar.readonly", "gmail.readonly"]
},
"commands": [
{
"name": "calendar list-events",
"description": "List upcoming calendar events",
"args": [
{
"name": "--limit",
"required": false,
"description": "Maximum number of events to return"
}
]
}
]
}
Manifest fields
| Field | Type | Description |
|---|
name | string | Plugin name (matches binary name without oc- prefix) |
version | string | Semantic version |
description | string | Short description of what the plugin provides |
auth.required | boolean | Whether credentials are needed to run commands |
auth.local_flow | string | Auth flow type (e.g., "oauth"). Optional. |
auth.scopes | string[] | OAuth scopes or permission descriptions. Optional. |
commands | array | Available commands with descriptions and arguments |
commands[].name | string | Command name (can include subcommands separated by spaces) |
commands[].description | string | What the command does |
commands[].args | array | Available arguments |
commands[].args[].name | string | Argument name |
commands[].args[].required | boolean | Whether the argument is required |
commands[].args[].description | string | What the argument does |
Auth interface
Plugins that require authentication must respond to the auth subcommand. The auth flow uses newline-delimited JSON (NDJSON) on stdout:
{"status": "pending", "url": "https://accounts.google.com/o/oauth2/auth?...", "code": "ABCD-1234"}
{"status": "ok", "credentials": {"access_token": "ya29...", "refresh_token": "1//...", "token_type": "Bearer", "expires_at": "2025-06-01T00:00:00Z"}}
oc reads the stdout stream and stores the first response where status is "ok" and credentials.access_token is non-empty.
Auth response fields
| Field | Type | Description |
|---|
status | string | "pending", "ok", "authenticated", or "expired" |
credentials.access_token | string | The primary authentication token |
credentials.refresh_token | string | Optional refresh token |
credentials.token_type | string | Token type (usually "Bearer") |
credentials.expires_at | string | ISO 8601 expiration timestamp |
url | string | URL the user should visit (for device/OAuth flows) |
code | string | Code to display to the user (for device flows) |
message | string | Human-readable status message |
Command execution
When oc runs a plugin command, it:
- Resolves credentials from the vault or local storage
- Injects credentials as environment variables into the plugin’s process
- Executes the plugin binary as a subprocess with the remaining arguments
- Passes stdin/stdout/stderr directly between the caller and the plugin
Environment variable injection
Credentials are passed as environment variables with the naming convention OC_{PLUGINNAME}_{FIELD}:
| Variable | Source |
|---|
OC_GOOGLE_ACCESS_TOKEN | credentials.access_token |
OC_GOOGLE_REFRESH_TOKEN | credentials.refresh_token |
OC_GOOGLE_TOKEN_TYPE | credentials.token_type |
OC_GOOGLE_EXPIRES_AT | credentials.expires_at |
The plugin name is uppercased. All four fields are set if available.
Execution model
oc google calendar list-events --limit 5
│
├── Finds: ~/.onecli/plugins/oc-google
├── Resolves credentials for "google"
├── Sets env: OC_GOOGLE_ACCESS_TOKEN=..., etc.
├── Executes: oc-google calendar list-events --limit 5
│
└── Plugin writes JSON to stdout, oc passes it through
The plugin inherits the caller’s stdin, stdout, and stderr. oc does not modify the plugin’s output; it passes through directly.
Two subcommands are special and run without credentials:
manifest returns the plugin’s manifest JSON
auth runs the plugin’s authentication flow
All other subcommands go through credential resolution first.
Plugin releases follow the goreleaser naming convention:
oc-{name}_{version}_{os}_{arch}.tar.gz
Example: oc-google_1.0.1_darwin_arm64.tar.gz
Each release must include a checksums.txt file with SHA256 hashes:
a1b2c3d4... oc-google_1.0.1_darwin_arm64.tar.gz
e5f6g7h8... oc-google_1.0.1_linux_amd64.tar.gz