I did not want my portfolio to be another static page that only lists projects.
A portfolio already tells people what I have built. But I wanted mine to do something closer to how I actually work: answer questions, explain projects, help visitors understand my background, and show the automation layer behind my workflow.
Since I already had Hermes running as my AI assistant, the question became simple:
Could I connect the assistant I actually use every day to my public portfolio without turning the site into an unsafe open chat box?
That became the real problem. Not “how do I add a chatbot?” but “how do I expose an existing agent safely?”
The problem
Most portfolio chat widgets are isolated demos.
They can answer a few scripted questions. They can summarize resume data. Maybe they can collect a lead. But they do not represent the actual working system behind the developer.
My setup was different. I already had Hermes running with memory, tools, skills, Telegram access, scheduled jobs, and my own workflow context. Hermes was not just a wrapper around a model. It was already part of how I manage job applications, automations, website tasks, Churv operations, and developer work.
So I did not want to rebuild a second fake assistant just for the website.
I wanted the website to talk to the same existing agent, but with boundaries.
The public visitor should be able to ask about my work, projects, skills, and availability. They should not get access to my private tools, credentials, internal files, Telegram conversations, cron jobs, or anything meant only for me.
That boundary shaped the whole integration.
The basic architecture
The portfolio became a client. Hermes stayed on the server.
Instead of putting any AI provider key or Hermes secret inside the browser, I routed messages through a backend endpoint. The frontend chat widget sends a visitor message to the portfolio backend. The backend applies rate limits and session handling, then forwards the request to the Hermes API endpoint.
The browser never talks directly to the model provider. It also never receives Hermes credentials.
Visitor
↓
Portfolio chat widget
↓
Astro API route
↓
Rate limit + session state
↓
Hermes API endpoint
↓
Existing Gyan/Hermes agent
↓
Response back to portfolio
That separation matters. The site can feel interactive, but the sensitive parts stay server side.
The public website is only allowed to send a controlled request. Hermes handles the response as the agent. The portfolio backend decides what gets passed through and what gets blocked.
Reusing the existing agent
The biggest design decision was reusing the agent I already had instead of creating a separate “portfolio bot.”
Hermes already had my profile, preferences, workflow rules, project context, and assistant identity. That gave the chat widget a better starting point than a basic prompt pasted into an API call.
The agent already knows that I am Angelo Sinday, a full stack developer in the Philippines. It knows my stack: WordPress, React, Next.js, PHP, Laravel, Vue, Supabase, Prisma, Tailwind, MySQL, Vercel, Git. It also knows my projects: Churv, Beemodo, client WordPress sites, automation workflows, and AI-assisted development.
That existing context made the chat feel less like a generic website widget. It could answer in a way that fits my actual work.
But I still treated the portfolio as a public surface. Just because Hermes has deeper context does not mean every context should be exposed.
The rule was: use the agent’s understanding, not its private access.
The portfolio side
On the portfolio, I added a chat interface that behaves like a normal product feature instead of a toy popup.
The widget handles the visitor message, keeps the conversation state, shows loading states, and renders the assistant response. The UI is simple because the hard part is not the chat box. The hard part is everything behind it.
I used environment variables for server configuration instead of hardcoding URLs or secrets into the frontend. The public app only gets what it needs. Anything sensitive stays in server-only variables.
The portfolio backend became the gatekeeper.
It can:
- accept a visitor message
- attach session metadata
- enforce rate limits
- forward the request to Hermes
- return the response
- fail safely if Hermes is offline or slow
That last part matters. A portfolio should not break just because the agent is unavailable. If Hermes is down, the site should still load, and the chat should show a clean fallback.
Rate limiting and session state
A public chat endpoint can get abused quickly.
Even if the site has low traffic, the endpoint is still public. Someone can spam it, scrape it, or try to burn tokens. I did not want the portfolio to become an open relay to my assistant.
So I added rate limiting and lightweight state management. Upstash Redis fits this kind of problem well because it gives a simple serverless-friendly place to track request counts and session data.
The rate limit is not there to punish normal visitors. It is there to prevent obvious abuse.
Visitor message
↓
Check rate limit
↓
Create or reuse session id
↓
Forward allowed request
↓
Store minimal state
The important part is that the website does not need to store full private Hermes context. It only needs enough state to keep the visitor experience usable.
The server boundary
Hermes runs behind a server boundary, not inside the browser.
I used Caddy as the reverse proxy layer so the public domain can point to the running Hermes service cleanly. That keeps the deployment simple: the portfolio talks to a known HTTPS endpoint, and Caddy handles routing to the local Hermes service on the VPS.
This also let me avoid exposing raw internal ports directly.
Public HTTPS domain
↓
Caddy reverse proxy
↓
Local Hermes service
The cleanest part of this setup is that Hermes can keep running as the same assistant I use in Telegram and other workflows. The website becomes another controlled entry point instead of a separate system.
Security boundaries
The main security rule was simple: the browser gets no secrets.
- No model API keys.
- No Hermes credentials.
- No database service keys.
- No Telegram tokens.
- No internal config.
The portfolio frontend only talks to my own backend route. The backend decides whether to forward the message to Hermes.
I also treated the public chat as a different trust level from my private assistant session. A visitor asking about my portfolio is not the same as me asking Hermes to inspect files, run commands, apply to jobs, or operate Churv.
That difference has to be enforced by architecture, not by vibes.
A public-facing assistant should be helpful, but it should not be powerful in the same way a private agent is powerful.
Why this is better than a normal chatbot
A normal chatbot on a portfolio answers questions.
This setup does more than that because it connects to the same assistant system behind my workflow. It reflects how I actually build and automate things.
For example, someone visiting my portfolio can ask about:
- my WordPress experience
- Churv and Beemodo
- client sites I worked on
- my stack and availability
- how I use AI tools in development
- what kind of projects I can handle
That makes the portfolio less passive. It becomes a small product surface for my own developer workflow.
It also demonstrates something important about my work: I do not just talk about AI automation. I actually wire systems together, put boundaries around them, and make them usable.
What I learned
Connecting Hermes to my portfolio taught me that the hard part is not the AI response.
The hard part is deciding where the AI is allowed to live.
If it lives entirely in the frontend, secrets leak and control disappears. If it lives only in a private terminal, nobody visiting the portfolio can experience it. The useful middle ground is a controlled backend bridge.
That bridge lets the public website access the assistant without giving the public user the same authority I have.
It also made me think about AI features as infrastructure, not decoration. The chat widget is the visible part, but the real work is the routing, rate limiting, session state, server boundary, fallback behavior, and security model behind it.
That is the version I wanted on my portfolio: not a fake chatbot, not a hardcoded demo, but a controlled window into the agent I already use.
The result is a portfolio that can speak for my work while still respecting the line between public interaction and private automation.