νκ΅μ΄ | English
A personal homepage and AI-operated knowledge base for robotics & AI research.
Live: www.terryum.ai
On the Manifold is a bilingual (Korean/English) research blog, knowledge graph, and personal homepage. Inspired by Andrej Karpathy's approach to external-brain knowledge management, the entire content pipeline is operated by Claude Code β papers are summarized, indexed, connected, and published through natural language commands.
The site hosts 40+ research paper summaries, tech essays, notes, and an interactive paper relationship graph. The project uses a multi-workspace setup:
| Workspace | Role | Repository |
|---|---|---|
| terryum-ai (this repo) | Site code + infrastructure | terryum/terryum-ai |
| terry-papers | Paper posting + knowledge graph | terryum/terry-papers |
| terry-surveys | Survey book creation + management | terryum/terry-surveys |
| terry-obsidian | Obsidian vault + content publishing | (private) |
βββββββββββββββββββββββββββββββββββββββββββββ
β Claude Code (AI Agent) β
β /post /project /post-share β
ββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββ
v v v
posts/ (MDX) Supabase Obsidian Vault
index.json (Graph DB) (Local Knowledge)
| | |
v v v
ββββββββββββ ββββββββββββ ββββββββββββββ
βCF Worker β β Paper β β Wikilinks β
β (OpenNxt)β β Map UI β β + Dataview β
ββββββββββββ ββββββββββββ ββββββββββββββ
| Layer | Stack |
|---|---|
| Frontend | Next.js 15 (App Router) + TypeScript + Tailwind CSS v4 |
| Content | Bilingual MDX (ko.mdx / en.mdx) + frontmatter metadata |
| Images | Cloudflare R2 CDN (all post images served globally) |
| Deployment | Cloudflare Workers (OpenNext) + Pages + R2 |
| Database | Supabase (paper relationships, knowledge graph, private content) |
| Access Control | Group-based password auth (/co/[group]) + Admin |
| Knowledge Base | Obsidian (local) + sync script + Claude Code |
Skills are split across two workspaces:
This repo (terryum-ai) β site development + content pipeline:
| Skill | Description | Example |
|---|---|---|
/post |
Publish a research post from arXiv, blog, or journal URL | /post https://arxiv.org/abs/2505.22159 |
/post virtual |
Create a virtual paper (research proposal) post | /post virtual --group=snu tactile residual learning |
/share |
Share content to social media (Facebook, X, LinkedIn, Bluesky) | /share #5 facebook,x |
/project |
Add a project to the gallery | /project https://github.com/user/repo |
/survey |
Register a deployed survey book site | /survey https://survey.example.com |
/del |
Safely delete a post and clean all references | /del #26 or /del 2505-forcevla --force |
/paper-search |
Recommend papers via knowledge graph + external search | /paper-search #16 retargeting limitations |
terry-obsidian β Obsidian vault management + content publishing:
| Skill | Description | Example |
|---|---|---|
/write |
Generate a styled draft from Obsidian notes | /write #-1 #-3 --type=notes |
/draft |
Create a publishable draft in Obsidian Drafts folder | /draft essays This is the title... |
/memo |
Create an Obsidian memo with auto-indexed metadata | /memo AI and robotics intersection |
/tagging |
Auto-tag posts based on content analysis | /tagging |
/post |
(symlink) Same publishing pipeline, usable from Obsidian workspace | /post https://arxiv.org/abs/... |
/paper-search |
(symlink) Paper recommendations from knowledge graph | /paper-search #16 retargeting limitations |
This is a personal project, not a plug-and-play template. However, since the repository is public and MIT-licensed, you're welcome to study the structure and adapt it. Below is a guide covering what you get by cloning, what you need to set up yourself, and how the pieces connect.
- Full Next.js 15 site source code (App Router, i18n routing, MDX rendering)
- Content pipeline:
posts/{papers,essays,notes}/folder structure - Paper relationship graph UI (React Flow + Supabase)
- Admin dashboard (stats, graph editor β behind password)
- Group-based access control for private content (
/co/[group]) - Claude Code harness (
.claude/agents/,.claude/skills/) β site dev skills; Obsidian skills live interry-obsidian - Obsidian sync script (
scripts/sync-obsidian.mjs) - Social media publishing script (
scripts/publish-social.py) - All published post content (MDX + images)
| Component | Why it's not included | Setup effort |
|---|---|---|
| Environment variables | API keys, secrets | Copy .env.example β .env.local, fill in your keys |
| Supabase project | Database for paper graph | Create project, run migration in supabase/migrations/ |
| Obsidian vault | Local knowledge base | Install Obsidian, configure vault path |
| Cloudflare account | Deployment (Workers + Pages + R2) + DNS/CDN | Free plan is enough; set up wrangler CLI with API token |
| Social media tokens | Publishing automation | Platform-specific OAuth setup |
| Claude Code | AI agent operation | Install Claude Code CLI |
git clone https://github.com/terryum/terryum-ai.git
cd terryum-ai
npm install
cp .env.example .env.localAt minimum, you need:
# Site
NEXT_PUBLIC_SITE_URL=http://localhost:3040
# Identity / Session (HMAC cookie key + admin email)
SESSION_SECRET=generate-a-64-char-hex-string
ADMIN_EMAIL=you@example.com
# Google OAuth (register redirect URI at Google Cloud Console)
GOOGLE_OAUTH_CLIENT_ID=xxxxx.apps.googleusercontent.com
GOOGLE_OAUTH_CLIENT_SECRET=GOCSPX-xxxxx
# Supabase (optional β site works without it, but Paper Map won't)
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...For the full list, see .env.example.
The paper relationship graph requires three tables. Apply the migration:
# Option A: Supabase CLI
supabase db push
# Option B: Run SQL manually in Supabase Dashboard
# Copy contents of supabase/migrations/001_initial_schema.sqlTables created:
papersβ paper metadata (slug, title, domain, concepts)graph_edgesβ relationships between papers (builds_on, extends, etc.)node_layoutsβ React Flow canvas positions
If you skip this step, the site still works β the Paper Map page will show a fallback message.
Additionally, 002_acl_schema.sql creates tables for legacy group-based access control (deprecated β access control now uses inline visibility fields in meta.json instead of Supabase).
npm run dev # Starts on localhost:3040npm run build:cf # OpenNext build for Workers
npx opennextjs-cloudflare deploy # Deploy via wranglerRuntime env vars go in wrangler.jsonc (vars for public, secrets via wrangler secret put for sensitive). See .env.production for the set of NEXT_PUBLIC_* vars that Next.js inlines into the bundle at build time.
Private survey pages remain protected by their existing Cloudflare Access applications. The Worker serves them to an authenticated admin through the isolated private-surveys.terryum.ai iframe origin and /api/private-surveys/{slug}/{path...} proxy. The proxy derives every upstream URL from the registered private survey embed_url; anonymous users, members, public/group surveys, and unknown slugs receive an empty 404.
Create the non-expiring terryum-ai-private-surveys Cloudflare Access Service Token, add a Service Auth (non_identity) policy that allows only that token to the production Access application containing all four S11-S14 destinations, and retain the existing Terry email policy for emergency direct access. Store the token credentials only as encrypted Worker secrets:
wrangler secret put CF_ACCESS_CLIENT_ID
wrangler secret put CF_ACCESS_CLIENT_SECRETDeploy only after both secrets and the private-surveys.terryum.ai custom domain are configured. Never add either credential to wrangler.jsonc, a NEXT_PUBLIC_* variable, logs, or committed files.
The site supports per-post visibility scoping for sharing private content with specific collaborator groups.
Public posts Group-scoped posts
visibility: "public" visibility: "group", allowed_groups: ["snu"]
Visible to everyone Visible after /co/snu login
Same posts/ directory Same posts/ directory
How it works:
-
Each group has a password set via environment variable:
CO_SNU_PASSWORD=your-password CO_KAIST_PASSWORD=another-password
-
Group-scoped posts are stored in Git alongside public posts, with
visibilityandallowed_groupsfields inmeta.json -
Collaborators visit
/co/snu, enter the password, then get redirected to the main site where group-scoped posts become visible -
Unauthenticated users accessing a group post URL are redirected to the login page
-
Admin session grants access to all groups
Key features:
- HMAC-SHA256 signed session tokens (24-hour validity)
- Rate limiting (5 attempts per 15 minutes)
- Group posts excluded from sitemap and marked
noindex - Groups are isolated β
co-snusession cannot seeco-kaistcontent
This is the part that requires the most manual setup, since the Obsidian vault lives on your local machine and is not included in the repository.
Homepage (posts/) ββsync-obsidian.mjsβββΊ Obsidian Vault
βββ Public/Papers/ β research summaries
βββ Public/Essays/ β essays
βββ Public/Notes/ β short notes + ChatGPT summaries
βββ Private/Drafts/ β unpublished drafts
βββ Ops/Meta/ β taxonomy, concept index
- Published posts are synced as Obsidian notes with wikilinks and frontmatter
- Manual notes created in Obsidian get negative IDs (
#-1,#-2, ...) and can be referenced in Claude Code commands - The sync is one-directional (homepage β Obsidian) for published content, but Obsidian notes can be pulled back via
/write
-
Install Obsidian: Download from obsidian.md
-
Create a vault: Create or open a vault at your preferred location (e.g.,
~/Documents/Obsidian Vault) -
Initialize vault structure:
# Creates the required folder hierarchy node scripts/sync-obsidian.mjs --init --vault="/path/to/your/vault"
This creates:
Your Vault/ βββ Public/ β βββ Papers/ β βββ Essays/ β βββ Notes/ βββ Private/ β βββ Drafts/ β βββ Notes/ β βββ Tasks/ βββ Ops/ βββ Meta/ βββ Templates/ -
Sync posts to Obsidian:
node scripts/sync-obsidian.mjs --vault="/path/to/your/vault" -
Recommended Obsidian plugins:
- Dataview β query and filter notes by frontmatter fields
- Graph View (built-in) β visualize wikilink connections
- Templates β use templates in
Ops/Templates/
Each synced note gets frontmatter like:
---
doc_id: 5
slug: 2505-forcevla-force-aware-moe
content_type: papers
domain: robotics
tags: [VLA, force-control, MoE]
sync_hash: a1b2c3d4
synced_at: 2026-04-07T12:00:00Z
---And the body includes a ## Relations section with wikilinks to related papers β these are preserved even when re-syncing.
Posts follow a consistent directory pattern:
posts/
βββ index.json # Master index of all posts
βββ papers/
β βββ 2505-forcevla-force-aware-moe/
β βββ meta.json # Full metadata
β βββ ko.mdx # Korean content
β βββ en.mdx # English content
β βββ cover.webp # Cover image
βββ essays/
β βββ 260310-brain-augmentation/
β βββ [same structure]
βββ notes/
βββ 260419-vercel-quiet-bill/
βββ [same structure]
content_type= folder name = URL tab slug- Every post has both
ko.mdxanden.mdx(bilingual) index.jsonis the source of truth for post ordering and metadatameta.jsonper post is optional (frontmatter in MDX is the fallback)
- Public posts: positive IDs (
#1,#2, ...) β visible on the website - Private drafts: negative IDs (
#-1,#-2, ...) β Obsidian only, never published - Any document is referenceable by
#numberin Claude Code commands
If you want to build your own version rather than forking:
- Start with the site: The Next.js app works standalone. Remove my posts, update
src/lib/site-config.tswith your info - Add your content: Create posts in
posts/{type}/{slug}/withko.mdx,en.mdx,cover.webp - Set up Supabase (optional): Only needed for the Paper Map feature
- Set up Obsidian (optional): Only needed if you want local knowledge graph management
- Configure Claude Code (optional): The
.claude/harness is designed for my workflow β modify or remove as needed
MIT