Metadata-Version: 2.4
Name: guten-morgen
Version: 0.23.2
Summary: CLI for Morgen calendar and task management — optimised for LLM consumption
Project-URL: Repository, https://github.com/tenfourty/guten-morgen
Author: Jeremy Brown
License: Apache-2.0
License-File: LICENSE
Keywords: calendar,cli,llm,morgen,tasks
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Scheduling
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: click>=8.1
Requires-Dist: httpx>=0.27
Requires-Dist: jq>=1.8
Requires-Dist: markdown>=3.7
Requires-Dist: markdownify>=0.14
Requires-Dist: pydantic>=2.0
Requires-Dist: rich>=13.0
Requires-Dist: socksio>=1.0
Requires-Dist: tomli>=2.0; python_version < '3.11'
Provides-Extra: dev
Requires-Dist: bandit>=1.7; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Provides-Extra: mcp
Requires-Dist: mcp>=1.2; extra == 'mcp'
Provides-Extra: test
Requires-Dist: pytest-cov>=5.0; extra == 'test'
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# guten-morgen

A CLI for [Morgen](https://morgen.so) calendar and task management, designed for both humans and LLM agents.

All commands emit structured JSON, making it easy to pipe into scripts, `jq`, or feed directly to AI coding assistants like Claude Code.

## Features

- **Unified task view** — see tasks from Morgen, Linear, and Notion in one place
- **Calendar groups** — filter events by work/personal/family with a single flag
- **Time-blocking** — schedule tasks as calendar events with `tasks schedule`
- **Tag lifecycle** — model task stages (Active, Waiting-On, Someday) with tags
- **LLM-friendly output** — `--json`, `--response-format concise`, `--jq`, `--fields` for token-efficient responses
- **Smart caching** — TTL-based cache with `cache clear` and `cache stats`
- **Bearer token auth** — auto-detects Morgen desktop app for 5x higher rate limits

## Installation

Requires Python 3.10+.

```bash
# Run without installing (uv)
uvx guten-morgen --help

# Install globally (uv — recommended)
uv tool install guten-morgen

# Install globally (pipx)
pipx install guten-morgen

# Install into current environment (pip)
pip install guten-morgen

# From source (development)
git clone https://github.com/tenfourty/guten-morgen.git
cd guten-morgen
uv sync --all-extras
uv run pre-commit install
```

All methods expose both `gm` (short) and `guten-morgen` (long) commands.

## Setup

1. **Get an API key** from [Morgen Platform](https://platform.morgen.so/) (Settings > API Keys)

2. **Create config** (choose one):
   ```bash
   # Interactive setup (recommended)
   gm init

   # Or manually: project-local config
   cp config.toml.example guten-morgen.toml
   # Edit guten-morgen.toml and add your api_key
   ```

   Config discovery: `$GM_CONFIG` → `guten-morgen.toml` (walks up from CWD) → `~/.config/guten-morgen/config.toml`

3. **(Optional) Install [Morgen desktop app](https://morgen.so)** for 5x higher API rate limits. `gm` auto-detects the desktop app's auth token and uses it when available. No configuration needed.

4. **Verify it works:**
   ```bash
   gm accounts
   gm today --json
   ```

## Quick Start

```bash
# What's coming up?
gm next --json --response-format concise

# Full daily overview
gm today --json

# List overdue tasks across all sources
gm tasks list --status open --overdue --json --group-by-source

# Create and time-block a task
gm tasks create --title "Write design doc" --due 2026-02-20 --duration 90
gm tasks schedule <task-id> --start 2026-02-20T10:00:00

# Filter by tag
gm tasks list --tag "Active" --status open --json
```

Run `gm --help` for the full command reference.

## Calendar Groups

Groups let you filter events by context. Configure in `guten-morgen.toml`:

```toml
default_group = "work"
active_only = true

[groups.work]
accounts = ["you@company.com:google"]
calendars = ["Work Calendar"]

[groups.personal]
accounts = ["you@personal.com:fastmail"]
calendars = ["Personal"]
```

Use `--group personal` to switch context, or `--group all` to see everything.

## Global Options

| Option | Description |
|--------|-------------|
| `--format table\|json\|jsonl\|csv` | Output format (default: table) |
| `--json` | Shortcut for `--format json` |
| `--fields <list>` | Select specific fields |
| `--jq <expr>` | jq filtering on output |
| `--response-format concise` | ~1/3 the tokens (great for LLMs) |
| `--short-ids` | Truncate IDs to 12 chars |
| `--group NAME` | Filter by calendar group |
| `--no-cache` | Bypass cache |

## Development

```bash
# Install dev dependencies
uv sync --all-extras
uv run pre-commit install

# Run tests
uv run pytest -x -q --cov

# Type checking
uv run mypy src/

# Lint
uv run ruff check .
```

Pre-commit hooks enforce ruff, mypy, bandit, pytest (90% coverage minimum), and [ggshield](https://github.com/GitGuardian/ggshield) secret scanning. To use ggshield, [create a free account](https://dashboard.gitguardian.com/signup) and set `GITGUARDIAN_API_KEY`.

### Architecture

```
src/guten_morgen/
  cli.py        Click commands — boundary layer (model -> dict)
  client.py     MorgenClient — typed API wrapper (Pydantic models)
  models.py     Pydantic v2 models
  output.py     Render pipeline (table/json/jsonl/csv + fields + jq)
  errors.py     Exception hierarchy -> structured JSON on stderr
  config.py     XDG config discovery + API settings
  auth.py       Bearer token auth via Morgen desktop app
  time_utils.py Date range helpers
  cache.py      TTL-based request cache
  groups.py     Calendar group filtering from guten-morgen.toml
  retry.py      Rate-limit retry with dual-mode countdown
```

**The boundary rule:** `client.py` returns Pydantic models, `cli.py` converts with `model_dump()`, `output.py` only sees dicts.

## Claude Code Integration

This project includes a `CLAUDE.md` with conventions and a `.claude/` directory with hooks and skills for use with [Claude Code](https://docs.anthropic.com/en/docs/claude-code). These are optional — the CLI works without them.

## License

[Apache 2.0](LICENSE)
