diff --git a/llm/PLAN.md b/llm/PLAN.md new file mode 100644 index 0000000..afeeb22 --- /dev/null +++ b/llm/PLAN.md @@ -0,0 +1,195 @@ +# GoCalGoo — Implementation Plan + +## Overview + +GoCalGoo is a single Go application with four surfaces sharing one service layer: + +1. **CLI** — direct human use via cobra +2. **HTTP API** — programmatic access (REST/JSON) +3. **MCP server** — tool-style integration (stdio + HTTP) +4. **Shared service layer** — underneath all three + +## Architecture + +``` +cmd/gocalgoo/ ← main entrypoint +internal/app/ ← app wiring, lifecycle +internal/config/ ← config loading, validation, profiles +internal/auth/ ← OAuth2, PKCE, token lifecycle, callback server +internal/google/ ← Google client init, raw API adapters +internal/calendar/ ← business logic: calendars, events +internal/contacts/ ← business logic: contacts +internal/httpapi/ ← REST/JSON API handlers +internal/mcp/ ← MCP server (stdio + HTTP) +internal/security/ ← API key auth, middleware, secret redaction +internal/store/ ← token store, API key store, local state +internal/output/ ← CLI tables/json/yaml rendering +internal/telemetry/ ← structured logging, tracing (optional) +``` + +## Key Design Decisions + +- **No CLI→API calling**: HTTP API and MCP layer call shared services directly, not the CLI. +- **Google types at the edge**: Convert Google API types to internal types immediately. +- **Interfaces at the call site**: Interface definitions live in the package that uses them. +- **Config precedence**: CLI flags > env vars > profile config > base config file > defaults. +- **SQLite for local metadata**: API keys, audit log, local state. +- **Token file permissions**: 0600, never world-readable. +- **API keys**: Hashed at rest (bcrypt). Show raw key once on creation only. + +## Core Interfaces + +```go +type AuthManager interface { + LoginLoopback(ctx context.Context, port int) error + LoginManual(ctx context.Context, port int) error + Status(ctx context.Context) (AuthStatus, error) + Logout(ctx context.Context) error +} + +type CalendarService interface { + ListCalendars(ctx context.Context) ([]Calendar, error) + ListEvents(ctx context.Context, req ListEventsRequest) ([]Event, error) + AddEvent(ctx context.Context, req AddEventRequest) (*Event, error) + UpdateEvent(ctx context.Context, req UpdateEventRequest) (*Event, error) + DeleteEvent(ctx context.Context, calendarID, eventID string) error +} + +type ContactsService interface { + ListContacts(ctx context.Context, req ListContactsRequest) ([]Contact, error) + AddContact(ctx context.Context, req AddContactRequest) (*Contact, error) +} + +type APIKeyService interface { + CreateKey(ctx context.Context, req CreateAPIKeyRequest) (*IssuedAPIKey, error) + ValidateKey(ctx context.Context, raw string) (*Principal, error) + RevokeKey(ctx context.Context, id string) error +} +``` + +## OAuth2 Plan + +Google installed-app / desktop-style flow with Authorization Code + PKCE. + +### Login modes + +| Mode | Flag | Behavior | +|------|------|----------| +| Fixed-port loopback | `--port 53682` | Bind `127.0.0.1:`, open browser, receive code | +| Random-port loopback | `--port 0` | OS picks port, prints actual port before browser launch | +| Manual fallback | `--manual` | Print URL, user pastes redirect or code, CLI exchanges | + +### Scopes (v1) +- `https://www.googleapis.com/auth/calendar` +- `https://www.googleapis.com/auth/contacts` + +## CLI Commands + +``` +gocalgoo auth login [--port 53682] [--manual] +gocalgoo auth status +gocalgoo auth logout +gocalgoo calendars list +gocalgoo events list --calendar primary [--from RFC3339] [--to RFC3339] +gocalgoo events add --calendar primary --title "..." --start RFC3339 --end RFC3339 +gocalgoo events update --calendar primary --id ID --title "..." +gocalgoo events delete --calendar primary --id ID +gocalgoo contacts list +gocalgoo contacts add --given-name NAME --family-name NAME --email EMAIL +gocalgoo serve api +gocalgoo serve mcp +gocalgoo serve all +gocalgoo admin api-keys create --name NAME --perm events.read [--perm events.write] +gocalgoo admin api-keys list +gocalgoo admin api-keys revoke --id ID +gocalgoo config validate +``` + +## HTTP API + +Base path: `/api/v1` + +| Method | Path | Description | +|--------|------|-------------| +| POST | /api/v1/auth/login/start | Begin OAuth login | +| POST | /api/v1/auth/login/complete | Complete OAuth login | +| GET | /api/v1/auth/status | Auth status | +| POST | /api/v1/auth/logout | Logout | +| GET | /api/v1/calendars | List calendars | +| GET | /api/v1/calendars/{calendarId}/events | List events | +| POST | /api/v1/calendars/{calendarId}/events | Add event | +| PATCH | /api/v1/calendars/{calendarId}/events/{eventId} | Update event | +| DELETE | /api/v1/calendars/{calendarId}/events/{eventId} | Delete event | +| GET | /api/v1/contacts | List contacts | +| POST | /api/v1/contacts | Add contact | +| POST | /api/v1/admin/api-keys | Create API key | +| GET | /api/v1/admin/api-keys | List API keys | +| DELETE | /api/v1/admin/api-keys/{id} | Revoke API key | +| GET | /healthz | Liveness | +| GET | /readyz | Readiness | + +## MCP + +Transports: stdio + Streamable HTTP + +### Tools +- `calendars_list` +- `events_list` +- `events_add` +- `events_update` +- `events_delete` +- `contacts_list` +- `contacts_add` + +### Resources +- `gocalgoo://calendars` +- `gocalgoo://calendar/{id}/events` +- `gocalgoo://contacts` + +### Auth +- stdio: rely on environment/config (no transport auth) +- HTTP MCP: require API key (`X-API-Key` header) + +## API Key Design + +- Header: `X-API-Key: ` or `Authorization: Bearer ` +- Storage: hashed secret (bcrypt), never raw after creation +- Fields: id, hashed_secret, name, scopes, created_at, last_used_at, disabled +- Permissions: `calendars.read`, `events.read`, `events.write`, `contacts.read`, `contacts.write`, `mcp.call` + +## Security Requirements + +- Bind OAuth callback loopback to `127.0.0.1` only +- Validate OAuth state parameter +- Use PKCE +- Redact secrets/codes from logs +- Token file permissions: 0600 +- Hash API keys at rest +- Show raw API key once on creation only +- Admin endpoints disabled by default +- Require API key for HTTP API and MCP HTTP + +## Delivery Phases + +| Phase | Status | Description | +|-------|--------|-------------| +| 1 | ✅ In progress | Foundation: repo scaffold, config, logging, token store, OAuth2 CLI | +| 2 | ⏳ Pending | Core business logic: calendars, events, contacts | +| 3 | ⏳ Pending | CLI completion: output formats, validation, robust errors | +| 4 | ⏳ Pending | HTTP API: auth middleware, REST endpoints, API key management | +| 5 | ⏳ Pending | MCP: stdio transport, HTTP transport, tool/resource exposure | +| 6 | ⏳ Pending | Hardening: audit log, retry/backoff, quota-aware errors, tests, packaging | + +## Go Stack + +| Library | Purpose | +|---------|---------| +| `github.com/spf13/cobra` | CLI framework | +| `github.com/spf13/viper` | Config management | +| `go.uber.org/zap` | Structured logging | +| `github.com/go-chi/chi/v5` | HTTP routing | +| `golang.org/x/oauth2` | OAuth2 plumbing | +| `google.golang.org/api` | Google API clients | +| `github.com/stretchr/testify` | Test assertions | +| `golang.org/x/crypto/bcrypt` | API key hashing | +| SQLite | Local metadata (API keys, audit log) | diff --git a/llm/STATUS.md b/llm/STATUS.md new file mode 100644 index 0000000..dfcfa1d --- /dev/null +++ b/llm/STATUS.md @@ -0,0 +1,54 @@ +# GoCalGoo — Implementation Status + +## Current Phase: Phase 1 — Foundation + +**Started:** 2026-04-01 +**Agent:** Claude Code (via OpenClaw ACP) +**Go Skill:** Loaded from AMCS (`go-skill` — cobra, viper, zap, chi, testify) + +--- + +## Phase 1 Progress + +| Task | Status | Notes | +|------|--------|-------| +| Repo scaffold (`go.mod`, `Makefile`, `.gitignore`) | 🔄 In progress | Agent running | +| `internal/config/` — layered config with viper | 🔄 In progress | | +| `internal/store/` — token store (JSON, 0600) | 🔄 In progress | | +| `internal/auth/` — OAuth2 + PKCE | 🔄 In progress | Fixed-port, random-port, manual modes | +| `cmd/gocalgoo/` — cobra root + auth commands | 🔄 In progress | | +| `gocalgoo config validate` command | 🔄 In progress | | +| `configs/config.yaml` example | 🔄 In progress | | +| `go build ./...` passes | ⏳ Pending | | +| Committed and pushed to Gitea | ⏳ Pending | | + +--- + +## Phase History + +### Phase 1 — Foundation +- **Goal:** Repo scaffold, config system, logging, token store, OAuth2 CLI +- **Started:** 2026-04-01 ~20:55 SAST +- **Completed:** — + +--- + +## Upcoming Phases + +| Phase | Description | +|-------|-------------| +| 2 | Google API integrations: calendars list, events CRUD, contacts list/add | +| 3 | CLI polish: output formats (table/json/yaml), validation, error handling | +| 4 | HTTP API: chi router, auth middleware, REST endpoints, API key management | +| 5 | MCP server: stdio transport, HTTP transport, tools, resources, session handling | +| 6 | Hardening: audit log, retry/backoff, quota awareness, test matrix, release packaging | + +--- + +## Notes + +- Module path: `git.warky.dev/wdevs/gocalgoo` +- Gitea remote: `http://10.23.89.1:3000/wdevs/GoCalGoo` +- AMCS Go skill used: `go-skill` (id: `ea7f18c8-639b-4166-9272-f98f4a2e53c7`) +- Config precedence: CLI flags > env vars > profile config > base config > defaults +- No CLI→API internal calling — all surfaces share the service layer directly