From d39d3ac367682685140198c09ba12f5d791ec597 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Tue, 10 Feb 2026 11:51:56 -0800 Subject: [PATCH] docs: add Google Calendar section and new-tool checklist Add GCal tools setup guide to README (prerequisites, config, fields). Add gmail-auth, gcal-auth, setup to the CLI commands table. Add "Adding a New Tool" checklist to CLAUDE.md covering the full wiring chain including the TUI registration gotcha. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 33 ++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index d94ed6a..5b1b6df 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -62,6 +62,70 @@ Registration chain: tool file → `src/tools/builtin/index.ts` → `src/tools/in - **Target**: ES2022, NodeNext modules, strict mode. Requires Node.js >=22. - **Error pattern**: `instanceof Error` checks, descriptive messages, try-catch in stream handlers +## Adding a New Tool + +Checklist for adding a tool (or tool set) to Flynn. Every step is required unless noted. + +### 1. Create the tool file — `src/tools/builtin/.ts` + +Pick the right pattern: +- **Static** (`export const fooTool: Tool`) — no runtime deps (e.g. `system-info.ts`) +- **Factory** (`export function createFooTool(dep): Tool`) — needs one dep (e.g. `memory-read.ts`) +- **Multi-factory** (`export function createFooTools(dep): Tool[]`) — related tool set (e.g. `gmail.ts`, `gcal.ts`) + +Each tool needs: `name` (dotted, e.g. `calendar.today`), `description`, `inputSchema` (JSON Schema object), `execute(args): Promise`. + +### 2. Create tests — `src/tools/builtin/.test.ts` + +Co-located next to the source file. Use the hoisted mock pattern for external deps: +```typescript +const { mockFn } = vi.hoisted(() => ({ mockFn: vi.fn() })); +vi.mock('some-module', () => ({ thing: mockFn })); +``` + +Cover: factory output (correct names/count), auth/config errors, happy paths, empty results, API errors. + +### 3. Wire up the export chain + +Three files, in order: + +| File | Add | +|------|-----| +| `src/tools/builtin/index.ts` | `export { createFooTools } from './foo.js';` | +| `src/tools/index.ts` | Add `createFooTools` to the barrel re-export from `./builtin/index.js` | +| `src/daemon/index.ts` | Import + conditional registration (see existing `gmail`/`gcal` blocks) | + +### 4. Register in TUI — `src/cli/tui.ts` + +The TUI has its own tool registration (separate from the daemon). Add the import to the dynamic `import('../tools/index.js')` destructure and add a registration block matching the daemon pattern. **This is easy to forget.** + +### 5. Config schema (if tool needs config) + +In `src/config/schema.ts`: +- Define a Zod schema (e.g. `const fooSchema = z.object({ ... }).optional()`) +- Add the field to the parent schema (e.g. `automationSchema`) +- Export the inferred type: `export type FooConfig = z.infer;` + +### 6. Tool policy — `src/tools/policy.ts` + +- Add tool names to the appropriate **profile sets** (`messaging`, `coding`, or both). The `full` profile matches everything automatically. +- Add a **tool group** entry: `'group:foo': ['foo.bar', 'foo.baz']` + +### 7. CLI auth command (if tool needs OAuth) + +Mirror `src/cli/gmail-auth.ts` or `src/cli/gcal-auth.ts`: +- Create `src/cli/-auth.ts` with `registerFooAuthCommand(program)` +- Register in `src/cli/index.ts` +- Use the correct OAuth scope, token path, and config key + +### Verification + +```bash +pnpm test:run src/tools/builtin/.test.ts # new tests pass +pnpm typecheck # no type errors +pnpm test:run # full suite still passes +``` + ## State Tracking After implementing features, update `docs/plans/state.json` (test counts, progress, feature gap scorecard). Commit alongside the feature change. diff --git a/README.md b/README.md index 6f7ce7e..190c61a 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ Flynn provides a full CLI via the `flynn` binary (or `npx tsx src/cli/index.ts` | `flynn doctor` | Validate config and check system health | | `flynn config` | Show resolved configuration (secrets redacted) | | `flynn completion ` | Generate shell completions (bash, zsh, fish) | +| `flynn setup` | Interactive setup wizard | +| `flynn gmail-auth` | Authenticate with Gmail via OAuth2 | +| `flynn gcal-auth` | Authenticate with Google Calendar via OAuth2 | ### Examples @@ -417,6 +420,36 @@ Push notifications arrive at `POST /gmail/push` on the gateway HTTP server (bypa | `{{id}}` | Gmail message ID | | `{{labels}}` | Comma-separated label names | +## Google Calendar Tools + +Query Google Calendar events from within conversations. Provides three tools: `calendar.today` (today's agenda), `calendar.list` (date range), and `calendar.search` (full-text search). + +### Prerequisites + +1. A Google Cloud project with the **Calendar API** enabled +2. OAuth2 credentials (Desktop application type) — the same credentials file used for Gmail works +3. Run `flynn gcal-auth` to complete the OAuth2 flow and store the refresh token + +### Configuration + +```yaml +automation: + gcal: + enabled: true + credentials_file: ~/.config/flynn/gmail-credentials.json + token_file: ~/.config/flynn/gcal-token.json # Default location + calendar_ids: [primary] # Calendar IDs to query +``` + +### Google Calendar Config Fields + +| Field | Required | Description | +|-------|----------|-------------| +| `enabled` | no | Enable the calendar tools (default: `false`) | +| `credentials_file` | yes | Path to Google OAuth2 credentials JSON | +| `token_file` | no | Path to stored OAuth2 refresh token (default: `~/.config/flynn/gcal-token.json`) | +| `calendar_ids` | no | Calendar IDs available for queries (default: `[primary]`) | + ## Vector Memory Search The memory system supports hybrid search combining keyword matching with semantic vector similarity. When embeddings are enabled, `memory.search` uses both approaches and merges results with configurable weighting.