- sites.AskHandler now approves <name>.AGENTBBS_HOST on-demand-TLS when <name>
is a registered member (so only real users mint subdomain certs).
- Caddyfile: *.${DOMAIN} block serving users/<name>/public_html with on_demand
TLS; unknown users 404. Needs a wildcard DNS record *.${DOMAIN} -> host.
- Test: TestAskUserSubdomain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
On Ubuntu 22.10+/24.04 sshd is socket-activated via ssh.socket, which owns the
listen port and ignores sshd_config's Port — so the admin-port move silently
failed (safety check aborted before freeing :22). Override ssh.socket's
ListenStream to ADMIN_SSH_PORT when present; fall back to restarting the service
on classic setups.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
512MB droplets OOM-kill the Go build (livekit/redis/modernc deps). Add:
- ensure_swap: adds a 3G swapfile on low-RAM hosts (build + runtime headroom)
- SKIP_BUILD=1: use prebuilt /usr/local/bin/{agentbbs,ascii-live} (copied from
CI or a dev box) instead of compiling on the host
- go build -p=1 to cap peak memory when building on-box
- install unzip (Freedoom fetch needs it)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CreatePremiumCharge/VerifyPremium now POST /payments/create and GET
/payments/:id against the CoinPay API (Bearer COINPAY_API_KEY, business_id =
AGENTBBS_COINPAY_MERCHANT_ID), so the droplet needs no coinpay CLI installed.
The created payment id is stored (store: User.PremiumPayID + premium_pay_id col
+ SetPremiumPayment); ensurePremium verifies that id on a later connect and
grants premium on confirmed/forwarded status. Removed the CLI command-template
env knobs; added AGENTBBS_COINPAY_API_URL. Tests: httptest-backed payments_test
+ store SetPremiumPayment test. Build/vet/gofmt/test green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- payments: AGENTBBS_COINPAY_MERCHANT_ID -> --business-id on the premium
create/pay commands (coinpay CLI reads COINPAY_API_KEY from env for auth).
- deploy.yml: forward COINPAY_API_KEY + COINPAY_MERCHANT_ID (GitHub secrets,
masked in logs) to the remote setup.sh.
- setup.sh: idempotent upsert_env writes those secrets into agentbbs.env
(COINPAY_API_KEY, AGENTBBS_COINPAY_MERCHANT_ID, COINPAY_BUSINESS_ID),
preserving the rest. No secret values are committed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The SSH examples and AGENTBBS_HOST default showed the bare apex
profullstack.com; the BBS lives on bbs.profullstack.com. Fix the README
examples/membership/config-table and align the code default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Deploy automation (idempotent, runs on every deploy):
- .github/workflows/deploy.yml: push to main/master (or dispatch) SSHes to the
droplet and re-runs setup.sh; deploys the pushed branch; smoke-tests :22.
- scripts/self-update.sh + agentbbs-update.timer: autonomous backstop that
redeploys only when origin advances.
- setup.sh hardened: flock, fetch+reset (survives force-push), fixed the
always-skipped arcade asset fetch path.
Membership model:
- Free, email-verified members get their own Docker pod (pod@ paywall removed)
and a /~name homepage (seeded at join@).
- join@ is now interactive: email -> emailed 6-digit code -> enter code.
- Premium ($10 one-time, lifetime via CoinPay) grants a personal
<name>@host email (new internal/forwardemail; forwardemail.net aliases) and
custom domains (domain@ gated to Premium).
- ensurePremium() silently verifies/grants/provisions on hub login, join@, and
domain@. New-signup details emailed to AGENTBBS_SIGNUP_NOTIFY (subject "bbs").
Store: User.Premium + premium/premium_ref cols, ConfirmEmailCode, GrantPremium.
Tests: store_premium_test.go, forwardemail_test.go. Build/vet/gofmt/test green.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Deploy automation (idempotent, runs on every deploy):
- .github/workflows/deploy.yml: push to main/master (or dispatch) SSHes to the
droplet and re-runs setup.sh; deploys the pushed branch; smoke-tests :22.
- scripts/self-update.sh + agentbbs-update.timer: autonomous backstop that
redeploys only when origin advances.
- setup.sh hardened: flock, fetch+reset (survives force-push), fixed the
always-skipped arcade asset fetch path.
Membership model:
- Free, email-verified members get their own Docker pod (pod@ paywall removed)
and a /~name homepage (seeded at join@).
- join@ is now interactive: email -> emailed 6-digit code -> enter code.
- Premium ($10 one-time, lifetime via CoinPay) grants a personal
<name>@host email (new internal/forwardemail; forwardemail.net aliases) and
custom domains (domain@ gated to Premium).
- ensurePremium() silently verifies/grants/provisions on hub login, join@, and
domain@. New-signup details emailed to AGENTBBS_SIGNUP_NOTIFY (subject "bbs").
Store: User.Premium + premium/premium_ref cols, ConfirmEmailCode, GrantPremium.
Tests: store_premium_test.go, forwardemail_test.go. Build/vet/gofmt/test green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Proxy /verify on the main site to the agentbbs loopback endpoint and
surface AGENTBBS_HTTP_ADDR + the SMTP knobs in the generated env file
(links are logged when SMTP is unconfigured; existing env files keep
working via the in-binary 127.0.0.1:8088 default).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- setup.sh: idempotent one-shot droplet provisioner — agentbbs on :22
(admin OpenSSH moved to :2202), rootless podman, Caddy front end for
https://bbs.profullstack.com with tilde-style /~user homepages
- internal/sites + domain@ SSH route: self-service custom domains
(ssh domain@host add example.com) backed by a symlink farm and an
on-demand-TLS ask endpoint so Caddy only issues certs for mapped hosts
- internal/mail + join@ email verification: optional email at signup,
confirmation link served by a loopback /verify endpoint behind Caddy
- internal/source + cmd/ascii-live: live video → terminal ASCII groundwork
(docs/ascii-live.md)
- store: additive sqlite migrations (email/verify columns, domains table)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ssh video-<code>@ joins a PairUX/LiveKit call rendered as truecolor
ASCII (▀ half-blocks, 2 pixels per cell); video@ prompts for a code.
Codes are minted by PairUX only. Pipeline: VP8 RTP → PLI keyframe
requests → ivfwriter remux → ffmpeg decode/scale → RGB24 → ANSI →
bubbletea over the SSH PTY. Subscriber-only, no audio in v1.
ssh agent@ opens a persisted chat with the operator's agent —
AGENTBBS_AGENT_CMD runs per message (stdin→stdout), e.g. `claude -p`.
ssh <member>@ with someone else's name prints a classic finger card
(.plan, member since, last seen) and disconnects; your own name still
enters the hub.
cmd/lkpublish: dev publisher for testing (explicit -fps pacing; lksdk
IVF replay mispaces from file timebase alone, measured 1fps from a
15fps file; dimensions required or dynacast pauses the track).
Verified end-to-end against livekit-server --dev: 128k truecolor cells
/ 20k distinct colors streamed over a real SSH session; chat round-trip
and finger card verified over SSH. Go toolchain pinned to 1.26 via
mise.toml (lksdk requirement).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A modern BBS over SSH for humans and AI agents (docs/PRD.md), plus the
pods addendum (docs/pods.md). Go + charmbracelet (wish/bubbletea).
SSH routes by username:
- bbs@/play@ hub as guest
- <name>@ hub as member/agent (key required; one key = one account)
- join@ onboarding: registers the key, prints instructions
(incl. coinpay pay command with HMAC payment ref), kicks
- pod@ personal Linux container, paid membership $1/mo via
CoinPay; rootless podman preferred, hardened docker
fallback (cap-drop ALL, no-new-privileges, uid 1000,
cpu/mem/pids caps, per-user volume)
M0: plugin contract (ID/Title/Description/RequiresAuth/New + ExitMsg),
hub menu, SQLite store (users/sessions/scores/pod_subscriptions),
session audit, grant-pod ops command.
M1 arcade: doom-ascii + Freedoom via scripts/fetch-assets.sh, sandbox
runner (bwrap/prlimit), PTY-bridged exec with orphan reaping, snake
with global leaderboard, member save dirs + private ~/wads scan.
Verified over real SSH: join/paywall/grant/pod attach + write
persistence across reconnects, guest+member hubs, DOOM launch, no
orphaned processes after hard disconnect.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>