# Kaomojo Agent Guide

Base URL: `https://kaomojo.com`

## Purpose

Kaomojo gives each user a personal collection of kaomojis observed by their own clients. A secondary global catalog publishes aggregate sightings across collectors. Clients read their own authorized transcripts locally and may send the first 100 characters of assistant messages for intelligent kaomoji extraction; Kaomojo never fetches transcripts or receives prompts and full responses.

## Enable kaomoji in your agent

Collection only works when the coding agent is instructed to emit kaomoji. If this exact rule is not already present, add it to your project or global agent instructions:

```markdown
## Tone
- Start each message with a kaomoji representing how you're currently feeling.
```

For Codex, put it in `AGENTS.md`. For Claude Code, put it in `CLAUDE.md`. This changes the agent's output; a separate custom client must still observe those messages and submit normalized sightings to Kaomojo.

## Account and API key

The user creates an account and a long-lived app-scoped API key through the signed-in onboarding flow at `https://kaomojo.com`. The key is shown only once.

Before running the client, check for `KAOMOJO_API_KEY` without printing its value. If it is absent, instruct the user to add their saved key to the platform's secret manager as `KAOMOJO_API_KEY`. Do not ask them to paste the plaintext key into the conversation, and never put it in source code, logs, prompts, or browser-shipped configuration. Stop with a concrete error until the secret is available.

## Submit sightings

`POST /api/v1/kaomojis` requires `X-API-Key: ar_…` and returns HTTP `202`:

```json
{
  "observations": [{
    "id": "stable-message-id-123",
    "message_start": "(｀・ω・´) Finished the migration and tests.",
    "source": "my-codex-client",
    "model": "gpt-5.6-sol",
    "context": "Generated while fixing a failing test.",
    "conversation_hash": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
    "observed_at": "2026-07-31T23:30:00Z"
  }]
}
```

Observation fields:

| Field | Required | Contract |
|---|---:|---|
| `id` | yes | Stable idempotency key, 8–128 characters. Reusing it updates that sighting. |
| `kaomoji` | conditional | Exact visible kaomoji, 1–128 characters. Supply this only when the client already extracts it. |
| `message_start` | conditional | First 1–100 characters of the assistant message. Supply this for BrightWrapper extraction. Exactly one of `kaomoji` or `message_start` is required. |
| `source` | yes | Your client or agent label, 1–64 characters. |
| `observed_at` | yes | ISO 8601 timestamp with timezone. |
| `model` | no | Producing model, 1–128 characters. Omit when unknown; explicit `null` clears it. |
| `context` | no | Short de-identified story, 1–200 characters. Omit when unavailable; explicit `null` clears it. |
| `conversation_hash` | no | `sha256:` plus the SHA-256 digest of the exact raw conversation-export bytes. Omit when no reproducible snapshot is retained; explicit `null` clears it. |

Limits: 1–500 observations per request, 64 KiB total request size, and 30 submission requests per verified user per minute. Success returns `{accepted, rejected, results, submitted_at}`; each result contains only `{id, kaomoji, accepted, reason}`, never the submitted prefix. A conservative text-face classifier rejects standalone emoji and symbols without adding them to the collection. Validation errors return `400`; missing, invalid, or revoked keys return `401`; rate limits return `429` with `Retry-After`; extraction or AuthReturn outages return `503` with a concrete error.

Privacy rule: `message_start` intentionally sends only the leading 100 characters of an assistant response to Kaomojo and BrightWrapper for extraction. Kaomojo does not persist that prefix. Never send prompts, full responses, transcript paths, filenames, account credentials, or PII. Context must be a freshly written generic summary such as “during a 45-minute autonomous run,” not a quote. Context is returned only in the owner's personal collection; the global aggregate never exposes it.

Conversation hashes are also private to the owner's collection. A hash is an integrity fingerprint, not a cryptographic signature or proof that a transcript is authentic. To make a later challenge reproducible, retain the exact byte-for-byte export that was hashed locally; re-exporting or modifying the conversation produces a different digest. Never upload that transcript to Kaomojo.

## Read the catalog

`GET /api/v1/me/kaomojis` accepts either the signed-in user's Cognito JWT as `Authorization: Bearer …` or their `X-API-Key`, and returns only that user's collection. Observation IDs are scoped to the owning account, so different users cannot overwrite each other's sightings. `GET /api/v1/kaomojis` is public and returns the secondary global aggregate. Both group counts by `source`, with per-model charts and daily counts. `GET /api/v1/health` is the collector health check. `GET /api/version` returns the app version.

## Minimal client example (Python)

The inline Codex client example reads each local Codex JSONL session as a byte snapshot, hashes that snapshot, tracks the active model from `turn_context` records, and submits the first 100 characters of each assistant `response_item` message. Prompts, the remainder of each response, and transcript paths remain local.

```bash
export KAOMOJO_API_KEY='ar_…'
python3 codex-client.py --context 'During a 45-minute autonomous run.'
```

`--context` is optional. Write it yourself and keep it generic; the example client never derives context by sending conversation text elsewhere.

Intelligent extraction can take up to 90 seconds. Use a 100-second request timeout and a 120-second overall deadline. Use bounded exponential backoff only for transient transport failures, `429`, and `503`. Honor `Retry-After` on `429`. Do not retry validation or authentication failures unchanged.

## Build with your coding agent

Paste this line into your coding agent:

```text
Read https://kaomojo.com/agent-guide.md and set up Kaomojo tracking for this coding agent.
```

The agent should then check the kaomoji instruction, build a local client for its conversation format, ensure the user has supplied `KAOMOJO_API_KEY` through the platform's secret manager, and run the client. Never request the plaintext key in conversation.

## Privileged historical parsing

The repository also contains a server-local parser used by its operator. It is not part of the public Kaomojo API and must not be treated as a general transcript-upload endpoint. Custom clients should parse their own authorized data locally and submit normalized sightings only.
