Provider
April 26, 2026 ยท View on GitHub
About
The provider directory contains external provider implementations used by lssh.
Providers are grouped by capability or implementation style:
inventory: generateserverentries from cloud or API inventoriesmixed: multi-capability providers that combine inventory with connector behaviorconnector: define or mediate how a resolvedservercan actually be connectedsecret: resolve*_refvalues just before connect
Shared provider-side helper libraries live under ../providerutil/.
Those packages are reusable support code for provider implementations and are intentionally kept outside the capability-oriented provider/* layout.
Each provider is a standalone executable that communicates with lssh over JSON via stdin/stdout.
A single provider implementation may support one capability or multiple capabilities.
For example, one executable may expose only inventory, while another may expose both inventory and connector.
Current maturity in v0.10.0 is intentionally mixed:
- provider-backed inventory and secret resolution are usable as
beta - connector-backed access beyond native SSH is still
experimental
Design Goals
The provider protocol should be:
- extensible
- new methods and optional fields can be added without breaking older plugins
- integrated
inventory,connector, andsecretuse one common JSON envelope
- capability-oriented
- each plugin can declare what it supports at runtime
- debuggable
- errors should be machine-readable and helpful to users
- backward-compatible
- current
inventory.listandsecret.getplugins should be migratable with small changes
- current
Two Capability Layers
The word capabilities is used in two different layers and they should be kept separate.
1. Plugin Capabilities
These describe which provider categories a plugin implements.
Examples:
inventoryconnectorsecret
These are returned by plugin.describe.
2. Connector Operation Capabilities
These describe what a resolved target can actually do through a connector.
Examples:
shellexecexec_ptyuploaddownloadport_forward_localport_forward_remotemount
These are returned by connector.describe.
This separation is important because connector alone does not tell the caller whether a target supports interactive shell, command execution, or file transfer.
Transport-Oriented Connector Design
Some connectors are best treated as transport providers rather than as full end-user feature providers.
The clearest case is an OpenSSH-based connector.
In that model:
- OpenSSH is responsible for the base connection
- authentication
- bastion / jump host behavior
- ProxyJump / ProxyCommand compatibility
- ControlMaster / session reuse
- Go-side code is responsible for higher-level behavior
- file transfer
- sync logic
- mount-facing file operations
- command integration with
lscp,lsftp,lssync, andlsshfs
This keeps the connector thin while still allowing the lssh family to present a consistent feature set.
Recommended Transport Capabilities
For transport-oriented connectors, the connector layer may expose finer-grained capabilities internally.
Examples:
shell_transportexec_transportsftp_transportport_forward_transport
These are not necessarily user-facing command capabilities. Instead, they are building blocks used by higher-level commands.
Example interpretation:
shell_transport- the connector can open an interactive shell transport
exec_transport- the connector can execute a command transport
sftp_transport- the connector can open an SFTP subsystem stream
port_forward_transport- the connector can establish forwarding-compatible transport
This model is especially useful when:
- the connector uses OpenSSH for base connectivity
lscp/lsftp/lssyncshould use Go-side SFTP logic instead of shelling out toscporsftplsshfsshould use Go-side file operations rather than delegating to ansshfsexecutable
Command Capability Requirements
Each cmd/* command should decide support based on connector operation capabilities, not only on the presence of the connector provider category.
Recommended mapping:
| Command | Required operation capabilities | Notes |
|---|---|---|
lssh | shell | interactive login/session |
lssh command... | exec | non-interactive command execution |
lsshell | exec | parallel shell UI sends commands, but does not require connector-backed interactive shell |
lsmux | shell or exec | pane shells need shell; command panes need exec |
lssh -P | shell or exec | same runtime model as lsmux |
lscp | upload, download | exact direction depends on source/target |
lsftp | upload, download | interactive file transfer |
lssync | upload, download | bi-directional sync planning may require both |
lsshfs | mount | filesystem-like mount capability |
lspipe | exec | remote command execution with local piping |
Notes:
lsshellis intentionally different fromlssh.lsshneeds connector-backed interactive shell supportlsshellcan still work with connectors that support only remote command execution
lsmuxandlssh -Pshould choose capability by pane mode.- shell panes use
shell - command panes use
exec
- shell panes use
Unified JSON Protocol
Transport
lsshsends exactly one JSON request to provider stdin- the provider writes exactly one JSON response to stdout
- human-oriented logs should go to stderr
- the provider process exit code should still indicate success or failure
- but stdout should contain a JSON response even on provider-reported errors when possible
Common Request Envelope
{
"version": "v1",
"id": "optional-request-id",
"method": "inventory.list",
"params": {}
}
Fields:
version- protocol version string
id- optional request id for tracing and future multiplexing
method- provider method name
params- method-specific object
Common Response Envelope
{
"version": "v1",
"id": "optional-request-id",
"result": {},
"error": null,
"warnings": []
}
Fields:
version- protocol version string
id- optional echo of request id
result- method-specific result object
error- machine-readable error object
warnings- optional non-fatal warnings
Exactly one of result or error should be set.
Common Error Object
{
"code": "auth_failed",
"message": "token is invalid",
"details": {
"provider": "proxmox"
},
"retryable": false
}
Recommended fields:
code- stable machine-readable error code
message- human-readable summary
details- optional method-specific structured details
retryable- optional hint for retry behavior
Common Warning Object
{
"code": "partial_data",
"message": "guest ostype could not be fetched for qemu/10082"
}
Warnings are optional and should be used for partial success cases where returning error would be too strong.
Common Methods
plugin.describe
This method is the recommended runtime entry point for capability discovery.
Request:
{
"version": "v1",
"method": "plugin.describe",
"params": {}
}
Result:
{
"name": "provider-inventory-proxmox",
"capabilities": ["inventory"],
"methods": ["plugin.describe", "health.check", "inventory.list"],
"protocol_version": "v1"
}
Recommended result fields:
namecapabilities- one or more of
inventory,connector,secret
- one or more of
methods- supported method names
protocol_versionplugin_version- optional plugin build/version string
Capability Source Of Truth
Plugin capabilities should be owned by the plugin source itself.
The recommended model is:
- the plugin executable declares its supported provider categories via
plugin.describe - user config may narrow usage of those categories
- user config must not be treated as authoritative for unsupported categories
In other words:
- plugin source is the source of truth for supported provider categories
- config is allowed to restrict usage
- config should not be allowed to invent unsupported categories
Recommended future core behavior:
- call
plugin.describe - compare configured plugin capabilities with runtime-declared plugin capabilities
- reject or warn if config asks for unsupported categories
health.check
This method is recommended for preflight checks and diagnostics.
Request:
{
"version": "v1",
"method": "health.check",
"params": {
"provider": "proxmox",
"config": {}
}
}
Result:
{
"ok": true,
"message": "configuration looks valid"
}
Recommended result fields:
okmessagechecks- optional list of individual check results
Capability Boundaries
Inventory
- discovers candidate targets
- returns stable names, config fragments, and metadata
- may be consumed later by
connector
Connector
- describes how a resolved target can actually be used
- may depend on metadata produced by
inventory - must not silently reimplement inventory discovery as an undocumented side effect
- may expose operation-level capabilities such as
shell,exec, andupload
Secret
- resolves secret references close to execution time
- should not discover targets or define transport behavior
Compatibility Notes
The current repository already has a minimal shared provider protocol in code:
- request envelope with
version,method,params - response envelope with
version,result,error - implemented methods:
inventory.listsecret.getplugin.describehealth.checkconnector.describeconnector.prepare- selected runtime methods such as
connector.shell,connector.exec, andconnector.dial
However, the current implementation does not yet expose the full recommended protocol above.
Missing or partial pieces today:
- core-side use of
plugin.describeandhealth.checkis still incomplete and continues to evolve warningsexist in the protocol shape but are not yet produced consistently across all providers
Current Plugin Fit And Migration Plan
Inventory Plugins
Current plugins:
provider-mixed-aws-ec2provider-mixed-azure-computeprovider-mixed-gcp-computeprovider-inventory-proxmox
Current connector-oriented plugins or families:
provider-connector-telnetprovider-connector-winrmprovider-connector-opensshprovider-mixed-aws-ec2- exposes both
inventoryandconnector - covers AWS EC2 inventory plus AWS SSM / EC2 Instance Connect Endpoint connector behavior
- exposes both
Current fit:
- already aligned with the common JSON envelope
- already aligned with
inventory.list - already return
servers[].name,servers[].config,servers[].meta - partially aligned with the future design because metadata is already exposed
Gaps:
- no structured warning return
- warnings currently go to stderr in the Proxmox plugin
- no explicit result pagination or cursor support
Recommended migration:
- Add
plugin.describeto each inventory plugin. - Add
health.checkwith cheap auth/config validation where possible. - Keep
inventory.listas-is for backward compatibility. - Add optional
warningssupport for partial-success cases. - Add optional pagination only if a provider needs it later.
Secret Plugins
Current plugins:
provider-secret-onepasswordprovider-secret-bitwardenprovider-secret-os-keychainprovider-secret-custom-script
Current fit:
- already aligned with the common JSON envelope
- already aligned with
secret.get - already accept provider config plus a reference string
Gaps:
SecretGetResult.typeis mostly unused- provider-specific error codes are now partially structured, but not yet normalized across all backends
Recommended migration:
- Add
plugin.describeto each secret plugin. - Add
health.checkwhere backend login/config can be validated safely. - Start populating
error.codefor stable failure classes. - Populate
result.typewhen the backend can identify a value type.
Special note:
provider-secret-os-keychain- currently shells out to the macOS
securitycommand - outwardly it still follows the provider JSON contract
- if stricter backend abstraction is needed later, the internal implementation can be revisited without changing the outer protocol
- currently shells out to the macOS
provider-secret-custom-script- already follows the provider JSON contract as an
lsshplugin - internally it delegates to an external command through env vars and stdout
- this is acceptable as an explicit escape hatch, but it should remain documented as a special-case backend
- already follows the provider JSON contract as an
Connector Plugins
Current fit:
- connector plugins exist today:
provider-connector-opensshprovider-connector-telnetprovider-connector-winrmprovider-mixed-aws-ec2inventory: AWS EC2 inventoryconnector:aws-ssm,aws-eice
Recommended migration:
- Keep expanding
plugin.describeandconnector.describeas the compatibility boundary. - Continue tightening command-side gating based on connector capabilities.
- Add operation-specific preparation/runtime methods conservatively as real connector backends mature.
Recommended Next Protocol Steps
To evolve the current implementation without breaking existing users:
- Keep
inventory.listandsecret.getunchanged. - Add
plugin.describeto all plugins. - Implement
health.checkin core and providers. - Extend the response envelope with optional
warnings,details, andid. - Design
connectormethods after the runtime capability discovery path is in place.