A replica of Keytrace
1# Keytrace
2
3Identity verification for ATProto. Link your decentralized identity (DID) to external accounts like GitHub, LinkedIn, Instagram, DNS, and Mastodon with cryptographically signed attestations.
4
5## What is Keytrace?
6
7Keytrace allows Bluesky users to prove ownership of external accounts by:
8
91. **Creating a claim** - Post a verification token to your GitHub gist, DNS TXT record, or other supported platform
102. **Verification** - Keytrace fetches and validates the proof contains your DID
113. **Attestation** - A cryptographic signature is created and stored in your ATProto repo as a `dev.keytrace.claim` record
12
13Claims are user-owned, portable, and stored directly in your ATProto repository.
14
15## Project Structure
16
17```text
18keytrace/
19├── apps/
20│ └── keytrace.dev/ # Nuxt 3 web application
21├── packages/
22│ ├── runner/ # Core verification library (@keytrace/runner)
23│ └── lexicon/ # ATProto lexicon schemas
24```
25
26## Development
27
28```bash
29# Install dependencies
30yarn install
31
32# Start development server
33yarn dev
34
35# Run tests
36yarn test
37
38# Type checking
39yarn typecheck
40
41# Format code
42yarn format
43```
44
45## How Verification Works
46
47The runner package implements a recipe-based verification system:
48
491. **Service Providers** match claim URIs to verification strategies
502. **Recipes** define verification steps as JSON specifications
513. **Verification Steps** are composable actions: `http-get`, `dns-txt`, `css-select`, `json-path`, `regex-match`
52
53Example flow:
54
55```text
56User submits gist URL
57 → Match URI to GitHub provider
58 → Execute recipe: HTTP GET → CSS select → regex match for DID
59 → Extract identity metadata (username, avatar)
60 → Create attestation signature
61 → Write dev.keytrace.claim to user's ATProto repo
62```
63
64## ATProto Lexicons
65
66- `dev.keytrace.claim` - Identity claim linking a DID to an external account
67- `dev.keytrace.recipe` - Verification recipe specification
68- `dev.keytrace.key` - Daily signing key for attestations
69- `dev.keytrace.signature` - Cryptographic attestation structure
70
71## Deployment
72
73### Publishing Packages
74
75Use the deploy script to bump versions and publish all packages to npm:
76
77```bash
78./scripts/deploy.sh patch # 0.0.1 → 0.0.2
79./scripts/deploy.sh minor # 0.0.2 → 0.1.0
80./scripts/deploy.sh major # 0.1.0 → 1.0.0
81```
82
83This will:
841. Bump versions in `@keytrace/runner`, `@keytrace/claims`, and `@keytrace/lexicon`
852. Build all packages
863. Publish to npm
874. Create a git commit and tag
88
89After running, push to remote:
90
91```bash
92git push && git push --tags
93```
94
95
96## Adding a New Service Provider
97
98Want to add support for a new platform (e.g., GitLab, Codeberg, Tangled.) The key requirement is that the platform must have some way for users to **publicly post text content** that Keytrace can fetch and verify — things like profile bios, public posts, gists, comments, or files.
99
100### Proof of Identity Pattern
101
102Every service provider follows the same pattern:
103
1041. The user places a **proof string** (containing their DID) somewhere publicly readable on the service
1052. Keytrace fetches that public URL and checks that the proof string is present
1063. Metadata (username, avatar, profile URL) is extracted from the response
107
108Good proof locations include: public gists/snippets, profile bios, DNS TXT records, public repos, pinned posts, or any content the user controls that's fetchable via HTTP.
109
110You need to be careful that it's a place where only the identity can post. For example you can post a GitHub gist with a keytrace DID but the comments can also contain keytrace DIDs for other people. This could be used to make a false claim.
111
112### What You Need to Create
113
114All you need to touch is the `packages/runner/` package — the web app picks up new providers automatically via the `/api/services` endpoint and a shared `useServiceRegistry` composable.
115
1161. **Create a provider file** in `packages/runner/src/serviceProviders/` implementing the `ServiceProvider` interface:
117 - `id`, `name`, `homepage` — basic metadata
118 - `reUri` — regex to match claim URIs
119 - `ui` — wizard configuration (icon, instructions, proof template, input labels)
120 - `processURI()` — converts a matched URI into fetch + verification config
121 - `postprocess()` — extracts identity metadata (username, avatar, profile URL)
122 - `getProofText()` — generates the proof string for the user
123 - `tests` — URI match test cases
124
1252. **Register it** in `packages/runner/src/serviceProviders/index.ts`
126
1273. **Icon**: Set `ui.icon` to a [Lucide](https://lucide.dev/icons/) icon name (e.g., `"github"`, `"globe"`, `"shield"`) and the web app renders it automatically. If your service needs a custom SVG icon, add a component to `apps/keytrace.dev/components/icons/` and register it in the `iconMap` in `apps/keytrace.dev/composables/useServiceRegistry.ts`. Set `ui.iconDisplay: "raw"` for standalone SVGs (like npm/tangled) that shouldn't be wrapped in a circular badge.
128
129### Using Claude Code to Add a Provider
130
131From the repo root, try a prompt like:
132
133> Add a new service provider for [ServiceName]. Users will prove their identity by [describe the proof location, e.g. "creating a public snippet on GitLab containing their DID", or "adding their DID to their Codeberg profile bio"]. The proof URL format is [e.g. "https://gitlab.com/-/snippets/:id"]. Look at the existing providers in `packages/runner/src/serviceProviders/` for the pattern — especially `github.ts` for an HTTP+JSON example or `dns.ts` for a simpler one. Register the new provider in the index file and add URI match tests.
134
135That should give Claude Code enough to:
136
137- Create a new file in `packages/runner/src/serviceProviders/`
138- Implement the `ServiceProvider` interface (URI regex, `processURI`, `ui` config, `getProofText`, test cases)
139- Register it in `packages/runner/src/serviceProviders/index.ts`
140
141### What Goes in the PR
142
143When you open your PR, please include:
144
145- **How to create a proof**: Step-by-step instructions for how a user creates the public proof on the service (e.g., "go to gitlab.com/-/snippets/new, paste this, make it public")
146- **Example proof URL**: A real or realistic example URL so I can test the flow
147- **Any API quirks**: Rate limits, auth requirements, non-standard response formats, CORS issues, etc.
148- **Fetcher needs**: The existing fetchers are `http`, `dns`, and `activitypub`. If your service needs something different, note that
149
150## License
151
152MIT