# AGENTS.md — eutopic eutopic is a photo-first social app for small, trusted, invite-only communities. not a global network. not optimized for engagement or attention. target: 5–50 users at launch, growing by invite only. --- ## where to look | what you need | read | when | |---|---|---| | vision + values | docs/CONCEPT.md | onboarding, big picture, tone questions | | interaction + UI decisions | docs/DESIGN.md | frontend, UX, feature work | | entities + schema | docs/DATA-MODEL.md | backend, db, API work | | what's decided vs open | docs/OPEN-QUESTIONS.md | before proposing anything new — always | | versioned plan | docs/ROADMAP.md | scoping, prioritization | | backend + API structure | docs/ARCHITECTURE.md | does not exist yet. create before v0 alpha. | --- ## locked — do not relitigate **product** - chronological feed only. no algorithm, no ranking, no engagement bait. - no push notifications in v1. - no DMs in v1. - no analytics or tracking. zero. not even self-hosted. - no federation UI. activitypub via fedify is in the stack, federation flag is OFF. - no premium tier. no donor badges. no class hierarchy in the app. - no manifesto, no political iconography on any user-facing surface. - `is_event` flag on posts for bulletin board. not a separate entity. - posters: anyone can post. three post types, single required tag: `event` | `fundraiser` | `current affairs`. auto-archives 1 day after `event_ends_at`. layout: 2-column grid, infinite scroll, paginated fetch. - reactions: poster defines up to 5 emoji + open picker fallback. stored as user + post + emoji + timestamp. - save/bookmark: optional, toggled by poster at compose. default off. - story interactions: no replies. "witnessed" metadata only, private, 24h. - comments: flat, chronological, on posts only. - surveys: admin-only creation. multiple choice only. 36h expiry. injected as slot-1 feed card (not a real post), drops per-user after response. `/feedback` always has free text field regardless of active survey. **ux** - users should never be asked to understand anything instagram doesn't ask them to understand. - onboarding: invite link → install → email + username → magic link → in. - the activitypub layer is invisible to users, always. **never use** - firebase, meta SDKs, google analytics, cloudflare, amazon, github, stripe-as-primary. --- ## conditionally open - **notifications**: off in v1. DM notifications only if DMs land in v2. never for feed activity. - **DMs**: deferred to v2. three options on table. not decided. - **federation**: flag off. may flip in v2/v3. UI stays invisible either way. - **PWA**: fallback option to consider if run into problems with apple app store. --- ## stack (settled) runtime: bun / framework: elysia / activitypub: fedify / db: sqlite (postgres-ready) / storage: filesystem → s3-compatible / uploads: tus.io / mobile: flutter + go_router / hosting: njalla VPS / proxy: nginx / process: systemd / forge: radicle / funding: liberapay --- ## tone + voice - quiet, not precious. - no manifestos. no "we believe in" statements. - register: "eutopic is a quiet place for friends to share photos." - corporate, activist, or startup-y copy is wrong. - transparency about costs: fine. nagging: not. --- ## values (as constraints) - anti-attention economy: check every feature decision against this. - "the architecture is the belief" — values show in what's built and refused, not in copy. - compromises (flutter/dart, app stores) are named honestly in the about/credits page. --- ## when in doubt 1. check OPEN-QUESTIONS.md before proposing anything. don't relitigate closed decisions. 2. check tone: would this copy sound corporate or activist? wrong register. 3. check values: does this feature serve attention extraction? if yes, refuse it. 4. don't invent answers to open questions. flag them instead.