KarpathyTalk Community Skill Skill by ara.so — Daily 2026 Skills collection. KarpathyTalk is a Go-based developer social network (Twitter × GitHub Gists) where posts are plain markdown, the social layer supports likes/reposts/follows/replies, and all data is openly accessible via JSON and markdown APIs — designed for both humans and LLM agents. What It Does GitHub OAuth sign-in (no new credentials) Posts are GFM markdown with syntax-highlighted code blocks and image uploads Social features: likes, reposts, quote posts, replies, follows REST API returns JSON (for agents/code) or markdown (for humans) Single Go binary + SQLite + uploads/ directory — trivial to self-host Built with: Go, SQLite, htmx, goldmark Installation & Local Setup 1. Create a GitHub OAuth App Go to GitHub → Settings → Developer settings → OAuth Apps → New OAuth App : Field Value Application name KarpathyTalk Homepage URL http://localhost:8080 Authorization callback URL http://localhost:8080/auth/callback Save the Client ID and Client Secret . 2. Clone & Build git clone https://github.com/karpathy/KarpathyTalk.git cd KarpathyTalk go build -o karpathytalk ./cmd/karpathytalk 3. Configure Environment export GITHUB_CLIENT_ID = $GITHUB_CLIENT_ID export GITHUB_CLIENT_SECRET = $GITHUB_CLIENT_SECRET export BASE_URL = http://localhost:8080
optional, defaults to this
- Run ./karpathytalk
or with options:
./karpathytalk -addr :9090 -db ./data/karpathytalk.db Visit http://localhost:8080 . CLI Flags -addr string HTTP listen address (default ":8080") -db string SQLite database path (default "karpathytalk.db") Environment Variables Variable Required Default Description GITHUB_CLIENT_ID ✅ — GitHub OAuth client ID GITHUB_CLIENT_SECRET ✅ — GitHub OAuth client secret BASE_URL ❌ http://localhost:8080 Public URL of the deployed app Deployment (Production) Build & Copy
Build binary
go build -o karpathytalk ./cmd/karpathytalk
Copy to server (adjust user/host)
scp karpathytalk schema.sql user@yourserver:~/karpathytalk/ scp -r templates static user@yourserver:~/karpathytalk/ Run on Server ssh user@yourserver cd ~/karpathytalk export GITHUB_CLIENT_ID = $GITHUB_CLIENT_ID export GITHUB_CLIENT_SECRET = $GITHUB_CLIENT_SECRET export BASE_URL = https://yourdomain.com ./karpathytalk -addr :8080 Caddy TLS (recommended) yourdomain.com { reverse_proxy localhost:8080 } nginx TLS server { listen 443 ssl ; server_name yourdomain.com ; ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem ; ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem ; location / { proxy_pass http://localhost:8080 ; proxy_set_header Host $host ; proxy_set_header X-Real-IP $remote_addr ; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for ; proxy_set_header X-Forwarded-Proto $scheme ; } } systemd Service [ Unit ] Description = KarpathyTalk After = network.target [ Service ] WorkingDirectory = /home/deploy/karpathytalk ExecStart = /home/deploy/karpathytalk/karpathytalk -addr :8080 Restart = always Environment = GITHUB_CLIENT_ID=$GITHUB_CLIENT_ID Environment = GITHUB_CLIENT_SECRET=$GITHUB_CLIENT_SECRET Environment = BASE_URL=https://yourdomain.com [ Install ] WantedBy = multi-user.target API Usage All data is open — no auth required for reads. The API returns JSON for programmatic access and markdown for human/agent reading. Fetch Posts as JSON
Timeline / recent posts
curl https://karpathytalk.com/api/posts
Single post
curl https://karpathytalk.com/api/posts/ { postID }
User's posts
curl https://karpathytalk.com/api/users/ { username } /posts Fetch Posts as Markdown
Human/agent-readable markdown
curl
https://karpathytalk.com/api/posts/
{
postID
}
.md
Go Agent Example — Read Timeline
package
main
import
(
"encoding/json"
"fmt"
"io"
"net/http"
)
type
Post
struct
{
ID
int64
json:"id"
Username
string
json:"username"
Content
string
json:"content"
Likes
int
json:"likes"
Reposts
int
json:"reposts"
CreatedAt
string
json:"created_at"
}
func
fetchTimeline
(
baseURL
string
)
(
[
]
Post
,
error
)
{
resp
,
err
:=
http
.
Get
(
baseURL
+
"/api/posts"
)
if
err
!=
nil
{
return
nil
,
err
}
defer
resp
.
Body
.
Close
(
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
nil
,
err
}
var
posts
[
]
Post
if
err
:=
json
.
Unmarshal
(
body
,
&
posts
)
;
err
!=
nil
{
return
nil
,
err
}
return
posts
,
nil
}
func
main
(
)
{
posts
,
err
:=
fetchTimeline
(
"https://karpathytalk.com"
)
if
err
!=
nil
{
panic
(
err
)
}
for
_
,
p
:=
range
posts
{
fmt
.
Printf
(
"[%s] %s (👍 %d)\n"
,
p
.
Username
,
p
.
Content
[
:
min
(
80
,
len
(
p
.
Content
)
)
]
,
p
.
Likes
)
}
}
func
min
(
a
,
b
int
)
int
{
if
a
<
b
{
return
a
}
return
b
}
Go Agent Example — Fetch User Posts as Markdown
package
main
import
(
"fmt"
"io"
"net/http"
)
func
fetchUserPostsMarkdown
(
baseURL
,
username
string
)
(
string
,
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/api/users/%s/posts.md"
,
baseURL
,
username
)
resp
,
err
:=
http
.
Get
(
url
)
if
err
!=
nil
{
return
""
,
err
}
defer
resp
.
Body
.
Close
(
)
body
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
return
string
(
body
)
,
err
}
func
main
(
)
{
md
,
err
:=
fetchUserPostsMarkdown
(
"https://karpathytalk.com"
,
"karpathy"
)
if
err
!=
nil
{
panic
(
err
)
}
fmt
.
Println
(
md
)
}
Content Limits
Content Type
Max Length
Rate Limit
Posts
10,000 characters
30 per hour
Replies
5,000 characters
60 per hour
Images
5 MB
PNG/JPEG/GIF/WebP only
Database — Direct SQLite Access
The SQLite database is a single file. You can query it directly for analytics, backups, or migrations:
Open database
sqlite3 karpathytalk.db
List tables
.tables
Recent posts
SELECT username, substr ( content, 1 , 80 ) , created_at FROM posts ORDER BY created_at DESC LIMIT 20 ;
Most liked posts
SELECT username, likes, substr ( content, 1 , 60 ) FROM posts ORDER BY likes DESC LIMIT 10 ;
User follower counts
SELECT username, COUNT ( * ) as followers FROM follows GROUP BY username ORDER BY followers DESC ; Backup
Simple file copy (safe while running with WAL mode)
cp karpathytalk.db karpathytalk.db.backup
Or use sqlite3 online backup
sqlite3 karpathytalk.db
".backup karpathytalk_backup.db"
Project Structure
KarpathyTalk/
├── cmd/
│ └── karpathytalk/ # main entrypoint
├── templates/ # HTML templates (htmx-powered)
├── static/ # CSS, JS assets
├── uploads/ # User image uploads
├── schema.sql # SQLite schema
└── karpathytalk.db # Database (created at runtime)
Common Patterns
Pattern: Agent That Monitors New Posts
package
main
import
(
"encoding/json"
"fmt"
"net/http"
"time"
)
type
Post
struct
{
ID
int64
json:"id"
Username
string
json:"username"
Content
string
json:"content"
CreatedAt
string
json:"created_at"
}
func
pollNewPosts
(
baseURL
string
,
sinceID
int64
)
(
[
]
Post
,
error
)
{
url
:=
fmt
.
Sprintf
(
"%s/api/posts?since_id=%d"
,
baseURL
,
sinceID
)
resp
,
err
:=
http
.
Get
(
url
)
if
err
!=
nil
{
return
nil
,
err
}
defer
resp
.
Body
.
Close
(
)
var
posts
[
]
Post
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
posts
)
return
posts
,
nil
}
func
main
(
)
{
var
lastSeenID
int64
=
0
for
{
posts
,
err
:=
pollNewPosts
(
"https://karpathytalk.com"
,
lastSeenID
)
if
err
!=
nil
{
fmt
.
Println
(
"Error:"
,
err
)
}
else
{
for
_
,
p
:=
range
posts
{
fmt
.
Printf
(
"New post by @%s: %s\n"
,
p
.
Username
,
p
.
Content
[
:
min
(
60
,
len
(
p
.
Content
)
)
]
)
if
p
.
ID
lastSeenID { lastSeenID = p . ID } } } time . Sleep ( 30 * time . Second ) } } func min ( a , b int ) int { if a < b { return a } return b } Pattern: Embedding KarpathyTalk Content in an LLM Prompt package main import ( "fmt" "io" "net/http" ) // Fetch markdown content to inject into an LLM system prompt or context window func getContextForLLM ( baseURL , username string ) ( string , error ) { url := fmt . Sprintf ( "%s/api/users/%s/posts.md" , baseURL , username ) resp , err := http . Get ( url ) if err != nil { return "" , err } defer resp . Body . Close ( ) body , err := io . ReadAll ( resp . Body ) return string ( body ) , err } func main ( ) { context , _ := getContextForLLM ( "https://karpathytalk.com" , "karpathy" ) systemPrompt := fmt . Sprintf (
You are a helpful assistant. Here are recent posts from the community: %s Answer questions about these posts., context ) fmt . Println ( systemPrompt ) } Troubleshooting Problem Cause Fix GITHUB_CLIENT_ID not set Missing env var Export GITHUB_CLIENT_ID before running OAuth callback fails Callback URL mismatch Ensure GitHub OAuth App callback URL exactly matches BASE_URL/auth/callback Binary not found after build Wrong output path Run go build -o karpathytalk ./cmd/karpathytalk from repo root templates: no such file Missing templates dir Run the binary from the repo root, or copy templates/ and static/ next to the binary Database locked Concurrent writers SQLite WAL mode is set by default; avoid multiple binary instances against same .db Images not serving Missing uploads/ dir The directory is created automatically on first upload; check write permissions Port already in use Another process on 8080 Use -addr :9090 to change the port Check the App is Running curl -I http://localhost:8080/
Expect: HTTP/1.1 200 OK
Rebuild After Code Changes go build -o karpathytalk ./cmd/karpathytalk && ./karpathytalk Run Tests go test ./ .. .