Files
13ft/CLAUDE.md
T
2026-10-14 11:23:49 -05:00

3.0 KiB

13ft — OTM's fork

A self-hosted "read the article" fetcher (Python/Flask + gunicorn, ~200 lines in app/ (portable.py is the entrypoint)): it refetches a URL as Googlebot and serves the page without the paywall/ad cruft. Forked 2026-10-14 from wasi-master/13ft (the original project was taken down once already — wasm-fyi → wasi-master — which is WHY we hold a fork, not a dependency on GitHub/Docker Hub).

  • Remotes: gitea = tonym/13ft on git.poweredbyotm.com (ours, push here); upstream = GitHub wasi-master/13ft (pull only: git fetch upstream && git merge upstream/main). Token for Gitea lives in ~/Projects/CLAUDE.md.
  • Running today: https://13ft.poweredbyotm.com on anvil, hand-provisioned from the STOCK image wasimaster/13ft:latest (0.3.4) via platform/infra/13ft/setup-13ft-anvil.sh (platform#91, closed) — a /srv/otm/clients/13ft/ compose stack + Caddy site with basic auth (user tony; password root-only in /srv/otm/clients/13ft/secrets/basic-auth.txt). Nothing in this repo is deployed yet.

Where this is going (the reason for the fork)

Make it a proper OTM first-party app per platform/docs/first-party-app-guide.md (house rules are CI-enforced by platform/test/first-party-house-rules.test.ts):

  1. Build from this repo — catalogue entry in platform/apps/otm-admin/lib/first-party-apps.ts (id: "13ft", repo tonym/13ft, image platform-13ft:latest, port 5000, hostname: 13ft.poweredbyotm.com), then build_app 13ft / deploy_app 13ft via the platform MCP. First: destroy or rename the hand-provisioned 13ft stack (same slug + hostname + container name) or the two will fight over the Caddy site and the container name.
  2. Sign in with OTM replaces Caddy basic auth: needsAuthSecret → OTM_SSO_SECRET; add /api/auth/otm-sso (verify the HS256 ticket for aud app:13ft — port pickup/src/sso.js, or in Python: HMAC-SHA256 over header.payload, base64url, check exp/aud/jti, single-use) and a session cookie; gate every fetch route on it. Grant-only (NOT publicAccess) — a stranger's OTM account must not get a free fetch proxy.
  3. tides (needsAnalytics) — the beacon <script defer src="${TIDES_HOST}/t.js" data-site="${TIDES_SITE_ID}"> in the page template. Ideas (needsSuggestions) — a lightbulb that files Gitea issues (see pickup/src/ideas.js for the plain-HTTP shape). Version + /changelog + /api/health reporting the version + footer "Powered by OTM".
  4. Keep the Dockerfile's non-root user (thirteener) and gunicorn; add a HEALTHCHECK.

Until step 2 lands, basic auth stays — it is the whole gate.

Dev

python3 -m venv .venv && . .venv/bin/activate && pip install -r requirements.txt
cd app && python portable.py   # http://127.0.0.1:5000 (the app lives in app/)
docker build -t 13ft-dev . && docker run --rm -p 5000:5000 13ft-dev

Upstream README (below in this repo's README.md) covers the rest. Keep upstream's MIT license file.