← projects
Philbot & philtompkins.com

Philbot & philtompkins.com

Creator

2025 — present

Personal site · AI chat · conversational contact

Next.js 16React 19Tailwind CSS 4Framer MotionxAI GrokNemotron EmbeddingsMDX

The site

philtompkins.com holds project write-ups, a blog, the career stops, and notes from the lab. It is not a résumé with nicer fonts. Next.js 16, React 19, Tailwind CSS 4. App Router and server components. Framer Motion for scroll reveals. Builder's Study is dark charcoal, emerald, DM Sans, JetBrains Mono. Production is a VPS behind Caddy with automatic HTTPS.

Ask Philbot

The chat bubble in the corner is Philbot. It answers questions about my work and this site. It retrieves chunks first. It does not get to freestyle from the open internet.

Site content is chunked and embedded on the homelab Nemotron endpoint, the same local embedder RivetOS memory uses on pve3, then stored as JSON. A question gets embedded, cosine similarity against those chunks, and anything over the threshold goes into the prompt. Grok 4.3 streams the answer. The system prompt says: only this site, no general knowledge.

Rate limit: 10 messages a minute per IP. 500-character input cap.

Conversational contact

Philbot can take a contact. Name, how to reach them, email, phone, text, Twitter, Discord, LinkedIn, and what they want. After they confirm, the server writes it.

There is a normal form behind the envelope icon too. Same fields. Same store. Rivet watches for new rows and pings me.

Tool calls go through xAI's tool API. The model picks when to submit. The server validates. Separate limit: 3 submissions an hour per IP.

Technical details

Chunks cover career, projects, skills, and a bit of personal context. Similarity search is server-side. No vector database at this size. A JSON file and cosine. Streaming uses the Web Streams API.

Inputs get sanitized and capped. Email is checked on the server when they pick email. Unknown tools get rejected. Submissions land in a JSON file on disk. Rivet polls it on a heartbeat.