Files
project-orchestrator/memory/tangled-bot-and-repo-creation.md

43 lines
2.8 KiB
Markdown

---
name: tangled-bot-and-repo-creation
description: notplants-bot bsky creds location + how to create a Tangled repo programmatically
metadata:
node_type: memory
type: reference
originSessionId: 5c93c441-4896-4a82-9dc4-0f7f39db24f0
---
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):
1. `com.atproto.server.createSession` on the PDS → `accessJwt`, `did`.
2. `com.atproto.server.getServiceAuth?aud=did:web:knot1.tangled.sh&lxm=sh.tangled.repo.create&exp=<now+300>`
with `Authorization: Bearer <accessJwt>` → service-auth `token`.
3. `POST https://knot1.tangled.sh/xrpc/sh.tangled.repo.create` (Bearer = service token, JSON
`{rkey,name,defaultBranch:"main"}`) → `{repoDid}`. (Needs `server:member` on the knot; the bot
already has it since it pushes existing repos there.)
4. `POST <PDS>/xrpc/com.atproto.repo.createRecord` (Bearer = accessJwt) collection `sh.tangled.repo`,
record `{$type:"sh.tangled.repo", knot:"knot1.tangled.sh", name, description, createdAt, repoDid}`.
5. `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]].