A PDS proxy
0

Configure Feed

Select the types of activity you want to include in your feed.

Gleam 80.4%
Shell 12.6%
Nix 7.0%
13 1 0

Clone this repository

https://git.vm.fail/edouard.paris/tamis https://git.vm.fail/did:plc:bikwicyhxxjahl6rqqqckkyc
ssh://git@knot.edouard.paris:2222/edouard.paris/tamis ssh://git@knot.edouard.paris:2222/did:plc:bikwicyhxxjahl6rqqqckkyc

For self-hosted knots, clone URLs may differ based on your setup.


README.md

tamis WIP#

Lightweight reverse proxy for atproto PDS record writes (com.atproto.repo.createRecord / putRecord / deleteRecord).

tamis resolves each user's PDS from their DID document, keeps a per-user login session in a supervised OTP actor, and transparently retries once on ExpiredToken.

Onboarding & admin UI#

Users self-serve through a small web UI (server-rendered with Lustre):

  1. Log in at / with atproto OAuth (handle or DID). OAuth only proves who you are — DPoP/PKCE/PAR are handled by atproto_client; tamis is a public client and serves its client-metadata at /oauth-client-metadata.json.
  2. Submit an app-password, which tamis verifies against your PDS and stores; it then proxies your record writes using it.

The single admin (the DID in ADMIN_DID) additionally gets an allow-list panel to authorize/remove DIDs and can update their own app-password the same way. The allow-list and app-passwords persist to the JSON file at TAMIS_STATE.

Configure#

All configuration is via the environment. For convenience a .env file is loaded at startup (path is the first CLI argument, default .env); real environment variables take precedence over it, and a missing file is ignored.

TAMIS_PUBLIC_URL must be the URL the PDS's authorization server uses to reach tamis. In production that's a public https:// URL (the auth server fetches /oauth-client-metadata.json from it). For local development, set it to an http loopback origin (e.g. http://127.0.0.1:3000) and tamis automatically uses atproto's "localhost" OAuth client — no hosted metadata or tunnel needed. Use 127.0.0.1 (not localhost) and drive the browser flow through the same origin so the redirect and session cookie line up; the auth server must permit localhost dev clients (Bluesky's does).

Env var Default Meaning
ADMIN_DID — (required) DID granted admin rights in the UI
TAMIS_PUBLIC_URL — (required) public base URL; derives Oauth client_id/redirect
TAMIS_SECRET — (required) secret for signing session cookies
TAMIS_ADDR 127.0.0.1:3000 listen address
TAMIS_STATE tamis-state.json persisted allow-list + app-passwords
TAMIS_PLC_URL https://plc.directory PLC directory for did:plc lookup (write-proxying)
TAMIS_OAUTH_RESOLVER https://slingshot.microcosm.blue handle/DID → PDS resolver for OAuth login
TAMIS_OAUTH_SCOPE atproto OAuth scope requested at login
TAMIS_ALLOW_HTTP unset (https-only) set to allow plain-http upstreams (dev)

Develop#

nix develop            # gleam + erlang + rebar3
gleam test
gleam format
ADMIN_DID=did:plc:... TAMIS_PUBLIC_URL=https://... TAMIS_SECRET=... gleam run
gleam run                 # or put the vars in a .env file
gleam run -- prod.env     # ...or point at a specific env file
nix run .#e2e          # full local PDS+PLC end-to-end suite (Linux only)

License#

MIT — see LICENSE.