Generalize for non-author users: derived defaults, owner naming, docker engine, zero-config previews, README #134

Merged
chad merged 17 commits from feat/generalize-for-new-users into main 2026-10-20 17:59:56 -04:00
Collaborator

Makes sweatshop runnable by someone other than its author — no GLM subscription, a different name, and a local Docker engine (OrbStack on macOS) instead of podman on a remote server.

Defaults without GLM (4): built-in default routes now derive from which provider keys exist (glm > openrouter > gloo; none → glm so validation reports the missing key clearly). SWEATSHOP_DEFAULT_PROVIDER + SWEATSHOP_DEFAULT_MODEL (both required) override; verified openai/gpt-5.6-sol is live on OpenRouter. Full test matrix included.

Owner naming (5): SWEATSHOP_OWNER_NAME (default "Chad" — your deployment unchanged) interpolates into instructions, tool descriptions, result strings, and skills. ask_chad itself is NOT renamed; code comments and docs/NNNN history untouched.

Zero-config previews (1): base domain falls back to previews.localhost instead of internal.crussell.io; scheme defaults http only on that fallback (no wildcard cert locally), https with a real PREVIEW_BASE_DOMAIN, PREVIEW_URL_SCHEME overrides both.

Engine-agnostic runtime (10–12): dev wrapper takes CONTAINER_ENGINE=auto|podman|docker (auto prefers podman — your flow unchanged) with per-engine socket probing (OrbStack/colima/Docker Desktop), docker-portable existence checks, bash-3.2-safe arrays (stock macOS), optional DEV_PUBLISH port publishing for the all-local mode, and a loud error on a set-but-missing DOCKER_SOCK. SWEATSHOP_SANDBOX_IMAGE overrides the default sandbox image.

Docs & misc (2, 3, 6–9): new README (requirements, the one-engine rule, all-local vs all-on-one-box topologies, quickstart with DEV_PUBLISH, provider/harness matrix, security posture); .env.example rewritten for fresh installs (all three provider keys, git-credentials-in-sqlite reality, new vars, dropped unread PI_MODEL); generic forgejo tool description; OpenRouter referer via SWEATSHOP_PUBLIC_ORIGIN; generic host-form placeholders.

⚠️ Deployment note (review finding 6): two silent behavior changes unless bee's env sets them — preview base default is now previews.localhost (set PREVIEW_BASE_DOMAIN=internal.crussell.io to keep today's URLs) and the OpenRouter referer defaults to http://localhost:3000 (set SWEATSHOP_PUBLIC_ORIGIN to keep the current value).

Process: pi implemented the bulk (two calls), I wrote the README/placeholders and landed the review fixes; a fresh-eyes review child found 3 blockers (docker-incompatible dev subcommands, macOS bash-3.2 crash, unreachable all-local quickstart) — all fixed, all should-fixes and nits addressed. Gate at HEAD: typecheck clean, lint 0 errors (2 pre-existing warnings), 863 passed / 16 skipped. 17 commits.

Makes sweatshop runnable by someone other than its author — no GLM subscription, a different name, and a local Docker engine (OrbStack on macOS) instead of podman on a remote server. **Defaults without GLM (4):** built-in default routes now derive from which provider keys exist (glm > openrouter > gloo; none → glm so validation reports the missing key clearly). `SWEATSHOP_DEFAULT_PROVIDER` + `SWEATSHOP_DEFAULT_MODEL` (both required) override; verified `openai/gpt-5.6-sol` is live on OpenRouter. Full test matrix included. **Owner naming (5):** `SWEATSHOP_OWNER_NAME` (default "Chad" — your deployment unchanged) interpolates into instructions, tool descriptions, result strings, and skills. `ask_chad` itself is NOT renamed; code comments and docs/NNNN history untouched. **Zero-config previews (1):** base domain falls back to `previews.localhost` instead of `internal.crussell.io`; scheme defaults `http` only on that fallback (no wildcard cert locally), `https` with a real `PREVIEW_BASE_DOMAIN`, `PREVIEW_URL_SCHEME` overrides both. **Engine-agnostic runtime (10–12):** `dev` wrapper takes `CONTAINER_ENGINE=auto|podman|docker` (auto prefers podman — your flow unchanged) with per-engine socket probing (OrbStack/colima/Docker Desktop), docker-portable existence checks, bash-3.2-safe arrays (stock macOS), optional `DEV_PUBLISH` port publishing for the all-local mode, and a loud error on a set-but-missing `DOCKER_SOCK`. `SWEATSHOP_SANDBOX_IMAGE` overrides the default sandbox image. **Docs & misc (2, 3, 6–9):** new README (requirements, the one-engine rule, all-local vs all-on-one-box topologies, quickstart with `DEV_PUBLISH`, provider/harness matrix, security posture); `.env.example` rewritten for fresh installs (all three provider keys, git-credentials-in-sqlite reality, new vars, dropped unread `PI_MODEL`); generic forgejo tool description; OpenRouter referer via `SWEATSHOP_PUBLIC_ORIGIN`; generic host-form placeholders. **⚠️ Deployment note (review finding 6):** two silent behavior changes unless bee's env sets them — preview base default is now `previews.localhost` (set `PREVIEW_BASE_DOMAIN=internal.crussell.io` to keep today's URLs) and the OpenRouter referer defaults to `http://localhost:3000` (set `SWEATSHOP_PUBLIC_ORIGIN` to keep the current value). Process: pi implemented the bulk (two calls), I wrote the README/placeholders and landed the review fixes; a fresh-eyes review child found 3 blockers (docker-incompatible `dev` subcommands, macOS bash-3.2 crash, unreachable all-local quickstart) — all fixed, all should-fixes and nits addressed. Gate at HEAD: typecheck clean, lint 0 errors (2 pre-existing warnings), 863 passed / 16 skipped. 17 commits.
glen added 17 commits 2026-10-20 17:55:01 -04:00
previewBaseDomain() fell back to the author's internal.crussell.io —
an error-grade host for anyone else. Fall back to previews.localhost
instead (browsers resolve *.localhost to 127.0.0.1, so the local
preview proxy answers with no config); PREVIEW_BASE_DOMAIN stays the
full override and slugFromHost parses either form's labels identically.
Update the previews capability doc's hardcoded URL line to match.
The HTTP-Referer sent to OpenRouter was hardcoded to the author's
deployment origin. Read it from SWEATSHOP_PUBLIC_ORIGIN (this app's
public origin — the var the preview fallback page already links back
to), defaulting to http://localhost:3000. X-Title is unchanged.
The description hardcoded the author's instance ("Chad's self-hosted
instance (git.crussell.io)") and a personal repo path example. Name no
person and no host: "the configured forgejo instance" with the owner's
stored credentials; {owner}/{repo} placeholders in the example.
BUILTIN_DEFAULTS pinned glm-5.3-flash on chat/agent/pi/titles, so an
install without the author's Z.AI plan validated its very first turn
into 'provider not configured'. Replace the constant with a pure
deriveBuiltinDefaults(available, override?): glm (historical) >
openrouter (openai/gpt-5.6-sol) > gloo (gloo-openai-gpt-6-sol), glm
kept when nothing is available (the validation message names the env
key). getGlobalDefaults derives per call from availableProviders() and
honors SWEATSHOP_DEFAULT_PROVIDER + SWEATSHOP_DEFAULT_MODEL (both
required; unknown provider ignored; model checked at route validation
as usual). Subscription-harness defaults never move.
New lib/agent/owner.ts — ownerName() (SWEATSHOP_OWNER_NAME, default
Chad) and possessive() — read fresh per call. Interpolated at runtime
everywhere the agent reads or reports the owner: turn instructions
(BASE_INSTRUCTIONS is now built per turn), ask_chad/create_pr/
use_skill/system_docs, project tool descriptions and denials, exec,
gh/forgejo, commandDescription, plan tools and plan cores (present/
accept/approve wake), preview and screenshot descriptions and results,
the budget CONTINUE_TEXT, the [viewing] note, and the plan-approval
wake. ask_chad keeps its name; comments, docs/NNNN history and
AGENTS.md still say Chad. DISMISS_ANSWER (built in client components
that never see the env) goes name-free: 'the owner'.

docs/agent: models/projects/hosts/previews drop the personal
references (employer gloo, self-hosted instance, Chad/his) for
owner-neutral wording; models.md notes the derived default and loses
the deleted-machines paragraph.
GLOO_API_KEY / OPENROUTER_API_KEY join ZAI (one key is enough to
run; web_search specifically needs ZAI). The stale db:seed block is
replaced by how git credentials actually work now: rows in the
git_credentials table, inserted directly (schema documented inline).
New knobs: SWEATSHOP_OWNER_NAME, SWEATSHOP_DEFAULT_PROVIDER/MODEL,
PREVIEW_URL_SCHEME; SWEATSHOP_PUBLIC_ORIGIN also notes its second job
as the OpenRouter referer. Personal host names in preview comments
made generic.
Requirements, the two supported topologies (all-local, all-on-one-box)
around the one hard rule (app + sandboxes share one engine), quickstart
via ./dev, the provider-key/harness-login matrix, previews, and the
single-user security posture.
bee/10.10.0.12/crussell → web-1/192.168.1.50/deploy — examples that
aren't the author's actual host.
One line pointing general setups at README.md.
CONTAINER_ENGINE=auto|podman|docker (default auto: podman when
installed, else docker) selects the engine for every invocation. The
host socket mount follows the engine: podman keeps PODMAN_SOCK
(/run/user/$(id -u)/podman/podman.sock); docker mounts the first
existing socket of OrbStack, colima, Docker Desktop, or /var/run —
DOCKER_SOCK overrides the probe, and no socket found means no mount.
The app container and sandboxes still share one engine.
The default sandbox image ref (localhost/sweatshop-sandbox) is now
env-overridable, so a fresh install can point at a differently-tagged
or pullable build without editing code. Noted in .env.example;
tests/sandbox-image.test.ts pins both the fallback and the override.
previewUrl() now defaults to https only when PREVIEW_BASE_DOMAIN is
set (a real wildcard-cert domain); the zero-config previews.localhost
fallback has no cert, so it defaults to http. An explicit
PREVIEW_URL_SCHEME still overrides both. .env.example comment updated
to match; tests pin all three cases.
assertRuntimeOnHarnessNetwork's failure no longer assumes the ./dev
podman wrapper: it says the app container must be on the
sweatshop-harness network, runnable via ./dev or the engine
equivalent.
A sandbox is a container on the harness network, not specifically a
podman one; a pinned image ref must exist in (or be pullable by) the
host's container engine — any Docker-compatible one: podman,
OrbStack, Docker Desktop, colima. No other docs/agent file names an
engine.
An explicit override silently skipping the socket mount would surface
later as broken sibling sandboxes; the probe path stays quiet (its
no-socket case is the documented no-mount).
- image/network existence via inspect (docker has no image/network
  exists subcommands; the engine-docker path died on first command)
- ${ARR[@]+...} guards: macOS stock bash 3.2 + set -u treats an empty
  array expansion as unbound (./dev install before .env.local exists)
- DEV_PUBLISH: optional -p pairs for the all-local mode; default still
  publishes nothing (the membership-is-the-boundary rule)

README: key-first quickstart order, DEV_PUBLISH in the quickstart and
previews section (the wrapper never publishes by default).
fix(review): address fresh-eyes findings 5-11
All checks were successful
deploy / checks (pull_request) Successful in 42s
deploy / deploy (pull_request) Has been skipped
59bc865a64
- skills: owner wording throughout (bodies join turn instructions;
  a non-default owner reads their own name, not Chad's)
- docs/agent/models.md: drop deleted-machine references (start_machine,
  machine stages), fix a mangled sentence from the earlier pass
- .env.example: createdAt in ms, drop unread PI_MODEL, document
  CONTAINER_ENGINE/DOCKER_SOCK/DEV_PUBLISH
- provision.ts: note the env read is at module load
chad approved these changes 2026-10-20 17:59:53 -04:00
chad merged commit 7d1c60892a into main 2026-10-20 17:59:56 -04:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
chad/sweatshop-legacy!134
No description provided.