An embeddable Go core for running authenticated CLI/API tools with injected credentials.
AnyCLI is a library, not a standalone CLI. A host program (e.g. Helio's heliox) embeds it in-process, supplies a CredentialResolver for its own credential sources, and calls Execute. AnyCLI loads the matching embedded tool definition, resolves and injects credentials (env var / CLI flag / ephemeral config file), runs before/after middleware, and execs the underlying binary or built-in service.
The supported tools and their definitions live inside AnyCLI (embedded JSON). The embedder never supplies tool definitions — only a credential resolver and an optional cache.
LLMs are trained on billions of CLI examples. They already know git, gh, curl, jq, and thousands of other tools. MCP forces agents to learn new schemas from scratch, consuming far more tokens per operation with lower reliability. CLI is the natural interface between agents and the world. Read the full rationale.
AnyCLI's job is the missing piece: let an agent run those tools authenticated, without the host shipping long-lived secrets to disk. The host owns where credentials come from; AnyCLI owns how they are injected and how long they live.
import "github.com/heliohq/anycli"
// 1. Construct an engine. Cache is optional; nil uses an in-memory default.
engine, err := anycli.New(anycli.Config{
Cache: myCache, // optional: implements anycli.Cache
})
if err != nil {
return err
}
// 2. Run a tool. The resolver supplies credentials for this tool; AnyCLI
// loads the embedded definition, injects, and execs.
exitCode, err := engine.Execute(ctx, anycli.Tool("gh"), []string{"pr", "list"}, resolver)type Config struct {
// Cache is the credential cache the engine uses to avoid re-resolving on
// every call. Optional — nil installs an in-memory cache. The on-disk
// cache that the old standalone CLI used is gone; the host decides the
// storage (per-process, per-assistant, shared, …) by supplying a Cache.
Cache Cache
}The resolver is the only thing that crosses the boundary into AnyCLI. It returns in-memory data; AnyCLI owns injection, caching, and lifecycle. Where the data comes from (stored OAuth, an on-demand minted token, anything) is entirely the host's business — the resolver never learns how the data is injected.
type CredentialResolver interface {
// Resolve returns the credential fields for one tool/account pair, plus
// when they go stale. An empty account selects the host's default.
Resolve(ctx context.Context, tool Tool, account string) (*Credential, error)
}
type Credential struct {
Data map[string]string // credential fields; bindings index into it by field name
CacheUntil time.Time // when this credential goes stale (drives the cache)
}type Cache interface {
Get(key string) (*CacheEntry, bool)
Set(key string, entry *CacheEntry)
MarkStale(key string)
}CacheEntry stores only the extracted credential fields plus CacheUntil/Stale. The engine derives a collision-free key from (tool, account). Supply your own cache or pass nil to use the built-in in-memory implementation.
ListTools returns credential-safe manifests for every embedded tool in deterministic name order. Discovery also validates that service definitions have registered implementations and CLI definitions declare a binary.
tools, err := anycli.ListTools()Tool is type Tool string; pass a raw anycli.Tool("…") whose name matches
an embedded definition. The built-in service tools are slack, notion,
google, discord, linkedin, x, and figma; github wraps the gh
binary. An unknown tool is an error from Execute, not a compile error.
The Figma service uses personal access tokens and exposes every PAT-compatible
operation in the pinned official OpenAPI catalog: 47 operations across files,
projects, comments/reactions, libraries, variables, Dev Mode resources,
webhooks, library analytics, payments, and oEmbed. Every operation has a named
command and is also callable by operation ID through figma api call.
Agent-oriented commands accept Figma URLs directly: figma context metadata,
context design, context figjam, context screenshot, and context variables. figma assets download and download-fills materialize signed
render/image-fill URLs without forwarding the PAT to the asset host. Run
figma capabilities for the machine-readable boundary: PAT REST has no general
native-canvas create/edit/delete API, so hosted-MCP operations such as
use_figma, new-file/design generation, uploads, shaders, and native Code
Connect mappings require Figma's hosted MCP or a Figma plugin bridge.
The x service supports OAuth 2.0 user-context identity and user lookup,
recent post search, timelines, post/reply/thread/repost management, simple
JPEG/PNG/WebP uploads for posts or DMs, alt text, and legacy Direct Messages.
Every list/search command retrieves one explicit page; callers pass the
returned token with --next-token. XChat and chunked video/GIF uploads are not
part of this surface.
- Why AnyCLI — CLI vs MCP for agents
- Credential Lifecycle — how credentials are resolved, cached, and injected at runtime
- Tool Definition Schema — field reference for the embedded tool definitions
- Design 001: Vault Credential Integration — superseded historical vault/local design
- Design 002: Embeddable Core + Credential Resolver — the library architecture
- Design 003: Multi-account + Helio toolset — account-aware execution and built-in services
- Design 005: Tool Manifest Discovery — deterministic discovery and definition/executor validation
- Design 006: Figma REST Service — PAT-authenticated Figma command surface
Apache License 2.0