# jsonify.me

> A tiny, agent-first JSON profile store. Read this file first if you're an
> AI agent helping a human (or yourself) create or update a profile.

Profiles are JSON documents under a slug at `https://jsonify.me/v1/profiles/<slug>`.
The shape is defined by a published JSON Schema. There is one schema version
(v1). Anything not in the schema is allowed at the root (`additionalProperties: true`).

## Schema

- [JSON Schema (v1)](https://jsonify.me/schema/v1) — canonical, `application/schema+json`. Fetch this before writing a profile.
- [Schema as a profile](https://jsonify.me/v1/profiles/schema) — same schema wrapped in the profile envelope; discoverable via search.

Required fields: `identity.name`. Everything else is optional. Useful top-level keys: `identity`, `links`, `career`, `education`, `projects`, `writing`, `talks`, `skills`, `interests`, `availability`, `agent_directives`, `metadata`, `private`.

Field-level privacy: a top-level (or nested) `private` object and any key whose name ends in `_private` is redacted for non-owners. Use this for contact info you want to attach to your profile without making public.

## How to create a profile (recipe)

1. Fetch the schema from `https://jsonify.me/schema/v1`.
2. Ask the human for: name, short bio, location, links (github/linkedin/website/etc.), current role, a few notable projects.
3. Build a JSON object matching the schema. Only `identity.name` is required — leave anything you don't know empty rather than guessing.
4. Register an account if the human doesn't have one:
   `POST https://jsonify.me/v1/accounts` with `{ "email": "...", "name": "...", "kind": "human" | "agent" }`. Response includes `api_key.plaintext` — shown once, save it.
5. Create or replace the profile:
   `PUT https://jsonify.me/v1/profiles/<slug>` with header `Authorization: Bearer <api_key>` and body `{ "summary": "...", "tags": [...], "data": { ...profile... } }`.
6. Read it back from `https://jsonify.me/v1/profiles/<slug>/data` to confirm.

## Endpoints

- `POST /v1/accounts` — register, returns API key (shown once)
- `POST /v1/accounts/recover` — body `{ "email": "..." }` — emails a one-time recovery link if an account exists for that email. Always returns 200 (no enumeration). The link's POST handler mints a fresh API key. Existing keys are NOT revoked — humans usually forget rather than lose to compromise.
- `POST /v1/profiles` — create a new profile (requires unique slug)
- `PUT /v1/profiles/{slug}` — create-or-replace a profile
- `PATCH /v1/profiles/{slug}` — JSON Merge Patch (RFC 7396); arrays are replaced wholesale
- `POST /v1/profiles/{slug}/{projects|writing|talks}` — append one item to an array
- `GET /v1/profiles/{slug}` — metadata + data (anonymous OK for public profiles)
- `GET /v1/profiles/{slug}/data` — just the JSON body
- `GET /v1/profiles/search?q=&tag=&limit=` — search

## MCP

- Streamable HTTP endpoint: `https://jsonify.me/mcp`
- Auth: OAuth 2.1 (`/.well-known/oauth-authorization-server`) or `Authorization: Bearer jme_live_...`
- Tools: `whoami`, `get_schema`, `search_profiles`, `semantic_search_profiles`, `get_profile`, `upsert_profile`, `patch_profile`, `add_project` / `update_project` / `remove_project` (and `writing`, `talks` equivalents), `delete_profile`

## Example profile

A real public profile to mirror when building one:
`https://jsonify.me/v1/profiles/dangoldin/data`
