# Agent Instructions β jmap-server
## 𧬠Canonical foundation server β every `*-server` extension uses this
This crate is the **foundation that every `jmap-*-server` extension is built
on**. The `Dispatcher`, `JmapHandler` trait, `JmapBackend` supertrait,
`SetError` / `SetErrorType`, `BackendChangesError`, `BackendSetError`,
`ChangesResult`, `QueryResult`, `QueryChangesResult`, and the standard
`/get`, `/changes`, `/query`, `/queryChanges` handlers all live here.
Extension `*-server` crates import these and add their own `Backend`
trait + method handlers on top.
**The propagation rule** (workspace AGENTS.md "Canonical Templates"):
- Any reshape of `Dispatcher`, `JmapHandler`, `JmapBackend`, `SetError`
variants, or the standard handler signatures ripples through every
`*-server` extension crate. Plan the downstream propagation in the
same pass (or file a follow-up sweep bead before merging).
- New variants on `#[non_exhaustive]` enums and new methods on traits
with default impls are the additive shape β no SemVer break, no
propagation churn.
Prefer non-breaking changes. Reshape only when the workspace is bumping
a major.
This project uses **bd** (beads) for issue tracking. Run `bd prime` for full workflow context.
## Before Starting Any Work
1. Read `PLAN.md` β full public API, module layout, settled design decisions, migration notes
2. Run `bd ready` β check for open issues before creating new ones
3. Grep kith source for the relevant type/function before implementing it from scratch
## What This Is
A backend-agnostic JMAP server framework library for Rust. Implements RFC 8620 wire protocol,
request parsing, ResultReference resolution, and `Dispatcher` dispatch machinery.
No auth, no method opinions, no capability URIs. Pure protocol layer.
## Crate Family Context
This crate sits at the base of a planned family (naming: `jmap-{extension}-{role}`):
```
jmap-types (planned) serde/serde_json only β shared wire types
βββ jmap-server this crate β dispatcher, parse, http response helpers
βββ jmap-mail-types (planned)
βββ jmap-chat-types (planned, replaces jmapchat-types)
```
Everything is fluid. See PLAN.md Β§Crate Family for the full graph.
The existing `crate-jmapchat-server` and `crate-jmapchat-client` will eventually be renamed
to `crate-jmap-chat-server` / `crate-jmap-chat-client` to match the convention.
## Source Material
All types and logic exist in kith β this crate is an extraction, not a greenfield impl.
| `JmapError` | `~/PROJECT/kith/crates/kith-core/src/error.rs` |
| `Invocation`, `JmapRequest`, `JmapResponse` | `~/PROJECT/kith/crates/kith-core/src/jmap.rs` |
| `ResultReference`, `Argument<T>` | `~/PROJECT/kith/crates/kith-core/src/resultref.rs` |
| `parse_request`, `resolve_args` | `~/PROJECT/kith/crates/kith-jmap/src/lib.rs` |
| `Dispatcher`, `JmapHandler` trait | `~/PROJECT/kith/crates/kith-jmap/src/lib.rs` |
**Do NOT copy kith-specific items** into this crate:
- `Role` (Owner/Peer) β Tailscale auth concept
- `Identity` β Tailscale WhoIs result
- Method-role ACL table (`METHOD_ROLES`)
- `AuthError`, `KithError`
- Session/capability structs (those stay in kith-jmap and stoa)
## Spec References
This crate implements **RFC 8620** (JMAP base protocol):
```
~/PROJECT/jmap-chat-spec/references/rfc8620.txt β primary normative reference
~/PROJECT/jmap-chat-spec/references/rfc8621.txt β JMAP for Mail (structural analogue)
```
Additional IETF drafts are in `~/PROJECT/jmap-chat-spec/references/` (blobext, quotas, etc.).
The JMAP Chat extension drafts (for `kith`/`stoa` consumers, not this crate):
| Core Chat objects | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-chat-00.md` |
| Push | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-chat-push-00.md` |
| WebSocket events | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-chat-wss-00.md` |
| Federation | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-chat-federation-00.md` |
| FileNode | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-chat-filenode-00.md` |
| CID scheme | `~/PROJECT/jmap-chat-spec/draft-atwood-jmap-cid-00.md` |
**Stale copies exist in** `jmap-chat-js/docs/`, `jmap-chat-jsbig/docs/`, and `~/GIT/ideas/`.
Always use `~/PROJECT/jmap-chat-spec/` as the authoritative source.
## Non-Interactive Shell Commands
Shell commands like `cp`, `mv`, `rm` may be aliased with `-i` on this system β use explicit
flags to avoid hanging on confirmation prompts:
```bash
cp -f source dest # NOT: cp source dest
mv -f source dest # NOT: mv source dest
rm -f file # NOT: rm file
rm -rf directory # NOT: rm -r directory
cp -rf source dest # NOT: cp -r source dest
```
Other commands that may prompt:
- `scp` / `ssh` β use `-o BatchMode=yes`
- `apt-get` β use `-y`
## Build & Test
```bash
cargo fmt --all
cargo clippy -- -D warnings
cargo test
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps
```
Run all four before considering any work done.
## Design Constraints (Settled β Do Not Revisit)
| Async vs sync | Always async (tokio) | No sync path; `maybe-async` is dead weight |
| Auth | HTTP layer authenticates; JMAP layer reads caller via `JmapBackend::principal_id` | Foundation provides the identity seam (bd:JMAP-ga0q.1); backends decide what to do with it. **Handler-side permission gates are FORBIDDEN β backends are canonical.** |
| `max_calls` | Parameter to `parse_request` | Each consumer sets its own limit |
| Unknown method | `unknownMethod` error invocation | Not a crash, not a 4xx |
| Panic isolation | `tokio::task::spawn` per handler | Panicking handler β `serverFail`, not crashed task |
| `createdIds` | Accumulated by dispatcher | Per RFC 8620 Β§3.4 |
| Unsafe code | Forbidden | `#[forbid(unsafe_code)]` at crate root |
## Backend trait rule: secret-minting methods require CSPRNG
Any new method on `JmapBackend` (or on a downstream `*Backend` extension
trait) that **mints credential-grade material** β verification codes,
invite codes, push-subscription tokens, ownership proofs, anything an
attacker could exploit by guessing β MUST:
1. **In the trait method's doc comment**, require a CSPRNG verbatim:
*"Implementations MUST use a cryptographically-secure random number
generator (e.g. `OsRng` / `getrandom::getrandom`). Do not derive from
a clock, a counter, or any process-local non-CSPRNG source."*
2. **In the reference `MemoryBackend` implementation**, actually use
`OsRng` / `getrandom` β not a timestamp, not a counter, not
`rand::thread_rng` (which is CSPRNG today on most platforms but is
not contractually guaranteed to remain so).
Precedent: bd:JMAP-sc1b.78 (`ChatBackend::generate_invite_code` trait
doc CSPRNG requirement) and the matching reference-impl audit work in
bd:JMAP-sc1b.93. Forward-looking placeholder for the
`PushSubscriptionBackend::generate_verification_code` method when the
RFC 8620 Β§7.2 surface lands: bd:JMAP-sc1b.101.
## Cross-Crate Consistency
When this crate is consumed by kith or stoa:
- kith re-exports `JmapError`, `JmapRequest`, `JmapResponse`, `Invocation`, `ResultReference`
from this crate; its own copies are deleted
- stoa deletes `crates/mail/src/jmap/types.rs` and rewrites its dispatcher using `Dispatcher<StoaCallerCtx>`
If you change a public API type or function signature, check that both consumers still compile.
## Subagent Guidance
- Spawn subagents for parallel extraction work on independent modules (`types.rs` vs `parse.rs`)
- Never spawn two subagents editing the same file β serialize those
- Each subagent reads only what it needs β grep for specific symbols; do not dump full files
- For consistency checks between kith source and extracted code, give the subagent both files explicitly
- If a subagent makes 3 failed attempts at the same error without progress, stop and escalate
## Restrictions
- Push freely β `git push`, no `pull --rebase` ritual (workspace AGENTS.md "Git Commit and Push Policy")
- Do not use TodoWrite or markdown task lists β use `bd create` for all tracking
- Do not add features not in PLAN.md or not explicitly directed
- Do not introduce dependencies beyond: serde, serde_json, tokio, http, thiserror
- Do not add auth logic, role checks, capability structs, or application-specific types