{"id":51718480,"url":"https://github.com/ubugeeei/learn-at","last_synced_at":"2026-07-17T06:38:24.486Z","repository":{"id":371046641,"uuid":"1296029259","full_name":"ubugeeei/learn-at","owner":"ubugeeei","description":"A hands-on guide to AT Protocol that builds both a Scala 3 client and a Personal Data Server (PDS).","archived":false,"fork":false,"pushed_at":"2026-07-13T00:22:33.000Z","size":437,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-17T06:38:10.452Z","etag":null,"topics":["at-protocol","blues","mas","pds","protocol","sca","sns"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ubugeeei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-10T04:02:34.000Z","updated_at":"2026-07-13T00:22:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ubugeeei/learn-at","commit_stats":null,"previous_names":["ubugeeei/learn-at"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ubugeeei/learn-at","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubugeeei%2Flearn-at","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubugeeei%2Flearn-at/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubugeeei%2Flearn-at/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubugeeei%2Flearn-at/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ubugeeei","download_url":"https://codeload.github.com/ubugeeei/learn-at/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ubugeeei%2Flearn-at/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35571461,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-17T02:00:06.162Z","response_time":116,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["at-protocol","blues","mas","pds","protocol","sca","sns"],"created_at":"2026-07-17T06:38:23.870Z","updated_at":"2026-07-17T06:38:24.479Z","avatar_url":"https://github.com/ubugeeei.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# learn-at\n\nA hands-on guide to AT Protocol that builds both a Scala 3 client and a Personal\nData Server (PDS).\n\nThis repository does not begin with a finished SDK. It constructs string\nvalidation, JSON, HTTP, DID resolution, DAG-CBOR, CIDs, CAR, Merkle Search\nTrees, signed repositories, synchronization, and authentication in dependency\norder. Every chapter covers:\n\n- why the mechanism exists;\n- the invariants required by the specification;\n- a minimal Scala 3 implementation;\n- commands that let you observe it;\n- exercises that deliberately break it;\n- the remaining gap before production use.\n\n## Start here\n\nThere are three useful entry points. They serve different jobs:\n\n1. [`README.md`](README.md) is the map of the repository.\n2. [`docs/00-prerequisites.md`](docs/00-prerequisites.md) explains the web,\n   identity, hash, signature, JSON, and schema ideas assumed by the book.\n3. [`docs/00-learning-path.md`](docs/00-learning-path.md) is the table of\n   contents. Read the chapters in number order.\n4. [`src/learnat/LearnAt.scala`](src/learnat/LearnAt.scala) is the executable\n   entry point. Run it when you want to observe the implementation.\n\nIf you want to read code before prose, use the\n[`src/README.md`](src/README.md) source tour. It traces one record through the\nclient, validation, repository, cryptography, and storage boundaries.\n\nThe source tree is organized by concept, not by build phase. Production code\nand its executable test sit beside each other:\n\n```text\nsrc/learnat/\n├── LearnAt.scala                 one obvious executable entry point\n├── json/\n│   ├── Json.scala                implementation\n│   └── Json.test.scala           examples, edge cases, and rejection paths\n├── syntax/\n│   ├── Identifiers.scala\n│   ├── Identifiers.test.scala\n│   └── IdentifiersInterop.test.scala\n└── ...                           one directory per protocol concept\n```\n\nThe `.test.scala` suffix is the boundary: sbt compiles ordinary `.scala` files\nas the application and adjacent `.test.scala` files as tests. This keeps the\ncode you are learning and the evidence for its behavior on the same screen\nwithout shipping test code in the application.\n\n## Run it\n\nThe development environment is a Nix flake. You do not need to install the JDK,\nScala, or sbt separately. Protocol codecs remain implemented in the repository;\nthe local server uses Undertow Core for standards-compliant HTTP/WebSocket\ntransport instead of reimplementing a network server.\n\n```console\n$ nix develop --command sbt verify\n$ nix develop --command sbt run\n```\n\nFormat all Scala and sbt sources with the repository-pinned formatter:\n\n```console\n$ nix develop --command sbt scalafmtAll\n```\n\n`verify` runs `scalafmtCheckAll`, so CI rejects formatting drift.\n\nRun the local client/server exercise:\n\n```console\n$ LEARN_AT_PASSWORD=local-secret nix develop --command sbt \"run pds 2583\"\n$ LEARN_AT_PASSWORD=local-secret nix develop --command sbt \\\n    'run client post http://localhost:2583 alice.test com.example.note \"hello\"'\n```\n\nThe local PDS persists its development key, records, last revision, and bounded\nfirehose history under `data/local-pds` by default. Keep the same port across\nrestarts because it is part of the localhost `did:web` identifier.\n\nStart with the [learning path](docs/00-learning-path.md). Implementation\nchapters point to the matching source and explain why it has its current shape,\nwhich invariants it enforces, how tests break those invariants, and what is\nstill intentionally missing. See\n[the Nix environment chapter](docs/02-environment.md) for setup details and the\n[glossary](docs/glossary.md) whenever a protocol term is unfamiliar.\n\n## Target skills\n\nBy the end, you should be able to explain, implement, and debug all of these:\n\n- follow the relationship among a handle, DID, DID document, and PDS;\n- read a Lexicon and construct XRPC requests and responses;\n- use a CLI client with an arbitrary PDS;\n- encode records as DAG-CBOR and verify their content with CIDs;\n- build and verify an MST and signed repository commit;\n- use CAR exports and a firehose for continuous synchronization;\n- host a local account and read or write it from a separate client;\n- explain OAuth discovery, PKCE, PAR, DPoP, and legacy-session differences;\n- evaluate persistence, rate limits, key custody, moderation, and backup needs.\n\nEvery chapter and the [implementation scope](docs/architecture/scope.md) keeps\n“implemented for learning” distinct from “required for a production PDS.”\nThe [coverage matrix](docs/architecture/coverage.md) links every claimed topic\nto its explanation, runnable implementation, executable specification, and\nexplicit exclusions.\n\n## Specification baseline\n\nThe normative source is the [AT Protocol specifications](https://atproto.com/specs/atp).\nThis guide was checked on 2026-07-10 against the official\n`bluesky-social/atproto` implementation at commit\n`a9ff2da83b93e5211f45667e652f8a928f4dce29`. When the guide and specification\ndisagree, follow the specification.\n\nThe project uses Scala 3.8.4 and sbt 1.10.11 for the build definition only.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubugeeei%2Flearn-at","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fubugeeei%2Flearn-at","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fubugeeei%2Flearn-at/lists"}