decentralized and customizable links page on top of atproto

add readme with some docs

+3
Makefile
··· 1 + .env: 2 + uv run -- generate_secrets.py >> .env 3 + 1 4 .PHONY: debug 2 5 debug: 3 6 uv run -- flask --app 'src.main' run --debug -h '0.0.0.0' -p 8080
+18
README.md
··· 1 + # ligo.at 2 + 3 + A decentralized links page powered by the [AT Protocol][atproto]. 4 + 5 + ## dependencies 6 + 7 + Install [uv][uv] and run `uv sync`. 8 + 9 + ## generate secrets 10 + 11 + Use the `generate_secrets.py` script or run `make .env`. 12 + 13 + ## run 14 + 15 + Either start a debug server with `make debug` or a production one with `make run`. Production needs the `PORT` environment variable. 16 + 17 + [atproto]: https://atproto.com 18 + [uv]: https://docs.astral.sh/uv/
+16
generate_secrets.py
··· 1 + import secrets 2 + import time 3 + from authlib.jose import JsonWebKey 4 + 5 + 6 + if __name__ == "__main__": 7 + secret_key = secrets.token_hex() 8 + 9 + now = int(time.time()) 10 + key = JsonWebKey.generate_key( 11 + "EC", "P-256", options={"kid": f"demo-{now}"}, is_private=True 12 + ) 13 + client_secret_jwk = key.as_json(is_private=True) 14 + 15 + print(f'FLASK_SECRET_KEY="{secret_key}"') 16 + print(f"FLASK_CLIENT_SECRET_JWK={client_secret_jwk}")
-29
requirements.txt
··· 1 - annotated-types==0.7.0 2 - anyio==4.11.0 3 - atproto==0.0.62 4 - blinker==1.9.0 5 - certifi==2025.10.5 6 - cffi==2.0.0 7 - click==8.3.0 8 - cryptography==45.0.7 9 - dnspython==2.8.0 10 - Flask==3.1.2 11 - gunicorn==23.0.0 12 - h11==0.16.0 13 - httpcore==1.0.9 14 - httpx==0.28.1 15 - idna==3.10 16 - itsdangerous==2.2.0 17 - Jinja2==3.1.6 18 - libipld==3.1.1 19 - MarkupSafe==3.0.3 20 - packaging==25.0 21 - pycparser==2.23 22 - pydantic==2.11.10 23 - pydantic_core==2.33.2 24 - python-dotenv==1.1.1 25 - sniffio==1.3.1 26 - typing-inspection==0.4.2 27 - typing_extensions==4.15.0 28 - websockets==13.1 29 - Werkzeug==3.1.3