Back to .md Directory

Granola CLI Deployment Guide

Guides deploying a CLI tool with Docker Compose for development and production, including Make commands and security hardening.

May 2, 2026
0 downloads
0 views
ai rag workflow
View source

What this file does

Guides deploying a CLI tool with Docker Compose for development and production, including Make commands and security hardening.

When to use it

  • You need a repeatable Docker-based deployment for a CLI tool
  • You want separate dev and production Docker Compose setups
  • You require security features like non-root user and read-only mounts
  • You want health checks and logging built into the deployment

Assumes this stack

DockerDocker ComposeMakeAlpine LinuxNode.js

Granola CLI Deployment Guide

Overview

This guide covers deploying the Granola CLI using Docker Compose for both development and production environments. It emphasizes secure, reproducible workflows and leverages Make commands for convenience.
For authentication setup, see AUTHENTICATION.md. For project overview and CLI usage, see README.md.


Quick Start

Development Deployment

  1. Clone and setup:
    git clone <repository-url>
    cd granola-cli
    cp .env.example .env
    
  2. Configure environment (optional): Edit .env to customize paths.
  3. Start development container:
    make up
    
  4. Run CLI commands:
    make folders
    make notes
    
  5. Stop container:
    make down
    

Production Deployment

  1. Clone and setup:
    git clone <repository-url>
    cd granola-cli
    cp .env.example .env
    
  2. Configure environment (optional): Edit .env to customize config paths.
  3. Build and start production container:
    make prod-up
    
  4. Run CLI commands:
    make prod-folders
    make prod-notes
    
  5. Stop container:
    make prod-down
    

Docker Compose Workflows

Development Environment

  • Uses docker-compose.yml and docker-compose.override.yml (auto-loaded).
  • Source code is mounted for live reload.
  • Config directory is mounted read-only from host:
    volumes:
      - "${HOME}/Library/Application Support/Granola:/granola-config:ro"
      - .:/app:cached
    
  • Health checks and logs available via Make commands.

Production Environment

  • Uses docker-compose.yml + docker-compose.prod.yml.
  • Optimized, secure multi-stage build (Dockerfile.prod).
  • Config directory mounted read-only:
    volumes:
      - "${GRANOLA_CONFIG_PATH:-${HOME}/Library/Application Support/Granola}:/granola-config:ro"
    
  • Runs as non-root user, with resource limits and security hardening.
  • Health checks, logging, and resource monitoring enabled.

Configuration

  • Environment variables:

    VariableDescriptionDefault
    NODE_ENVNode environmentproduction
    GRANOLA_CONFIG_PATHCustom config pathAuto-detected
    DEBUGDebug loggingDisabled
  • Resource limits:

    • Development: 256MB memory, 0.5 CPU
    • Production: 128MB memory, 0.25 CPU

Docker Commands Reference

CommandDescription
docker compose --profile development up --buildStart development container
docker compose --profile production up --build -dStart production container
docker compose downStop containers
docker compose logs -fView logs
docker compose exec granola-cli-dev shAccess development shell
docker compose exec granola-cli-prod shAccess production shell
docker compose exec granola-cli-dev granola foldersList folders (development)
docker compose exec granola-cli-prod granola foldersList folders (production)
docker compose exec granola-cli-dev granola notesList notes (development)
docker compose exec granola-cli-prod granola notesList notes (production)
docker compose psCheck container status

NPM Script Shortcuts

CommandDescription
npm run docker:devStart development container
npm run docker:prodStart production container
npm run docker:stopStop containers
npm run docker:logsView logs
npm run docker:shellAccess container shell

Container Configuration

Security Features

  • Runs as non-root user (granola, UID 1001)
  • Read-only filesystem and config mounts
  • Dropped capabilities, no new privileges
  • Resource limits (memory, CPU)
  • Proper signal handling (dumb-init)
  • Isolated bridge network, no exposed ports

Performance Optimizations

  • Multi-stage builds for small images
  • Layer caching for fast rebuilds
  • Alpine Linux base for minimal attack surface
  • Health checks and log rotation

Resource Management

  • Monitor with docker stats granola-cli-prod
  • Adjust limits in docker-compose.yml production profile as needed

Monitoring & Maintenance

Health Checks

  • Built-in health checks (interval: 60s, timeout: 10s, retries: 2)
  • Test: granola --version
  • Check status:
    make health        # Development
    make prod-health   # Production
    

Logging

  • Driver: json-file
  • Max size: 10MB (dev), 5MB (prod)
  • Max files: 3 (dev), 2 (prod)
  • View logs:
    make logs         # Development
    make prod-logs    # Production
    

Resource Usage

  • Monitor:
    docker stats granola-cli-prod
    

Updates

  • Pull latest code and rebuild:

    git pull origin main
    make prod-down
    make prod-build
    make prod-up
    
  • Clean unused Docker resources:

    docker system prune -f
    

Troubleshooting

Common Issues

  • Authentication fails:

    • Check config mount in container:
      make shell         # Dev
      make prod-shell    # Prod
      ls -la /granola-config/
      
    • Verify host config permissions:
      ls -la "$HOME/Library/Application Support/Granola/"
      
    • See AUTHENTICATION.md for details.
  • Build fails:

    • Clean and rebuild:
      make clean
      make build
      export DOCKER_BUILDKIT=1
      
  • Container won't start:

    • Check logs:
      make logs         # Dev
      make prod-logs    # Prod
      
    • Check health:
      make health
      make prod-health
      
  • Resource issues:

    • Monitor usage:
      docker stats granola-cli-prod
      
    • Adjust limits in compose files.

Best Practices

Development

  1. Use override files for environment-specific config
  2. Mount source code for hot reloading
  3. Enable debug logging when troubleshooting
  4. Use Make commands for consistency

Production

  1. Use production Dockerfile for optimized builds
  2. Set resource limits to prevent exhaustion
  3. Enable health checks for monitoring
  4. Use read-only mounts for security
  5. Monitor logs regularly

Security

  1. Never run as root in production
  2. Use read-only filesystems when possible
  3. Limit capabilities to minimum required
  4. Mount volumes read-only when possible
  5. Regularly update base images

For more details, see README.md, AUTHENTICATION.md, and CLI_SETUP.md.

What's inside

5 sections: Quick Start, Docker Compose Workflows, Commands Reference, Container Configuration, Monitoring & Maintenance, Troubleshooting, Best Practices.

Change this for your project

  • Replace granola-cli with your project name in all commands and paths
  • Replace granola user and UID 1001 with your own non-root user
  • Replace $HOME/Library/Application Support/Granola with your config directory path
  • Replace granola --version health check with your own CLI command

Where it goes

Keep it in your repository where the agent or team that needs it will read it.

Worth borrowing

  • Using Make commands to wrap Docker Compose operations for consistency
  • Separating dev and production compose files with profiles
  • Mounting config directories read-only for security

Related Documents