···2626# List repositories for a user
2727tg repo list microcosm.blue
28282929+# Create a repository (requires `tg auth login`)
3030+tg repo create my-tool --description "A small tool"
3131+3232+# Create and clone it into the current directory
3333+tg repo create my-tool --clone
3434+3535+# Create and push an existing local repo (at the given path) to the new remote
3636+tg repo create my-tool --push=.
3737+2938# Clone a repository
3039tg repo clone microcosm.blue/microcosm-rs
3140
+33
atproto/records.go
···11+package atproto
22+33+import (
44+ "context"
55+ "fmt"
66+77+ "github.com/bluesky-social/indigo/atproto/atclient"
88+ "github.com/bluesky-social/indigo/atproto/syntax"
99+)
1010+1111+// PutRecordInput is the argument to a com.atproto.repo.putRecord call.
1212+type PutRecordInput struct {
1313+ Repo string `json:"repo"`
1414+ Collection string `json:"collection"`
1515+ Rkey string `json:"rkey"`
1616+ Record any `json:"record"`
1717+}
1818+1919+// PutRecord writes a record to the PDS, returning its at:// URI and CID. The
2020+// record must include its $type field.
2121+func PutRecord(ctx context.Context, pds *atclient.APIClient, in PutRecordInput) (uri, cid string, err error) {
2222+ if pds == nil {
2323+ return "", "", fmt.Errorf("PDS client is required")
2424+ }
2525+ var out struct {
2626+ URI string `json:"uri"`
2727+ CID string `json:"cid,omitempty"`
2828+ }
2929+ if err := pds.Post(ctx, syntax.NSID("com.atproto.repo.putRecord"), in, &out); err != nil {
3030+ return "", "", fmt.Errorf("put %s/%s record: %w", in.Collection, in.Rkey, err)
3131+ }
3232+ return out.URI, out.CID, nil
3333+}
+36
atproto/serviceauth.go
···11+package atproto
22+33+import (
44+ "context"
55+ "fmt"
66+ "time"
77+88+ "github.com/bluesky-social/indigo/atproto/atclient"
99+ "github.com/bluesky-social/indigo/atproto/syntax"
1010+)
1111+1212+const serviceAuthTTL = 60 * time.Second
1313+1414+// GetServiceAuth mints a short-lived service-auth JWT scoped to one lexicon
1515+// method on one audience (e.g. a knot's did:web). Present it to that audience
1616+// as a Bearer token.
1717+func GetServiceAuth(ctx context.Context, pds *atclient.APIClient, audience, lexiconMethod string) (string, error) {
1818+ if pds == nil {
1919+ return "", fmt.Errorf("PDS client is required")
2020+ }
2121+ var out struct {
2222+ Token string `json:"token"`
2323+ }
2424+ params := map[string]any{
2525+ "aud": audience,
2626+ "exp": time.Now().Add(serviceAuthTTL).Unix(),
2727+ "lxm": lexiconMethod,
2828+ }
2929+ if err := pds.Get(ctx, syntax.NSID("com.atproto.server.getServiceAuth"), params, &out); err != nil {
3030+ return "", fmt.Errorf("get service auth for %q: %w", audience, err)
3131+ }
3232+ if out.Token == "" {
3333+ return "", fmt.Errorf("PDS returned an empty service auth token for %q", audience)
3434+ }
3535+ return out.Token, nil
3636+}