An autonomous AI agent system that turns GitHub issues into code. Open an issue, and a Claude agent picks it up, writes the code, and either merges it directly or creates a PR for review.
Running on ai.memention.net
- Open a GitHub issue describing what you want
- A webhook fires and the server picks it up
- A comment is posted on the issue that the agent has started
- Claude runs in an isolated git worktree, working on the task
- When done, a PR is created for review
- The agent posts a summary comment on the issue and closes it
GitHub Issue
│
▼
webhook-receiver.py ◄── nginx reverse proxy (HTTPS)
│
▼
monitor-issues.sh ◄── fetches issue, creates issue-N.md
│
▼
run-agent.sh ◄── creates worktree, runs Claude, handles output
│
└──► push branch + create PR
A post-merge git hook auto-restarts systemd services when their files change. Flutter web apps are built and deployed by GitHub Actions, not on the server.
graph TD
A[Push to main / Merge PR] --> B[GitHub sends webhook]
B --> C[webhook-receiver.py]
C --> D[git pull on server]
D --> E[post-merge hook runs]
E --> F{What changed?}
F -->|Service files| G[systemctl restart service]
F -->|Other files| I[No action needed]
J[Push to main affecting projects/**/lib or pubspec] --> K[GitHub Actions]
K --> L[flutter build web per matrix project]
L --> M[rsync into ~/vps-ai/projects/<name>/build/web/]
M --> N[POST event to /status/log]
style G fill:#81C784,color:#000
style L fill:#FFB74D,color:#000
style M fill:#4FC3F7,color:#000
Key points:
- Build output is not stored in git — Flutter apps are built in CI and
rsync'd to the server over a restricted SSH key (rrsync -wo) - Flutter is not installed on the server — the VPS only runs the deployed assets
- The
--base-href /<project-name>/flag is applied automatically by the workflow - Adding a new Flutter project requires no workflow changes — any
projects/*/directory with apubspec.yamlis auto-detected - The status page shows a "Recent Events" panel; CI posts deploy results there via
POST /status/log
# One-time server provisioning
sudo bash setup-server.sh
# Create config
cat > .env.issues << 'EOF'
GITHUB_TOKEN=<fine-grained-pat>
GITHUB_REPO=epatel/vps-ai
WEBHOOK_SECRET=<random-secret>
EOF
chmod 600 .env.issuesBeyond that, a few things live outside this repo and must be configured by hand — see Manual configuration below.
Just open an issue. The agent handles the rest.
# Manual trigger for a specific issue
bash monitor-issues.sh <issue_number>
# Watch logs
tail -f .issues-monitor.log
tail -f .agent-issue-N.logCreate a token at GitHub → Settings → Developer settings → Fine-grained personal access tokens, scoped to the epatel/vps-ai repo, with:
- Issues: Read and write
- Pull requests: Read and write
- Contents: Read and write
Put it in .env.issues as GITHUB_TOKEN.
In the repo's Settings → Webhooks, create a webhook with:
- URL:
https://ai.memention.net/webhook - Content type:
application/json - Secret: must match
WEBHOOK_SECRETin.env.issues - Events: Issues, Pull requests, and Pushes (Issues triggers the agent; Pull requests and Pushes trigger
git pull+ the post-merge hook on the server)
Nginx is the single public entry point for everything on ai.memention.net. It handles TLS, reverse-proxies the webhook and backend services, and serves static and Flutter web projects directly from disk. The config lives at /etc/nginx/sites-available/ai.memention.net; sites-enabled is a symlink to it, so always edit the sites-available copy.
The config is organized as a set of location blocks, one per project, in front of a catch-all that serves the landing page. The block type depends on what the project is:
- Static sites — an
aliaspointing at the project directory - Flutter web apps — an
aliastobuild/web/plustry_filesfor SPA routing - Python / HTTP services — a
proxy_passto the service's local port - WebSocket services — a dedicated block with
proxy_http_version 1.1and theUpgradeheaders - Webhook — a
proxy_passto the local webhook receiver
Because nginx uses longest-prefix match and the root location / is an alias for the landing page, new project blocks must be added before the catch-all or they will be shadowed by it. After editing, validate and reload:
sudo nginx -t && sudo systemctl reload nginxThe webhook receiver runs as a systemd service. See setup-server.sh for the service definition. If the service file changes, reload and restart manually:
sudo systemctl daemon-reload
sudo systemctl restart vps-ai-webhookGitHub Actions deploys Flutter builds via rsync over SSH. Two repo secrets and one authorized_keys entry are involved (set up once):
DEPLOY_SSH_KEY— private ed25519 key for the deploy userDEPLOY_KNOWN_HOSTS— output ofssh-keyscan -t ed25519 ai.memention.net- The matching public key on the VPS, prefixed with
command="rrsync -wo /home/epatel/vps-ai/projects",no-pty,no-agent-forwarding,no-port-forwarding,no-X11-forwarding, so the key can onlyrsyncinto project subdirs
The status page exposes POST /status/log for arbitrary deploy/notification events. Events are kept on disk (projects/status-page/.events.jsonl, last 200) and the last five are rendered in the "Recent Events" panel. Auth is a Bearer token (STATUS_LOG_TOKEN) configured in two places:
- The
status-page.servicesystemd unit on the server (drop-in at/etc/systemd/system/status-page.service.d/env.conf) - The
STATUS_LOG_TOKENGitHub Actions secret, used by the Flutter workflow
Posting from anywhere:
curl -fsS -m 5 -X POST https://ai.memention.net/status/log \
-H "Authorization: Bearer $STATUS_LOG_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"source":"manual","message":"deployed v1.2"}'Agent-created projects live under projects/. Services are managed via systemd — add entries to hooks/post-merge to auto-restart on deploy.
| Project | Description |
|---|---|
| asteroids | Multiplayer Asteroids arcade game with WebSocket networking |
| badge | E-paper badge designer/writer over BLE |
| breakout | Classic Breakout brick-breaker game (single-page HTML) |
| drop | Instant cross-device sharing (text, links, images, files) via paired PWA |
| flutter_demo | Flutter web demo app |
| poem | A poem about working with AI |
| scramble | Vectrex-style arcade flight shooter with terrain and enemies |
| status-page | Server status dashboard with metrics graphs and a deploy/event log (Python + systemd service) |
| todo-api | REST API for todos with JWT auth (Python/Flask) |
| todo-app | Flutter web frontend for the todo API |
| trumps48hours | Sci-fi countdown timer with particle effects |