Otter simplifies development environment setup through a layer concept that pulls other templates containing files into the project it's run inside of.
- Layer-based configuration: Define layers from git repositories that are pulled into your project
- Dockerfile-like syntax: Familiar syntax for defining layers and targets
- Intelligent file handling: Support for
.otterignoreto exclude files from layers - Caching: Git repositories are cached locally for faster subsequent builds
- Flexible targeting: Specify custom target directories for each layer
Download the latest release for your platform from the GitHub Releases page.
go install github.com/geoffjay/otter@latest- Clone this repository:
git clone <this-repo-url>
cd otter- Build the binary:
make build
# or manually: go mod tidy && go build -o bin/otter- (Optional) Install globally:
make install# Run directly
docker run --rm -it ghcr.io/geoffjay/otter:latest --help
# Use in a project directory
docker run --rm -v $(pwd):/workspace -w /workspace ghcr.io/geoffjay/otter:latest init- Initialize a project:
otter initThis creates:
.otter/cache/directory for caching git repositories.otterignorefile with sensible defaults- Sample
Otterfilewith example layer definitions
- Define layers in your
Otterfile:
# Pull a Go CLI template
LAYER git@github.com:otter-layers/go-cobra-cli.git
# Pull Cursor rules to a specific directory
LAYER git@github.com:otter-layers/cursor-go-rules.git TARGET .cursor/rules
# Pull configuration files
LAYER https://github.com/user/dotfiles.git TARGET config- Build your environment:
otter buildInitialize the current directory for otter by creating:
.otter/cache/directory for layer caching.otterignorefile with default ignore patterns- Sample
Otterfilewith example usage
Read the Otterfile (or Envfile) and apply all defined layers to the current project.
Options:
-f, --file <path>: Specify a custom Otterfile/Envfile path
The Otterfile uses a Dockerfile-like syntax:
LAYER <git-repository-url> [TARGET <target-directory>]Examples:
# Clone to project root
LAYER git@github.com:user/template.git
# Clone to specific directory
LAYER https://github.com/user/configs.git TARGET .config
# SSH repository with custom target
LAYER git@github.com:company/internal-template.git TARGET internalThe .otterignore file works similarly to .gitignore and specifies files and patterns to exclude when merging layers.
Example .otterignore:
# Version control
.git/
.svn/
# Otter internals
.otter/
# Dependencies
node_modules/
vendor/
# Temporary files
*.log
*.tmp
.DS_Store
# Specific files
secrets.yaml
local-config.json
- Initialization:
otter initsets up the.otter/cache/directory structure - Layer Processing:
otter buildreads yourOtterfileand processes eachLAYERcommand:- Clones git repositories to
.otter/cache/(or updates if already cached) - Applies
.otterignorepatterns to filter files - Copies allowed files to the specified target directory
- Clones git repositories to
- File Merging: Files from layers are merged into your project, with existing files being overwritten
your-project/
├── .otter/
│ └── cache/ # Cached git repositories
├── .otterignore # File ignore patterns
├── Otterfile # Layer definitions
└── [your project files]
When creating layer repositories:
- Keep layers focused: Each layer should serve a specific purpose
- Use descriptive README: Document what the layer provides
- Avoid large files: Layers should contain configuration and template files, not large assets
- Consider ignore patterns: Structure your layer so common ignore patterns work well
- Version your layers: Use git tags for stable layer versions
# Otterfile
LAYER git@github.com:otter-layers/go-mod.git
LAYER git@github.com:otter-layers/go-cobra-cli.git
LAYER git@github.com:otter-layers/go-gitignore.git# Backend setup
LAYER git@github.com:otter-layers/go-api.git TARGET backend
LAYER git@github.com:otter-layers/docker-compose.git
# Frontend setup
LAYER git@github.com:otter-layers/react-typescript.git TARGET frontend
LAYER git@github.com:otter-layers/tailwind-config.git TARGET frontend
# Development tools
LAYER git@github.com:otter-layers/vscode-settings.git TARGET .vscode
LAYER git@github.com:otter-layers/cursor-rules.git TARGET .cursor- Go 1.21 or later
- Docker (optional, for containerized builds)
- Make (for using the Makefile targets)
# Install dependencies
make deps
# Run linting
make lint
# Run tests
make test
# Build binary
make build
# Build for all platforms
make build-all
# Run example workflow
make run-example# Build Docker image
make docker-build
# Run with Docker
make docker-run
# Get shell access in container
make docker-shellThis project uses GitHub Actions for continuous integration and deployment:
- Lint workflow (
.github/workflows/lint.yml): Runs on every push and PR- Go formatting checks
- go vet
- golangci-lint
- Unit tests with coverage
- Build workflow (
.github/workflows/build.yml): Builds for multiple platforms- Linux (amd64, arm64)
- macOS (amd64, arm64)
- Windows (amd64)
- Creates GitHub releases on tags
- Builds and pushes Docker images
- Create and push a git tag:
git tag v1.0.0 && git push origin v1.0.0 - GitHub Actions will automatically:
- Build binaries for all platforms
- Create a GitHub release with binaries
- Build and push Docker image to GitHub Container Registry
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run tests:
make test - Run linting:
make lint - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
The CI/CD pipeline will automatically run tests and linting on your PR.