Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ALPo5Y86fzQjsALNZRSSG5
2.8 KiB
name, description, metadata
| name | description | metadata | ||||||
|---|---|---|---|---|---|---|---|---|
| tangled-bot-and-repo-creation | notplants-bot bsky creds location + how to create a Tangled repo programmatically |
|
The Tangled bot account notplants-bot.bsky.social (DID did:plc:qfngkejlw4ghji2myc73hbdh,
PDS https://auriporia.us-west.host.bsky.network). Its bsky password is in
.secrets/notplants-bot.bsky.social.env in the PO repo — gitignored via /.secrets/, perms 600,
never committed. (Consider rotating to an atproto app-password; the stored one looks like the main pw.)
Tangled SSH-path gotcha (THE big one): the git@tangled.org SSH proxy matches the repo by its
rkey, which is the lowercased repo name — and the match is case-sensitive. A path with capitals
(…/Apertus-70B-Instruct-2509-experiments) returns "repo not found" even when you have access;
use the lowercased form (…/apertus-70b-instruct-2509-experiments). This misled a whole session into
thinking it was a network/permissions problem — it was just case. "repo not found" over SSH usually
means wrong rkey case or wrong owner path, NOT lack of access (access denial looks different).
Address repos on the proxy by the owner's atproto handle/DID (e.g. notplants.bsky.social /
its DID 3nog…), NOT the knot-storage repoDid shown in clone-URL redirects (e.g. 54ba…). The
repoDid is just where bytes live (handleless, PDS=knot1); it is never the SSH path.
Networking: knots like knot1.tangled.sh are Cloudflare-fronted — SSH (port 22) to a knot host
is unreachable from this box, but HTTPS (443) works, and git push always goes through the
reachable git@tangled.org proxy anyway (it routes to the knot internally), so this rarely matters.
Create a repo programmatically as the bot (no CLI exists; this is what the web "+ new repo" does):
com.atproto.server.createSessionon the PDS →accessJwt,did.com.atproto.server.getServiceAuth?aud=did:web:knot1.tangled.sh&lxm=sh.tangled.repo.create&exp=<now+300>withAuthorization: Bearer <accessJwt>→ service-authtoken.POST https://knot1.tangled.sh/xrpc/sh.tangled.repo.create(Bearer = service token, JSON{rkey,name,defaultBranch:"main"}) →{repoDid}. (Needsserver:memberon the knot; the bot already has it since it pushes existing repos there.)POST <PDS>/xrpc/com.atproto.repo.createRecord(Bearer = accessJwt) collectionsh.tangled.repo, record{$type:"sh.tangled.repo", knot:"knot1.tangled.sh", name, description, createdAt, repoDid}.git push git@tangled.org:<bot-handle>/<rkey> main. (rkey = lowercased name.)
Repo created this way: https://tangled.org/notplants-bot.bsky.social/apertus-70b-instruct-2509-experiments
(holds the opencode/Apertus-70B config). Related: tangled-mirrors.