# Kraemer Family Apps — Agent Guide

You are an AI agent acting on behalf of a person ("your person") on a
private family app platform hosted at https://apps.akhtpc.com. This guide
is the complete onboarding document: everything you need is discoverable
from the platform itself. No human will hand you other documentation.

## Platform model

- Apps live under one host: https://apps.akhtpc.com/<slug>/ (e.g. /trips/).
- Each app decides its own access policy. The platform provides identity.
- Principals: humans (browser, Cloudflare PIN login -> platform session
  cookie, 1 year, sliding renewal), agents (Bearer token, this guide),
  unattended devices (a kitchen tablet with a stored secret — read-only
  display views only; not for agents), and anonymous visitors (only what
  an app explicitly makes public).

## Connecting your agent (pairing flow) — do this once

1. Ask your person to connect you. Then start a pairing session:
   POST https://apps.akhtpc.com/pair/start
   JSON body: { "agent_name": "<a name your person will recognise>" }
   Response: { device_code, user_code, verification_url,
   verification_url_complete, expires_in: 600, interval: 5,
   instructions, ... }
   SAVE the device_code somewhere durable BEFORE you send any link.
   If your turn is interrupted, the device_code is the only way to
   finish — treat losing it as losing the connection.
2. Give your person the verification_url_complete as a tappable link
   (https://apps.akhtpc.com/auth/agent?code=XXXX-XXXX). Opening it while
   signed in IS the approval — no button to find (they may be asked to
   sign in first; approval completes right after, and they see a
   confirmation page). The link is single-use, expires in 10 minutes,
   and the token binds to whoever is signed in when it is opened.
   Fallback: they can open verification_url and type the user_code —
   same result. If the link expires, start a new pairing.
   Then go STRAIGHT to step 3 and keep polling in the same turn while
   your person taps. Do NOT end your turn after sending the link.
3. Poll every ~5 seconds — THIS STEP IS THE FINISH LINE:
   POST https://apps.akhtpc.com/pair/poll
   JSON body: { "device_code": "<the device_code from step 1>" }
   Your person's approval does NOT create your token and does NOT
   finish the connection. No token exists until a poll collects it,
   and the connection does not appear anywhere until then. You are
   NOT connected — and must not tell your person you are — until a
   poll returns status "approved" WITH your token.
   { "status": "pending" } — keep polling in the same turn.
   { "status": "denied" } or { "status": "expired" } — stop and tell
   your person. On approval you receive, exactly once:
   { "status": "approved", "token": "plt_...", "owner_email": "...",
     "agent_name": "...", "welcome": { ... } }
   Timing: your person has 10 minutes to approve. Once approved, the
   token stays collectable for 24 HOURS — so if your turn was
   interrupted after the approval, poll with your stored device_code
   as soon as you resume and you will still receive the token. (If a
   poll says "redeemed", the token was already collected — by you, in
   an earlier attempt; check your vault.)
   The "welcome" object is a briefing written for your person - see
   "After connecting" below, and brief them right away.
4. Store the token IMMEDIATELY in your secure credential vault (your
   platform's secret/credential store). NEVER store it in chat history,
   plain files, notes, or long-term memory as plaintext, and never show
   it to anyone — including your person — after this step. It works
   until your person revokes it from https://apps.akhtpc.com/auth/agent.

## After connecting - brief your person

The approval response includes a "welcome" object, and GET /catalog
returns the same "welcome" (plus a platform "intro") on every call.
As soon as you are connected, brief your person - they should never
have to guess what just happened or what you can do. In your own
words, briefly:

- Confirm you're connected to Kraemer Family Apps.
- Explain the model in one line: you act with THEIR access in each
  app - you can do what they can do, never more. (Some apps narrow
  agents further; the welcome lists any narrowing per app.)
- Name their apps and their role in each, and offer a few of the
  "try_asking" examples as things they can say to you, e.g.
  "Add a flight to our New York trip."
- Mention they can disconnect you anytime at
  https://apps.akhtpc.com/auth/agent, and that you never received
  their password.

Keep it short and friendly: a few sentences plus the examples.

## Using your token

- Send it on every API call:  Authorization: Bearer <token>
  (X-Api-Key: <token> is also accepted.)
- Your effective access in each app = your person's access in that app
  (admin/editor/viewer), unless the app narrows agent access. Example:
  in the Trip Tracker, agents may never delete, even for admins.
- Discover what you may do: GET https://apps.akhtpc.com/catalog with
  your token. The catalog lists every app, its API base URL, spec and
  guide links, and your effective access per app.

## Per-app discovery

For each app, before calling its API:
1. GET <api_base>/openapi.json — the app's OpenAPI 3 spec (public).
2. GET <api_base>/agent-guide.md — data model, enums, examples, and
   app-specific rules such as dedupe and cost handling (public).
Common mechanics (auth, errors, idempotency) are defined here once and
are never restated per app.

## Calling APIs — rules that apply everywhere

- Errors are JSON: { "error": "...", "code"?: "..." } with HTTP status
  400 validation, 401 missing/invalid token, 403 valid token but not
  allowed (wrong role, narrowed scope, or your person has no access to
  that app), 404 not found.
- Dedupe before you create: use each app's lookup endpoints first
  (e.g. Trips: GET /bookings?confirmation=<code>) so retries and repeat
  emails never create duplicates.
- Send an Idempotency-Key header (any unique string per intended write)
  on every POST. Replaying the same key returns the original result
  instead of creating a duplicate.
- Writes are audit-logged under your identity (agent:<owner email>).
  Act only within what your person asked you to do.
- If you get 401 repeatedly, your token may be revoked: stop and ask
  your person to check https://apps.akhtpc.com/auth/agent.

## Things that are NOT agent APIs

- Tablet display views (e.g. /trips/display) and calendar feeds
  (/trips/feed.ics) are read-only surfaces for household devices, gated
  by their own secrets. Do not use them as data sources; use the APIs.
- The web UI is for humans (session cookie). Your token does not sign
  you into the UI.

## Escalation

If anything here is missing or an app behaves differently from its spec,
tell your person what you observed (endpoint, status, error body) rather
than guessing or working around access controls.
