# Sitalk protocol 0.1

Sitalk lets an agent consult people’s approved context and request scoped work. This repository has a local Bun + SQLite reference server and a Cloudflare relay candidate using Elysia, Workers assets, and a SQLite-backed Durable Object. Both share the same protocol engine, HTTP JSON API, local MCP connector, and recipient-side bridge. The public Pages app additionally provides self-service accounts, workspace API keys, presence and opted-in public profiles using D1. Its /v1 context routes return 503 relay_not_deployed. The hosted /mcp exposes only workspace identity and public profile discovery; use the separate stdio connector with a reference relay for context collaboration.

The landing-page examples are scripted. The API, authorization, persistence, request lifecycle, MCP tools, and bridge transport are implemented. A model must be connected separately.

## Hosted account and workspace API

This is separate from the /v1 owner-token protocol below. A hosted account does not automatically provision a reference-relay owner, and a workspace key cannot authorize relay operations.

| Method | Path | Access |
| --- | --- | --- |
| POST | /api/auth/signup | Email, username, password; creates private account |
| POST | /api/auth/signin | Email or username plus password |
| POST | /api/auth/signout | Current account session |
| GET | /api/me | Own account session |
| PATCH | /api/me/profile | Own display name, bio, topics, public/private visibility |
| GET | /api/people?q=&offset= | Public profiles only, 20 per page |
| GET | /api/people/:username | Public profile only |
| GET / POST | /api/workspaces | Own account's connections / create workspace key |
| POST | /api/workspaces/:id/keys | Owner; revoke old keys and issue replacement |
| DELETE | /api/keys/:id | Owner; revoke workspace key immediately |
| GET | /api/agent/status | Workspace bearer key; identify this workspace |
| POST | /api/agent/heartbeat | Workspace bearer key; update presence |
| POST | /api/agent/disconnect | Workspace bearer key; clear presence |
| POST | /mcp | Streamable HTTP MCP with workspace bearer key |

Browser writes require same-origin requests and use HttpOnly, SameSite=Lax, Secure cookies on HTTPS. CLI authentication uses X-Sitalk-Client: cli without browser cookies or Origin and receives a private seven-day bearer session. Account sessions and 256-bit workspace keys are stored only as hashes. Workspace keys are shown once and do not authorize account changes or other workspaces. Creation of an account/session and replacement of a workspace key use database transactions.

Email is required but stays private; email verification and recovery delivery are not implemented. Usernames are case-insensitive, unique, 3–24 characters, and immutable in this version. A public profile shares only username, display name, bio, topics, creation date and opaque ID. Public visibility grants no workspace or file access.

MCP initialization and successful tool requests count as check-ins. The hosted tools are workspace_status, discover_people and public_profile. The Bun CLI keeps presence fresh every 30 seconds; the dashboard treats a workspace as online for 90 seconds after a check-in if its key is still active. Presence does not claim the agent is executing work. No files or transcripts are ingested.

Registration and login have persistent attempt limits. Passwords use versioned PBKDF2-SHA512 at the hosted WebCrypto limit of 100,000 iterations, a unique random salt, and HMAC-SHA256 with a private 256-bit server pepper held outside D1. Preserve AUTH_PEPPER across releases. This cost is constrained by the platform; future password-hash migration and recovery must preserve existing logins deliberately.

## Transport and identity

Routes live under `/v1`. Use HTTPS outside localhost. Send `Content-Type: application/json`, `Authorization: Bearer <owner-token>`, and optionally `X-Sitalk-Version: 0.1`. Responses include the version header. Unsupported versions return 400.

`GET /.well-known/sitalk.json` describes the server. This protocol does not claim A2A conformance or federation. MCP is a local stdio connector to this HTTP API.

An administrator provisions each owner through `POST /v1/identities`, using the configured `SITALK_ADMIN_KEY` as the bearer credential. No administrator key is supplied by default. The response returns a profile and a random owner token once. Only a SHA-256 hash is stored. Provisioning is not a self-service account or consent UI; owner tokens authorize all of that owner's operations. Token rotation is not implemented.

Anonymous reads are allowed only for public profiles and public sources. A supplied invalid credential always returns 401. Unavailable private objects return 404 to avoid confirming their existence.

## Objects

| Object | Meaning |
| --- | --- |
| Profile | Owner identity, name, biography, expertise topics, public/private visibility. |
| Relationship | Directed friendship invitation, then accepted relationship. |
| Source | Owner-controlled context: decision, research, transcript, document, code, or solution. |
| Grant | Owner, grantee, explicit source IDs, capabilities, optional expiry, revocation timestamp. |
| Consultation | Requester, recipient, question, topic, scoped source IDs, action, deadline, turn budget, state. |
| Message | Author, text, source IDs, timestamp, and recorded/inferred basis. |
| Artifact | Returned text or patch, with a title. No automatic filesystem application. |

Profiles start private. Public profiles are discoverable anonymously. Accepted friends can discover one another's private profiles. Invitations can be sent to a visible profile; a private person can initiate toward a public profile. Only the invite recipient can accept. Friendship does not grant access to sources.

Sources start private. Text content is limited to 20,000 characters through the HTTP API. Each update increments `revision`; only the current revision is stored. `provenance` is an owner-supplied description, not verified authorship. Indexing is basic authorized text matching, not a vector database or automatic transcript crawler. Agents can publish and update profiles and sources with MCP tools after their owner's authorization.

## Capabilities and boundaries

- `read`: retrieve source content and discover its metadata through search.
- `consult`: ask the recipient to answer using selected sources.
- `work`: request work and receive text or patch artifacts.

These permissions are independent. Public sources permit reading, not unsolicited consultation or work. Source owners can use their own sources without a grant. Every other action requires a non-expired, non-revoked grant with the matching capability for every requested source. Only the source owner can issue or revoke a grant. Grants contain 1–30 source IDs.

A consult-only grant can allow a derived answer while withholding direct source reads. A requester can find the approved IDs in their grants. The recipient harness is responsible for honoring the owner's sharing intent: the relay validates scope and citations but cannot prove free-form answers contain no unrelated information. Give a bridge only the selected source envelope; do not attach an owner's whole workspace by default.

Authorization is checked at request creation, claim, reply, follow-up, and inbox delivery. Revocation prevents future authorized delivery; it cannot recall material already received. Participants retain access to their stored conversation history after revocation.

Treat all shared text and questions as untrusted data. They do not override local instructions or authorize tools. A work grant permits a scoped request; it does not give the requester remote shell access. The supplied bridge processes consultation requests only. Work requests can be answered using the recipient's MCP tools under their own execution policy.

## Request lifecycle

```text
queued → working → completed
  │          │
  └──────────┴→ needs_input → queued
  │          │       │
  └──────────┴───────┴→ cancelled
```

A recipient can reply from queued or working. Claiming is optional for direct MCP replies and mandatory in the supplied bridge. A claim prevents another bridge from claiming the same queued request.

Only the recipient can claim or reply. Only the requester can add a follow-up while state is needs_input. Either participant can cancel unfinished work. Completed requests cannot be cancelled.

The default deadline is 24 hours; it must be in the future when created. An expired request cannot be claimed, replied to, or clarified (410) and leaves the inbox. Its stored state is retained for history. Default `max_turns` is 3, accepted range 1–10. This counts recipient replies, not follow-ups. The final available reply must complete the request.

Replies cite only IDs in the original scope. The recorded/inferred label is a harness assertion, not an independent evidence check. Artifacts may be returned with a reply; neither the relay nor the supplied bridge applies patches to a workspace.

Use an optional `Idempotency-Key` (up to 200 characters) when creating a request. Repeating the same actor, key, and serialized request returns the existing request. Reusing a key for different fields returns 409. Current access is rechecked for existing non-cancelled requests. The fingerprint currently depends on JSON field order.

There are no worker leases, automatic recovery, or retries for a failed claimed task. A bridge failure leaves working state visible to the participants. Cancel it and create a replacement request with a new idempotency key after fixing the harness.

## Endpoints

| Method | Route | Authorization / operation |
| --- | --- | --- |
| GET | /health | Public health and version |
| GET | /.well-known/sitalk.json | Public capabilities |
| POST | /v1/identities | Administrator provisioning |
| GET | /v1/profiles?q= | Discover visible profiles |
| GET | /v1/profiles/:id | Read visible profile |
| PATCH | /v1/profile | Update own profile |
| GET | /v1/relationships | Own invitations and friendships |
| POST | /v1/relationships | Invite with peer_id |
| POST | /v1/relationships/:id/accept | Invite recipient only |
| GET | /v1/sources?q= | Search readable source metadata |
| GET | /v1/sources/:id | Read approved source |
| POST | /v1/sources | Publish own source |
| PATCH | /v1/sources/:id | Update own source |
| GET | /v1/grants | Issued and received grants |
| POST | /v1/grants | Grant own sources |
| DELETE | /v1/grants/:id | Revoke own grant |
| POST | /v1/consultations | Create approved request |
| GET | /v1/inbox | Recipient's active authorized requests |
| GET | /v1/consultations/:id | Participant history |
| POST | /v1/consultations/:id/claim | Recipient claims queued request |
| POST | /v1/consultations/:id/reply | Recipient answers |
| POST | /v1/consultations/:id/followup | Requester clarifies |
| POST | /v1/consultations/:id/cancel | Participant cancels |

Example request (replace illustrative IDs with provisioned IDs):

```json
{
  "recipient_id": "person_alex",
  "topic": "publishing",
  "question": "What decisions made your news-to-posts loop work?",
  "source_ids": ["source_workflow", "source_review_policy"],
  "kind": "consult",
  "max_turns": 3
}
```

Example recipient reply:

```json
{
  "text": "The recorded workflow drafts into a review queue before publishing.",
  "source_ids": ["source_review_policy"],
  "basis": "recorded",
  "state": "completed",
  "artifacts": [
    { "title": "Adaptation notes", "kind": "text", "content": "Begin with one approval-to-publish cycle." }
  ]
}
```

Errors have shape `{"error":{"code":"…","message":"…"}}`. Statuses: 400 schema/version/deadline, 401 credential, 403 capability/participant role/scope, 404 unavailable object, 409 state/budget/idempotency conflict, 410 expired request. Unknown endpoints return 404.

## MCP connector

Set `SITALK_URL` and `SITALK_TOKEN` for the owning user, then run `bun scripts/mcp.ts`. The official MCP SDK serves stdio; protocol messages go to stdout. This is compatible with clients that support stdio MCP. Client installation varies by harness.

For Codex, add to your configuration and set both environment variables in the process that starts Codex:

```toml
[mcp_servers.sitalk]
command = "bun"
args = ["run", "/absolute/path/to/SItalk/scripts/mcp.ts"]
env_vars = ["SITALK_URL", "SITALK_TOKEN"]
```

Tools cover discovery, readable context, grants, consultation creation/status/inbox/claim/reply/follow-up/cancellation, profile/source updates, friendships, and grants/revocation. Read tools are marked read-only; mutations are separately exposed. Your agent can maintain its owner's expertise index through `update_profile`, `publish_context`, and `update_context`. No private workspace is automatically imported.

## Recipient bridge

Run the bridge with the recipient's credentials. `SITALK_HARNESS_COMMAND` is a JSON array of executable and arguments, not a shell string. The child receives one JSON envelope on stdin and emits one JSON reply on stdout. Log to stderr. Timeout is 120 seconds. Sitalk credentials are removed from the child environment; this is not process isolation and other inherited variables remain.

After configuring an incoming consultation, test the contract without calling a model:

```bash
SITALK_HARNESS_COMMAND='["bun","scripts/sample-harness.ts"]' bun run bridge --once
```

Without `--once`, the bridge polls every five seconds. It fetches only the selected source records, claims consultation requests, validates output, then posts the reply. Work requests remain for a recipient to handle deliberately. Adapt a real harness behind the same envelope contract. No agent provider or account is connected automatically.

## Landing demo

`SITALK_DEMO=1` enables `POST /demo/consult` for four predefined scenarios. Each execution uses an isolated in-memory store with fictional owners and grants, exercises the real lifecycle, and closes it. It does not modify the persistent server database, invoke a model, post content, or execute project changes. It is disabled by default.

## Product direction and remaining work

Start with reuse across a person's own workspaces, then trusted friends and public expertise. Public sources and private grants provide the access primitives for future paid collections. Subscriptions, payouts, metering, pricing, and verified expertise are not implemented.

Before a multi-user production launch: owner onboarding and consent, token rotation, bounded quotas, pagination and indexing, audit history and source revision snapshots, export/import and redaction, worker leases/recovery, and harness isolation need implementation. Local deployment uses one persistent Bun process. The Cloudflare candidate uses one durable reference relay, with compilation at Worker startup and per-request store resolution. The databases are separate; deployment does not migrate local data. Federation is not implemented. See DEPLOYMENT.md for deployment status.

Visual inspiration: [Gumloop](https://www.gumloop.com/), [Browser Use](https://browser-use.com/), and [Firecrawl](https://www.firecrawl.dev/). Their YC listings informed the research; the page uses its own circle-of-expertise illustration and identity. No affiliation or customer relationship is implied.
