karpathytalk-community
Installation
SKILL.md
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
4. 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 ./...
Weekly Installs
41
Repository
aradotso/trending-skillsGitHub Stars
25
First Seen
3 days ago
Security Audits
Installed on
claude-code38
opencode34
deepagents34
antigravity34
github-copilot34
codex34