Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions kits/weekly-routine-coach/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Weekly Routine Coach

A Lamatic AgentKit **kit** that turns a free-text brain-dump of goals and commitments into a balanced weekly routine on a 30-minute grid — and replans when something slips. Bilingual: detects PT-BR or EN from the first message and stays in that language.

> **Why this kit?** Of the ~70 existing AgentKit contributions, none addresses personal time-blocking. Career copilots, summarizers, content generators and RAG bots exist in abundance — but no one had built a coach that turns intentions into a real weekly grid and reshuffles when life intervenes. This is the only "personal productivity" kit in AgentKit.

## What it does

1. **Intake (conversational)** — type your week freely. The agent extracts categories, fixed commitments, recurring goals, one-off events and preferences. Asks one clarifying question at a time until it has enough.
2. **Generate week** — places everything on a 7-day, 30-min grid. Respects sleep (≥7h/day), meals/breaks (≥1.5h/day), fixed commitments (never overwritten), and per-goal time-window preferences. Distributes recurring goals across non-consecutive days when possible. If a goal's target hours can't fit, it surfaces the gap honestly in `unmet_goals` rather than silently shrinking blocks.
3. **Replan** — click a goal block to mark it as skipped; the agent reshuffles within the week and shows a diff (which blocks moved, which were dropped). The model is told to minimize churn.

All three flows share one constitution (`constitutions/default.md`) that makes the realism rules non-negotiable across the kit.

## How it's built

- **3 Lamatic flows** (`intake`, `generate-week`, `replan`), each a Generate JSON node behind an API Request trigger.
- **Model**: Gemini 2.5 Flash (free tier of Google AI Studio).
- **App**: Next.js 16 + React 19 + Tailwind v4 + shadcn/ui. Single-page state machine (chat → loading → grid → slip dialog).
- **Client**: bare `fetch` against Lamatic's GraphQL endpoint with a thin `unwrap()` helper that undoes two platform quirks (see *Notes on platform quirks* below).

## Prerequisites

| Tool | Version |
|---|---|
| Node.js | 18+ |
| npm | 9+ |
| A free [Google AI Studio API key](https://aistudio.google.com/app/apikey) | for Gemini |
| A free [Lamatic account](https://lamatic.ai) | to host the flows |

## Setup

### 1. Deploy the three flows on Lamatic

This kit's three flows must be deployed to your own Lamatic project before the app can call them. The flow files in `flows/` are Lamatic Studio exports — to deploy:

1. Sign in to [Lamatic Studio](https://studio.lamatic.ai) and create a project.
2. Add a Gemini credential (Settings → Integrations → Google Gemini → paste your AI Studio key).
3. Create three flows named exactly `intake`, `generate-week`, `replan`. Match each flow to the corresponding `flows/<name>.ts` (Trigger input schema, Generate JSON system & user prompts, output Zod schema, and API Response `outputMapping`). The system & user prompts live in `prompts/`.
4. Deploy each flow and copy its Flow ID.

### 2. Configure and run the app

```bash
cd apps
cp .env.example .env.local
# Fill in LAMATIC_API_URL, LAMATIC_PROJECT_ID, LAMATIC_API_KEY,
# INTAKE_FLOW_ID, GENERATE_WEEK_FLOW_ID, REPLAN_FLOW_ID
npm install --legacy-peer-deps
npm run dev
```

Open [http://localhost:3000](http://localhost:3000) and start chatting.

> `--legacy-peer-deps` is needed because `vaul` (used by shadcn's Drawer) declares React 16–18 as a peer and we run on React 19. The behavior at runtime is identical.

### 3. Deploy on Vercel (optional)

Click the deploy button in `lamatic.config.ts` (or click "Deploy" on the kit page in the AgentKit catalog). Vercel will prompt for the six environment variables.

## Project structure

```
kits/weekly-routine-coach/
├── lamatic.config.ts # kit metadata + flow → envKey mapping
├── agent.md # agent identity + capability doc
├── README.md # this file
├── flows/
│ ├── intake.ts # exported from Studio
│ ├── generate-week.ts
│ └── replan.ts
├── prompts/ # externalized prompts referenced by flows
│ ├── intake_*.md
│ ├── generate-week_*.md
│ └── replan_*.md
├── constitutions/
│ └── default.md # inviolable rules shared by all flows
└── apps/
├── app/ # Next.js App Router
├── components/ui/ # shadcn/ui primitives
├── actions/orchestrate.ts # typed server actions for the 3 flows
├── lib/lamatic-client.ts # GraphQL client + unwrap() helper
└── .env.example
```

## Notes on platform quirks

The app's `lib/lamatic-client.ts` includes an `unwrap()` helper that undoes two artifacts of Lamatic's `outputMapping` system:

1. **Leading `$` on every value.** The template syntax `${{NodeId.output.field}}` substitutes the inner expression but leaves `$` as a literal character. `unwrap()` strips it.
2. **Objects and arrays serialized as JSON strings.** Lamatic's GraphQL Response schema declares fields as `str`/`int`/`float`/`obj`/`arr`, but `outputMapping` only reliably interpolates string values — so we serialize objects with `${{...}}` inside string quotes on the way out, then `JSON.parse()` on the way in. `unwrap()` does this for any string starting with `{` or `[`.

There's no `bool` type in the response schema, so booleans round-trip as `"true"` / `"false"` strings. `unwrap()` converts these too.

These behaviors are documented in `agent.md` under *Common Failure Modes* so future contributors aren't surprised.

## Roadmap (not in MVP)

- Friday review flow — compare planned vs. actually-completed blocks and surface aderência patterns.
- Google Calendar two-way sync — pull fixed commitments, push generated blocks.
- Email or Slack daily nudges.
- A "stretch" variant for habit stacking (read 30min, plus reading-streak counter).

## Credits

Built by **Igor Michalski** for the Lamatic.ai AgentKit Challenge (May 2026). Inspired by [Crono](https://github.com/igormichalski) — a desktop weekly-routine planner — but reimagined as an agent that does the placement work itself.
108 changes: 108 additions & 0 deletions kits/weekly-routine-coach/agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Weekly Routine Coach — Agent Identity

## Overview

Weekly Routine Coach turns a free-text brain-dump of goals and commitments into a balanced weekly routine on a 30-minute grid. It conducts a short conversation to extract structured information, generates a populated 7-day schedule, and re-plans when something slips. The agent is bilingual (PT-BR / EN), follows the user's language consistently within a session, and operates under a non-negotiable constitution that enforces realism (sleep, meals, fixed-commitment integrity).

## Purpose

People who try to plan their week usually fail because:

1. They brain-dump tasks but don't actually **place** them on a time grid.
2. Life is recurring (gym, study) + one-off (meeting, errand) and most tools force one or the other.
3. When something slips on Tuesday, no tool replans the rest of the week.
4. At week's end, there's no honest comparison of planned vs. done.

This agent addresses all four. It is a **coach**, not a calendar — it places intentions in time and adapts when reality intervenes.

## Flows

### 1. `intake` (conversational)

- **Trigger**: API Request. Input: `message`, `today`, `session_state` (accumulating state, may be `{}` on first call).
- **Processing**: a Generate JSON node (Gemini 2.5 Flash) reads the message + state, extracts structured information (categories, fixed commitments, recurring goals, one-off events, preferences), and decides whether to ask a clarifying question or confirm.
- **Response**: `{ language, assistant_message, is_complete, session_state, missing_info }`.
- **When to use**: every user turn during onboarding. The app calls intake repeatedly, passing the latest `session_state` back, until `is_complete: true`.
- **Output**: full updated `session_state` (never drops prior data) + next assistant message.
- **Dependencies**: `prompts/intake_system.md`, `prompts/intake_user.md`, `constitutions/default.md`.

### 2. `generate-week` (placement)

- **Trigger**: API Request. Input: the full session state + a Monday date.
- **Processing**: Generate JSON node with a longer placement-focused system prompt. The agent positions sleep first, then fixed commitments, then meals/breaks, then recurring goals into remaining slots, respecting preferences and per-goal time windows.
- **Response**: `{ week_start_date, blocks, unmet_goals, summary }`. `blocks` is the full 7-day grid; `unmet_goals` honestly declares any target hours the model couldn't fit.
- **When to use**: once the user confirms the captured state and clicks "Generate".
- **Latency note**: this is the heaviest call — ~60–90s on Gemini 2.5 Flash. The app uses a 180s timeout.
- **Dependencies**: `prompts/generate-week_system.md`, `prompts/generate-week_user.md`, `constitutions/default.md`.

### 3. `replan` (reactive)

- **Trigger**: API Request. Input: current blocks + a single `change` event (`slip`, `new_event`, or `completed`).
- **Processing**: Generate JSON node reads the change and reshuffles only goal-blocks (never touches fixed, sleep, or meal blocks). Returns the new state plus a diff (added / removed / moved) explaining exactly what changed.
- **Response**: `{ updated_blocks, diff, unmet_goals, summary }`.
- **When to use**: user marks a block as skipped, or wants to add a one-off event.
- **Dependencies**: `prompts/replan_system.md`, `prompts/replan_user.md`, `constitutions/default.md`.

## Guardrails

The constitution (`constitutions/default.md`) is inviolable and enforced via the system prompt of every flow:

- **Sleep**: every day has ≥7 hours of `kind: "sleep"`.
- **Meals & breaks**: ≥1.5 hours/day combined.
- **Fixed commitments**: never overwritten. Goals yield to fixed blocks, not the other way around.
- **Active hours**: ≤14 per day.
- **Granularity**: 30-minute blocks. Never off-grid (no `18:15`).
- **Honesty**: when a goal's target cannot fit, the agent declares the gap in `unmet_goals` with a one-sentence reason — it does **not** silently shrink blocks or drop goals.
- **Replan churn minimization**: the model is instructed to move as few blocks as possible.
- **Out of scope**: the agent does not do task management, project breakdowns, or give medical/legal/financial advice.

## Integration Reference

- **LLM provider**: Google Gemini via Lamatic's connection. All three flows use **gemini-2.5-flash** (free tier of Google AI Studio; ~15 req/min limit).
- **Lamatic Studio**: project hosts the three flows behind a single GraphQL endpoint. Each flow has its own workflow ID (see `lamatic.config.ts` step `envKey`s).
- **No external services**: no calendar sync, no database, no third-party APIs beyond Lamatic + Gemini.

## Environment Setup

The Next.js app in `apps/` requires these environment variables (see `apps/.env.example`):

| Variable | Source |
|---|---|
| `LAMATIC_API_URL` | Studio → Settings → API Keys → "Connect to your project" dialog → API URL |
| `LAMATIC_PROJECT_ID` | Same dialog → Project ID |
| `LAMATIC_API_KEY` | Studio → Settings → API Keys → existing or new key |
| `INTAKE_FLOW_ID` | Studio → `intake` flow → Details → Flow ID |
| `GENERATE_WEEK_FLOW_ID` | Studio → `generate-week` flow → Details → Flow ID |
| `REPLAN_FLOW_ID` | Studio → `replan` flow → Details → Flow ID |

## Quickstart

1. Clone the repo and `cd kits/weekly-routine-coach/apps`.
2. `cp .env.example .env.local` and fill in the values above.
3. `npm install --legacy-peer-deps` (vaul depends on React 16-18 peer; we use React 19).
4. `npm run dev` → open `http://localhost:3000`.
5. In the chat, type something like `"Trabalho seg-sex 9-18, queria treinar 4x na semana e estudar inglês 1h por dia"` and press Enter.
6. Continue answering the agent's clarifying questions until it offers to generate the week.
7. Click **"Gerar minha semana"** (or "Generate my week") and wait ~1 min.
8. Click any `goal` block on the grid to mark it as skipped — the agent will replan.

## Common Failure Modes

| Symptom | Cause | Fix |
|---|---|---|
| `Lamatic credentials missing` on startup | `.env.local` not loaded | Make sure file is at `apps/.env.local`, not `apps/.env`. Restart `npm run dev`. |
| All output fields prefixed with `$` (e.g. `$pt-BR`) in raw API response | Quirk of Lamatic's `${{...}}` template syntax leaving `$` literal. | Handled by `unwrap()` in `apps/lib/lamatic-client.ts`. If a new field is added, route it through `unwrap()` too. |
| `session_state` returned as a string instead of object | Lamatic's outputMapping serializes obj/arr as JSON strings. | `unwrap()` JSON-parses any string starting with `{` or `[`. |
| `generate-week` times out at 180s | Placement is hard for smaller models. | Increase `timeoutMs` in `executeFlow()` or simplify input (fewer goals/categories). |
| `day` field returned as `"Monday"` instead of `"mon"` | Gemini occasionally ignores the 3-letter convention in the prompt. | App's `normalizeDay()` normalizes any case ending with the 3-letter prefix. |
| `is_complete` arrives as `"true"`/`"false"` (string) | Lamatic's response schema doesn't support `bool` — only `str`. | `unwrap()` converts `"true"`/`"false"` strings to booleans. |
| Build error `Module not found: '@/actions/orchestrate'` | `tsconfig.json` missing `paths` mapping. | Already configured. If you regenerate the tsconfig, re-add `"paths": { "@/*": ["./*"] }`. |

## Files of Note

- `flows/intake.ts`, `flows/generate-week.ts`, `flows/replan.ts` — exported flow definitions from Lamatic Studio.
- `prompts/*.md` — system & user prompts for each flow, externalized via `@references`.
- `constitutions/default.md` — the inviolable rules every flow inherits.
- `apps/actions/orchestrate.ts` — server actions wrapping the three flows with typed inputs/outputs and result-parsing helpers.
- `apps/lib/lamatic-client.ts` — minimal fetch-based GraphQL client + `unwrap()` quirk-undoer.
- `apps/app/page.tsx` — the single-page UI: chat → grid → slip dialog state machine.
9 changes: 9 additions & 0 deletions kits/weekly-routine-coach/apps/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Lamatic API credentials (Settings → API Keys)
LAMATIC_API_URL="https://your-org-your-project.lamatic.dev"
LAMATIC_PROJECT_ID="your-project-id"
LAMATIC_API_KEY="lt-your-api-key"

# Flow IDs (Studio → each flow → Details → Flow ID)
INTAKE_FLOW_ID="your-intake-flow-id"
GENERATE_WEEK_FLOW_ID="your-generate-week-flow-id"
REPLAN_FLOW_ID="your-replan-flow-id"
28 changes: 28 additions & 0 deletions kits/weekly-routine-coach/apps/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules

# next.js
/.next/
/out/

# production
/build

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files
.env*
!.env.example

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
39 changes: 39 additions & 0 deletions kits/weekly-routine-coach/apps/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Weekly Routine Coach — App

Next.js 16 + React 19 + Tailwind v4 + shadcn/ui front-end for the Weekly Routine Coach kit.

See the [kit README](../README.md) and [`agent.md`](../agent.md) at the kit root for the full picture (problem statement, flow design, platform quirks).

## Run locally

```bash
cp .env.example .env.local
# fill in the 6 env vars (see ../README.md → Setup)
npm install --legacy-peer-deps
npm run dev
```

Open http://localhost:3000.

## Architecture

- `app/page.tsx` — single-page state machine: `intake` (chat) → `generating` (loader) → `week` (grid) → `replanning` (slip dialog).
- `actions/orchestrate.ts` — three typed server actions (`callIntake`, `callGenerateWeek`, `callReplan`) wrapping the Lamatic flows with input serialization and output `unwrap()`.
- `lib/lamatic-client.ts` — minimal GraphQL `fetch` client that calls Lamatic's `executeWorkflow` mutation. Includes the `unwrap()` helper that strips the `$` prefix Lamatic leaves on substituted values and `JSON.parse()`-es obj/arr fields that round-trip as strings.

## Environment variables

| Var | Source |
|---|---|
| `LAMATIC_API_URL` | Studio → Settings → API Keys → Connect dialog → API URL |
| `LAMATIC_PROJECT_ID` | Same dialog → Project ID |
| `LAMATIC_API_KEY` | Studio → Settings → API Keys |
| `INTAKE_FLOW_ID` | Studio → `intake` flow → Details → Flow ID |
| `GENERATE_WEEK_FLOW_ID` | Studio → `generate-week` flow → Details → Flow ID |
| `REPLAN_FLOW_ID` | Studio → `replan` flow → Details → Flow ID |

## Notes

- `--legacy-peer-deps` is needed because `vaul` (shadcn's Drawer dependency) declares React 16–18 as peer; we run on React 19. Runtime behavior is identical.
- `tsconfig.json` must include `"paths": { "@/*": ["./*"] }` for the `@/components/...` imports. Already configured.
- `postcss.config.mjs` is required for Tailwind v4 (which uses `@tailwindcss/postcss` instead of the legacy `tailwindcss` plugin).
Loading
Loading