Temporary text review page. Not a GitHub PR. Generated from local draft.

My current coding setup

I have a Raspberry Pi running at home that has slowly become my AI coding box.

It runs Hermes, has a few local repos checked out, can talk to GitHub, and can trigger Cloudflare deploys. I talk to it mostly through Telegram. If I send a voice note with a blog idea or a coding task, Hermes can turn that into files, commands, commits, previews or PRs.

The laptop is no longer the only place where coding work starts. That is the main change.

The setup

The pieces are:

The rough flow:

  1. I send a Telegram message or voice note.
  2. Hermes turns it into a task.
  3. For small edits, Hermes can change files directly.
  4. For bigger coding tasks, I use Claude Code on the Pi.
  5. Changes happen in a local repo.
  6. For review, I either deploy a temporary Cloudflare preview or open a GitHub PR.

For blog posts, I think the temp preview is better than opening a PR every time. PRs are useful when the text is close. For early drafts, a Cloudflare page is enough.

Why the Pi works well

The Pi is always on. That is the useful bit.

I can message it from my phone and leave it running. It can keep a repo checked out, run cron jobs, hold credentials, and keep tmux sessions alive. My laptop can be closed.

This fits how ideas actually show up. Usually not while I am sitting in front of VS Code. More often while walking, in a cab, or before sleeping.

Claude Code on the Pi

Claude Code runs on the Pi, but auth was the part that took time.

The route that worked was:


claude setup-token

Then the token needs to be available to the shell that Hermes uses:


export CLAUDE_CODE_OAUTH_TOKEN="..."

One gotcha: .bashrc often exits early for non-interactive shells. If the export is below that guard, Claude Code may work over SSH but fail when Hermes calls it.

I ended up launching Claude Code through an interactive bash wrapper when needed:


bash -ic 'claude'

For long sessions, I run it inside tmux:


tmux new -s coding
bash -ic 'claude'

Detach with Ctrl-b d, then come back later:


tmux attach -t coding

GitHub access

For this blog repo, I use a fine-grained GitHub token scoped only to this repository.

Minimum useful permissions:

I store it as a repo-specific environment variable, not a broad global token:


AKASHPERSONAL_GITHUB_TOKEN=...

Then git can use it for clone/push, and Hermes can use the GitHub API if it needs to open a PR.

A deploy key would also work for clone/push. But deploy keys do not help with the GitHub API, so PR creation becomes more annoying.

Blog review flow

For the blog, I now prefer this flow:

  1. Voice note or Telegram message with the idea.
  2. Hermes extracts the angle and checks the backlog.
  3. I approve the angle.
  4. Hermes writes a draft locally.
  5. Hermes deploys a temporary Cloudflare review page.
  6. I review the text in Telegram/browser.
  7. Only after that, Hermes opens a PR or commits to the repo.

That should keep GitHub cleaner. Fewer throwaway PRs.

Commands to replicate the basic setup

Install the basics on the Pi:


sudo apt update
sudo apt install -y git tmux python3 python3-venv nodejs npm

Install Claude Code:


npm install -g @anthropic-ai/claude-code
claude setup-token

Make sure the token is available to non-interactive commands. Put this somewhere Hermes will actually load, not below the early .bashrc return:


export CLAUDE_CODE_OAUTH_TOKEN="your_token_here"

Create a tmux session for coding:


tmux new -s coding
bash -ic 'claude'

Clone the repo with a fine-grained token:


export AKASHPERSONAL_GITHUB_TOKEN="your_github_token_here"

git clone https://x-access-token:${AKASHPERSONAL_GITHUB_TOKEN}@github.com/senapaty/akashpersonal.git
cd akashpersonal

Create a branch and commit changes:


git checkout -b draft/my-post
# edit files
git add content/blog/my-post/index.md
git commit -m "Add draft post"
git push origin draft/my-post

Deploy a temporary static review page with Cloudflare Wrangler:


npm install -g wrangler

mkdir -p /tmp/blog-review
cp review.html /tmp/blog-review/index.html

wrangler pages deploy /tmp/blog-review \
  --project-name akash-blog-review \
  --branch v$(date +%Y%m%d-%H%M%S)

If the draft is approved, open a PR:


curl -X POST \
  -H "Authorization: Bearer $AKASHPERSONAL_GITHUB_TOKEN" \
  -H "Accept: application/vnd.github+json" \
  https://api.github.com/repos/senapaty/akashpersonal/pulls \
  -d '{
    "title": "Add draft post",
    "head": "draft/my-post",
    "base": "main",
    "body": "Draft post for review."
  }'

What I would change

I would not make PRs the first review artifact for blog posts.

For code, PRs are still right. For text, a temporary Cloudflare page is cleaner. It gives me a link to read and comment on, without filling the repo with half-formed drafts.

So the better setup is: