CLI Factory builds factory: a single static binary for AI agents to discover and invoke curated SaaS/tool commands.
Most CLIs are human-first. factory is agent-first: semantic search, progressive discovery, structured schemas, terse status output, full JSON invocation logs, and provider commands designed as useful workflows rather than raw API CRUD.
Agents need tool access that is compact, predictable, and safe to reason about in limited context windows. CLI Factory provides a repeatable way to add SaaS providers with high-level commands like:
factory google send-email --to user@example.com --subject "Hello" --body "..."The CLI helps agents find the right capability, inspect only the detail they need, invoke it once with explicit params, and keep full output in local logs instead of flooding the conversation.
- Single static Go binary for macOS, Linux, and Windows
- Agent-first semantic search across providers and tools
- Progressive discovery with
factory discover shortandfactory discover long - Default output is only
SUCCESSorFAILUREplus a full JSON log path --debugfor full stdout/stderr JSON when needed- Provider-level optional auth/connection params such as
--bearer-token,--api-key, and--base-url - No credential storage or profiles
- Compact embedded binary embedding catalogue
- Provider e2e test harness with SOPS-encrypted
test_secrets.enc.yaml - Generated provider docs into the shared
trytilde/docsMintlify submodule - Add/update provider skills for contributors
Latest release:
curl -sSfL https://raw.githubusercontent.com/trytilde/cli-factory/main/install.sh | bashThis installs factory to ~/.factory/bin/factory.
Install a specific release:
curl -sSfL https://raw.githubusercontent.com/trytilde/cli-factory/main/install.sh | bash -s -- --version v0.1.0Add it to your shell path if needed:
export PATH="$HOME/.factory/bin:$PATH"Search first:
factory search "send an email"Then progressively discover only what you need:
factory discover short google
factory discover short google send-email
factory discover long google send-emailInvoke directly:
factory google send-email --bearer-token "$TOKEN" --to user@example.com --subject "Hello" --body "Hi"By default, commands print:
SUCCESS
full logs at /absolute/path/to/log.json
Use --debug when you want the full JSON result in the terminal.
Clone with the docs submodule:
git clone --recurse-submodules https://github.com/trytilde/cli-factory
cd cli-factoryRun the core checks:
make generate-metadata
go test ./...
make generate-docs
make generate-catalog
make buildCross-compile static binaries:
make build-allCI runs unit tests, provider e2e tests, docs/catalogue generation, and static builds. Releases publish Go binaries to GitHub Releases.
Use the repo skills:
skills/add-provider/SKILL.mdfor a new providerskills/update-provider/SKILL.mdfor existing provider changesskills/use-factory-cli/SKILL.mdfor production agent usage
Provider layout:
providers/<provider>/
├── cli-metadata.yaml
├── metadata_gen.go
├── generator-metadata.yaml
├── generator-prompt.md
├── test_secrets.example.yaml
├── test_secrets.enc.yaml
├── mod.go
└── <tool>/
├── cli-metadata.yaml
├── input-schema.yaml
├── output-schema.yaml
├── metadata_gen.go
├── mod.go
└── e2e_test.go
Provider rules:
- Build high-level agent workflows, not low-level CRUD dumps.
- Treat
cli-metadata.yaml,input-schema.yaml, andoutput-schema.yamlas the source of truth for provider/tool metadata and schemas. - Run
make generate-metadataafter metadata/schema edits. It emitsmetadata_gen.gofiles with static strings and schema maps compiled into thefactorybinary. - Do not hand-edit
metadata_gen.go, or duplicate descriptions, categories, aliases, provider params, or JSON schemas in handwritten Go files. - For OAuth client flows, the CLI should usually accept an access token or bearer token provider parameter. E2E tests may use durable test secrets such as
client_id,client_secret, andrefresh_tokento mint a fresh access token before invoking the CLI. - Add/update e2e tests for every provider command.
- Use
override_test_secrets.yamlfor local throwaway credentials; never commit it. - Commit only encrypted shared provider secrets as
test_secrets.enc.yaml. - Run
make generate-docsandmake generate-catalogafter metadata/schema changes.
harness-shop is included as a submodule for structured provider-building workflows. The Factory CLI provider harness is separate from the generic experiment harness, but reuses shared UI pieces such as chat, runs, diffs, and secrets.
Factory provider harness runs should follow these phases:
- Discovery: confirm provider goals, tool goals, auth model, docs, examples, and reference links.
- Plan: define provider behavior, each tool, and input/output schemas before implementation.
- Testing: define real Go e2e tests, required credentials, cleanup behavior, target account/workspace, and rate/spend limits.
- Implementation: clone CLI Factory into a run-specific checkout, create a
provider-harness/<id>branch, write provider code and Go e2e tests, then iterate until targeted e2e tests and required checks pass.
The harness secrets form writes providers/<provider>/override_test_secrets.yaml for local runs. Shared secrets should be promoted to test_secrets.yaml, encrypted with SOPS, and committed as test_secrets.enc.yaml.
CLI Factory is intended to become a shared catalogue of high-quality agent tools. If you want agents to use your SaaS product well, contribute a provider with a small set of thoughtful commands and real e2e tests.
Star the project, open issues or PRs, and join the Tilde community on Discord.
Repository decisions and change records live in docs/. Shared
Mintlify pages are generated into the independent public-docs/ submodule.
DOCS_REPO_DIR can select a different checkout of the shared documentation.
When updating an existing checkout that still uses the old docs/ submodule,
commit or back up any submodule changes first, then run git submodule deinit docs
before switching to this revision. Do not force deinitialization past local
changes. After updating the branch, run git submodule sync and
git submodule update --init --recursive public-docs; make generate-docs
initializes the new location as needed. Fresh clones only need the latter update.
If an existing checkout was updated before deinitialization, the old submodule may
leave a stale docs/.git and shared-documentation files behind. Preserve that
checkout's changes before cleaning up the old files. Do not remove the entire
docs/ directory: it now contains tracked repository records.