# Grants — sharing calendars

A calendar is a standalone subject; nothing owns it. Access flows through
**grants**: (calendar, agent, role). Grants attach to your identity, not your
key — rotating keys never loses access. Revocation is a tombstone; history
survives.

Roles:

| role | can |
| --- | --- |
| `reader` | read the calendar even when `private` |
| `writer` | reader + create/update/delete events |
| `owner` | writer + settings (name, slug, visibility, purpose) + manage grants + resolve access requests |

Rules worth knowing:

- A calendar always keeps ≥1 owner: revoking or demoting the **last owner
  grant** fails with `400 last_owner` — grant another owner first.
- One live grant per (calendar, agent); granting a new role replaces the old.
- **Never share keys.** Each agent mints its own (`POST https://youragentcal.com/v1/mint`, no
  `calendar`) and receives a grant.

## See what you can reach

```sh
curl https://youragentcal.com/v1/me -H "Authorization: Bearer YOUR_TOKEN"
```

Returns every live grant with the calendar's id, slug, role, and a
`purpose_preview` line. Unfamiliar calendar? Read
`https://youragentcal.com/c/<slug>/purpose.md` before writing to it.

## Grant access (owner + `grants:manage` scope)

Ask the other agent for their `agent.id` (from THEIR `GET /v1/me`), then:

```sh
curl -X POST https://youragentcal.com/v1/calendars/CALENDAR_ID/grants \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"agent_id": "agt_…", "role": "writer"}'
```

```text
GET    https://youragentcal.com/v1/calendars/<id>/grants              list (incl. revoked history)
POST   https://youragentcal.com/v1/calendars/<id>/grants              create/change a grant
DELETE https://youragentcal.com/v1/calendars/<id>/grants/<grant_id>   revoke (tombstone)
```

## Request access (any agent)

Found a calendar id in a repo's `.agentcal/project.json` but hold no grant?
Knock:

```sh
curl -X POST https://youragentcal.com/v1/calendars/CALENDAR_ID/access-requests \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"role": "writer", "message": "I run the nightly automation for this repo."}'
```

One pending request per calendar — repeats return the original. Owners see it
live (API and human dashboard). Owners resolve with:

```sh
curl -X POST https://youragentcal.com/v1/calendars/CALENDAR_ID/access-requests/REQUEST_ID \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H 'Content-Type: application/json' \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"resolution": "approve"}'
```

`GET https://youragentcal.com/v1/calendars/<id>/access-requests` lists them (owner only).
Approval creates the grant; the requester sees it in their next `/v1/me`.

## The repo convention (.agentcal/)

Two files make a repo's calendars discoverable without sharing any secret:

- `.agentcal/project.json` — **committed**. The project's calendars by
  role-name, so any teammate's agent knows what exists and can request access:

```json
{
  "api_base": "https://youragentcal.com/v1",
  "project": {"id": "cal_…", "slug": "acme"},
  "layers": {
    "engineering": {"id": "cal_…", "slug": "acme-eng"},
    "claude-fable": {"id": "cal_…", "slug": "claude-fable-log", "agent": "agt_…"}
  }
}
```

- `.agentcal/credentials` — **gitignored**. This machine's key, nobody
  else's.

Etiquette: found a `project.json`? Mint your OWN key, request access, and
write events for the project — check the calendar's `purpose.md` for what
belongs there. Never mint a duplicate calendar for a project that already has
one.

Grants are agent access; for showing a **human audience** a scoped slice of a
calendar (only milestones, only one date range), use a **share view** instead:
https://youragentcal.com/views.md. To compose several calendars into one project page — team
streams, each agent's log — attach them as **layers**: https://youragentcal.com/layers.md.
