As development teams scale their use of goose across multiple projects, a new challenge emerges: how do you maintain consistent configurations while adapting to each project's unique needs? In my previous post on team environments, we explored shared workflows within a single project. Now, let's tackle the multi-project configuration challenge.
The Multi-Project Configuration Problem
When working with goose across multiple projects, teams often face:
- Configuration drift between projects leading to inconsistent behavior
- Duplicated configuration that becomes painful to maintain
- Context switching overhead when moving between projects
- Onboarding friction as team members learn different configurations for each project
The goal is to establish a scalable configuration strategy that maintains consistency where needed while allowing project-specific customization.
Configuration Hierarchy Strategy
The most effective approach uses a three-tier configuration hierarchy:
1. Global Base Configuration
Create a shared base configuration that defines organization-wide standards:
# ~/.config/goose/profiles.yaml (global) default: provider: openai processor: gpt-4 accelerator: gpt-4 moderator: truncate organization-standards: provider: openai processor: gpt-4 accelerator: gpt-4 moderator: truncate toolkits: - name: developer - name: github requires: GITHUB_TOKEN: github-token This global configuration serves as your baseline, ensuring all projects start with consistent standards.
2. Project-Specific Configuration
Each project maintains its own .goose/profiles.yaml that extends or overrides the base:
# project-a/.goose/profiles.yaml default: provider: openai processor: gpt-4 accelerator: gpt-4 moderator: truncate toolkits: - name: developer - name: github requires: GITHUB_TOKEN: github-token - name: repo_context requires: path: . backend-dev: extends: default toolkits: - name: docker - name: database 3. Personal Overrides
Individual developers can customize further with local overrides:
# project-a/.goose/profiles.local.yaml (gitignored) default: provider: anthropic # Personal preference processor: claude-sonnet-4.5 ## Practical Implementation Strategies ### Strategy 1: Configuration Templates Repository Create a dedicated repository for configuration templates: goose-configs/ ├── README.md ├── templates/ │ ├── base/ │ │ └── profiles.yaml │ ├── web-app/ │ │ └── profiles.yaml │ ├── api-service/ │ │ └── profiles.yaml │ └── data-pipeline/ │ └── profiles.yaml └── scripts/ ├── init-project.sh └── sync-config.sh init-project.sh example:
#!/bin/bash # Initialize goose config for a new project PROJECT_TYPE=$1 TEMPLATE_PATH="templates/${PROJECT_TYPE}/profiles.yaml" if [ ! -f "$TEMPLATE_PATH" ]; then echo "Unknown project type: $PROJECT_TYPE" echo "Available types: base, web-app, api-service, data-pipeline" exit 1 fi mkdir -p .goose cp "$TEMPLATE_PATH" .goose/profiles.yaml echo "✓ goose configuration initialized for $PROJECT_TYPE" echo "Next steps:" echo "1. Review .goose/profiles.yaml" echo "2. Add .goose/profiles.local.yaml to .gitignore" echo "3. Commit .goose/profiles.yaml to version control" Strategy 2: Configuration as Code with Validation
Implement configuration validation to catch issues early:
# .goose/profiles.yaml with schema validation default: provider: openai processor: gpt-4 accelerator: gpt-4 moderator: truncate # Validation metadata _metadata: schema_version: "1.0" required_env_vars: - OPENAI_API_KEY - GITHUB_TOKEN team: "platform-team" last_updated: "2025-10-30" Create a validation script:
# scripts/validate-goose-config.py import yaml import os import sys def validate_config(config_path): """Validate Goose configuration file""" errors = [] with open(config_path) as f: config = yaml.safe_load(f) # Check required environment variables metadata = config.get('default', {}).get('_metadata', {}) required_vars = metadata.get('required_env_vars', []) for var in required_vars: if not os.getenv(var): errors.append(f"Missing required environment variable: {var}") # Validate profile structure for profile_name, profile in config.items(): if profile_name.startswith('_'): continue if 'provider' not in profile: errors.append(f"Profile '{profile_name}' missing required 'provider' field") return errors if __name__ == '__main__': errors = validate_config('.goose/profiles.yaml') if errors: print("❌ Configuration validation failed:") for error in errors: print(f" - {error}") sys.exit(1) else: print("✓ Configuration valid") Strategy 3: Environment-Specific Profiles
Structure profiles to handle different environments:
# .goose/profiles.yaml default: provider: openai processor: gpt-4 accelerator: gpt-4 moderator: truncate toolkits: - name: developer development: extends: default toolkits: - name: developer - name: github - name: docker requires: DOCKER_HOST: "unix:///var/run/docker.sock" staging: extends: default toolkits: - name: developer - name: github - name: kubernetes requires: KUBE_CONFIG: staging-config production: extends: default toolkits: - name: developer - name: github - name: kubernetes requires: KUBE_CONFIG: production-config # More restrictive settings for production moderator: conservative Syncing Configurations Across Projects
Automated Sync Script
#!/bin/bash # scripts/sync-goose-configs.sh # Sync base configuration across all projects CONFIG_REPO="git@github.com:your-org/goose-configs.git" TEMP_DIR=$(mktemp -d) # Clone config repository git clone "$CONFIG_REPO" "$TEMP_DIR" # Find all projects with goose configs find ~/projects -name ".goose" -type d | while read goose_dir; do project_dir=$(dirname "$goose_dir") project_name=$(basename "$project_dir") echo "Syncing config for $project_name..." # Backup existing config cp "$goose_dir/profiles.yaml" "$goose_dir/profiles.yaml.bak" # Merge base config with project-specific settings python3 "$TEMP_DIR/scripts/merge-configs.py" \ "$TEMP_DIR/templates/base/profiles.yaml" \ "$goose_dir/profiles.yaml" \ > "$goose_dir/profiles.yaml.new" # Replace if merge successful if [ $? -eq 0 ]; then mv "$goose_dir/profiles.yaml.new" "$goose_dir/profiles.yaml" echo "✓ Updated $project_name" else echo "✗ Failed to update $project_name" rm "$goose_dir/profiles.yaml.new" fi done # Cleanup rm -rf "$TEMP_DIR" Best Practices for Multi-Project Management
1. Document Your Configuration Strategy
Create a clear README in your configuration repository:
# goose Configuration Standards ## Configuration Hierarchy 1. **Global base** (~/.config/goose/profiles.yaml) 2. **Project-specific** (.goose/profiles.yaml) - Committed to git 3. **Personal overrides** (.goose/profiles.local.yaml) - Gitignored ## Project Types and Templates - **web-app**: Frontend applications (React, Vue, Angular) - **api-service**: Backend APIs and microservices - **data-pipeline**: ETL and data processing projects - **infrastructure**: Terraform, Kubernetes configurations ## Adding a New Project `./scripts/init-project.sh <project-type>` ## Updating Configurations Run monthly to sync base configurations: `./scripts/sync-goose-configs.sh` 2. Version Control Strategy
DO commit to git:
.goose/profiles.yaml (project configuration)
.goose/toolkit-configs/ (shared toolkit settings)
Documentation about configuration choices
DO NOT commit to git:
.goose/profiles.local.yaml (personal overrides)
.goose/sessions/ (session history)
API keys or secrets
Add to .gitignore:
# Goose personal configurations and sessions .goose/profiles.local.yaml .goose/sessions/ .goose/**/*.log 3. Toolkit Management Across Projects
Standardize commonly used toolkits:
# Standard toolkit configurations default: toolkits: # Core toolkits - always included - name: developer # Version control - most projects - name: github requires: GITHUB_TOKEN: github-token # Project-specific toolkits added per project # Examples: docker, kubernetes, database, etc. 4. Environment Variable Management
Use a consistent approach for environment variables across projects:
Option A: .env files (per project)
# .env.goose (gitignored) GOOSE_PROVIDER=openai OPENAI_API_KEY=sk-... GITHUB_TOKEN=ghp_... Option B: Shared secrets manager
# Use tools like 1Password, AWS Secrets Manager, or HashiCorp Vault export OPENAI_API_KEY=$(op read "op://Development/Goose/OPENAI_API_KEY") 5. Testing Configuration Changes
Before rolling out configuration changes, test in a sandbox:
# Test configuration in a sandbox project mkdir -p /tmp/goose-config-test cd /tmp/goose-config-test cp -r ~/goose-configs/templates/base/.goose . goose session start --profile default # Verify configuration loaded correctly # Test key workflows # Check for errors or warnings ## Advanced Patterns ### Pattern 1: Monorepo Configuration For monorepos with multiple sub-projects: monorepo/ ├── .goose/ │ └── profiles.yaml # Root configuration ├── packages/ │ ├── frontend/ │ │ └── .goose/ │ │ └── profiles.yaml # Frontend-specific │ ├── backend/ │ │ └── .goose/ │ │ └── profiles.yaml # Backend-specific │ └── shared/ │ └── .goose/ │ └── profiles.yaml # Shared library config Pattern 2: Dynamic Profile Selection
Use shell aliases to quickly switch contexts:
# ~/.bashrc or ~/.zshrc alias goose-fe='cd ~/projects/myapp/frontend && goose session start --profile frontend' alias goose-be='cd ~/projects/myapp/backend && goose session start --profile backend' alias goose-infra='cd ~/projects/myapp/infra && goose session start --profile infrastructure' Pattern 3: Configuration Inheritance Chain
# Complex inheritance for specialized needs base: provider: openai processor: gpt-4 python-base: extends: base toolkits: - name: developer - name: python django-app: extends: python-base toolkits: - name: database - name: docker ml-pipeline: extends: python-base toolkits: - name: jupyter - name: data-science Monitoring and Maintenance
Configuration Drift Detection
Create a script to identify configuration drift:
# scripts/detect-config-drift.py import yaml import os from pathlib import Path def compare_configs(base_config, project_config): """Compare project config against base and report differences""" differences = [] # Compare provider settings if project_config.get('provider') != base_config.get('provider'): differences.append( f"Provider mismatch: {project_config.get('provider')} vs {base_config.get('provider')}" ) # Add more comparison logic return differences # Scan all projects projects_dir = Path.home() / 'projects' for goose_config in projects_dir.glob('**/.goose/profiles.yaml'): # Load and compare... pass Regular Maintenance Schedule
Establish a maintenance routine:
- Weekly: Review new toolkit releases and compatibility
- Monthly: Audit configurations across projects for drift
- Quarterly: Update base templates and roll out to projects
- Annually: Review and refactor configuration strategy
Troubleshooting Common Issues
Issue 1: Configuration Not Loading
Problem: Goose not picking up project configuration
Solution: Check configuration precedence
# Debug which config is being used goose config show --verbose # Verify file exists and is valid YAML cat .goose/profiles.yaml | python -m yaml Issue 2: Toolkit Conflicts
Problem: Toolkits behaving differently across projects
Solution: Standardize toolkit versions and dependencies
default: toolkits: - name: developer version: "1.0.0" # Pin versions when possible Issue 3: Environment Variable Confusion
Problem: Different projects expecting different environment variables
Solution: Use project-specific .env files and document clearly
# Add to project README ## Required Environment Variables - GOOSE_PROVIDER: OpenAI or Anthropic - OPENAI_API_KEY: Your OpenAI API key - GITHUB_TOKEN: GitHub personal access token Conclusion
Managing goose configurations across multiple projects requires a thoughtful strategy that balances consistency with flexibility. By implementing a configuration hierarchy, using templates, automating synchronization, and following best practices, you can scale goose across your organization without sacrificing maintainability.
Key takeaways
- Establish a clear hierarchy: Global base → Project-specific → Personal overrides
- Use configuration templates: Create reusable templates for common project types
- Automate where possible: Scripts for initialization, validation, and synchronization
- Version control strategically: Commit shared configs, ignore personal overrides
- Document thoroughly: Make it easy for team members to understand and follow standards
- Monitor for drift: Regularly audit configurations to maintain consistency.
As your team grows and adopts goose more widely, these strategies will help you maintain a scalable, consistent configuration management approach that empowers developers rather than constrains them.
Do you have questions about managing Goose across your projects? Drop a comment below
Top comments (0)