Skip to content

F.5: Pixelfed bundle — federated photo-sharing#14

Open
kh0pper wants to merge 1 commit intof4-funkwhale-bundlefrom
f5-pixelfed-bundle
Open

F.5: Pixelfed bundle — federated photo-sharing#14
kh0pper wants to merge 1 commit intof4-funkwhale-bundlefrom
f5-pixelfed-bundle

Conversation

@kh0pper
Copy link
Copy Markdown
Owner

@kh0pper kh0pper commented Apr 12, 2026

Summary

Second federated-media bundle. Stacked on F.4 (Funkwhale). Pixelfed's Mastodon-compatible API overlaps heavily with F.1 GoToSocial, so this lands as a focused bundle rather than a new abstraction layer.

  • zknt/pixelfed:0.12 (4 containers): app (nginx+PHP-FPM via supervisord) + horizon queue worker + postgres:15 + redis:7. All on crow-federation where needed; exposed via caddy_add_federation_site → pixelfed:80 with the activitypub profile.
  • 14 MCP tools per the federated-media verb taxonomy, including pf_post_photo (media upload + status in a single call), full moderation surface (inline block/mute, queued domain-block/defederate/blocklist-import), admin reports, remote reporting, and manual pf_media_prune.
  • Storage: on-disk default; set PIXELFED_S3_* to route through F.0's storage-translators.pixelfed() (AWS_* + FILESYSTEM_CLOUD=s3 + PF_ENABLE_CLOUD=true). Second consumer of the translator surface after F.4.
  • Hardware gate: min_ram_mb=1500, recommended=3000. Horizon workers + image transforms are the hot paths.
  • Consent text (EN/ES) covers federation reach, remote-media cache growth, and — critically — CSAM/moderation responsibility (non-optional on a federated photo server).

Test plan

  • node --check on all JS files
  • bash -n on shell scripts
  • MCP server boots via createPixelfedServer() with no env set
  • docker compose config parses with required env set
  • JSON parse on manifest, package, registry
  • npm run check passes
  • End-to-end install on a test host (deferred to roll-out QA)
  • S3 translation exercise (MinIO → Pixelfed photo upload → verify in bucket)
  • Queued moderation end-to-end (needs F.11 panel UI)

Integration notes

  • Verb taxonomy cross-checked against F.1 GoToSocialpf_search, pf_feed, pf_follow are near-identical to gts_* equivalents. resolveAccount() is duplicated here rather than extracted — wait until F.7 Mastodon to decide whether to hoist into a shared helper.
  • loadSharedDeps() pattern from F.1. Works both monorepo-mode and installed-to-~/.crow.
  • Image tag zknt/pixelfed:0.12 floats within 0.12.x; CVE feed verified at implementation time, will be re-checked before merge.

Rollout position

  • F.0 → F.4 shipped
  • F.5 (this PR)
  • Next: F.6 Lemmy → F.7 Mastodon → F.8 PeerTube → F.11 identity attestation → F.12 cross-app bridging

🤖 Generated with Claude Code

Second federated-media bundle. Stacked on F.4 (Funkwhale). Reuses F.4's
storage-translator wiring pattern — Pixelfed uses AWS_* + FILESYSTEM_CLOUD=s3
+ PF_ENABLE_CLOUD=true per F.0's translator map.

Pixelfed is the fediverse's Instagram-alternative: upload photos, browse
a chronological feed, follow accounts on any ActivityPub server
(Mastodon, GoToSocial, Funkwhale, other Pixelfed pods). Its REST API
is Mastodon v1/v2 compatible — most verbs cross over cleanly from the
GoToSocial bundle (F.1), which is why this one lands cleanly in a
single bundle rather than forcing a new API abstraction.

Bundle (bundles/pixelfed/):

- manifest.json  consent_required with EN/ES covering federation reach,
                 remote-media cache growth (10-50 GB within weeks under
                 active federation), CSAM/moderation responsibility
                 (non-optional on a federated photo server), and
                 hardware gate (min 1.5 GB effective RAM, warn <8 GB).
                 Declares PIXELFED_S3_* optionals that activate the
                 storage-translator wiring.
- docker-compose.yml  zknt/pixelfed:0.12 (nginx+PHP-FPM+supervisord
                 all-in-one) + horizon queue worker + postgres:15 +
                 redis:7. app + horizon both on crow-federation so they
                 can reach DB/redis peers AND be reached by Caddy.
                 Blank-default AWS_* passthrough so configure-storage.mjs
                 can populate them at install. mem_limits: app=1500m,
                 horizon=768m, postgres=512m, redis=256m. Media retention
                 wired to PIXELFED_MEDIA_RETENTION_DAYS env var (default 14).
- server/server.js  14 MCP tools per the federated-media verb taxonomy:
                 pf_status, pf_post_photo (upload + status in one call),
                 pf_feed (home/public/local/notifications), pf_search,
                 pf_follow/pf_unfollow, pf_block_user/pf_mute_user
                 (inline, rate-limited), pf_block_domain/pf_defederate/
                 pf_import_blocklist (QUEUED via moderation_actions +
                 notification), pf_review_reports, pf_report_remote,
                 pf_media_prune. resolveAccount() helper does the
                 WebFinger-via-search dance shared with F.1. All z.string()
                 fields bounded with .max(). loadSharedDeps() pattern
                 from GoToSocial so monorepo + installed-mode both work.
- server/index.js  stdio transport.
- panel/pixelfed.js + panel/routes.js  Nest panel — instance status +
                 home-timeline recent posts. XSS-safe
                 (textContent/createElement). API routes serve
                 /api/pixelfed/{status,feed}.
- skills/pixelfed.md  first-run workflow (APP_KEY gen, Caddy, admin
                 user, PAT), photo-post/feed/search/follow examples,
                 moderation + CSAM warning, troubleshooting (horizon,
                 413 payload, disk pressure).
- scripts/post-install.sh  180s health wait, invokes configure-storage.mjs
                 if PIXELFED_S3_ENDPOINT is set, prints Caddy + admin +
                 PAT + baseline-blocklist-import steps.
- scripts/configure-storage.mjs  imports storage-translators.pixelfed()
                 and writes a managed block to .env. Same shape as F.4's
                 helper — falls back to inline map in installed-mode.
- scripts/backup.sh  pg_dump + storage/uploads tar (excludes framework
                 cache/logs/sessions — regenerable). S3-backed media NOT
                 in scope.
- package.json  MCP + zod deps only.

Integrations with shipped F-series:

- F.0 storage-translators.pixelfed()  activated at install time when
  PIXELFED_S3_* is set. Same pattern as F.4 — second consumer validates
  the translator surface.
- F.0 rate limiter  post_photo, feed, search, follow, unfollow, blocks,
  mutes, report_remote, import_blocklist, media_prune.
- F.0 hardware gate  min/recommended RAM + disk per manifest schema.
- F.1 GoToSocial  Mastodon-compatible API overlap confirmed the verb
  taxonomy generalizes. pf_search / pf_feed / pf_follow are near-identical
  to gts_* equivalents; resolveAccount() is deduplicated here but the
  same WebFinger-via-search pattern.
- F.1 federated-media category wiring (extensions.js, nav-registry.js,
  i18n) already present — no new wiring needed.

Human-in-the-loop moderation:

- Inline (rate-limited, fires immediately): pf_block_user, pf_mute_user,
  pf_report_remote.
- Queued (operator confirms in Nest within 72h): pf_block_domain,
  pf_defederate, pf_import_blocklist. Writes moderation_actions row +
  surfaces a Crow notification; returns {status: "queued", action_id,
  expires_at} to the AI. Confirmation UI lands with F.11.

Image tag policy:

- zknt/pixelfed:0.12 floats within 0.12.x; the CVE feed + release notes
  were checked at implementation time. Pin will be re-verified before
  merge and bumped if a more current minor is out.

Registry / discovery surface:

- registry/add-ons.json  entry inserted before developer-kit.
- skills/superpowers.md  trigger row added between funkwhale and tutoring
  (EN+ES: pixelfed, post photo, share picture, photo feed, fediverse photo,
  instagram alternative).
- CLAUDE.md  Skills Reference entry added after funkwhale.md.

Verified:

- node --check on all JS files (server, panel, configure-storage)
- bash -n on both shell scripts
- MCP server boots via createPixelfedServer() with no env set
- docker compose config parses with required env set
- JSON parse on manifest, package, registry
- npm run check passes

Next in the roll-out:

- F.6 Lemmy (link aggregator, 1 GB min)
- F.7 Mastodon (flagship AP, 3 GB min — heaviest small-AP)
- F.8 PeerTube (video, needs S3 + aggressive transcoding policy)
- F.11 identity attestation, F.12 cross-app bridging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant