← JayCorp

Handoff README

For AI systems (and people) picking up work on JayCorp's AI server: how the machine is set up, what runs on it, and how to add or change sites and pages. Facts were checked on the machine on 2026-10-09. No secret values appear here, and none ever should.

1. Read these first

2. The machine

Hostnamededicated-ai-x1-00
HardwareLenovo ThinkPad X1 Extreme 2nd gen laptop, 16 CPU threads, 30 GiB RAM, NVIDIA GTX 1650 Max-Q (4 GiB) plus Intel UHD 630, 937 GB NVMe
OSUbuntu 26.04.1 LTS, kernel 7.0
Userjayai; everything runs as this user, not root
Project root/home/jayai/Projects/jayai (not a git repository yet; static_www/ is its own git repository, branch main, local only, since 2026-10-15)
Servicesuser systemd units with lingering on (Linger=yes), so they run at boot without a login
Exposurethe only way in from the internet is the edge: a DigitalOcean droplet (174.138.65.239, ssh edge) running Caddy and Authelia, which reaches this machine over a WireGuard tunnel (wg0, droplet 10.88.0.1, this machine 10.88.0.2). Only what the edge serves listens beyond 127.0.0.1: static-www and radio on 0.0.0.0, Grafana, live and opencode on 10.88.0.2. ngrok was retired on 2026-10-18. See edge/README.md.

Installed tools

ToolVersionWhere
Ruby, RubyGems3.3.8, 3.6.7system (/usr/bin)
Bundleruser gem~/.local/share/gem/ruby/3.3.0/bin/bundle (not on PATH; units call it by full path). Each app vendors gems in vendor/bundle.
Claude Code2.1.295~/.local/bin/claude, telemetry on to the local collector
TypeSafe skill (Claude Code plugin)0.5.7typesafe@typesafe-ai, user scope, in ~/.claude/plugins; guidance for building with TypeSafe's Jev decision model, invoked as /typesafe:typesafe-ai. Docs only; calling Jev itself needs a TypeSafe API key, not set up yet
Codex CLI0.162.1~/.local/bin/codex (GitHub release binary); signs in with ChatGPT, auth in ~/.codex
Kimi Code2.1.1~/.local/bin/kimi (global kimi.ai installer); auth in ~/.kimi-code
GitHub CLI2.102.0~/.local/bin/gh (release tarball); auth in ~/.config/gh
ngrok3.39.11~/.local/bin/ngrok, config ~/.config/ngrok/ngrok.yml; retired 2026-10-18, no longer running
Caddy, Authelia, WireGuard (on the edge droplet)2.11.7, 4.39.28, 1.0.20210914Ubuntu 24.04 droplet, from their apt repos; configs mirrored in edge/
Ollama0.40.1~/.local/bin/ollama; models qwen3:4b, qwen3-vl:2b, qwen2.5vl:3b, moondream
whisper.cppsmall.en modelbuilt from ~/.local/src/whisper.cpp
Grafana, Prometheus, Loki, Tempo, OpenTelemetry Collector13.2.3, 3.15.0, 3.7.8, 3.1.0, 0.162.0~/.local/opt/<name> symlinks to versioned folders
ffmpeg, git, curl, jq, ripgrep, Python8.0.1, 2.53.0, 8.18.0, 1.8.1, 14.1.1, 3.14.4system
NVIDIA driver595.99.02system (nvidia-smi)

Not installed today: Node, Docker, Bitwarden bws. AGENTS.md section 11 wants at least two swappable AI providers, so app code that calls Codex or Kimi goes behind an adapter.

3. Repository layout

/home/jayai/Projects/jayai
├── AGENTS.md, CLAUDE.md   rules for agents
├── static_www/            static sites, one folder per domain (this page lives here)
├── apps/live/             the one dynamic app so far
├── observability/         OpenTelemetry + Grafana stack and the service registry
└── secrets/               the secrets adapter

4. Static sites: static_www

Live sites

SiteWhat it is
jaycorp.usJayCorp's home: how we work, research pages on AI harnesses and graph engineering, and this handoff page.
www.ruby.imEngineering notes for people and coding agents: why Ruby, testing, identity, services, secrets, observability, hardware. Publishes AGENTS.md. Hosts the /live app.
aol.pmSecurity research notes: how systems fail and how to defend what we run.
bada.imAdversarial research on ML models and agents, including a "hacking with AI" page.
www.michigan.imMichigan events calendar, rendered from events.yml by static_www/bin/michigan-calendar.
_default"No site here yet" page for hosts with no folder, such as yohohoho.com today.

5. Apps: apps/live

Phone monitoring with local AI, at www.ruby.im/live (access token required). A phone streams camera and mic over a WebSocket to a Falcon server on 10.88.0.2:8090 (unit live); ffmpeg splits the stream into clips and frames, and scripts in analyzers/ transcribe audio with whisper.cpp (unit whisper, port 8178) and describe frames with Ollama (unit ollama, port 11434). Sessions are saved under apps/live/sessions/, and bin/summarize writes an AI summary per session through lib/llm.rb (LIVE_LLM=ollama by default, anthropic as the second provider). Details: apps/live/README.md.

New apps go in apps/<name>/ with their own Gemfile, README and user systemd unit, bound to 127.0.0.1 on a port from config. To publish one, bind it to 10.88.0.2 and add a route in edge/Caddyfile.

6. Observability

OpenTelemetry into a local Grafana stack, all on 127.0.0.1 (observability/README.md):

apps, agents ─OTLP :4317/:4318─▶ otelcol ─▶ Prometheus :9090  (metrics, 30 days)
host + GPU metrics, journald ──▶         ─▶ Loki :3100        (logs, 30 days)
health checks ─────────────────▶         ─▶ Tempo :3200       (traces, 7 days)
                                Grafana :3000 reads all three

7. Secrets

8. How to add or update a page

  1. Edit or create the HTML file in static_www/sites/<domain>/. Plain HTML with inline CSS, matching the site's existing pages (copy the <style> block, light and dark colors, from the home page). No build step.
  2. Link a new page from the site's home page (or the relevant section). Don't add a "More sites" footer; the server adds it.
  3. Add a changelog entry in the same change, one plain sentence:
    static_www/bin/changelog <domain> "What changed"
    It inserts a dated line at the top of sites/<domain>/changelog.html, creating the page if needed. Every www.ruby.im change needs one; every other site keeps one too.
  4. Nothing to restart: the file is live as soon as it's saved. Check it:
    curl -sI https://<domain>/<page>.html

9. How to add a new site

  1. Point the domain's @ and * A records at 174.138.65.239 (Name.com; edge/bin/dns add <domain> '*' with the token from ~/.config/environment.d/namecom.conf). For a new domain, also add it to the allow-list in edge/Caddyfile and copy that to the droplet.
  2. Create static_www/sites/<domain>/index.html. It's live as soon as DNS resolves; Caddy gets the certificate on the first visit. Use the www. name for the folder if that's the canonical host.
  3. Start its changelog: static_www/bin/changelog <domain> "Launched the first version of <domain>.", and link /changelog.html from its footer.
  4. Register it in observability/services.yml (unit static-www.service, health https://<domain>/), then restart otelcol.
  5. Confirm: curl -sI https://<domain>/ returns 200 with a valid certificate.

10. Useful commands

systemctl --user status static-www live whisper ollama
systemctl --user status otelcol prometheus loki tempo grafana gpu-metrics
ssh edge 'systemctl status caddy authelia wg-quick@wg0'
ssh edge 'journalctl -u caddy -f'
scp edge/Caddyfile edge:/etc/caddy/ && ssh edge 'caddy validate --config /etc/caddy/Caddyfile && systemctl reload caddy'
observability/bin/check
ruby static_www/test/network_footer_test.rb

Provided as is, for information only, with no warranty and no liability. Not legal or professional advice. Security and radio material is for authorized, lawful use only. Full disclaimer.

Visits are logged on our own server: IP address, browser and device details, and pages viewed. We use them to understand traffic and spot attacks, and never share or sell them.