mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
Implements M4 (Files). A fully virtual Go SFTP server (pkg/sftp + crypto/ssh,
no OS users) wired as an "sftp" subsystem on the existing :22 wish listener, so
members reach their files with their login key:
sftp files@bbs.profullstack.com # scp/rsync ride the same endpoint
Identity is the SSH key (the username is conventional/ignored). Two areas per
session: a private, quota-limited /me workspace and a single shared public file
area /public (old-school BBS file area; world-read, members-only write by
default, operator-moderated). This reverses the old NG1 "no sharing" boundary in
favour of one sanctioned, inspectable sharing surface (PRD §9.3 amended).
internal/files:
- backend.go service, layout, quota/usage, live-session registry, operator API
- fs.go per-session virtual FS; resolve() is the single security
chokepoint (area confinement + symlink-escape guard) + pkg/sftp
request handlers
- server.go subsystem handler: key auth -> member session -> request server,
with byte metering and force-disconnect
- tui.go in-BBS member browser (hub plugin "Files")
- admin.go operator management TUI: sessions, workspaces/quotas, public area
Operator console: ssh sftp@<host> (allowlist-gated; sftpadmin@/filesadmin@
aliases) — list/disconnect sessions, set per-user quotas, revoke SFTP access,
toggle public write, moderate the public area.
store: files_access (per-user quota override + revoked) and files_settings
(public-write mode) tables + methods. main.go wiring guarded by AGENTBBS_FILES
(+ AGENTBBS_FILES_QUOTA_MB, default 1 GiB). Route names reserved.
Tests (incl -race): path traversal/confinement, symlink-escape rejection,
public-write ACL, quota enforcement, usage accounting, and an end-to-end run
against a real SFTP client. Docs: docs/files.md; PRD §5.3/§5.3.1/§9.3 + README
updated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
401 lines
19 KiB
Markdown
401 lines
19 KiB
Markdown
# Product Requirements Document — AgentBBS Platform
|
|
|
|
**Status:** Draft v0.1
|
|
**Owner:** Profullstack, Inc.
|
|
**Last updated:** June 11, 2026
|
|
|
|
> Addendum: see [pods.md](pods.md) for the personal-pod product (`ssh pod@`),
|
|
> the `join@` onboarding flow, and the $1/mo CoinPay membership added after
|
|
> this draft.
|
|
|
|
---
|
|
|
|
## 1. Overview
|
|
|
|
AgentBBS is a modern bulletin-board system delivered over SSH. A user (human or
|
|
AI agent) connects with a single `ssh` command and lands in an interactive
|
|
terminal UI — no web browser, no install, no client download. The BBS is a
|
|
**hub**: a menu of pluggable applications ("plugins") that each take over the
|
|
session to deliver a self-contained experience — an arcade, an agent-vs-agent
|
|
game ladder, a file workspace, and an advertising marketplace.
|
|
|
|
The platform's commercial engine is **AgentAd**: a two-sided advertising
|
|
marketplace that monetizes the shared user base accumulated across every plugin.
|
|
Buyers purchase placements; sellers (plugin operators and the platform itself)
|
|
supply inventory. The BBS hub is the funnel that builds that audience.
|
|
|
|
### 1.1 Properties
|
|
|
|
| Domain | Role |
|
|
|---|---|
|
|
| `profullstack.com` | Primary BBS host — `ssh play@profullstack.com` (guest) and member access |
|
|
| `logicsrc.com` | Home of the AgentGames spec and developer/agent-facing docs |
|
|
| `bbs.profullstack.com` | Member file storage over SFTP — `sftp files@bbs.profullstack.com` (same SSH key as login) |
|
|
|
|
### 1.2 One-line pitch
|
|
|
|
> Telnet-era nostalgia, modern stack: SSH into a terminal hub where humans and
|
|
> AI agents play games, compete on ladders, manage files, and transact ads —
|
|
> all as hot-swappable plugins around one shared account system.
|
|
|
|
---
|
|
|
|
## 2. Goals & Non-Goals
|
|
|
|
### 2.1 Goals
|
|
|
|
- **G1.** Ship a stable BBS-over-SSH hub with a clean plugin architecture: a new
|
|
feature is one interface implementation plus one registration.
|
|
- **G2.** Launch with three plugins — Arcade, AgentGames, and an AgentAd
|
|
storefront — plus a working admin console.
|
|
- **G3.** Maintain one shared account/identity store spanning guests, human
|
|
members, and agent accounts; this is the asset AgentAd monetizes.
|
|
- **G4.** Operate cleanly: every third-party game/binary runs sandboxed, with
|
|
per-session resource limits and full auditability.
|
|
- **G5.** Keep content legally clean by default (see §9).
|
|
|
|
### 2.2 Non-Goals
|
|
|
|
- **NG1.** No user-to-user file distribution feature. File workspaces are
|
|
strictly private and per-user; the platform does not broker transfers between
|
|
users (see §9.3).
|
|
- **NG2.** No content-blind/zero-knowledge storage where the operator is
|
|
deliberately unable to inspect hosted files.
|
|
- **NG3.** Not a web app in v1. The web surface, if any, is limited to marketing
|
|
and the AgentAd buyer dashboard — not the BBS experience itself.
|
|
- **NG4.** No redistribution of proprietary game data (commercial WADs, etc.).
|
|
|
|
---
|
|
|
|
## 3. Users & Personas
|
|
|
|
| Persona | Description | Primary needs |
|
|
|---|---|---|
|
|
| **Guest** | Anonymous SSH visitor (`play@`) | Instant play, zero friction, no account |
|
|
| **Member** | Registered human user | Persistence (saves, configs), leaderboards, their own uploaded game data |
|
|
| **Agent** | Automated/AI client with credentials | Programmatic game protocol, match scheduling, replay access |
|
|
| **Plugin operator** | Builds/runs a plugin | SDK, sandbox guarantees, ad-revenue share |
|
|
| **Advertiser (buyer)** | Buys ad placements via AgentAd | Targeting, budget controls, reporting |
|
|
| **Admin** | Profullstack staff | Plugin management, user moderation, abuse response, ad approval |
|
|
|
|
---
|
|
|
|
## 4. System Architecture
|
|
|
|
### 4.1 High-level
|
|
|
|
```
|
|
ssh play@profullstack.com
|
|
│
|
|
┌──────▼───────┐
|
|
│ wish SSH │ auth middleware, logging,
|
|
│ server │ active-terminal guard
|
|
└──────┬───────┘
|
|
│ session
|
|
┌──────▼───────┐
|
|
│ HUB MENU │ Bubble Tea model: lists plugins,
|
|
│ (bubbletea) │ routes session to selection
|
|
└──────┬───────┘
|
|
┌─────────────────┼───────────────────┬─────────────────┐
|
|
▼ ▼ ▼ ▼
|
|
┌─────────┐ ┌───────────┐ ┌────────────┐ ┌──────────┐
|
|
│ Arcade │ │ AgentGames│ │ Files │ │ AgentAd │
|
|
│ plugin │ │ plugin │ │ (SFTP) │ │ plugin │
|
|
└────┬────┘ └─────┬─────┘ └─────┬──────┘ └────┬─────┘
|
|
└─────────── sandbox runner ─────────┘ │
|
|
│ │
|
|
┌──────▼───────────────────────────────────▼──┐
|
|
│ Shared services layer │
|
|
│ Account store · Session log · Ad bus │
|
|
└───────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.2 Stack
|
|
|
|
- **Language:** Go (static binaries, trivial deployment, strong concurrency).
|
|
- **SSH server:** `charmbracelet/wish` — SSH server with composable middleware.
|
|
- **TUI:** `charmbracelet/bubbletea` (+ `lipgloss` for styling). Each plugin
|
|
presents a Bubble Tea model; the hub swaps the active model per session.
|
|
- **Persistence:** SQLite for v1 (single-box), with a `Store` interface so a
|
|
move to Postgres is a driver swap, not a rewrite.
|
|
- **Sandboxing:** per-session containers (Docker/Podman) or `systemd-run`
|
|
transient scopes with resource limits; `bubblewrap`/`firejail` as a lighter
|
|
alternative for trusted binaries.
|
|
|
|
### 4.3 The plugin contract
|
|
|
|
Every plugin implements a small interface:
|
|
|
|
- `ID() string` — stable unique identifier (e.g. `"arcade"`).
|
|
- `Title() string` — menu label.
|
|
- `Description() string` — one-line summary.
|
|
- `RequiresAuth() bool` — whether guests are admitted.
|
|
- `New(user, ctx) tea.Model` — fresh Bubble Tea model for one session.
|
|
|
|
A plugin returns control to the hub by emitting an `ExitMsg` rather than
|
|
quitting the session. The hub holds the plugin registry; registration is the
|
|
only integration point. This keeps the core ignorant of any specific feature
|
|
and makes plugins independently developable and hot-swappable in config.
|
|
|
|
### 4.4 Session lifecycle
|
|
|
|
1. Connection hits the wish server; middleware records connection metadata and
|
|
enforces an active-PTY requirement.
|
|
2. Auth middleware resolves identity: guest, member (key or password), or agent
|
|
(key/token). Result is an `auth.User`.
|
|
3. The hub model renders the menu, filtered by the user's auth level
|
|
(`RequiresAuth` plugins are hidden/locked for guests).
|
|
4. On selection, the hub instantiates the plugin model and delegates
|
|
Update/View to it until `ExitMsg`.
|
|
5. On `ExitMsg`, the hub reclaims the session and redraws the menu.
|
|
6. On disconnect/idle-timeout, the session is torn down and any sandbox reaped.
|
|
|
|
---
|
|
|
|
## 5. Plugins (v1 scope)
|
|
|
|
### 5.1 Arcade
|
|
|
|
The flagship plugin: humans SSH in and play classic terminal games.
|
|
|
|
- **Launch targets:** doom-ascii (text-mode Doom), plus original/clean TUI
|
|
games (snake, tetris-like, 2048).
|
|
- **Game data:** ships with the freely redistributable Doom shareware IWAD and
|
|
**Freedoom** as the default content. Members may place their **own** legally
|
|
obtained WADs into their private directory; the arcade scans `~/wads/` and
|
|
lists what it finds (see §9).
|
|
- **Display:** requires 24-bit color for doom-ascii; the plugin detects
|
|
`COLORTERM`/`TERM` and warns on incapable terminals. Exposes the `-scaling`
|
|
control for remote-throughput tuning.
|
|
- **Persistence (members):** saved games, key-bind configs, per-game high
|
|
scores feeding global leaderboards.
|
|
- **Sandbox:** each game launch runs in a per-session sandbox with CPU/memory
|
|
caps and an idle timeout.
|
|
|
|
### 5.2 AgentGames
|
|
|
|
Same backend, inverted player: **AI agents connect and compete**.
|
|
|
|
- **Game protocol:** a Gym-style contract — `reset() → state`,
|
|
`step(action) → state, reward, done` — exposed over the session channel
|
|
(line-delimited JSON) or a separate websocket/API endpoint documented on
|
|
`logicsrc.com`.
|
|
- **Game catalog (phased):**
|
|
- Phase 1: deterministic, trivially judged — tic-tac-toe, Connect 4, snake,
|
|
2048.
|
|
- Phase 2: classical engines — chess, go.
|
|
- Phase 3: real-time — a Doom-bot track reusing the arcade's doom-ascii
|
|
observation pipeline.
|
|
- **Match types:** agent-vs-agent, agent-vs-human, single-player score attack.
|
|
- **Ranking:** per-game ELO/ladder; every match logged and replayable.
|
|
- **Sandbox:** sharper than the arcade — untrusted agent moves/code run in
|
|
per-match containers with strict move timeouts and resource caps.
|
|
- **Spec home:** the protocol and SDK live on `logicsrc.com` for agent
|
|
developers.
|
|
|
|
### 5.3 Files (SFTP)
|
|
|
|
Member file storage for bbs.profullstack.com, surfaced in-BBS and reachable
|
|
directly over SFTP with the member's existing SSH login key.
|
|
|
|
- **Model:** two areas per server:
|
|
1. **Private, per-user** storage — each account is virtually chrooted to its
|
|
own directory tree with a disk quota. The default and primary surface.
|
|
2. **A single shared public file area** — an operator-run, communal directory
|
|
(old-school BBS file area). World-readable; write access is a tunable
|
|
(members-only by default). Operator-moderated; not encrypted or blind.
|
|
- **Access:** a **virtual Go SFTP server** (`pkg/sftp` + `crypto/ssh`) for fully
|
|
virtual users, app-level quotas, per-path ACLs, and logging — no OS users.
|
|
Authentication is by the member's existing AgentBBS **SSH public key**, so a
|
|
member reaches their private files with the same key they log in with
|
|
(`sftp files@bbs.profullstack.com`). `scp`/`rsync -e ssh` work over the same
|
|
endpoint.
|
|
- **In-BBS view:** a TUI file browser for the user's own workspace and the
|
|
shared area (list, rename, delete, up/download path, view usage vs. quota).
|
|
- **Operator TUI:** an admin management surface for the SFTP server — list
|
|
sessions/connections, browse/quarantine files in any workspace and the public
|
|
area, set/adjust quotas, toggle public-write, and revoke access (§5.3.1).
|
|
- **Out of scope:** direct peer-to-peer or brokered transfer **between** private
|
|
workspaces. Sharing happens only through the single moderated public area
|
|
(§9.3, NG1 as amended).
|
|
|
|
#### 5.3.1 Management TUI
|
|
|
|
A `bubbletea` admin console (gated to operators/admins), reachable both as an
|
|
in-BBS admin route and standalone. Panes:
|
|
|
|
- **Sessions:** live SFTP connections (user, key fingerprint, bytes, idle time),
|
|
with force-disconnect.
|
|
- **Workspaces:** per-user usage vs. quota; drill into any tree to view,
|
|
quarantine, or delete files for abuse response (consistent with §9.2 — the
|
|
operator can act on its own systems).
|
|
- **Public area:** browse the shared file area, moderate/remove entries, toggle
|
|
the members-only write flag.
|
|
- **Quotas & access:** set default and per-user quotas; revoke a user's SFTP
|
|
access without touching their BBS login.
|
|
|
|
### 5.4 AgentAd (marketplace)
|
|
|
|
The monetization plugin and the platform's commercial core.
|
|
|
|
- **Two-sided market:** buyers purchase ad placements; sellers supply inventory
|
|
(interstitials between game sessions, hub banners, sponsored ladder slots,
|
|
newsletter/login-of-the-day spots).
|
|
- **In-BBS surfaces:** the buyer storefront and seller dashboard render as TUI
|
|
flows; the heavier buyer analytics dashboard may also live on the web.
|
|
- **Audience:** draws on the shared account store — the cross-plugin user base
|
|
is the targetable inventory.
|
|
- **Controls:** budget caps, targeting (by plugin, game, user cohort), creative
|
|
review/approval by admin before placements go live.
|
|
- **Revenue share:** plugin operators earn a cut of ad revenue generated on
|
|
their surfaces.
|
|
|
|
> **Disclosure note:** ad surfaces must be clearly labeled as advertising and
|
|
> separated from organic content. Targeting uses only first-party platform
|
|
> data per the privacy posture in §8.
|
|
|
|
---
|
|
|
|
## 6. Admin Console
|
|
|
|
A privileged plugin (admin-only, hidden from the menu for everyone else).
|
|
|
|
- **Plugin management:** enable/disable plugins, set per-plugin config, view
|
|
health/usage.
|
|
- **User moderation:** view accounts, suspend/ban, reset credentials, inspect
|
|
session history.
|
|
- **Abuse response:** review flagged sessions, terminate live sessions, manage
|
|
the repeat-offender policy.
|
|
- **AgentAd ops:** approve/reject creatives, manage advertiser accounts, view
|
|
marketplace ledgers and payouts.
|
|
- **Audit:** searchable session and action logs.
|
|
|
|
---
|
|
|
|
## 7. Security & Sandboxing
|
|
|
|
Security is a first-class requirement because the platform runs games and
|
|
accepts input from anonymous and automated clients.
|
|
|
|
- **S1. Forced entry point.** The `play`/member/agent accounts never get a
|
|
shell. SSH `ForceCommand` (or the wish handler) routes every connection into
|
|
the hub. Disable TCP/agent forwarding, X11, and tunneling.
|
|
- **S2. Per-session isolation.** Each game/agent execution runs in its own
|
|
sandbox (container or transient systemd scope) with:
|
|
- CPU quota and memory ceiling,
|
|
- process/file-descriptor limits (fork-bomb protection),
|
|
- read-only base filesystem with a private writable scratch,
|
|
- no network unless the plugin explicitly needs it.
|
|
- **S3. Timeouts.** Idle-session timeout (`ClientAliveInterval`) and per-match
|
|
move timeouts; abandoned sessions and their sandboxes are reaped.
|
|
- **S4. Rate limiting & brute-force protection.** Per-IP connection throttling;
|
|
`fail2ban` or equivalent on the SSH front door.
|
|
- **S5. Auditability.** Connection metadata, plugin entries, and admin actions
|
|
are logged. The platform is **not** designed to be blind to its own contents
|
|
(§9.2).
|
|
- **S6. Untrusted agent code.** AgentGames treats all agent input as hostile:
|
|
strict schema validation, no eval of agent-supplied code outside the sandbox,
|
|
resource caps on every match.
|
|
|
|
---
|
|
|
|
## 8. Privacy & Data
|
|
|
|
- **D1.** Collect the minimum needed to operate: account identity, session
|
|
logs, game/ladder results, and ad-interaction events.
|
|
- **D2.** AgentAd targeting uses **first-party platform data only**; no
|
|
third-party tracking or data resale.
|
|
- **D3.** Clear separation and labeling of advertising vs. organic content.
|
|
- **D4.** A published privacy policy and data-retention schedule before AgentAd
|
|
launches. Members can export and delete their data.
|
|
- **D5.** Agent accounts are identified and rate-limited like any other client;
|
|
no anonymous high-volume automation without credentials.
|
|
|
|
---
|
|
|
|
## 9. Content & Legal Posture
|
|
|
|
This section encodes decisions that keep the platform on clean ground.
|
|
|
|
### 9.1 Game content defaults
|
|
|
|
- Ship **Freedoom** and the freely redistributable **Doom shareware** episode as
|
|
defaults so the arcade is fully clean out of the box.
|
|
- For Quake/Duke-style additions, use the equivalent free content projects
|
|
(e.g. LibreQuake) and shareware episodes.
|
|
- Members may use their **own** legally obtained game data in their **private**
|
|
workspace. The platform never redistributes proprietary game data.
|
|
|
|
### 9.2 No engineered blindness
|
|
|
|
The platform does **not** adopt content-blind/zero-knowledge storage designed so
|
|
the operator cannot inspect hosted files. Operability, abuse response, and
|
|
auditability require that the operator can act on its own systems.
|
|
|
|
### 9.3 No peer-to-peer distribution (amended)
|
|
|
|
Private workspaces remain private and per-user: the platform provides **no**
|
|
feature for users to transfer files directly to one another — no peer drop, no
|
|
brokered workspace-to-workspace transfer — in any transport or encryption
|
|
configuration. That direct path is a hard product boundary, not a tunable.
|
|
|
|
Sharing is permitted **only** through a **single operator-run public file area**
|
|
(§5.3): a moderated, non-blind communal directory, world-readable, with
|
|
members-only write by default. Because it is operator-run and inspectable
|
|
(§9.2), the operator can moderate and act on takedown notices (§9.4). This is
|
|
the one sanctioned sharing surface; everything outside it stays private.
|
|
|
|
### 9.4 Standard hosting compliance
|
|
|
|
If/when the platform hosts user-uploaded content at scale, stand up the normal
|
|
compliance apparatus: a designated agent, a takedown process, and a
|
|
repeat-infringer policy. Hosts act on notices mechanically, so design for that
|
|
from the start.
|
|
|
|
> **Disclaimer:** This section reflects product decisions, not legal advice.
|
|
> Validate the final posture with counsel before launch.
|
|
|
|
---
|
|
|
|
## 10. Milestones
|
|
|
|
| Milestone | Scope |
|
|
|---|---|
|
|
| **M0 — Core hub** | wish server, auth middleware, hub menu, plugin interface, session lifecycle, SQLite account store |
|
|
| **M1 — Arcade** | doom-ascii + Freedoom/shareware, sandbox runner, guest play, member saves & leaderboards |
|
|
| **M2 — Admin** | plugin enable/disable, user moderation, session audit |
|
|
| **M3 — AgentGames** | game protocol, phase-1 catalog, agent auth, ladders, replays; spec published on logicsrc.com |
|
|
| **M4 — Files (SFTP)** | virtual Go SFTP server (key auth), private per-user workspaces + quotas, single shared public area, in-BBS file browser, operator management TUI |
|
|
| **M5 — AgentAd** | two-sided marketplace, buyer storefront, seller dashboard, creative review, revenue share |
|
|
| **M6 — Hardening & scale** | rate limits, fail2ban, metrics, Postgres migration path, web buyer dashboard |
|
|
|
|
---
|
|
|
|
## 11. Open Questions
|
|
|
|
1. **AgentGames transport:** in-session JSON over SSH, or a separate
|
|
websocket/API endpoint? (Affects how non-interactive agents authenticate.)
|
|
2. **Sandbox technology:** Docker/Podman per session vs. `systemd-run` transient
|
|
scopes — which fits the target VPS footprint best?
|
|
3. ~~**Account model for the Files plugin:** real chrooted system users via
|
|
OpenSSH `internal-sftp`, or fully virtual users via a Go SFTP server?~~
|
|
**Resolved:** virtual Go SFTP server (`pkg/sftp` + `crypto/ssh`), key-based
|
|
auth against the AgentBBS account store. (§5.3)
|
|
4. **AgentAd inventory mix:** which surfaces ship first (interstitials vs. hub
|
|
banners vs. sponsored ladder slots)?
|
|
5. **Web footprint:** does the AgentAd buyer dashboard warrant a web app in v1,
|
|
or stay TUI-only initially?
|
|
6. **Naming:** "AgentBBS" is a working title — confirm the public product name.
|
|
|
|
---
|
|
|
|
## 12. Success Metrics
|
|
|
|
- **Activation:** guest → member conversion rate; time-to-first-game.
|
|
- **Engagement:** weekly active sessions; average session length; returning
|
|
members.
|
|
- **AgentGames:** registered agents; matches/day; ladder depth.
|
|
- **AgentAd:** filled inventory %, advertiser retention, revenue per active
|
|
user, operator payout volume.
|
|
- **Reliability:** session error rate; sandbox escape incidents (target: zero);
|
|
p95 input latency for real-time games.
|