This file provides guidance to coding agents when working with code in this repository.
Cog is a tool that packages machine learning models in production-ready containers.
It consists of:
- Cog CLI (
cmd/cog/) - Command-line interface for building, running, and deploying models, written in Go - Python SDK (
python/cog/) - Python library for defining model predictors and training in Python - Coglet (
crates/) - Rust-based prediction server that runs inside containers, with Python bindings via PyO3
Documentation for the CLI and SDK is available by reading ./docs/llms.txt.
Development tasks are managed with mise. Run mise tasks to see all available tasks.
| Task | Description |
|---|---|
mise run fmt |
Check formatting (all languages) |
mise run fmt:fix |
Fix formatting (all languages) |
mise run lint |
Run linters (all languages) |
mise run lint:fix |
Fix lint issues (all languages) |
mise run test:go |
Run Go tests |
mise run test:rust |
Run Rust tests |
mise run test:python |
Run Python tests |
mise run test:integration |
Run integration tests |
mise run build:cog |
Build cog CLI binary |
mise run build:coglet |
Build coglet wheel (dev) |
mise run build:sdk |
Build SDK wheel |
mise run install |
Build and symlink cog to /usr/local/bin |
mise run docs:llm |
IMPORTANT: Regenerate docs/llms.txt after editing docs |
mise run docs:cli |
Generate CLI reference docs from Go source code |
mise run version |
Show current version from VERSION.txt |
mise run version:bump <ver> |
Bump version everywhere and commit |
Tasks follow a consistent naming pattern:
- Language-based tasks for fmt/lint/test/typecheck:
task:go,task:rust,task:python - Component-based tasks for build:
build:cog,build:coglet,build:sdk - Check vs Fix:
fmtandlintdefault to check mode (non-destructive); use:fixsuffix to auto-fix
Format:
mise run fmt/mise run fmt:check- Check all (alias)mise run fmt:fix- Fix allmise run fmt:go/mise run fmt:rust/mise run fmt:python- Per-language
Lint:
mise run lint/mise run lint:check- Check all (alias)mise run lint:fix- Fix allmise run lint:go/mise run lint:rust/mise run lint:python- Per-languagemise run lint:rust:deny- Check Rust licenses/advisories
Test:
mise run test:go- Go unit testsmise run test:rust- Rust unit testsmise run test:python- Python unit tests (via tox)mise run test:coglet:python- Coglet Python binding testsmise run test:integration- Integration tests
Build:
mise run build:cog- Build cog CLI (development)mise run build:cog:release- Build cog CLI (release)mise run build:coglet- Build coglet wheel (dev install)mise run build:coglet:wheel- Build coglet wheel (native platform)mise run build:coglet:wheel:linux-x64- Build for Linux x86_64mise run build:coglet:wheel:linux-arm64- Build for Linux ARM64mise run build:sdk- Build SDK wheel
Install:
mise run install- Symlink cog CLI to/usr/local/bin(requiresbuild:cogfirst)PREFIX=/custom/path mise run install- Symlink to custom location
Version:
mise run version- Show current version from VERSION.txtmise run version:bump <ver>- Bump version everywhere and commitmise run version:check- Verify VERSION.txt matches Cargo.toml
Other:
mise run typecheck- Type check all languagesmise run generate- Run code generationmise run clean- Clean all build artifactsmise run docs- Build documentationmise run docs:serve- Serve docs locally
- Imports: Organize in three groups separated by blank lines: (1) Standard library, (2) Third-party packages, (3) Internal packages (
github.com/replicate/cog/pkg/...) - Formatting: Use
mise run fmt:go:fix - Linting: Must pass golangci-lint with: errcheck, gocritic, gosec, govet, ineffassign, misspell, revive, staticcheck, unused
- Error Handling: Return errors as values; use
pkg/errors.CodedErrorfor user-facing errors with error codes - Naming: CamelCase for exported, camelCase for unexported
- Testing: Use
testify/requirefor assertions; prefer table-driven tests
Example import block:
import (
"fmt"
"github.com/spf13/cobra"
"github.com/replicate/cog/pkg/config"
)- Imports: Automatically organized by ruff/isort (stdlib → third-party → local)
- Formatting: Use
mise run fmt:python:fix - Linting: Must pass ruff checks: E (pycodestyle), F (Pyflakes), I (isort), W (warnings), S (bandit), B (bugbear), ANN (annotations)
- Type Annotations: Required on all function signatures; use
typing_extensionsfor compatibility; avoidAnywhere possible - Error Handling: Raise exceptions with descriptive messages; avoid generic exception catching
- Naming: snake_case for functions/variables/modules, PascalCase for classes
- Testing: Use pytest with fixtures; async tests with pytest-asyncio
- Compatibility: Must support Python 3.10-3.13
- Formatting: Use
mise run fmt:rust:fix - Linting: Must pass
mise run lint:rust(clippy) - Dependencies: Audited with
cargo-deny(seecrates/deny.toml); runmise run lint:rust:deny - Error Handling: Use
thiserrorfor typed errors,anyhowfor application errors - Naming: snake_case for functions/variables, PascalCase for types
- Testing: Use
cargo test; snapshot tests useinsta - Async: tokio runtime; async/await patterns
The CLI code is in the cmd/cog/ and pkg/ directories. Support tooling is in the tools/ directory.
The main commands for working on the CLI are:
go run ./cmd/cog- Runs the Cog CLI directly from source (requires wheel to be built first)mise run build:cog- Builds the Cog CLI binarymise run install- Symlinks the built binary to/usr/local/bin(runbuild:cogfirst), or to a custom path withPREFIX=/custom/path mise run installmise run test:go- Runs all Go unit testsgo test ./pkg/...- Runs tests directly withgo test
The Python SDK is developed in the python/cog/ directory. It uses uv for virtual environments and tox for testing across multiple Python versions.
The main commands for working on the SDK are:
mise run build:sdk- Builds the Python wheelmise run test:python- Runs Python tests across all supported versions
Coglet is the Rust-based prediction server that runs inside Cog containers, handling HTTP requests, worker process management, and prediction execution.
The code is in the crates/ directory:
crates/coglet/- Core Rust library (HTTP server, worker orchestration, IPC)crates/coglet-python/- PyO3 bindings for Python predictor integration (requires Python 3.10+)
For detailed architecture documentation, see crates/README.md and crates/coglet/README.md.
The main commands for working on Coglet are:
mise run build:coglet- Build and install coglet wheel for development (macOS, for local Rust/Python tests)mise run build:coglet:wheel:linux-x64- Build Linux x86_64 wheel (required to test Rust changes in Docker containers viacog predict/cog train)mise run test:rust- Run Rust unit testsmise run lint:rust- Run clippy lintermise run fmt:rust:fix- Format code
Go code is tested using the built-in go test framework:
go test ./pkg/... -run <name>- Runs specific Go tests by namemise run test:go- Runs all Go unit tests
Python code is tested using tox, which allows testing across multiple Python versions and configurations:
mise run test:python- Runs all Python unit testsuv run tox -e py312-tests -- python/tests/server/test_http.py::test_openapi_specification_with_yield- Runs a specific Python test
The integration test suite in integration-tests/ tests the end-to-end functionality of the Cog CLI and Python SDK using Go's testscript framework:
mise run test:integration- Runs the integration testsmise run test:integration string_predictor- Runs a specific integration test
The integration tests require a built Cog binary, which defaults to the first cog in PATH. Run tests against a specific binary with the COG_BINARY environment variable:
mise run build:cog
COG_BINARY=dist/go/*/cog mise run test:integration- Run
mise installto set up the development environment - Run
mise run build:sdkafter making changes to the./pythondirectory - Run
mise run build:coglet:wheel:linux-x64after making changes to the./cratesdirectory (needed for Docker testing) - Run
mise run build:cogto build the CLI (wheels are picked up fromdist/at Docker build time, not embedded in the binary) - Run
mise run fmt:fixto format code - Run
mise run lintto check code quality - Run
mise run docs:llmto regeneratedocs/llms.txtafter changingREADME.mdor anydocs/*.mdfile - Read the
./docsdirectory and make sure the documentation is up to date
IMPORTANT: Always run mise run lint (or the language-specific variant, e.g. mise run lint:go) before committing to catch linter errors early. CI will reject PRs that fail lint checks.
The CLI follows a command pattern with subcommands. The main components are:
pkg/cli/- Command definitions (build, run, predict, serve, etc.)pkg/docker/- Docker client and container managementpkg/dockerfile/- Dockerfile generation and templatingpkg/config/- cog.yaml parsing and validationpkg/image/- Image building and pushing logic
python/cog/- Core SDKbase_predictor.py- Base class for model predictorstypes.py- Input/output type definitionsserver/- HTTP/queue server implementationcommand/- Runner implementations for predict/train
The prediction server that runs inside Cog containers. Uses a two-process architecture: a parent process (HTTP server + orchestrator) and a worker subprocess (Python predictor execution).
See crates/README.md for detailed architecture documentation.
crates/coglet/- Core Rust library (HTTP server, worker orchestration, IPC bridge)crates/coglet-python/- PyO3 bindings for Python predictor integration
- Local Wheel Resolution: The CLI discovers SDK and coglet wheels from
dist/at Docker build time (not embedded in the binary) - Docker SDK Integration: Uses Docker Go SDK for container operations
- Type Safety: Dataclasses for Python type validation, strongly typed Go interfaces
- Compatibility Matrix: Automated CUDA/PyTorch/TensorFlow compatibility management
For comprehensive architecture documentation, see architecture/.
- Create command file in
pkg/cli/ - Add command to
pkg/cli/root.go - Implement business logic in appropriate
pkg/subdirectory - Add tests
- Edit files in
python/cog/ - Run
mise run build:sdkto rebuild wheel - Test with
mise run test:python - Integration test with
mise run test:integration
- See
tools/compatgen/for compatibility matrix generation - Update framework versions in relevant Dockerfile templates
- Test with various framework combinations
- Documentation is in the
docs/directory, written in Markdown and generated into HTML usingmkdocs. - IMPORTANT: After editing any file in
docs/orREADME.md, you MUST runmise run docs:llmto regeneratedocs/llms.txt. This file is used by coding agents and should be kept in sync with the documentation. - IMPORTANT: CLI reference docs (
docs/cli.md) are auto-generated from Go source code. After modifying CLI commands incmd/orpkg/cli/, runmise run docs:clito regenerate, and ensuremise run docs:cli:checkpasses before committing.
Development tools are managed in two places that must be kept in sync:
mise.toml— Tool versions for local development (uses aqua backend for prebuilt binaries).github/workflows/ci.yaml— Tool installation for CI (uses dedicated GitHub Actions)
CI deliberately avoids aqua downloads from GitHub Releases to prevent transient 502 failures. Instead, it uses:
| Tool | CI installation method | Why |
|---|---|---|
| gotestsum | go install |
Uses Go module proxy, not GitHub Releases |
| cargo-deny | taiki-e/install-action |
Prebuilt with checksum verification |
| cargo-nextest | taiki-e/install-action |
Prebuilt with checksum verification |
| coglet wheel (maturin+zig) | PyO3/maturin-action |
Bundles maturin and zig |
| golangci-lint | golangci/golangci-lint-action |
Built-in caching |
| Rust toolchain | dtolnay/rust-toolchain |
Guaranteed ordering |
Tools disabled in CI are listed in MISE_DISABLE_TOOLS in ci.yaml.
When updating a tool version, update both:
- The version in
mise.toml(for local dev) - The corresponding version pin in
.github/workflows/ci.yaml(for CI)
VERSION.txt- Canonical version (single source of truth)cog.yaml- User-facing model configurationpkg/config/config.go- Go code for parsing and validatingcog.yamlpkg/config/data/config_schema_v1.0.json- JSON schema forcog.yamlpython/cog/base_predictor.py- Predictor interfacecrates/Cargo.toml- Rust workspace configuration (version must match VERSION.txt)crates/README.md- Coglet architecture overviewmise.toml- Task definitions for development workflow
- Unit tests for individual components (Go and Python)
- Integration tests for end-to-end workflows
- Tests use real Docker operations (no mocking Docker API)
- Always run
mise run build:sdkafter making Python changes before testing Go code - Python 3.10-3.13 compatibility is required
All Go tests must use testify for assertions. Do not use raw if checks with t.Fatal/t.Errorf — use require and assert instead.
require— for fatal assertions that should stop the test (setup failures, preconditions):require.NoError(t, err, "failed to create client") require.Equal(t, expected, actual) require.True(t, condition, "server should be ready")
assert— for non-fatal checks where the test should continue (e.g. validating multiple fields in a loop):assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Contains(t, output, "expected substring") assert.NoError(t, err, "prediction %d failed", i)
- Use
requirefor errors in setup/teardown andassertfor the actual test expectations - Prefer specific assertions (
Equal,Contains,NoError,Len,Less) over genericTrue/False— they produce better failure messages - Prefer table-driven tests for testing multiple similar cases