This file follows the agents.md specification. It gives AI coding agents the context they need to work effectively in this repository.
infs is a fast, provider-agnostic CLI for discovering, connecting to, and running AI apps and models from multiple cloud providers through one consistent interface.
- Language: Rust 2021 edition
- Binary name:
infs - Crate name:
infs(seeCargo.toml) - Minimum Rust version: 1.75
# Build (debug)
cargo build
# Build (optimised release binary → target/release/infs)
cargo build --release
# Run all tests
cargo test
# Run a specific test
cargo test <test_name>
# Run tests for a module
cargo test providers::
# Enable debug logging during tests
RUST_LOG=debug cargo testAll tests must pass before submitting any change.
.
├── Cargo.toml # Package manifest (name = "infs", version controlled by Release Please)
├── Cargo.lock
├── release-please-config.json # Release Please: changelog section definitions
├── .release-please-manifest.json # Release Please: current version tracking
├── README.md
├── CONTRIBUTING.md
├── AGENTS.md # ← this file
├── .github/
│ └── workflows/
│ ├── release.yml # Builds binaries for 5 targets on GitHub Release
│ └── release-please.yml # Automates changelogs + version bumps on push to main
└── src/
├── main.rs # Entry point — parses CLI args and dispatches
├── error.rs # InfsError (thiserror)
├── types.rs # AppDescriptor, RunResponse, ProviderDescriptor, AuthMethod, …
├── config/
│ └── mod.rs # Config + credentials load/save; credentials written mode 0600 on Unix
├── auth/
│ └── mod.rs # AuthMethod enum
├── providers/
│ ├── mod.rs # Provider async trait
│ ├── registry.rs # ProviderRegistry::build_registry()
│ ├── openrouter.rs # ✅ Reference implementation (LLM)
│ ├── falai.rs # ✅ Full implementation (image, async queue pattern)
│ ├── replicate.rs # ✅ Full implementation (image, prediction polling)
│ └── wavespeed.rs # ✅ Full implementation (image/video)
├── catalog/
│ └── mod.rs # AppCatalog — aggregates listings across all providers
└── cli/
├── mod.rs # CLI root; Clap Command enum
├── provider.rs # provider list / connect / show / disconnect
├── app.rs # app list / run / show
├── config.rs # config path
├── update.rs # self check / self update
└── doctor.rs # doctor
Every provider implements this async trait:
#[async_trait]
pub trait Provider: Send + Sync {
fn descriptor(&self) -> &ProviderDescriptor;
fn supported_auth_methods(&self) -> Vec<AuthMethod>;
async fn list_apps(&self, config: &ProviderConfig) -> Result<Vec<AppDescriptor>, InfsError>;
async fn run_app(&self, app_id: &str, input: serde_json::Value, config: &ProviderConfig) -> Result<RunResponse, InfsError>;
fn validate_config(&self, config: &ProviderConfig) -> Result<(), InfsError>;
}Contains id, name, description, website, and api_key_help_url. Always use d.api_key_help_url in the CLI — do not construct {website}/keys manually.
The full app ID used on the command line is <provider_id>/<app_id>, e.g. openrouter/anthropic/claude-sonnet-4-5.
AppDescriptor::full_id() returns this prefixed form. Provider::run_app receives only the provider-local part (everything after the first /).
- Config directory: resolved by the
directoriescrate (ProjectDirs). config.toml— non-sensitive settings;credentials.toml— API keys.save_configdeliberately strips credentials before writingconfig.toml.- On Unix,
credentials.tomlis created with mode0o600.
- Create
src/providers/myprovider.rs— implement theProvidertrait. - Register in
src/providers/registry.rsinsidebuild_registry(). - Add unit tests (mock HTTP responses where practical).
- Use
openrouter.rs(LLM) orwavespeed.rs(async poll pattern) as a reference.
Use InfsError variants (src/error.rs) for all errors that propagate to the CLI. anyhow is used internally in functions that never surface to end users.
Use reqwest with the rustls-tls feature (no OpenSSL dependency). The client is constructed per-provider.
This repo follows Conventional Commits:
feat: new user-visible feature → minor version bump
fix: bug fix → patch bump
perf: performance improvement → patch bump
deps: dependency update → patch bump
docs: documentation only → no bump
chore: maintenance (no public API change)→ no bump
feat!: breaking change → major bump
Release Please reads these commit messages to auto-generate CHANGELOG.md and version bumps. See CONTRIBUTING.md for the full release workflow.
| Workflow | Trigger | What it does |
|---|---|---|
ci.yml |
pull request / push to main |
Builds, tests, lints (cargo build, cargo test, cargo clippy, cargo fmt) on Linux, macOS, Windows |
release-please.yml |
push to main |
Opens/updates a Release PR; on merge creates a GitHub Release |
release.yml |
GitHub Release published | Builds infs for 5 targets; uploads binaries as release assets |
Binary targets built on each release:
| Asset name | Target triple |
|---|---|
infs-linux-x86_64 |
x86_64-unknown-linux-musl |
infs-linux-aarch64 |
aarch64-unknown-linux-musl |
infs-macos-x86_64 |
x86_64-apple-darwin |
infs-macos-aarch64 |
aarch64-apple-darwin |
infs-windows-x86_64.exe |
x86_64-pc-windows-msvc |
- Always run
cargo testbefore submitting a PR. - Always use
cargo fmtandcargo clippyto maintain code quality and consistency. - Always keep
README.mdup to date when shipping user-visible features, CLI behavior changes, new workflows, or credential/auth changes that matter to users. - If you are unsure how to do something, use
gh_grepto search code examples from GitHub.
- Do not hardcode API endpoints inside test code; use mocks or feature flags.
- Do not store secrets in
config.toml; they belong incredentials.toml. - Do not bump versions in
Cargo.tomlmanually — Release Please does this automatically. - Do not use
{provider.website}/keysto construct help URLs; usedescriptor.api_key_help_url.