From ef5dc588bcdaaebf76c9beda0210ecf3d441488b Mon Sep 17 00:00:00 2001 From: tmad4000 Date: Sat, 11 Jul 2026 17:32:35 -0700 Subject: [PATCH] docs: prepare App Store launch readiness OpenChat-ig3 --- .beads/interactions.jsonl | 1 + .beads/issues.jsonl | 145 +++++++++++++++-------------- apps/server/src/legal/privacy.md | 34 +++++-- docs/app-store-launch-readiness.md | 86 +++++++++++++++++ docs/app-store-privacy-labels.md | 57 ++++++------ docs/testers.md | 4 + 6 files changed, 221 insertions(+), 106 deletions(-) create mode 100644 docs/app-store-launch-readiness.md diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index f29efc0..ed92bc4 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -83,3 +83,4 @@ {"id":"int-4a5d788f","kind":"field_change","created_at":"2026-06-01T22:37:26.718366Z","actor":"Jacob Cole","issue_id":"OpenChat-ap3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Decision shipped 2026-06-01 in docs/decisions/2026-06-01-expo-contacts.md: DEFER expo-contacts integration. Blocked by phone-sign-in decision (xf4 also deferred today). Without phone-keyed users, contacts match rate is 5-10% β€” not worth the 40-60% iOS permission decline rate. Re-open when xf4 ships phone sign-in OR we get β‰₯3 user requests for contact-discovery."}} {"id":"int-54d5fe80","kind":"field_change","created_at":"2026-06-01T22:38:00.242989Z","actor":"Jacob Cole","issue_id":"OpenChat-3kr.2","extra":{"field":"status","new_value":"in_progress","old_value":"open"}} {"id":"int-ee89998e","kind":"field_change","created_at":"2026-06-01T22:40:15.033587Z","actor":"Jacob Cole","issue_id":"OpenChat-3kr.2","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Shipped 2026-06-01: NVCComposerModal + πŸ’™ button in ChatScreen composer. Fields: Observation (required), Feeling (required), Need, Request. Assembled message uses unicode bullet prefixes for visual structure. Stuffs draft into composer text on submit so user gets one revision pass before send (self-empathy moment per ticket stretch goal). Bot-side @nvc coaching deferred to OpenChat-3kr.3."}} +{"id":"int-10eb2708","kind":"field_change","created_at":"2026-07-12T00:32:05.202115Z","actor":"tmad4000","issue_id":"OpenChat-ig3","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Completed launch-readiness audit and safe documentation/legal updates. Added docs/app-store-launch-readiness.md, refreshed privacy policy and App Store privacy labels, linked from testers guide, wrote required report, and filed OpenChat-epd for remaining human/App Store Connect blockers."}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 8932a6f..d0bbfb0 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -7,42 +7,45 @@ {"_type":"issue","id":"OpenChat-wgl","title":"[P0] Report message / user (App Store 1.2 UGC requirement)","description":"App Store guideline 1.2 mandatory for UGC apps.\n\nSERVER:\n- POST /api/chat/reports {targetType:'message'|'user', targetId, reason, freeform?}\n- Writes :Report node\n- Posts to a Slack webhook or emails Jacob (decide)\n\nMOBILE:\n- Long-press bubble β†’ ActionSheet β†’ 'Report message'\n- User profile / conversation header β†’ 'Report user'\n\nREQUIRES JACOB DECISION: report destination (Slack webhook to #moderation, email, or just log).\n\nAC: report submitted in \u003c2s, user sees 'Thanks β€” we've received your report' toast, server log entry created.","status":"closed","priority":0,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-06-01T03:17:53Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:35:20Z","started_at":"2026-06-01T03:53:26Z","closed_at":"2026-06-01T04:35:20Z","close_reason":"DB storage shipped. Admin triage view filed separately as future work (Slack webhook env var optional, default off).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-46p","title":"[P0] Block user (App Store 1.2 UGC requirement)","description":"App Store guideline 1.2 BLOCKS UGC APPS WITHOUT THIS.\n\nSERVER:\n- BLOCKED edge: (User)-[:BLOCKED {createdAt}]-\u003e(User)\n- chatHandler message:send: filter sender-\u003etarget where BLOCKED exists (silently drop, no error to sender for graceful UX)\n- chat.ts /conversations: omit conversations whose only other participant has blocked me\n\nMOBILE:\n- Long-press contact in DM header β†’ Block (mirror existing GroupSettings header pattern)\n- ContactRow long-press in NewConversation β†’ Block\n- Settings β†’ Blocked Users list with unblock\n\nAC: blocking hides the conversation, prevents new messages from delivering, surfaces in Settings.","status":"closed","priority":0,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-06-01T03:17:52Z","created_by":"Jacob Cole","updated_at":"2026-06-01T03:57:31Z","started_at":"2026-06-01T03:53:26Z","closed_at":"2026-06-01T03:57:31Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-nhy","title":"[P0] Account deletion (App Store 5.1.1(v))","description":"Apple has required in-app account deletion since 2022. Apple WILL REJECT the next submission without this.\n\nCODEX REVIEW REVISION (2026-05-31): Apple's account-deletion guidance is stricter than 'anonymize'. Per https://developer.apple.com/support/offering-account-deletion-in-your-app/ users expect their UGC to actually be deleted. Recommended implementation:\n- Hard-delete: User node + tokens + push subs + media uploads\n- For messages: REPLACE the body with 'Message deleted' (NOT anonymize-with-sender-name). This preserves conversation structure but removes content that could identify the deleted user.\n- This is safer under GDPR Recital 26 (true non-identifiability) and CCPA deletion rights.\n\nSERVER:\n- DELETE /api/auth/me endpoint\n- Wipes: User node, owned Conversations (or remove participation if shared), NativePushToken, sessions/refresh-tokens, uploaded media\n- For all of the user's messages: UPDATE content='Message deleted', editedAt=now, senderName='Former user'\n- Cascade revocation of any OAuth grants\n\nMOBILE:\n- SettingsScreen β†’ 'Legal \u0026 Account' section β†’ 'Delete my account' (danger style)\n- Confirmation modal with typed 'DELETE' confirmation\n- POST DELETE /api/auth/me, then signOut()\n- After: cannot sign back in with same email (or: re-signup creates a new fresh account)\n\nAC: account deletion completes in \u003c5s; reopening app returns to Login; other participants see 'Message deleted' placeholders where the user's messages were; no media or sender info remains.","status":"closed","priority":0,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-06-01T03:17:51Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:00:25Z","started_at":"2026-06-01T03:53:25Z","closed_at":"2026-06-01T04:00:25Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-hzz.2.2","title":"Play Console one-time setup: create app + service-account JSON for API submit (human-gated)","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:18:01Z","created_by":"tmad4000","updated_at":"2026-06-08T07:18:01Z","dependencies":[{"issue_id":"openchat-hzz.2.2","depends_on_id":"openchat-hzz.2","type":"parent-child","created_at":"2026-06-08T00:18:01Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-hzz.2.1","title":"Android AAB gradle build regressed (errors since SDK54/vc2; vc1 succeeded 5/31)","status":"open","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:17:59Z","created_by":"tmad4000","updated_at":"2026-06-08T07:17:59Z","dependencies":[{"issue_id":"openchat-hzz.2.1","depends_on_id":"openchat-hzz.2","type":"parent-child","created_at":"2026-06-08T00:17:59Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-epd","title":"Prepare App Store human-gated submission assets","description":"Complete the remaining human/App Store Connect blockers for public App Store submission: create and seed openchat-reviewer@globalbr.ai, store reviewer credentials in 1Password, prepare required iPhone screenshots, fill App Store Connect metadata/privacy labels/review notes, verify production backend/legal URLs, and obtain explicit approval before submitting for App Review.","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-07-12T00:31:54Z","created_by":"tmad4000","updated_at":"2026-07-12T00:31:54Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-ig3","title":"Audit App Store launch readiness","description":"Audit OpenChat against Apple App Store launch requirements, implement safe bounded fixes, prepare submission runbooks, and record remaining human/App Store Connect blockers for openchat-appstore-launch-r1.","status":"closed","priority":1,"issue_type":"task","assignee":"tmad4000","owner":"dev.jacobcole@gmail.com","created_at":"2026-07-12T00:29:20Z","created_by":"tmad4000","updated_at":"2026-07-12T00:32:05Z","started_at":"2026-07-12T00:29:25Z","closed_at":"2026-07-12T00:32:05Z","close_reason":"Completed launch-readiness audit and safe documentation/legal updates. Added docs/app-store-launch-readiness.md, refreshed privacy policy and App Store privacy labels, linked from testers guide, wrote required report, and filed OpenChat-epd for remaining human/App Store Connect blockers.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-jmu","title":"Launch slice: agent-ready onboarding step + landing vision polish + launch doc + deploy","description":"Production / still serves RN-web while main routes / to landing.html β€” landing never deployed. Add Step 3 'Bring your AI' onboarding (Thoughts + Agent Keys), polish landing lede with Noos identity/thoughts vision line, add docs/launch.md grounded in shipped code, deploy via infra/deploy.sh.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-07-11T19:52:15Z","created_by":"tmad4000","updated_at":"2026-07-11T19:57:44Z","started_at":"2026-07-11T19:52:21Z","closed_at":"2026-07-11T19:57:44Z","close_reason":"Shipped: agent-ready onboarding step, landing vision polish, docs/launch.md. Deployed via infra/deploy.sh; landing now live at chat.globalbr.ai/. PR #2.","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-hzz.2.2","title":"Play Console one-time setup: create app + service-account JSON for API submit (human-gated)","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:18:01Z","created_by":"tmad4000","updated_at":"2026-06-08T07:18:01Z","dependencies":[{"issue_id":"openchat-hzz.2.2","depends_on_id":"openchat-hzz.2","type":"parent-child","created_at":"2026-06-08T00:18:01Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-hzz.2.1","title":"Android AAB gradle build regressed (errors since SDK54/vc2; vc1 succeeded 5/31)","status":"open","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:17:59Z","created_by":"tmad4000","updated_at":"2026-06-08T07:17:59Z","dependencies":[{"issue_id":"openchat-hzz.2.1","depends_on_id":"openchat-hzz.2","type":"parent-child","created_at":"2026-06-08T00:17:59Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-oa3","title":"Android Google sign-in strands user on Google homepage β€” needs Android-type OAuth client","description":"ROOT CAUSE (code-confirmed): apps/mobile/src/screens/LoginScreen.tsx used androidClientId = GOOGLE_IOS_CLIENT_ID for the native Android Google flow. Android rejects iOS/Web OAuth clients, so after auth there's no valid Android redirect target and the Chrome Custom Tab lands on Google's homepage (β†’ news). Web /m + iOS unaffected.\n\nCODE DONE: added GOOGLE_ANDROID_CLIENT_ID (EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID), wired to androidClientId, falls back to iOS client so no build break.\n\nREMAINING (human gate β€” GCP console + a rebuild):\n1. GCP Console β†’ APIs \u0026 Services β†’ Credentials β†’ Create OAuth client ID β†’ Android. Package: com.jacobcole.openchat. SHA-1: the signing cert's fingerprint β€” for EAS builds run 'eas credentials -p android' (production) to read the keystore SHA-1; ALSO add Google Play App Signing's SHA-1 from Play Console once the AAB is uploaded (Play App Signing re-signs).\n2. Set EXPO_PUBLIC_GOOGLE_ANDROID_CLIENT_ID to the new client ID (eas.json env / EAS secret).\n3. Rebuild Android (eas build -p android) so testers get the fix.","status":"open","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:10:49Z","created_by":"tmad4000","updated_at":"2026-06-08T07:10:49Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-hzz.2","title":"Android: build AAB, create Play listing, submit to Google Play","status":"in_progress","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:54:08Z","created_by":"tmad4000","updated_at":"2026-06-08T07:17:57Z","started_at":"2026-06-08T07:17:57Z","dependencies":[{"issue_id":"openchat-hzz.2","depends_on_id":"openchat-hzz","type":"parent-child","created_at":"2026-06-07T23:54:07Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-hzz.1","title":"iOS: fill App Store metadata + screenshots + submit v1.0 for review","status":"in_progress","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:54:06Z","created_by":"tmad4000","updated_at":"2026-06-08T06:54:51Z","started_at":"2026-06-08T06:54:51Z","dependencies":[{"issue_id":"openchat-hzz.1","depends_on_id":"openchat-hzz","type":"parent-child","created_at":"2026-06-07T23:54:05Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-hzz.2","title":"Android: build AAB, create Play listing, submit to Google Play","status":"in_progress","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:54:08Z","created_by":"tmad4000","updated_at":"2026-06-08T07:17:57Z","started_at":"2026-06-08T07:17:57Z","dependencies":[{"issue_id":"openchat-hzz.2","depends_on_id":"openchat-hzz","type":"parent-child","created_at":"2026-06-07T23:54:07Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-hzz.1","title":"iOS: fill App Store metadata + screenshots + submit v1.0 for review","status":"in_progress","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:54:06Z","created_by":"tmad4000","updated_at":"2026-06-08T06:54:51Z","started_at":"2026-06-08T06:54:51Z","dependencies":[{"issue_id":"openchat-hzz.1","depends_on_id":"openchat-hzz","type":"parent-child","created_at":"2026-06-07T23:54:05Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-hzz","title":"Publish to App Store + Google Play (production)","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:53:59Z","created_by":"tmad4000","updated_at":"2026-06-08T06:53:59Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-gii","title":"[bug] Voice messages not working β€” diagnose + fix end to end","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T02:33:31Z","created_by":"tmad4000","updated_at":"2026-06-08T06:51:25Z","closed_at":"2026-06-08T06:51:25Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-i0r","title":"Assistant reports errors intelligently (post a friendly error message on turn failure)","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:38:52Z","created_by":"tmad4000","updated_at":"2026-06-05T01:00:45Z","closed_at":"2026-06-05T01:00:45Z","close_reason":"Intelligent error reporting: runAssistantTurn now posts a friendly in-chat message on failure (rate-limit/overloaded, not-configured, generic), handles empty-final-text + no-ANTHROPIC_KEY. Deployed + builds green. Error paths verified by code, not by forcing a live failure.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-j0o.2","title":"Conversation/group-scoped read layer (the access-control substrate)","description":"Generalize the visibilityFilter helper across read paths; wire the 'group' tier to Conversation membership via (:User)-[:PARTICIPATES_IN]-\u003e(:Conversation)\u003c-[:SCOPED_TO]-(item). Default-deny; enforce tiers (don't just store). API keys inherit user visibility (already true via resolveActor). Optional per-user SHARED_WITH grants.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:06:58Z","created_by":"tmad4000","updated_at":"2026-06-05T00:06:58Z","dependencies":[{"issue_id":"openchat-j0o.2","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:06:58Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-j0o.1","title":"Thoughts visibility demo: private/group/public + single enforced visibilityFilter helper","description":"Minimal demo of the access-control model. Add visibility ('private'|'group'|'public', default private) to :Thought (routes/thoughts.ts + extractThoughtsFromMessage.ts: VALID_VISIBILITY set, CREATE map, PATCH CASE-WHEN, all RETURN projections). Add ONE visibilityFilter(viewerId) helper. Add a visibility-filtered read path (GET /api/thoughts/visible and/or a 7th Assistant tool search_visible_thoughts) returning public (now) + group (later) β€” never private. Default private = safe-by-default for existing thoughts.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:06:56Z","created_by":"tmad4000","updated_at":"2026-06-05T00:06:56Z","dependencies":[{"issue_id":"openchat-j0o.1","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:06:56Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-j0o.2","title":"Conversation/group-scoped read layer (the access-control substrate)","description":"Generalize the visibilityFilter helper across read paths; wire the 'group' tier to Conversation membership via (:User)-[:PARTICIPATES_IN]-\u003e(:Conversation)\u003c-[:SCOPED_TO]-(item). Default-deny; enforce tiers (don't just store). API keys inherit user visibility (already true via resolveActor). Optional per-user SHARED_WITH grants.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:06:58Z","created_by":"tmad4000","updated_at":"2026-06-05T00:06:58Z","dependencies":[{"issue_id":"openchat-j0o.2","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:06:58Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-j0o.1","title":"Thoughts visibility demo: private/group/public + single enforced visibilityFilter helper","description":"Minimal demo of the access-control model. Add visibility ('private'|'group'|'public', default private) to :Thought (routes/thoughts.ts + extractThoughtsFromMessage.ts: VALID_VISIBILITY set, CREATE map, PATCH CASE-WHEN, all RETURN projections). Add ONE visibilityFilter(viewerId) helper. Add a visibility-filtered read path (GET /api/thoughts/visible and/or a 7th Assistant tool search_visible_thoughts) returning public (now) + group (later) β€” never private. Default private = safe-by-default for existing thoughts.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:06:56Z","created_by":"tmad4000","updated_at":"2026-06-05T00:06:56Z","dependencies":[{"issue_id":"openchat-j0o.1","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:06:56Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-j0o","title":"[EPIC] Ambient agents in every chat + bot data-access/privacy model","description":"VISION (Jacob 2026-06-04): an AI agent implicitly present in every chat (yours + others'); bots present in group chats; ability to message someone's bot explicitly; your assistant can cause another's bot to kick something off. Open question: per-user agents ('Jacob's agent' + the other person's agent) vs ONE general useful agent with skills (e.g. NVC mediation as a built-in skill). \n\nTHE CRUX = bot DATA ACCESS / PRIVACY. Must not add your bot to a group and leak personal data. Reference models to mirror: Cortex (total isolation), Noos (private/public/group node visibility), WikiHub (public/public-edit/private/unlisted + teams/grants), Notestream (groups), Collura (?). Idea: tiered access control (private / group-or-team-scoped / public); the agent's data access = union of what the CURRENT context is allowed to see (group chat β†’ only group+public, never your private); approval workflow for the bot to use/send private data; separate scoped memory per bot/context.\n\nMINIMAL DEMO ('poor man's version'): apply the same visibility model (public / group / private) to the OpenChat Thoughtstream THOUGHTS already in-app β€” a small, concrete demonstration of the access-control behavior.\n\nThis epic is DESIGN-FIRST: research prior art across Jacob's projects, then a written design (data model, access-control rules, agent-context scoping, messaging-a-bot UX, NVC-skill plugin model, approval workflow), then phased build starting with the Thoughts-visibility demo.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:01:15Z","created_by":"tmad4000","updated_at":"2026-06-05T00:01:15Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.3","title":"Assistant bot: in-app participant + agentic tool loop (search + act)","description":"Thin non-coding agent: a pinned 'Assistant' bot DM. Reuse ANTHROPIC_API_KEY + containsBot. Tool loop with tools: search_messages, list_conversations, read_messages, send_message, create_conversation (user chose search+ACT). Posts replies as the bot participant. Trigger: message in a containsBot conversation -\u003e server runs loop -\u003e streams/posts reply.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:05Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:05Z","dependencies":[{"issue_id":"openchat-bfn.3","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:04Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.1","title":"Substrate v1: make /api/chat/search agent-accessible (resolveActor) + filters","description":"Switch /api/chat/search from requireAuth -\u003e resolveActor so oc_ agent keys can search the owner's chat history (read-only, safe). Already in OpenAPI as searchMessages. Optionally add sender/date filters + match snippets. This is the keystone: lets ANY external agent (Claude Code/ChatGPT) search chat history immediately, and is the bot's primary tool later.","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:01Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:01Z","dependencies":[{"issue_id":"openchat-bfn.1","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:01Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.3","title":"Assistant bot: in-app participant + agentic tool loop (search + act)","description":"Thin non-coding agent: a pinned 'Assistant' bot DM. Reuse ANTHROPIC_API_KEY + containsBot. Tool loop with tools: search_messages, list_conversations, read_messages, send_message, create_conversation (user chose search+ACT). Posts replies as the bot participant. Trigger: message in a containsBot conversation -\u003e server runs loop -\u003e streams/posts reply.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:05Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:05Z","dependencies":[{"issue_id":"openchat-bfn.3","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:04Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.1","title":"Substrate v1: make /api/chat/search agent-accessible (resolveActor) + filters","description":"Switch /api/chat/search from requireAuth -\u003e resolveActor so oc_ agent keys can search the owner's chat history (read-only, safe). Already in OpenAPI as searchMessages. Optionally add sender/date filters + match snippets. This is the keystone: lets ANY external agent (Claude Code/ChatGPT) search chat history immediately, and is the bot's primary tool later.","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:01Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:01Z","dependencies":[{"issue_id":"openchat-bfn.1","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:01Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-bfn","title":"Built-in agentic assistant over chat history (substrate-first)","description":"Per design decision 2026-06-04 (substrate-first, non-coding retrieval agent that can SEARCH + TAKE ACTIONS, grounded in Dan Shipper/Lenny ep: app = great tool agents call). Build the search substrate first (serves external agents AND a future in-app bot), then a thin in-app Assistant. Reuse existing ANTHROPIC_API_KEY + containsBot plumbing. Neo4j 5.15 Community supports vector indexes. No embedding key yet (Anthropic has none) -\u003e semantic search is v2 pending provider-key decision (OpenAI text-embedding-3-small or Voyage).","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:47:59Z","created_by":"tmad4000","updated_at":"2026-06-04T21:47:59Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-o7z","title":"Monorepo: server static-serve paths broke /m /d / (apps/server is a level deeper)","description":"After the migration, apps/server compiles to apps/server/dist, so __dirname/../../ resolves to apps/ not repo root. clientDistPath pointed at apps/client/dist (now apps/web/dist), and client-mobile/-desktop dist (repo root) needed one more '..'. Result: /m, /d 404 and / likely broken when deployed from monorepo. Fix: clientDistPath=../../web/dist; mobile dists=../../../client-mobile{,-desktop}/dist. Caught during cutover deploy (rolled back, no prod impact).","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T20:21:55Z","created_by":"tmad4000","updated_at":"2026-06-04T20:27:55Z","closed_at":"2026-06-04T20:27:55Z","close_reason":"Fixed server static-serve paths (web ../../web/dist; mobile dists ../../../). Deployed from monorepo, prod verified /m /d / all 200 with content.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-yvu","title":"Google sign-in doesn't show account chooser (can't pick which Google account)","description":"Sign in with Google reuses the single logged-in Google session instead of letting you choose/switch accounts. Cause: server /api/auth/google/url only sets prompt= if passed, and the mobile-web flow (openchat-mobile LoginScreen ~L217) doesn't pass it. Fix: server defaults prompt to 'select_account' when not provided (fixes web + mobile-web + any caller); mobile-web also passes \u0026prompt=select_account explicitly. Parity: server (OpenChat) + mobile (openchat-mobile).","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T20:03:57Z","created_by":"tmad4000","updated_at":"2026-06-04T20:05:36Z","closed_at":"2026-06-04T20:05:36Z","close_reason":"Server defaults Google /google/url prompt=select_account; mobile-web + native pass it explicitly. Built clean both. Deploying.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-bbr","title":"One-click 'Copy agent setup' from Settings (mint+copy, self-contained, no external guide) β€” web + mobile","description":"Per Jacob: setting up an agent should be ONE click from Settings, copying a ready-to-paste self-contained blob β€” no navigating to Agent Keys/create/reveal, no external guide file. Implement: a prominent 'Copy agent setup' button in Settings that (1) mints a fresh agent key via POST /api/agent-keys (returns plaintext 'key'), (2) builds the tool-less ChatGPT/Any-LLM REST onboarding blob with that key, (3) copies to clipboard, (4) confirms. No external /about/connect-your-bot dependency (blob is self-sufficient). Mobile: add to Settings (reuse McpSetupCard's blob via a shared util). Web: web has NO agent-key API/UI today β€” add api.createAgentKey + the one-click button (subset of bmp.10). Each tap mints a named, revocable key.","status":"open","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:57:19Z","created_by":"tmad4000","updated_at":"2026-06-04T12:57:19Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.4","title":"Web: read receipts + fix unread badges (stub empty Map)","description":"Server emits read:updated + PATCH /conversations/:id/read. Web useChatSocket drops the event; ChatContext.unreadByConv is hardcoded new Map() (line ~563) so badges never show. Wire both.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:58Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:19Z","closed_at":"2026-06-04T22:36:19Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.4","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:58Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.3","title":"Web: edit/delete message + action menu","description":"api.ts editMessage/deleteMessage exist but are never called; no context exposure, no hover/right-click menu. Add web message action menu (copy/edit/delete/reply/react/forward).","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:56Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:18Z","closed_at":"2026-06-04T22:36:18Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.3","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:56Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.2","title":"Web: reply / quote","description":"Server hydrates replyTo on every message + stores replyToId. Web MessageList renders no reply bubble; MessageInput has no reply bar. Pure frontend.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:55Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:17Z","closed_at":"2026-06-04T22:36:17Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.2","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:54Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.1","title":"Web: message reactions (tap/hover to react)","description":"Server POST/DELETE /messages/:id/reactions ready; mobile ReactionsBar/ReactionPicker. Web MessageList has none; add toggleReaction to web ChatContext + hover/long-press picker. Note: server allows 6 emoji.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:53Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:15Z","closed_at":"2026-06-04T22:36:15Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.1","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:53Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.4","title":"Web: read receipts + fix unread badges (stub empty Map)","description":"Server emits read:updated + PATCH /conversations/:id/read. Web useChatSocket drops the event; ChatContext.unreadByConv is hardcoded new Map() (line ~563) so badges never show. Wire both.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:58Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:19Z","closed_at":"2026-06-04T22:36:19Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.4","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:58Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.3","title":"Web: edit/delete message + action menu","description":"api.ts editMessage/deleteMessage exist but are never called; no context exposure, no hover/right-click menu. Add web message action menu (copy/edit/delete/reply/react/forward).","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:56Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:18Z","closed_at":"2026-06-04T22:36:18Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.3","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:56Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.2","title":"Web: reply / quote","description":"Server hydrates replyTo on every message + stores replyToId. Web MessageList renders no reply bubble; MessageInput has no reply bar. Pure frontend.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:55Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:17Z","closed_at":"2026-06-04T22:36:17Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.2","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:54Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.1","title":"Web: message reactions (tap/hover to react)","description":"Server POST/DELETE /messages/:id/reactions ready; mobile ReactionsBar/ReactionPicker. Web MessageList has none; add toggleReaction to web ChatContext + hover/long-press picker. Note: server allows 6 emoji.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:53Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:15Z","closed_at":"2026-06-04T22:36:15Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependencies":[{"issue_id":"openchat-bmp.1","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:53Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-bmp","title":"Web client ↔ mobile parity (web is a prototype; mobile is the reference)","description":"Audit 2026-06-04: the Vite web client lags mobile badly. Most features have full server API + mobile UI but NO web UI. Server is ready for ~all of it β€” this is frontend work, porting from openchat-mobile (ChatScreen.tsx, ChatContext.tsx, MessageActionSheet, ReactionsBar, etc.). Biggest web gaps live in client/src/contexts/ChatContext.tsx (missing editMessage/deleteMessage/toggleReaction/muteConv/readByOthers/markRead/blockUser), MessageList.tsx (no reactions/reply/date-separators/link-previews/voice/action-menu), MessageInput.tsx (images only), SettingsModal.tsx (version+1 toggle only), useChatSocket.ts (drops read:updated). See children.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:54:51Z","created_by":"tmad4000","updated_at":"2026-06-04T12:54:51Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-1pa","title":"Can't DM yourself: self filtered from composer (mobile) + only findable via magic word (server)","description":"User can't start a self-DM β€” they don't appear in the new-conversation composer. Two causes: (1) mobile NewConversationScreen did rows.filter(u=\u003eu.id!==currentUser.userId), hard-stripping self; (2) server /contacts only surfaced self for the literal 'self'/'me' query (typing your name excluded you; empty list excluded you). Fix: server /contacts always includes self (empty list + name/email match + magic words), self pinned first; mobile keeps self in results with a '(You) / Note to self' badge; tap -\u003e createConversation([self],direct) -\u003e self-DM. Web composer benefits from the server change (no client filter there).","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:43:50Z","created_by":"tmad4000","updated_at":"2026-06-04T12:43:57Z","closed_at":"2026-06-04T12:43:57Z","close_reason":"Server /contacts always includes self (pinned first, name/email + magic-word match); mobile composer no longer filters self out + shows '(You)/Note to self'. Built clean both. Deploying.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-1mo","title":"Hashtag-\u003eThought extraction misses the socket send path (apps don't create Thoughts)","description":"createThoughtsFromMessageTags is only called in the REST POST /conversations/:id/messages route. But both web (client useChatSocket.ts) and mobile (socket.ts) send via the WebSocket 'message:send' handler (chatHandler.ts ~line164), which does NOT extract. REST is only a fallback (flaky-network). Net: typing #fact/#decision/#commitment/#reminder/#observation (+ aliases #thought/#todo/#note) in the desktop or mobile app does NOT create a Thought today. Fix: mirror the best-effort extractor call into the socket message:send handler (fresh session, pass io for live thought:created emit), ideally via a shared helper both paths call. Ships on next server deploy.","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:47:00Z","created_by":"tmad4000","updated_at":"2026-06-04T11:48:18Z","closed_at":"2026-06-04T11:48:18Z","close_reason":"Fixed: socket message:send handler now calls createThoughtsFromMessageTags (mirror of REST route). Server build clean; extractor confirmed in compiled chatHandler. On main + pushed. Goes live on next deploy.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-n9a","title":"Google sign-in broken on web (/d,/m RN-web): COOP severs popup OAuth","description":"chat.globalbr.ai/d and /m: 'Continue with Google' disables button, never redirects. Console: 'Cross-Origin-Opener-Policy policy would block the window.closed call'. Expo web popup OAuth flow severed by Google's COOP header. Fix: redirect-based flow (legacy client already does this via /auth/google/callback + /api/auth/google/exchange). Workaround: email/password (Noos) sign-in works. Lives in openchat-mobile web build.","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T10:51:29Z","created_by":"tmad4000","updated_at":"2026-06-04T11:24:31Z","closed_at":"2026-06-04T11:24:31Z","close_reason":"Fixed in openchat-mobile 313c8b2 + deployed. Web Google sign-in now uses a full-page redirect (popup was severed by Google COOP). Verified on /d: redirects to accounts.google.com with redirect_uri=https://chat.globalbr.ai/d/ (registered), Google accepts it (advances to account chooser, no mismatch). /m identical.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-oc8","title":"OpenChat: connect-agent polish, updates, feedback chat, agent sidebar","description":"Batch of product directions from Jacob 2026-06-04 after the connect-agent + TestFlight work:\n1. Simplify Settings 'Connect an agent' card β€” make 'copy prompt for agent' front-and-center; keep blue accent; want a design second opinion (Gemini) + an alternate version.\n2. App update strategy β€” in-app 'update available' nudge vs automatic TestFlight updates vs EAS Update OTA. Decide + implement layered best practice.\n3. Feedback chat β€” does not exist yet. v1: a Feedback conversation/entry that auto-creates an issue on worldissuetracker.com (WIT) via its agent. Future: route to our own OpenChat agent that can converse back.\n4. Agent sidebar β€” chat with an agent to search your message history + (future) send messages on your behalf. Model: a bot represents you and can jump into any chat 'as you' by default, or 'message as \u003cbot\u003e' when specified.\n\nThis epic groups the subtasks; see children.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:54:28Z","created_by":"tmad4000","updated_at":"2026-06-04T08:54:28Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-aec.2","title":"Copy-paste agent onboarding blob (works in plain ChatGPT)","description":"One-click 'Copy for agent' button that yields a self-contained onboarding blob a user can paste into ANY LLM (ChatGPT, Claude, Gemini) β€” no coding-agent required. Blob contains:\n- Base URL (https://chat.globalbr.ai)\n- A freshly-minted live API key (mint-on-copy; embeds a live secret in clipboard text β€” acceptable per Jacob's decision 2026-06-04)\n- Endpoint cheatsheet (list convos, send message with {content} field, poll /messages/since)\n- Plain-English instructions ('You are operating Jacob's OpenChat account. To send a message, POST ... You appear AS the user, not a separate bot.')\n- The target conversation id (e.g. the self-DM) when launched from a conversation\n\nSecurity/UX notes:\n- Warn that the blob contains a live key; offer 'revoke' nearby.\n- Mint a NEW key per copy (named e.g. 'ChatGPT 2026-06-04') so it's individually revocable, rather than reusing one key everywhere.\n- Correct field is {\"content\":\"...\"} (also accepts {\"text\":...} alias per openchat-nqi).","notes":"PARTIALLY EXISTS in mobile McpSetupCard (Claude Desktop/Cursor/Codex/Claude Code/curl + one-shot agent prompt). REAL REMAINING GAP: a 'Plain ChatGPT / Any LLM' target β€” prose+REST blob (base URL + live key + endpoint cheatsheet + self-DM conv id) for a tool-less model that can't install MCP or run a shell. Building this into McpSetupCard now.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:15Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:19Z","closed_at":"2026-06-04T11:11:19Z","close_reason":"Shipped: 'ChatGPT / Any LLM' tool-less REST onboarding blob is the default tab in mobile McpSetupCard (commit 0578456, on mobile main + in the build now uploading). Lets a plain ChatGPT/Gemini/Claude.ai operate the account over HTTPS with no MCP/CLI.","dependencies":[{"issue_id":"openchat-aec.2","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:14Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-aec.1","title":"Settings: Agent keys section (create / list / reveal / revoke)","description":"Build the missing client UI for the existing /api/agent-keys backend. Settings page gets an 'Agent keys' (or 'Connect your agent') section:\n- List existing keys (name, prefix, scopes, last used, created)\n- Create key (name + scope toggles, default read+write)\n- Reveal full key on demand (re-viewable; each reveal audit-logged server-side)\n- Rename / change scopes\n- Revoke\n\nMake it OBVIOUS and discoverable β€” not buried. This is the foundation the copy-paste blob and share link build on.","notes":"Already implemented in openchat-mobile (AgentKeysScreen/AddAgentKeyScreen/AgentKeyDetailScreen + Settings 'Agent Keys' hero, OpenChat-i9h/OpenChat-7c9). Web-client parity is optional follow-up; mobile is the TestFlight target.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:13Z","created_by":"tmad4000","updated_at":"2026-06-04T08:39:01Z","closed_at":"2026-06-04T08:39:01Z","dependencies":[{"issue_id":"openchat-aec.1","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:13Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-aec","title":"Connect-your-agent UX: obvious in-app agent onboarding","description":"Today there is NO client UI for connecting an agent, even though the agent-keys backend is fully built on the investigate-url-sync-issue-2 branch (/api/agent-keys: create, list, reveal, rename/scope, revoke; encrypted at rest, audit-logged, read/write scopes). The connect-your-bot.md doc even claims a 'Settings -\u003e DEVELOPER -\u003e Agent keys' flow that does not exist in the client.\n\nGoal (Jacob, 2026-06-04): make it super obvious how to connect an agent from Settings, and provide a copy-paste onboarding blob so even a plain ChatGPT (not a coding agent) can operate the account.\n\nDecisions:\n- Branch strategy: merge to main first (see openchat-a9u / openchat-bv8), then build connect-UX on clean main.\n- Blob scope: FULL onboarding blob with a live freshly-minted key.\n\nSubtasks track the individual pieces.","notes":"All connect-agent + adjacent work landed: ChatGPT/Any-LLM blob (mobile), agent-keys backend (merged), feedback (oc8.3) + EAS Update (oc8.2) shipped. Remaining child aec.3 (share-self-DM link) still open.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:31:50Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:00Z","dependencies":[{"issue_id":"openchat-aec","depends_on_id":"openchat-a9u","type":"blocks","created_at":"2026-06-04T01:32:25Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-aec.2","title":"Copy-paste agent onboarding blob (works in plain ChatGPT)","description":"One-click 'Copy for agent' button that yields a self-contained onboarding blob a user can paste into ANY LLM (ChatGPT, Claude, Gemini) β€” no coding-agent required. Blob contains:\n- Base URL (https://chat.globalbr.ai)\n- A freshly-minted live API key (mint-on-copy; embeds a live secret in clipboard text β€” acceptable per Jacob's decision 2026-06-04)\n- Endpoint cheatsheet (list convos, send message with {content} field, poll /messages/since)\n- Plain-English instructions ('You are operating Jacob's OpenChat account. To send a message, POST ... You appear AS the user, not a separate bot.')\n- The target conversation id (e.g. the self-DM) when launched from a conversation\n\nSecurity/UX notes:\n- Warn that the blob contains a live key; offer 'revoke' nearby.\n- Mint a NEW key per copy (named e.g. 'ChatGPT 2026-06-04') so it's individually revocable, rather than reusing one key everywhere.\n- Correct field is {\"content\":\"...\"} (also accepts {\"text\":...} alias per openchat-nqi).","notes":"PARTIALLY EXISTS in mobile McpSetupCard (Claude Desktop/Cursor/Codex/Claude Code/curl + one-shot agent prompt). REAL REMAINING GAP: a 'Plain ChatGPT / Any LLM' target β€” prose+REST blob (base URL + live key + endpoint cheatsheet + self-DM conv id) for a tool-less model that can't install MCP or run a shell. Building this into McpSetupCard now.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:15Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:19Z","closed_at":"2026-06-04T11:11:19Z","close_reason":"Shipped: 'ChatGPT / Any LLM' tool-less REST onboarding blob is the default tab in mobile McpSetupCard (commit 0578456, on mobile main + in the build now uploading). Lets a plain ChatGPT/Gemini/Claude.ai operate the account over HTTPS with no MCP/CLI.","dependencies":[{"issue_id":"openchat-aec.2","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:14Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-aec.1","title":"Settings: Agent keys section (create / list / reveal / revoke)","description":"Build the missing client UI for the existing /api/agent-keys backend. Settings page gets an 'Agent keys' (or 'Connect your agent') section:\n- List existing keys (name, prefix, scopes, last used, created)\n- Create key (name + scope toggles, default read+write)\n- Reveal full key on demand (re-viewable; each reveal audit-logged server-side)\n- Rename / change scopes\n- Revoke\n\nMake it OBVIOUS and discoverable β€” not buried. This is the foundation the copy-paste blob and share link build on.","notes":"Already implemented in openchat-mobile (AgentKeysScreen/AddAgentKeyScreen/AgentKeyDetailScreen + Settings 'Agent Keys' hero, OpenChat-i9h/OpenChat-7c9). Web-client parity is optional follow-up; mobile is the TestFlight target.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:13Z","created_by":"tmad4000","updated_at":"2026-06-04T08:39:01Z","closed_at":"2026-06-04T08:39:01Z","dependencies":[{"issue_id":"openchat-aec.1","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:13Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-aec","title":"Connect-your-agent UX: obvious in-app agent onboarding","description":"Today there is NO client UI for connecting an agent, even though the agent-keys backend is fully built on the investigate-url-sync-issue-2 branch (/api/agent-keys: create, list, reveal, rename/scope, revoke; encrypted at rest, audit-logged, read/write scopes). The connect-your-bot.md doc even claims a 'Settings -\u003e DEVELOPER -\u003e Agent keys' flow that does not exist in the client.\n\nGoal (Jacob, 2026-06-04): make it super obvious how to connect an agent from Settings, and provide a copy-paste onboarding blob so even a plain ChatGPT (not a coding agent) can operate the account.\n\nDecisions:\n- Branch strategy: merge to main first (see openchat-a9u / openchat-bv8), then build connect-UX on clean main.\n- Blob scope: FULL onboarding blob with a live freshly-minted key.\n\nSubtasks track the individual pieces.","notes":"All connect-agent + adjacent work landed: ChatGPT/Any-LLM blob (mobile), agent-keys backend (merged), feedback (oc8.3) + EAS Update (oc8.2) shipped. Remaining child aec.3 (share-self-DM link) still open.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:31:50Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:00Z","dependencies":[{"issue_id":"openchat-aec","depends_on_id":"openchat-a9u","type":"blocks","created_at":"2026-06-04T01:32:25Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-60y","title":"Idempotent message send (client-gen id) + user-room delivery β€” fixes from Codex review of openchat-5q1","description":"Codex review of openchat-5q1 found a regression: the new 10s WS ack timeout + REST fallback can persist the SAME message twice with different server nanoids (WS persists row A, ack lost, REST persists row B). Fix with a client-generated message id used by BOTH paths + server MERGE (create-if-absent). Also: (2) broadcast message:new to each participant's user:\u003cid\u003e room so recipients who haven't joined the conversation room still get it live; (3) dedupe the manual setMessages append in ChatContext catch; (4) add an AbortController timeout to the REST send so the hard-failure path can't hang on mobile/VPN.","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T02:25:28Z","created_by":"tmad4000","updated_at":"2026-06-04T02:28:06Z","started_at":"2026-06-04T02:25:36Z","closed_at":"2026-06-04T02:28:06Z","close_reason":"Fixed in 7a87429: client-gen idempotency id + server MERGE (kills double-persist regression), per-user-room delivery, REST append dedupe, REST abort timeout. Build clean. Minor follow-ups split to new ticket.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-5q1","title":"Mobile/China-VPN users can't send: websocket-only transport + no send queue","description":"Lucy (mobile, China VPN) cannot send messages. Root cause: client pins Socket.IO to transports:['websocket'] (no polling fallback) and sendMessage rejects with 'Not connected' the instant the socket is down β€” no queue/retry. Mobile backgrounding + VPN/GFW reset the WS constantly, so sends land in the disconnected gap and silently drop. Fix: (1) queue-and-retry sends, (2) re-enable polling fallback with WS upgrade, (3) reconnect on visibilitychange. Preserve OpenChat-0kv Cloudflare WS fix.","notes":"Root causes: (1) REST POST /conversations/:id/messages never emitted message:new, so socket-down sends (mobile/China VPN) were invisible to recipients. (2) message:send ack had no timeout -\u003e on mobile the Promise hung forever and the REST fallback never fired. Fixed both + MessageInput restores text/toasts on hard failure + useChatSocket reconnects on visibilitychange/online/focus. Transport left websocket-only to preserve OpenChat-0kv. Builds clean. Commit 4908c0b.","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T02:17:10Z","created_by":"tmad4000","updated_at":"2026-06-04T02:21:18Z","started_at":"2026-06-04T02:17:16Z","closed_at":"2026-06-04T02:21:18Z","close_reason":"Fixed in 4908c0b: REST broadcast + ack timeout + send-failure UX + mobile reconnect. Both workspaces build clean.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-a9u","title":"Merge investigate-url-sync-issue-2 backlog (57 commits) to main","description":"Worktree ~/.omnara/worktrees/OpenChat/compress-ravine on branch investigate-url-sync-issue-2 has 57 commits ahead of main that haven't been merged. Includes many finished features:\n\n- Self-serve agent API keys (OpenChat-7c9)\n- OG link previews (OpenChat-hq2)\n- Typing indicator dots (OpenChat-zln)\n- Thoughts Stream feed endpoints (OpenChat-zi1)\n- Message forwarding (OpenChat-hhc)\n- @-mentions (OpenChat-0jy)\n- Image attachments (OpenChat-6bg)\n- Read receipts + profile editing (OpenChat-0nj, OpenChat-tml)\n- QR group invites (OpenChat-240)\n- AI message transforms (OpenChat-8a0)\n- Message search (OpenChat-kma, OpenChat-89g)\n- Reconnect catch-up + pagination (OpenChat-qz0, OpenChat-vjc)\n- Block/unblock (OpenChat-46p)\n- Sign in with Apple (OpenChat-c08)\n- Account deletion (OpenChat-nhy)\n- Privacy policy + ToS (OpenChat-wfz)\n- Google OAuth (OpenChat-hwi)\n- Native Expo Push (OpenChat-vg7)\n- Server-side search (OpenChat-kma)\n- Bot users first-class (OpenChat-aoy)\n- VAPID push backend (OpenChat-3fw)\n- Dark mode toggle\n- PWA polish\n- Data export downloads\n- Landing page (/about)\n\nThis is too large to merge blindly β€” likely needs:\n1. Review (Codex second opinion?) of what made it into the branch vs what should still ship\n2. Logical grouping into smaller merges or a single rebase + squash strategy\n3. Conflict resolution against the 4 commits on test-agent-key-integration (especially overlap with self-serve agent API keys OpenChat-7c9)\n\nAcceptance: branch is fully merged to main locally OR replaced by a deliberate subset of commits + the rest discarded with rationale documented.\n\nDO NOT auto-merge without review.","notes":"Merged investigate-url-sync-issue-2 into integration/connect-agent as checkpoint 54e3a18. Resolved expected .beads/issues.jsonl and .gitignore conflicts, kept investigate beads export, unioned ignore rules, removed client/tsconfig.tsbuildinfo from tracking and ignored it. Server/client/root builds pass after follow-up merge resolution. No push performed.","status":"closed","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T20:33:54Z","created_by":"tmad4000","updated_at":"2026-06-04T08:44:34Z","started_at":"2026-06-04T08:33:41Z","closed_at":"2026-06-04T08:44:34Z","close_reason":"Merged investigate-url-sync-issue-2 (57 commits) into integration/connect-agent, then fast-forwarded main to 0764136. Clean build (server+client). Local merge, not pushed.","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"openchat-bv8","title":"Merge test-agent-key-integration branch to main","description":"Branch test-agent-key-integration (worktree: ~/.omnara/worktrees/OpenChat/rejoicing-litigate) has 4 commits ahead of main implementing tickets openchat-67y, openchat-wa9, openchat-nqi, openchat-ia9 (all closed). Branch is 1 behind main β€” rebase or merge to land.\n\nCommits (newest first):\n- 99e3776 feat(settings): surface app version metadata (openchat-ia9)\n- 2020d51 fix(docs): clarify bot message payloads (openchat-nqi)\n- 32f8e3e feat(chat): mark self in search and conversations (openchat-wa9)\n- 2d9a460 fix(auth): broaden agent key access (openchat-67y)\n\nVerification before merge:\n- server + client npm run build pass on each commit (already verified)\n- scripts/test-agent-key.sh smoke test against local Neo4j\n\nPer CLAUDE.md ephemeral-worktree policy: merge to main locally, do not push.\n\nPOTENTIAL CONFLICT: openchat-67y's agent-key auth work may overlap with commit 4424742 'feat(auth): self-serve agent API keys (OpenChat-7c9)' on the investigate-url-sync-issue-2 branch (which is 57 ahead of main). Resolve conflicts deliberately β€” likely want the union of capabilities + the per-capability flag scheme from openchat-67y.","notes":"Merged test-agent-key-integration into integration/connect-agent as checkpoint 0764136. Kept investigate server/src/routes/agentKeys.ts wholesale. Dropped the alternate requireCapability auth path in favor of resolveActor; switched agent-required chat routes to resolveActor for list/create/fetch/send/edit/delete. Preserved text-\u003econtent alias, self-DM/self-search behavior, self labels, version settings UI, and connect-your-bot docs route. npm install regenerated package-lock; server/client/root builds pass. No push performed.","status":"closed","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T20:33:52Z","created_by":"tmad4000","updated_at":"2026-06-04T08:44:36Z","started_at":"2026-06-04T08:33:42Z","closed_at":"2026-06-04T08:44:36Z","close_reason":"Merged test-agent-key-integration (4 commits, openchat-67y/wa9/nqi/ia9) into integration/connect-agent. Kept canonical resolveActor agent-key path; dropped redundant requireCapability. Landed on main 0764136.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.4","title":"Collapse /m and /d onto one responsive RN-web source","description":"Remove the need for a separate openchat-mobile-desktop fork/artifact by making openchat-mobile handle both mobile-width and desktop-width RN-web layouts responsively.","acceptance_criteria":"/m and /d deploy from the same current RN-web source; desktop layout remains usable at wide widths; mobile layout remains usable at narrow widths; deploy no longer relies on an untracked desktop repo; fallback behavior is documented.","notes":"Finding: /m and /d are ALREADY one responsive RN-web source (differ only in export baseUrl prefix; layout switches by viewport width). deploy.sh refactored to export_rnweb() helper, byte-equivalent default + opt-in OPENCHAT_SINGLE_RNWEB_EXPORT flag (off). docs/collapse-m-d.md has the single-export spike plan. Core acceptance met; single-export optimization deferred behind the flag pending a real deploy test.","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:56Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:08Z","labels":["deploy","desktop","expo","monorepo","release","rn-web"],"dependencies":[{"issue_id":"openchat-3jq.4","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:56Z","created_by":"tmad4000","metadata":"{}"},{"issue_id":"openchat-3jq.4","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:34Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.2","title":"Add automated TestFlight build and submit workflow","description":"Create a CI workflow that builds the iOS app with EAS and submits it to App Store Connect/TestFlight using stored API credentials.","acceptance_criteria":"Workflow can run manually and on the intended branch/tag trigger; typecheck/build smoke checks run before submit; EAS build profile is documented; App Store Connect API key requirements are documented; successful runs submit a TestFlight build.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:51Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:03Z","closed_at":"2026-06-04T23:59:03Z","close_reason":"TestFlight CI workflow added (.github/workflows/testflight.yml, EAS cloud build+submit, documented secrets).","labels":["eas","expo","github-actions","monorepo","release","testflight"],"dependencies":[{"issue_id":"openchat-3jq.2","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:51Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.1","title":"Enable EAS Update for fast JS/UI releases","description":"Configure Expo Updates/EAS Update for openchat-mobile so compatible JS, styling, asset, and API-client changes can be shipped over the air without waiting for a new TestFlight binary.","acceptance_criteria":"expo-updates is configured; runtimeVersion policy is explicit; preview/production update channels exist; update commands are documented; incompatible native changes are clearly separated from OTA-safe changes.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:49Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:18Z","closed_at":"2026-06-04T11:11:18Z","close_reason":"Done via oc8.2 β€” expo-updates + EAS Update OTA configured (channels, runtimeVersion appVersion, ON_LOAD), merged to mobile main, activating on the TestFlight build in flight.","labels":["eas-update","expo","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.1","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:49Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.4","title":"Collapse /m and /d onto one responsive RN-web source","description":"Remove the need for a separate openchat-mobile-desktop fork/artifact by making openchat-mobile handle both mobile-width and desktop-width RN-web layouts responsively.","acceptance_criteria":"/m and /d deploy from the same current RN-web source; desktop layout remains usable at wide widths; mobile layout remains usable at narrow widths; deploy no longer relies on an untracked desktop repo; fallback behavior is documented.","notes":"Finding: /m and /d are ALREADY one responsive RN-web source (differ only in export baseUrl prefix; layout switches by viewport width). deploy.sh refactored to export_rnweb() helper, byte-equivalent default + opt-in OPENCHAT_SINGLE_RNWEB_EXPORT flag (off). docs/collapse-m-d.md has the single-export spike plan. Core acceptance met; single-export optimization deferred behind the flag pending a real deploy test.","status":"open","priority":1,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:56Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:08Z","labels":["deploy","desktop","expo","monorepo","release","rn-web"],"dependencies":[{"issue_id":"openchat-3jq.4","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:56Z","created_by":"auto-import","metadata":"{}"},{"issue_id":"openchat-3jq.4","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:34Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.2","title":"Add automated TestFlight build and submit workflow","description":"Create a CI workflow that builds the iOS app with EAS and submits it to App Store Connect/TestFlight using stored API credentials.","acceptance_criteria":"Workflow can run manually and on the intended branch/tag trigger; typecheck/build smoke checks run before submit; EAS build profile is documented; App Store Connect API key requirements are documented; successful runs submit a TestFlight build.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:51Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:03Z","closed_at":"2026-06-04T23:59:03Z","close_reason":"TestFlight CI workflow added (.github/workflows/testflight.yml, EAS cloud build+submit, documented secrets).","labels":["eas","expo","github-actions","monorepo","release","testflight"],"dependencies":[{"issue_id":"openchat-3jq.2","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:51Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.1","title":"Enable EAS Update for fast JS/UI releases","description":"Configure Expo Updates/EAS Update for openchat-mobile so compatible JS, styling, asset, and API-client changes can be shipped over the air without waiting for a new TestFlight binary.","acceptance_criteria":"expo-updates is configured; runtimeVersion policy is explicit; preview/production update channels exist; update commands are documented; incompatible native changes are clearly separated from OTA-safe changes.","status":"closed","priority":1,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:49Z","created_by":"tmad4000","updated_at":"2026-06-04T11:11:18Z","closed_at":"2026-06-04T11:11:18Z","close_reason":"Done via oc8.2 β€” expo-updates + EAS Update OTA configured (channels, runtimeVersion appVersion, ON_LOAD), merged to mobile main, activating on the TestFlight build in flight.","labels":["eas-update","expo","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.1","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:49Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-3jq","title":"Modernize OpenChat release/update pipeline and keep web/mobile in sync","description":"Track the work to make OpenChat updates predictable across TestFlight, native installs, and web. The goal is to reduce drift by using one canonical React Native/Expo app source for mobile and RN-web, while adding automated OTA and TestFlight release paths.","acceptance_criteria":"A maintained release plan exists in beads; OTA updates are configured; TestFlight builds/submits are automated; web/mobile version provenance is visible; /m and /d no longer depend on a stale desktop fork; monorepo migration has an executable path.","status":"open","priority":1,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:47Z","created_by":"tmad4000","updated_at":"2026-06-01T10:51:47Z","labels":["expo","monorepo","release"],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-67y","title":"Broaden agent-key scope: allow all chat API operations","description":"Agent key oc_* returns 'Invalid or expired token' on POST /api/chat/conversations, GET /api/chat/conversations/:id/messages, GET /api/agent-keys. Works for GET /api/chat/conversations, POST /api/chat/conversations/:id/messages, GET /api/chat/messages/since.\n\nGoal: agent keys should do everything a user session can. Add per-capability flags so dangerous abilities (e.g. agent-key management) can be opted out later.\n\nRepro (2026-06-01): key oc_uzt98CaewVo3wR7bRS6Nn3vPeABhy8PE on chat.globalbr.ai. Self-DM conv 2esEjqQ9cKCzTgN2uMM3B had to be created in UI first; after that POST /messages worked (msg 8WeahC5Jo41OaXdIoRjqT).\n\nAcceptance: agent key can create conversations (incl. self-DM), fetch single-conv messages directly, manage agent keys behind a capability flag.","status":"closed","priority":1,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:41:05Z","created_by":"tmad4000","updated_at":"2026-06-01T10:47:51Z","started_at":"2026-06-01T10:42:14Z","closed_at":"2026-06-01T10:47:51Z","close_reason":"Agent-key auth now covers user-session routes with default-on capability flags; added local self-DM smoke script.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-7c9","title":"[P1] Self-serve agent API keys β€” seamless 'connect your bot' onboarding","description":"Make it dead simple for anyone (Jacob, a user, a friend) to plug their own agent/bot into OpenChat. Today picortex uses a one-off out-of-band JWT minted by a developer. We need a self-serve API key flow with re-viewable keys (NOT one-time-view), provenance fields, scopes, and a working MCP surface.\n\nGOOD PRACTICES TO INHERIT FROM world-issue-tracker + wikihub:\n\n1. **Prefix convention**: keys start with 'oc_' (parallels 'wh_' / 'wit_'). First 12 chars are the visible 'key prefix' used for UI display, full key only visible when retrieved.\n2. **Standard Bearer auth**: 'Authorization: Bearer oc_…' on every endpoint, not a custom X-Agent-Key header. Matches WikiHub convention (cleaner than WIT's X-Agent-Key).\n3. **Provenance fields**: each key has agent_name (e.g. 'my-summary-bot') + agent_version + scopes + expires_at + last_used_at β€” same shape as WikiHub's ApiKey model.\n4. **Scopes**: at minimum 'read' + 'write'. Future: per-conversation scoping, send-only, read-only mention listening.\n5. **Credentials file convention**: agents should expect to read from ~/.openchat/credentials.json (mode 0600), parallel to ~/.wikihub/credentials.json.\n6. **MCP server**: build a sibling openchat-mcp-server adapter (parallel to wikihub's mcp-server/). Tools: oc_send_message, oc_list_conversations, oc_get_messages, oc_react, oc_create_dm, oc_register_agent. Exposes both stdio + HTTP transports.\n\nDEVIATIONS FROM WIT/WikiHub (per Jacob's explicit feedback):\n\n7. **Keys are RE-VIEWABLE, not one-time-view**. WIT + WikiHub both show the key once at creation and store only the hash β€” Jacob explicitly does NOT want that. Implementation: store the FULL plaintext key in DB, encrypted at rest with a server-side KMS key (OC_KEY_ENCRYPTION_SECRET env var, rotatable separately from the database). User can re-view any of their keys from Settings β†’ Agent Keys at any time. Threat model: DB read leaks encryption-key-encrypted blob, not plaintext.\n\nUI:\n- Settings β†’ Agent Keys (new section)\n- List existing keys: name, prefix (oc_xxxx…), last used, expiry, [View] [Revoke] buttons\n- 'New key' button: prompts for name + scopes + optional expiry β†’ returns the full key, copy-to-clipboard\n- Each key row has [View full key] β†’ reveals plaintext after Face ID / passphrase re-auth (TBD)\n- Each key row has [Copy] for the agent name + key in one shot\n\nSERVER:\n- New Neo4j node: :AgentKey { id, ownerUserId, name, keyPrefix, keyEncrypted, scopes, agentName, agentVersion, expiresAt, createdAt, lastUsedAt, revokedAt }\n- (User)-[:OWNS_KEY]-\u003e(AgentKey)\n- POST /api/agent-keys { name, scopes?, expiresAt? } β€” authed; mints + returns plaintext\n- GET /api/agent-keys β€” authed; lists keys with prefix-only (no plaintext)\n- GET /api/agent-keys/:id/reveal β€” authed; returns full plaintext key (with audit log entry)\n- PATCH /api/agent-keys/:id { name?, scopes? } β€” authed; rename or change scope\n- DELETE /api/agent-keys/:id β€” authed; sets revokedAt\n- New middleware resolveActor: tries JWT first, then Bearer oc_… key. Resolves to owning user. Updates lastUsedAt async.\n- Picortex's JWT-based auth stays (don't break) but is grandfathered; future bots go through this.\n\nDOCS:\n- README section: 'Connect your bot in 30 seconds'\n 1. Settings β†’ Agent Keys β†’ Create\n 2. curl -H 'Authorization: Bearer oc_…' https://chat.globalbr.ai/api/chat/conversations\n- openchat-mcp-server README + Cursor/Claude Desktop config snippet\n- Add to landing page /about: a 'Connect your bot' link with the 30-second walkthrough\n\nACCEPTANCE:\n- A non-technical user can sign up, get an API key, and POST a message via curl in under 2 minutes\n- An MCP-aware client (Claude Desktop) can be configured with one JSON snippet to talk to OpenChat\n- Keys are re-viewable from Settings indefinitely (until revoked)\n- Revocation is immediate (cached resolver invalidated within 60s)\n- Audit log of key reveal events\n\nREFERENCES:\n- /Users/jacobcole/code/world-issue-tracker/supabase/functions/_shared/resolve-actor.ts (resolveActor pattern)\n- /Users/jacobcole/code/world-issue-tracker/supabase/functions/register-agent/index.ts (mint flow)\n- /Users/jacobcole/code/wikihub/docs/MCP_CONNECTOR_BLUEPRINT.md (MCP server shape + tool surface)\n- /Users/jacobcole/code/wikihub/mcp-server/ (working impl reference)\n- /Users/jacobcole/code/picortex (current OpenChat bot for shape parity)","status":"in_progress","priority":1,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-06-01T09:58:32Z","created_by":"Jacob Cole","updated_at":"2026-06-01T10:01:17Z","started_at":"2026-06-01T10:01:17Z","dependency_count":0,"dependent_count":1,"comment_count":0} @@ -55,11 +58,11 @@ {"_type":"issue","id":"OpenChat-e3p","title":"[mobile][bug] iOS keyboard covers text input + send button in ChatScreen","description":"On iPhone, opening a conversation and tapping the message composer raises the iOS keyboard, but the text input + Send button slide PARTIALLY under the keyboard β€” not fully avoided.\n\nThe screen has \u003cKeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined}\u003e with keyboardVerticalOffset={Platform.OS === 'ios' ? 90 : 0} in ChatScreen.tsx. The offset 90 was an estimate; with the tab bar / nav-stack header heights and safe-area inset on newer iPhones, that's not enough to keep composer fully above the keyboard.\n\nRepro: open any conversation on iPhone (TestFlight build 14), tap the text input. Observe composer is partly visible / partly hidden.\n\nFix candidates:\n1. Switch to react-native-keyboard-controller (handles edge cases better than KeyboardAvoidingView; integrates with the native gesture handler)\n2. Or: read useSafeAreaInsets + the header height (useHeaderHeight from react-navigation) at runtime and compute the offset dynamically instead of hardcoding 90\n3. Or: behavior='height' instead of 'padding' on iOS\n\nAcceptance: composer + send button fully visible above the keyboard on iPhone 13/14/15-class devices in both light/dark mode, with and without the tab bar visible.","status":"closed","priority":1,"issue_type":"bug","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T09:52:26Z","created_by":"Jacob Cole","updated_at":"2026-05-31T10:08:52Z","started_at":"2026-05-31T10:04:59Z","closed_at":"2026-05-31T10:08:52Z","close_reason":"Replaced hardcoded keyboardVerticalOffset=90 with dynamic useHeaderHeight() + useSafeAreaInsets() on ChatScreen's KeyboardAvoidingView. Computes correctly across notched/non-notched iPhones. Committed c34acbb on openchat-mobile/main.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-vg7","title":"[mobile] Push notifications (APNs / Expo Push) for new messages","description":"Discussed earlier as a separate epic but never filed. Mobile app does NOT ask for notification permission and has no native push wiring. Steps: (1) expo install expo-notifications expo-device. (2) After sign-in, request perms; if granted call getDevicePushTokenAsync (APNs) or getExpoPushTokenAsync (Expo relay β€” simpler). (3) Server: POST /api/push/register-native to store the token on the user + new pushTokens table. (4) Existing web-push fan-out helper extends to native tokens. (5) app.json: UIBackgroundModes=[remote-notification], aps-environment entitlement (EAS adds on build). (6) Foreground handler shows in-app banner; tap-handler navigates into the conversation.","status":"closed","priority":1,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:07Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:44Z","started_at":"2026-05-31T06:53:17Z","closed_at":"2026-05-31T07:02:44Z","close_reason":"Native push wired end-to-end. Server: POST/DELETE /api/push/register-native + sendNativePushToUser via exp.host Expo Push API + fan-out on message:send (commit 6e48b7b openchat/main). Mobile: perms + token + idempotent server-register on sign-in + foreground suppression in-conv + tap-to-Chat navigation (commit aee9401 openchat-mobile/main). Cypher: MERGE NativePushToken keyed by (userId, platform), Expo DeviceNotRegistered cleanup. Manual to ship: EAS build to pick up plugin + entitlement; redeploy openchat server. Known gaps: REST-path message POST won't fan out (socket-only β€” fine since web+mobile use sockets), no badge counts yet (separate small follow-up).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-arh","title":"401 cascade: app shows error toast then strands user, no logout/refresh path","description":"When the access token expires (15min from Noos), the SPA at chat.globalbr.ai is left in a broken state:\n\nRepro (verified live with Chrome DevTools 2026-05-30, screenshots in /tmp/openchat-04-toast-broken-no-dismiss.png):\n1. Token in localStorage.openchat_token expires\n2. GET /api/chat/conversations returns 401\n3. ApiClient.fetch (client/src/api.ts) throws 'Invalid or expired token' β€” no refresh attempt, no localStorage clear, no logout, no redirect\n4. ChatContext.loadConversations catch shows toast.error('Failed to load conversations') β€” auto-dismisses after 6s, no X button, no way to dismiss manually\n5. Socket.IO useChatSocket connect_error fires with server-side Error('Invalid token') β€” only console.errors, perpetual 'Reconnecting...' spinner\n6. User is stranded on the chat page with stale UI, no way to recover without manually clearing localStorage\n\nFix work is in git stash@{0}: 'stash-during-darkmode-deploy' β€” 6 files, ~455 insertions, codex-reviewed shape + implementation. Includes:\n- Single-flight refresh via shared promise (Noos refresh tokens are rotated β€” would race otherwise)\n- New refreshAccessToken() / clearAuth() / emitTokenRefreshed / emitAuthExpired helpers in api.ts\n- 401-then-refresh-then-retry in fetch\u003cT\u003e() and getMe() (also fixes latent /me URL bug β€” was hitting /api/chat/me instead of /api/auth/me)\n- Refresh-loop guard: consecutiveRefreshes counter capped at REFRESH_LOOP_LIMIT=3 (codex 2026-05-30 caught the per-effect-run flag would loop forever if every refreshed token is rejected)\n- ChatProvider listens for noos:token-refreshed (updates React token state) + noos:auth-expired (clears state + navigate('/login') + toast)\n- New utils/toastError.tsx component: dismissible (X button + click-anywhere + Esc), role=alert, aria-live=assertive, stable-id de-dupe (so loadConversations spam doesn't stack)\n- All 10 toast.error() sites swapped to toastError() with stable IDs\n- logout() now clears openchat_refresh_token (was leaking)\n- register/ssoExchange now persist refreshToken (was dropping it)\n\nCodex critique status: blessed shape + impl after addressing the refresh-loop guard. Remaining concerns are non-blocking (SSR guards in ChatProvider, possible slight double-toast on auth-expired).","status":"closed","priority":1,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-05-30T12:13:51Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:28:52Z","closed_at":"2026-05-30T16:28:52Z","close_reason":"Shipped in eff5ca1 β€” 401 cascade fix from stash@{2} re-applied on top of Google OAuth merge, conflicts resolved, build clean. Includes single-flight refresh, refresh-loop guard, refreshToken persistence in register/ssoExchange (-bo6), getMe URL fix (-924), trust-proxy for express (-9jm), dismissible toast helper. Google OAuth smoke test 13/13 still green.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-9ey","title":"[Group chat] Group settings panel: member list, rename, leave","description":"No UI for viewing/managing a group post-creation. Add a settings panel/modal accessible from the chat header showing: full member list with roles, owner controls (rename group, add member, remove member), 'Leave group' button for non-owners. Wire to the API endpoints from the add/remove member ticket. Files: client/src/pages/ChatPage.tsx, new component e.g. GroupSettings.tsx.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:22Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-9ey","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:21Z","created_by":"tmad4000","metadata":"{}"},{"issue_id":"OpenChat-9ey","depends_on_id":"OpenChat-x4e","type":"blocks","created_at":"2026-04-25T04:11:37Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-x4e","title":"[Group chat] Add/remove member API + websocket events","description":"No endpoints exist for changing membership after group creation. Add: POST /conversations/:id/participants (owner-only), DELETE /conversations/:id/participants/:userId (owner can remove anyone, members can remove self = leave). Emit websocket events participant:added / participant:removed so all clients update participant lists in real time. Files: server/src/routes/chat.ts, server/src/socket/chatHandler.ts, client/src/contexts/ChatContext.tsx.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:17Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-x4e","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:16Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"OpenChat-sij","title":"[Group chat] Multi-select contact picker + group creation UI","description":"Data model already supports group conversations (conversation type='group', participants array, role owner/member) but there's no UI to create one. ChatSidebar 'New' button only does 1:1: handleSelectContact takes a single contactId and calls createConversation([contactId]). Add: multi-select contact picker (checkboxes), optional group title input, calls createConversation(participantIds[], title, 'group'). Files: client/src/components/ChatSidebar.tsx, client/src/api.ts (already supports it).","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:11Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-sij","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:10Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-sjr","title":"[Mobile] Touch targets, safe-area, and iOS keyboard handling","description":"Buttons and avatars are too small for thumbs (e.g. 10x10 avatar circles, default-padding buttons). Need: minimum 44x44 touch targets per Apple HIG, env(safe-area-inset-*) padding for notch/home-indicator, MessageInput should not be obscured by iOS keyboard (resize observer or visualViewport API), input font-size \u003e= 16px to prevent iOS auto-zoom on focus. Files: client/src/components/MessageInput.tsx, ChatSidebar.tsx, index.css.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:47Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-sjr","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:10:54Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-pmb","title":"[Mobile] Responsive layout + sidebar drawer for ChatSidebar","description":"ChatSidebar.tsx is hardcoded w-80 with no responsive breakpoints. ChatPage uses 'flex h-full' with sidebar+main always side-by-side. On mobile this leaves no room for messages. Implement: hamburger toggle on small screens, sidebar slides in as drawer (off-canvas), main chat area takes full width when drawer is closed, auto-close drawer on conversation select. Use Tailwind md:/lg: breakpoints. Files: client/src/components/ChatSidebar.tsx, client/src/pages/ChatPage.tsx (likely).","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:42Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-pmb","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:10:49Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} +{"_type":"issue","id":"OpenChat-9ey","title":"[Group chat] Group settings panel: member list, rename, leave","description":"No UI for viewing/managing a group post-creation. Add a settings panel/modal accessible from the chat header showing: full member list with roles, owner controls (rename group, add member, remove member), 'Leave group' button for non-owners. Wire to the API endpoints from the add/remove member ticket. Files: client/src/pages/ChatPage.tsx, new component e.g. GroupSettings.tsx.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:22Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-9ey","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:21Z","created_by":"auto-import","metadata":"{}"},{"issue_id":"OpenChat-9ey","depends_on_id":"OpenChat-x4e","type":"blocks","created_at":"2026-04-25T04:11:37Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-x4e","title":"[Group chat] Add/remove member API + websocket events","description":"No endpoints exist for changing membership after group creation. Add: POST /conversations/:id/participants (owner-only), DELETE /conversations/:id/participants/:userId (owner can remove anyone, members can remove self = leave). Emit websocket events participant:added / participant:removed so all clients update participant lists in real time. Files: server/src/routes/chat.ts, server/src/socket/chatHandler.ts, client/src/contexts/ChatContext.tsx.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:17Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-x4e","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:16Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} +{"_type":"issue","id":"OpenChat-sij","title":"[Group chat] Multi-select contact picker + group creation UI","description":"Data model already supports group conversations (conversation type='group', participants array, role owner/member) but there's no UI to create one. ChatSidebar 'New' button only does 1:1: handleSelectContact takes a single contactId and calls createConversation([contactId]). Add: multi-select contact picker (checkboxes), optional group title input, calls createConversation(participantIds[], title, 'group'). Files: client/src/components/ChatSidebar.tsx, client/src/api.ts (already supports it).","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:11Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-sij","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:10Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-sjr","title":"[Mobile] Touch targets, safe-area, and iOS keyboard handling","description":"Buttons and avatars are too small for thumbs (e.g. 10x10 avatar circles, default-padding buttons). Need: minimum 44x44 touch targets per Apple HIG, env(safe-area-inset-*) padding for notch/home-indicator, MessageInput should not be obscured by iOS keyboard (resize observer or visualViewport API), input font-size \u003e= 16px to prevent iOS auto-zoom on focus. Files: client/src/components/MessageInput.tsx, ChatSidebar.tsx, index.css.","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:47Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-sjr","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:10:54Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-pmb","title":"[Mobile] Responsive layout + sidebar drawer for ChatSidebar","description":"ChatSidebar.tsx is hardcoded w-80 with no responsive breakpoints. ChatPage uses 'flex h-full' with sidebar+main always side-by-side. On mobile this leaves no room for messages. Implement: hamburger toggle on small screens, sidebar slides in as drawer (off-canvas), main chat area takes full width when drawer is closed, auto-close drawer on conversation select. Use Tailwind md:/lg: breakpoints. Files: client/src/components/ChatSidebar.tsx, client/src/pages/ChatPage.tsx (likely).","status":"closed","priority":1,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:42Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-pmb","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:10:49Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"OpenChat-ph4","title":"Mobile + group chat readiness","description":"Bring OpenChat to a state where it works well on mobile and offers a good group chat experience. Tracks two parallel workstreams: (1) responsive/mobile UX, (2) group chat creation, membership, and conversational features. See sub-issues for individual gaps. Audit (2026-04-25) found: no responsive layout, no mobile drawer, undersized touch targets, no PWA. Group chat data model exists (conversation type, participants, typing) but UI cannot create groups, no add/remove members, no @-mentions, no member management.","notes":"6 of 9 sub-issues shipped (mobile drawer, mobile stack nav, touch/safe-area, group creation, member API/WS, group settings panel). Remaining: OpenChat-6ha (PWA), OpenChat-0jy (@-mentions), OpenChat-0nj (read receipts) β€” all P2/P3, deferred to a follow-up session.","status":"in_progress","priority":1,"issue_type":"epic","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:31Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:26Z","dependency_count":0,"dependent_count":9,"comment_count":0} {"_type":"issue","id":"OpenChat-0kv","title":"Alice (web client) stuck in 'Reconnecting...' loop; bot doesn't reply in affected sessions","description":"Repro: Jacob signs in as Alice on chat.globalbr.ai; UI shows 'Reconnecting...' badge continuously; bot ('picortex@bot.globalbr.ai') doesn't reply in DMs even though human↔human chat appears to work.\n\nServer logs (sudo docker logs openchat_app) show rapid connect/disconnect pairs for the same userId with different socket IDs β€” pattern: User connected β†’ User disconnected within sub-second gaps. This repeats indefinitely. Not caused by the OpenChat-09h deploy β€” pre-existing (logs show this pattern among MULTIPLE users not just Alice).\n\nLikely root cause: client uses transports: ['websocket', 'polling'] (see client/src/hooks/useChatSocket.ts:31). Cloudflare's proxy breaks socket.io polling fallback β€” the polling cycle of 'connect, XHR, close, new connect' is probably looking like real disconnects on server side. picortex bot hit the same bug and switched to transports: ['websocket']-only on 2026-04-23; fix verified empirically.\n\nFix to try first:\n1. client/src/hooks/useChatSocket.ts: change transports to ['websocket'] only (same as picortex OpenChatChannel). If WS fails, error visibly rather than silently degrading to polling.\n2. Ensure Cloudflare WebSocket upgrade is enabled for chat.globalbr.ai (should be β€” Noos works fine)\n3. If still reconnecting: add socket.io debug logging + inspect the disconnect reason ('transport close', 'ping timeout', etc.)\n\nBot-not-replying angle: if user is in a DM with picortex@bot that was created BEFORE picortex-6bw / OpenChat-09h deploy, the bot should still be joined to it from picortex's 30s poll β€” but if the openchat socket is unstable as above, message:new broadcasts may not reach the bot either. This ticket is likely the root cause of multiple bot-not-replying reports.","status":"closed","priority":1,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-04-24T08:21:56Z","created_by":"Jacob Cole","updated_at":"2026-04-24T08:30:10Z","closed_at":"2026-04-24T02:30:10Z","close_reason":"Shipped ws-only transport fix (6f229af). Verified: 0 disconnect events for picortex_bot in 2-minute post-deploy log window; pre-fix logs showed continuous sub-second connect/disconnect churn. Also added connect_error + disconnect-reason console logging for future visibility.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-09h","title":"[Bug] First message to picortex bot on a brand-new DM gets no reply (discovery race)","description":"Symptom (Jacob, 2026-04-23): DMing picortex@bot.globalbr.ai on chat.globalbr.ai for the first time, the bot does NOT reply. The SECOND message reliably gets a reply. Jacob suspected a timing issue.\n\nRoot cause: CONFIRMED β€” conversation-discovery race.\n\nEvidence (replicated 2026-04-24 03:37-03:38 UTC):\n- Fresh test user e2e_fresh_1777001825 creates NEW DM with bot via POST /api/chat/conversations (participantIds=['picortex_bot_...'], type='direct'). Convo id: bFh8_dWEIXwNvNEH3hwJF.\n- Tester immediately sends 'FIRST msg' (message id qXVCMaK2THy3zKYZMPtUT). Broadcast via io.to('conversation:bFh8...').emit('message:new', ...). Bot is NOT in that room yet β†’ not delivered.\n- ~2s later picortex's 30s poll fires (03:37:47), sees the new convo (total 3β†’4), emits conversation:join, enters the room.\n- Tester sends 'SECOND msg' at 03:38:00 (id 3uUODTcqrOLrrFa3cpdUb). Bot receives it and replies 2s later with 'Hey! Got your message. What can I help you with?'.\n- picortex journalctl confirms: the first message id NEVER appears in logs; the second message id does. Bot-side socket only received the convo it just joined.\n\nRoot cause in code\n- server/src/websocket/chatHandler.ts message:send handler (line 148): io.to('conversation:' + conversationId).emit('message:new', message). Only sockets that have previously called conversation:join are in the room.\n- server/src/routes/chat.ts POST /conversations (lines 66-138): creates Conversation + PARTICIPATES_IN edges, returns 201. NO socket emit to notify the other participants that they are now in a new conversation.\n- No conversation:created, conversation:new, or participant:added event exists on the socket server.\n- Bot-side mitigation is a 30s poll (OpenChat-3ld: 'Periodic re-poll every 30s for newly-added conversations'), which creates a 0-30s window where the first message is silently dropped.\n\nProposed fix (server side β€” this ticket)\n- In chat.ts POST /conversations: after CREATE, for each participant, io.to(\u003ctheir user room / sockets\u003e).emit('conversation:created', conversation) β€” or emit 'participant:added' to each participant.\n- Options for addressing sockets per user: (a) have every socket join a 'user:${userId}' room on connect in chatHandler.ts, then emit io.to('user:' + participantId); (b) iterate userSockets map.\n- Consider same event for 'add participant to existing conversation' flow (groups) once that UI ships β€” solves the same race for groups.\n- Optionally: also buffer/retry the initial message:send if it finds zero room members who are actual participants β€” but the proper fix is the event.\n\nProposed fix (bot side β€” track via OpenChat-3ld)\n- picortex listens for conversation:created / participant:added; on receipt, immediately GET conversation and emit conversation:join before any message arrives.\n- Keep the 30s poll as a fallback.\n\nRepro script\n- /Users/Jacob/code/picortex/.claude/worktrees/agent-a8b9f846/scripts/e2e-openchat-new-convo.mjs\n- Env: OPENCHAT_JWT_SECRET, TESTER_USER_ID, TESTER_EMAIL, BOT_USER_ID (default picortex_bot_7ecd2883dbd5ceef). Use a FRESH tester user that has no prior conversation with the bot (create in Neo4j first).\n- Verdict field 'hypothesis_confirmed' prints true when first msg gets no reply and second msg does.\n\nRelated tickets\n- OpenChat-3ld (picortex OpenChatChannel impl; v0.2 bullet listens for conversation:added β€” this is that event, needs server side)\n- OpenChat-aoy (Group chats validation β€” same race affects adding bot to existing group)\n- OpenChat-8bk (picortex bot user flow)\n- OpenChat-qz0 (Add connection recovery for missed messages β€” related but not the same issue)\n\nroot_cause_confirmed: yes","status":"closed","priority":1,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-04-24T03:39:28Z","created_by":"Jacob Cole","updated_at":"2026-04-24T07:49:39Z","closed_at":"2026-04-24T01:49:39Z","close_reason":"Shipped. OpenChat fd4c381 + picortex 6eea1c5. Server emits conversation:created to per-user sockets; picortex OpenChatChannel auto-joins on receipt. Verified via e2e-openchat-new-convo.mjs against prod: FIRST msg in fresh DM now gets bot reply in ~2.1s (msgId Ap24Rimu83fD1FdlHyrW0 -\u003e reply LSkyTkwakKE_gf4f52b94). hypothesis_confirmed: false.","dependency_count":0,"dependent_count":0,"comment_count":0} @@ -73,56 +76,56 @@ {"_type":"issue","id":"openchat-33x","title":"Landing: device-aware app guidance (evident native-app path on mobile)","description":"Homepage made it non-obvious that a native app exists β€” hero CTA only opened the web app. Added: (1) above-the-fold device-aware pointer ('On iPhone? Get the native iOS app β†’' / Android / desktop), (2) #install platform cards now float the visitor's OS card to the top with a 'β˜… Best for your device' badge. Pure landing.html (apps/server/src). data-platform attrs + extended smart-deeplink script.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:50:46Z","created_by":"tmad4000","updated_at":"2026-06-08T07:50:46Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-z1i","title":"Thoughts: new thought should appear instantly (live socket insert), not only on refresh","description":"Ordering is already newest-first (ORDER BY createdAt DESC) and the data confirms new tags create thoughts at the top β€” but there's a race: tag-extraction is async (fires a beat after send), so if the user switches to the Thoughts tab immediately, the focus-refresh can run BEFORE the thought exists, and it only shows on a later pull-to-refresh. Fix: emit a socket event when a thought is created (like message:transcript) and have the Thoughts screen prepend it live. Also confirm older native builds get the current focus-refresh behavior via a rebuild.","status":"open","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:42:30Z","created_by":"tmad4000","updated_at":"2026-06-08T07:42:30Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-c1h","title":"Thoughts: show source chat + filter Thoughts per-conversation","description":"Each Thought now carries sourceConversationId + sourceConversationName (server done). Client work: (1) render a 'from \u003cchat\u003e' label on each thought in the Thoughts tab (resolve direct-chat names from the conversation list when sourceConversationName is null); (2) a per-chat filter β€” either a chip/dropdown in the Thoughts tab to scope to one conversation, AND/OR a 'Thoughts' affordance inside a chat that opens the Thoughts tab pre-filtered to that conversation. This is the 'per chat' behavior Jacob expected. Web (/m,/d) + native.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:42:26Z","created_by":"tmad4000","updated_at":"2026-06-08T07:42:26Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-tcg.1","title":"Set up Google Play internal testing track (AAB via EAS submit)","description":"Wire + ship Android via Play internal testing so testers install without the Play Protect 'unknown developer' warning. EAS config + setup doc committed (apps/mobile/docs/android-play-internal-track.md). HUMAN GATES: (1) Play Console dev account ($25 + identity verification, can take days), (2) create app com.jacobcole.openchat + Play App Signing, (3) minimal listing/data-safety/content-rating, (4) service-account JSON β†’ ~/.config/google-play/openchat-play-service-account.json. AUTOMATABLE after gates: eas build --platform android --profile production --non-interactive; eas submit --platform android --profile production --latest. Blocked on the Play Console account.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:56:16Z","created_by":"tmad4000","updated_at":"2026-06-08T06:56:16Z","dependencies":[{"issue_id":"openchat-tcg.1","depends_on_id":"openchat-tcg","type":"parent-child","created_at":"2026-06-07T23:56:15Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.8","title":"[decision] Agent heartbeat β†’ outbound notifications to hooks: native vs external personal agent","description":"A periodic 'heartbeat' where the agent proactively reviews state (important new messages, triage results, reminders, things needing attention) and pushes notifications OUT to hooks β€” webhooks, push, Slack, the user's other channels.\n\nKEY DECISION (the reason this is a [decision] ticket): implement natively in OpenChat vs rely on the user's EXTERNAL personal agent.\n- NATIVE: server-side per-user scheduler + webhook/notification dispatch. Works for everyone out-of-box; we own the scheduler + inference cost + reliability.\n- EXTERNAL: the user's own personal agent polls OpenChat's API on its schedule and decides what to notify (fits the Shipper 'your app is a tool the agent calls' thesis). More personalized + offloads cost, but only works for users who HAVE a personal agent.\n\nRECOMMENDATION TO EVALUATE: do BOTH β€” expose the API/event surface (a webhook/events feed + 'what needs attention' endpoint) so external agents can drive it, AND ship a lightweight native heartbeat for users without a personal agent. Depends on the access-control model (openchat-j0o) and the triage feature (bfn inbound-triage). Decide before building.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:54Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:54Z","dependencies":[{"issue_id":"openchat-bfn.8","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:53Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.7","title":"Ambient agent sidebar: open an agent panel anywhere in-app, context-aware","description":"A persistent, always-available agent PANEL (not the Assistant DM conversation) you can open from anywhere in OpenChat and chat with your agent about the CURRENT context β€” the conversation you're viewing, your inbox, a selected message, etc. Like Cursor's sidebar / a copilot panel.\n\nReuses the Assistant runtime + tools (bfn.3) but as a docked overlay surface that knows where you are (active conversationId, selection) and can act (summarize this thread, draft a reply, search related, file feedback, triage). Web (side panel) + mobile (bottom sheet / slide-over). Distinct from the Assistant DM, which is a normal conversation. Relates to the 'agent sidebar' line in openchat-oc8 and the forward-to-agent plumbing (openchat-ug6).","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:52Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:52Z","dependencies":[{"issue_id":"openchat-bfn.7","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:51Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.6","title":"Inbound triage: classify new senders as relationship-worthy vs spam (a 'Requests'/'Filtered' inbox)","description":"An agent that processes INBOUND messages β€” especially from unknown/new senders β€” and classifies whether this is someone you'd want to relate with vs spam/unwanted, routing accordingly. Like iMessage 'Unknown Senders' / Instagram 'Message Requests', but agent-driven.\n\nSignals to combine: sender reputation/history, whether they're in your contacts or share a group, message content (LLM classification β€” outreach vs spam vs scam), your public profile/interests, and (later) the shared social graph. Output: route to Primary inbox vs a Requests queue vs Spam; optionally let your agent draft a reply, summarize the request, or auto-decline.\n\nSurfaces: a Requests/Filtered view in the conversation list (web + mobile). Respect the access-control model (openchat-j0o) β€” the agent only sees what the context allows. Ties to the contacts/people directory (openchat-2rn) and the assistant runtime (bfn.3).","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:50Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:50Z","dependencies":[{"issue_id":"openchat-bfn.6","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:49Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-tcg.1","title":"Set up Google Play internal testing track (AAB via EAS submit)","description":"Wire + ship Android via Play internal testing so testers install without the Play Protect 'unknown developer' warning. EAS config + setup doc committed (apps/mobile/docs/android-play-internal-track.md). HUMAN GATES: (1) Play Console dev account ($25 + identity verification, can take days), (2) create app com.jacobcole.openchat + Play App Signing, (3) minimal listing/data-safety/content-rating, (4) service-account JSON β†’ ~/.config/google-play/openchat-play-service-account.json. AUTOMATABLE after gates: eas build --platform android --profile production --non-interactive; eas submit --platform android --profile production --latest. Blocked on the Play Console account.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:56:16Z","created_by":"tmad4000","updated_at":"2026-06-08T06:56:16Z","dependencies":[{"issue_id":"openchat-tcg.1","depends_on_id":"openchat-tcg","type":"parent-child","created_at":"2026-06-07T23:56:15Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.8","title":"[decision] Agent heartbeat β†’ outbound notifications to hooks: native vs external personal agent","description":"A periodic 'heartbeat' where the agent proactively reviews state (important new messages, triage results, reminders, things needing attention) and pushes notifications OUT to hooks β€” webhooks, push, Slack, the user's other channels.\n\nKEY DECISION (the reason this is a [decision] ticket): implement natively in OpenChat vs rely on the user's EXTERNAL personal agent.\n- NATIVE: server-side per-user scheduler + webhook/notification dispatch. Works for everyone out-of-box; we own the scheduler + inference cost + reliability.\n- EXTERNAL: the user's own personal agent polls OpenChat's API on its schedule and decides what to notify (fits the Shipper 'your app is a tool the agent calls' thesis). More personalized + offloads cost, but only works for users who HAVE a personal agent.\n\nRECOMMENDATION TO EVALUATE: do BOTH β€” expose the API/event surface (a webhook/events feed + 'what needs attention' endpoint) so external agents can drive it, AND ship a lightweight native heartbeat for users without a personal agent. Depends on the access-control model (openchat-j0o) and the triage feature (bfn inbound-triage). Decide before building.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:54Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:54Z","dependencies":[{"issue_id":"openchat-bfn.8","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:53Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.7","title":"Ambient agent sidebar: open an agent panel anywhere in-app, context-aware","description":"A persistent, always-available agent PANEL (not the Assistant DM conversation) you can open from anywhere in OpenChat and chat with your agent about the CURRENT context β€” the conversation you're viewing, your inbox, a selected message, etc. Like Cursor's sidebar / a copilot panel.\n\nReuses the Assistant runtime + tools (bfn.3) but as a docked overlay surface that knows where you are (active conversationId, selection) and can act (summarize this thread, draft a reply, search related, file feedback, triage). Web (side panel) + mobile (bottom sheet / slide-over). Distinct from the Assistant DM, which is a normal conversation. Relates to the 'agent sidebar' line in openchat-oc8 and the forward-to-agent plumbing (openchat-ug6).","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:52Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:52Z","dependencies":[{"issue_id":"openchat-bfn.7","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:51Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.6","title":"Inbound triage: classify new senders as relationship-worthy vs spam (a 'Requests'/'Filtered' inbox)","description":"An agent that processes INBOUND messages β€” especially from unknown/new senders β€” and classifies whether this is someone you'd want to relate with vs spam/unwanted, routing accordingly. Like iMessage 'Unknown Senders' / Instagram 'Message Requests', but agent-driven.\n\nSignals to combine: sender reputation/history, whether they're in your contacts or share a group, message content (LLM classification β€” outreach vs spam vs scam), your public profile/interests, and (later) the shared social graph. Output: route to Primary inbox vs a Requests queue vs Spam; optionally let your agent draft a reply, summarize the request, or auto-decline.\n\nSurfaces: a Requests/Filtered view in the conversation list (web + mobile). Respect the access-control model (openchat-j0o) β€” the agent only sees what the context allows. Ties to the contacts/people directory (openchat-2rn) and the assistant runtime (bfn.3).","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:52:50Z","created_by":"tmad4000","updated_at":"2026-06-08T06:52:50Z","dependencies":[{"issue_id":"openchat-bfn.6","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-07T23:52:49Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-tcg","title":"Android install blocked by Google Play Protect (unknown-developer sideload)","description":"A tester's Android install of the OpenChat APK is blocked by Play Protect: 'App wurde zum Schutz deines GerΓ€ts blockiert β€” Play Protect kennt von diesem Entwickler noch keine anderen Apps. Die App kΓΆnnte unsicher sein.' This is the standard warning for a SIDELOADED APK from a developer Google doesn't recognize β€” NOT a real malware flag.\n\nINTERIM (works today): tester taps 'Trotzdem installieren' (Install anyway), the small link ABOVE the blue OK button. OK just cancels.\n\nPROPER FIXES (pick): (1) Distribute Android via Google Play **internal/closed testing track** (Play Console) β€” removes the Play Protect warning entirely; needs a Play Console developer account ($25 one-time) + app signing + a basic listing. (2) At minimum, add an 'Android: tap Install anyway when Play Protect warns' note + screenshot to the landing/download page (apps/server/src/landing.html Android section) so testers aren't scared off. (3) Longer term, building app reputation via Play distribution avoids it.\n\nRecommend (2) now (quick landing note) + (1) when ready for wider Android testing.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T06:51:24Z","created_by":"tmad4000","updated_at":"2026-06-08T06:51:24Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-37z","title":"Settings: 'Invite/Share OpenChat' β€” QR + share link to the landing/download page + TestFlight + view landing","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-07T21:25:04Z","created_by":"tmad4000","updated_at":"2026-06-07T21:29:55Z","closed_at":"2026-06-07T21:29:55Z","close_reason":"Settings 'Invite people' shipped (web + mobile): QR + Share/copy + TestFlight link + 'Open download page', all pointing at the landing page (chat.globalbr.ai) which branches to iOS/web/Android. Reused /about/qr.svg + the public TestFlight link + /about. Web deployed; native in TestFlight build 83. QR endpoint + routes verified in the build job.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-4jn","title":"Auto-transcribe voice messages (AssemblyAI/Deepgram/Whisper) + show transcript","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T02:33:34Z","created_by":"tmad4000","updated_at":"2026-06-05T02:46:57Z","closed_at":"2026-06-05T02:46:57Z","close_reason":"Auto-transcription: Whisper (whisper-1) transcribes voice messages async server-side, persists transcript, emits message:transcript; web+mobile render a caption under the voice bubble + live-update. Deployed (server). No AssemblyAI/Deepgram key on hand; OpenAI is forwarded.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-9de","title":"Voice recording: add tap-to-toggle (hands-free) in addition to hold-to-record (standard WhatsApp-style)","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T02:33:33Z","created_by":"tmad4000","updated_at":"2026-06-05T02:46:56Z","closed_at":"2026-06-05T02:46:56Z","close_reason":"Recording UX: tap-to-toggle hands-free (Stop/Cancel bar) added alongside hold-to-record on web (250ms threshold) + mobile (350ms, slide-to-cancel preserved). Mic-permission denial handled. Merged + deploying (web + TestFlight).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-ft1","title":"Assistant typing/thinking indicator (show bot is working, like a human)","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:38:51Z","created_by":"tmad4000","updated_at":"2026-06-05T01:00:43Z","closed_at":"2026-06-05T01:00:43Z","close_reason":"Typing/thinking indicator: server emits typing:start (2s heartbeat, since web auto-clears after 3s) + typing:stop as the assistant during runAssistantTurn; clients render via existing TypingBubble. Deployed. Verified assistant still replies (pong); did not observe the socket event live (no socket test client) β€” visible in-app.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-651","title":"Press-and-hold to Copy a message (mobile long-press + web menu)","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:38:49Z","created_by":"tmad4000","updated_at":"2026-06-05T01:00:41Z","closed_at":"2026-06-05T01:00:41Z","close_reason":"Copy shipped: web message menu (πŸ“‹ Copy, deployed) + mobile MessageActionSheet (πŸ“‹ Copy, TestFlight build 81). Web build green; mobile tsc green. Not UI-tested by me (no UI harness) β€” ready to try in-app.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-j0o.4","title":"Approval workflow for private-data use in shared contexts","description":"When the group agent / another's bot needs a private item, it DMs the owner: Approve once / Always for this group / No. One-time approve uses it for that act only; 'always' reclassifies to group for that conversation. The graceful middle between Cortex hard-isolation and an unsafe open agent.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:02Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:02Z","dependencies":[{"issue_id":"openchat-j0o.4","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:01Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-j0o.3","title":"Neutral group agent + skill-plugin model + NVC mediation skill","description":"Same Assistant runtime scoped to a conversation as a neutral facilitator with NO private data (reads via visibilityFilter for a generic member). Skill plugin interface {name, whenToUse, tools, prompt}. First skill: NVC mediation (@assistant mediate reframes a thread in Nonviolent Communication). Opt-in per conversation via containsBot.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:00Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:00Z","dependencies":[{"issue_id":"openchat-j0o.3","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:00Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-j0o.4","title":"Approval workflow for private-data use in shared contexts","description":"When the group agent / another's bot needs a private item, it DMs the owner: Approve once / Always for this group / No. One-time approve uses it for that act only; 'always' reclassifies to group for that conversation. The graceful middle between Cortex hard-isolation and an unsafe open agent.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:02Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:02Z","dependencies":[{"issue_id":"openchat-j0o.4","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:01Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-j0o.3","title":"Neutral group agent + skill-plugin model + NVC mediation skill","description":"Same Assistant runtime scoped to a conversation as a neutral facilitator with NO private data (reads via visibilityFilter for a generic member). Skill plugin interface {name, whenToUse, tools, prompt}. First skill: NVC mediation (@assistant mediate reframes a thread in Nonviolent Communication). Opt-in per conversation via containsBot.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:00Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:00Z","dependencies":[{"issue_id":"openchat-j0o.3","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:00Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-ug6","title":"Forward-to-my-agent: long-press any message in any chat to privately send it to my Assistant","description":"Idea (Jacob 2026-06-04): from EVERY conversation at all times, let me tag/forward a specific message to my own Assistant agent privately β€” e.g. long-press a message β†’ 'Ask my agent' / 'Forward to Assistant' β†’ it lands in my private Assistant DM (only I see it) with the original message as context, so I can ask the agent to act on it (summarize, draft a reply, remember it, file feedback, search related, etc.) without the other participants knowing.\n\nDesign considerations to weigh:\n- ENTRY POINT: message action menu (long-press mobile / hover menu web) item 'Ask my agent' or 'Forward to Assistant'. Possibly also an always-present affordance (a persistent '@agent' you can tag inline in any message β€” but inline @agent in a shared convo risks leaking to others, so the long-pressβ†’private-forward path is the privacy-safe default).\n- PRIVACY: the forward must go to the user's OWN Assistant DM (containsBot self-conversation), NOT post into the shared conversation. The other participants must never see it. Carry a reference {sourceConversationId, sourceMessageId, quoted content} so the Assistant has context.\n- TWO MODES likely: (a) 'Forward to Assistant' (just drops the message into the Assistant DM as quoted context), (b) 'Ask my agent about this' (forwards + prompts for a question). \n- INLINE @agent (stretch): typing @agent / #agent in a shared message could trigger the bot to reply β€” but only privately to the tagger, or visibly to all? Decide. Inline-visible @agent = a shared AI helper (different product surface). Keep separate from the private forward.\n- Reuse: builds on the Assistant bot (openchat-bfn.3) + its tools; the forward is essentially 'create/append to the self Assistant DM with a quoted message + optional FROM_MESSAGE link for provenance'.\n- Parity: implement in apps/mobile (long-press) AND apps/web (hover menu). Backend: a small endpoint POST /api/assistant/forward { sourceConversationId, sourceMessageId, question? } that injects the quoted context into the user's Assistant DM and triggers a turn.\n\nRelates to: openchat-bfn (assistant epic), openchat-bfn.4 (guardrails).","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T23:28:40Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:54Z","closed_at":"2026-06-04T23:58:54Z","close_reason":"Forward-to-agent shipped: POST /api/assistant/forward (verified end-to-end: forwarded 'Yo' to private Assistant DM, got summary, never posted to source). Web hover 'Ask my agent' + mobile long-press 'Forward to Assistant'/'Ask about this'.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-w1d","title":"[bug] Mobile contacts search: keyboard covers list, can't scroll to all people","status":"open","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T23:25:03Z","created_by":"tmad4000","updated_at":"2026-06-04T23:25:03Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-1ny","title":"Assistant: add submit_feedback tool (message the Assistant to file feedback β†’ WIT)","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T23:25:02Z","created_by":"tmad4000","updated_at":"2026-06-04T23:25:02Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-h7j","title":"Self-DM label: show email under 'Note to self' (know which account)","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T23:25:00Z","created_by":"tmad4000","updated_at":"2026-06-04T23:25:00Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.5","title":"Assistant + search exposed as MCP tools (in apps/mcp-server)","description":"Expose search_messages (+ the rest) as MCP tools in the folded-in apps/mcp-server (openchat-vcs), so Claude Code/Cowork get first-class chat-history tools, per the Shipper 'tools inside your agent' thesis.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:08Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:08Z","dependencies":[{"issue_id":"openchat-bfn.5","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:08Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.4","title":"Assistant bot: guardrails for taking actions (confirm, rate-limit, audit)","description":"Since the assistant can take actions (send/create as the user's account), add: explicit confirm for outbound sends to OTHER people, rate limits, audit log, and a clear 'AI acted' marker. Read-only search needs none of this; writes do.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:06Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:52Z","closed_at":"2026-06-04T23:58:52Z","close_reason":"Guardrails shipped+deployed: send_message requires confirm:true for convos with other humans (self/Assistant DM sends freely); 20/min rate limit; viaAssistant marker on Message; audit log. Code-verified; forward path verified live.","dependencies":[{"issue_id":"openchat-bfn.4","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:06Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bfn.2","title":"Substrate v2: semantic search over messages (Neo4j vector index + embeddings)","description":"Add embeddings per Message (Neo4j 5.15 vector index), backfill existing, hybrid keyword+vector ranking. DECISION NEEDED: embedding provider+key (OpenAI text-embedding-3-small cheap/good, or Voyage AI Anthropic-recommended). Provision key into prod .env + ~/.config. Gated by cost/recall need.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:03Z","created_by":"tmad4000","updated_at":"2026-06-04T23:17:40Z","closed_at":"2026-06-04T23:17:40Z","close_reason":"DONE: semantic search live + backfilled. OpenChat has 266 chat messages (the 82.7k :Message nodes are shared-Neo4j Noos data, not OpenChat). Backfilled 264 β†’ all history embedded. /api/chat/search?mode=semantic|hybrid returns vector hits; vector query scopes to the user's conversations so Noos nodes never leak.","dependencies":[{"issue_id":"openchat-bfn.2","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:03Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.5","title":"Assistant + search exposed as MCP tools (in apps/mcp-server)","description":"Expose search_messages (+ the rest) as MCP tools in the folded-in apps/mcp-server (openchat-vcs), so Claude Code/Cowork get first-class chat-history tools, per the Shipper 'tools inside your agent' thesis.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:08Z","created_by":"tmad4000","updated_at":"2026-06-04T21:48:08Z","dependencies":[{"issue_id":"openchat-bfn.5","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:08Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.4","title":"Assistant bot: guardrails for taking actions (confirm, rate-limit, audit)","description":"Since the assistant can take actions (send/create as the user's account), add: explicit confirm for outbound sends to OTHER people, rate limits, audit log, and a clear 'AI acted' marker. Read-only search needs none of this; writes do.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:06Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:52Z","closed_at":"2026-06-04T23:58:52Z","close_reason":"Guardrails shipped+deployed: send_message requires confirm:true for convos with other humans (self/Assistant DM sends freely); 20/min rate limit; viaAssistant marker on Message; audit log. Code-verified; forward path verified live.","dependencies":[{"issue_id":"openchat-bfn.4","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:06Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bfn.2","title":"Substrate v2: semantic search over messages (Neo4j vector index + embeddings)","description":"Add embeddings per Message (Neo4j 5.15 vector index), backfill existing, hybrid keyword+vector ranking. DECISION NEEDED: embedding provider+key (OpenAI text-embedding-3-small cheap/good, or Voyage AI Anthropic-recommended). Provision key into prod .env + ~/.config. Gated by cost/recall need.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:48:03Z","created_by":"tmad4000","updated_at":"2026-06-04T23:17:40Z","closed_at":"2026-06-04T23:17:40Z","close_reason":"DONE: semantic search live + backfilled. OpenChat has 266 chat messages (the 82.7k :Message nodes are shared-Neo4j Noos data, not OpenChat). Backfilled 264 β†’ all history embedded. /api/chat/search?mode=semantic|hybrid returns vector hits; vector query scopes to the user's conversations so Noos nodes never leak.","dependencies":[{"issue_id":"openchat-bfn.2","depends_on_id":"openchat-bfn","type":"parent-child","created_at":"2026-06-04T14:48:03Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-vcs","title":"Fold openchat-mcp-server into the monorepo as apps/mcp-server, then archive the standalone repo","description":"openchat-mcp-server (tmad4000/openchat-mcp-server, thin TS REST-\u003etools MCP bridge over OpenChat's API) should live in the monorepo, same rationale as apps/mobile: it's a pure client of apps/server's REST API and must stay in lockstep with API changes. Plan: (1) git subtree add --prefix=apps/mcp-server \u003crepo\u003e main (history-preserving); (2) wire it to consume packages/api-client + packages/types once openchat-0b8 lands (until then keep its own thin client); (3) add to root workspaces + turbo; (4) validate build; (5) freeze + GitHub-archive tmad4000/openchat-mcp-server (MIGRATED.md) AFTER fold-in is clean. Relates to the connect-agent/MCP path (openchat-2t7) and packages extraction (openchat-0b8).","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T21:31:13Z","created_by":"tmad4000","updated_at":"2026-06-04T21:31:13Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-2t7","title":"Connect-agent: honest copy + real ChatGPT path (Custom GPT via OpenAPI)","description":"The one-click 'Copy agent setup' blob/card says 'works in ChatGPT, any LLM', but plain chat-only ChatGPT can't make authenticated HTTP calls (verified: Jacob's coding agent fetched fine; ChatGPT just received the text). Two fixes: (1) HONEST COPY β€” reword card subtitle/alert + blob framing to 'works in any agent that can make web requests (Claude Code, Cursor, Codex) and ChatGPT via a Custom GPT / Code Interpreter'. (2) REAL CHATGPT PATH β€” add a 'Connect ChatGPT' affordance: instructions/deep-help to create a Custom GPT and import https://chat.globalbr.ai/api/openapi.json as an Action with API-key (Bearer) auth β€” genuinely lets ChatGPT operate the account. Touches shared agentSetupBlob.ts (both repos), McpSetupCard, mobile SettingsScreen one-click subtitle, web SettingsModal. Note: the OpenAPI may need an oauth/apiKey securityScheme tweak so ChatGPT's Action importer accepts Bearer auth.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T20:06:59Z","created_by":"tmad4000","updated_at":"2026-06-04T21:40:29Z","closed_at":"2026-06-04T21:40:29Z","close_reason":"Shipped: (1) all 19 OpenAPI ops now have operationIds + absolute server + bearerAuth scheme -\u003e spec is ChatGPT-Custom-GPT-Action importable (verified live at /api/openapi.json). (2) Connect-agent blob reworded honestly (works in agents that can make HTTP; for plain ChatGPT, import openapi.json as a Custom GPT Action w/ Bearer auth) β€” web+mobile identical. Deployed + verified prod.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-0b8","title":"Phase 2/3: extract packages/{types,protocol,api-client}","description":"Now that OpenChat is a monorepo (branch monorepo-migration, openchat-3jq.5), extract shared code into packages/. This was the original motivation for the migration β€” protocol changes currently land in two places.\n\nPhase 2 (types + protocol):\n- packages/types: canonical Conversation/Message/User/AgentKey/scopes shapes\n- packages/protocol: route paths, the content|text field alias, socket event names\n- re-export from server/web/mobile, delete duplicates one surface at a time, tsc-check each\n\nPhase 3 (api-client):\n- Diff apps/web/src/api.ts vs apps/mobile/src/api/client.ts (independent reimpls)\n- Build one packages/api-client parameterized by platform adapters (storage, fetch, socket impl)\n- web injects localStorage adapter; mobile injects expo-secure-store adapter\n- Swap web + mobile to @openchat/api-client; delete originals\n\nFollow the migration plan Β§3 Phases 2 and 3 in docs/monorepo-migration-plan.md.","notes":"Each subtask should leave both apps building and tests passing. Per the plan, api-client unify is 'the meatiest' phase β€” budget for a focused session.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T13:47:14Z","created_by":"tmad4000","updated_at":"2026-06-04T13:47:14Z","dependencies":[{"issue_id":"openchat-0b8","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:18Z","created_by":"tmad4000","metadata":"{}"},{"issue_id":"openchat-0b8","depends_on_id":"openchat-p24","type":"blocks","created_at":"2026-06-04T06:47:19Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-p24","title":"Validate native iOS EAS build under monorepo (apps/mobile)","description":"The monorepo migration (openchat-3jq.5, branch monorepo-migration) moved openchat-mobile in via git subtree to apps/mobile and added a monorepo-aware metro.config.js (watchFolders, nodeModulesPaths, disableHierarchicalLookup). Validated locally with 'expo export --platform web' (Metro resolves monorepo paths). NOT validated: native iOS EAS build via scripts/local-build.sh, because that script auto-submits to TestFlight and the autonomous run was under a no-deploy guardrail. A human should run a one-off EAS build from apps/mobile (TMPDIR=/private/tmp/ocbuild bash scripts/local-build.sh --no-bump or eas build --local --platform ios --profile preview) to confirm symlink hoist + nodeModules resolution work end-to-end before merging monorepo-migration to main.","notes":"Risk: EAS/Xcode resolution of hoisted node_modules may need extra config (.npmrc node-linker=hoisted-only or per-app symlink); failure usually shows as 'Unable to resolve module X' with module living at workspace root rather than apps/mobile/node_modules.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T13:46:59Z","created_by":"tmad4000","updated_at":"2026-06-04T20:33:05Z","started_at":"2026-06-04T20:27:57Z","closed_at":"2026-06-04T20:33:05Z","close_reason":"VALIDATED: monorepo eas build reached Archive Succeeded (projectRoot apps/mobile); Metro resolved hoisted node_modules, 101 pods compiled, xcarchive produced (OpenChat 2026-06-04 13.28.30.xcarchive). No nohoist/.npmrc needed. TMPDIR=$HOME/.ocbuild-tmp.","dependencies":[{"issue_id":"openchat-p24","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:03Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.10","title":"Web: Settings parity (profile edit, account delete, export, agent keys, notifications, feedback)","description":"Web SettingsModal = version + one toggle. Mobile has profile edit, account deletion, export, agent-keys (3 screens), notifications, feedback-\u003eWIT. Bring web settings to parity.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:08Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:02Z","closed_at":"2026-06-04T23:59:02Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.10","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:07Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.9","title":"Web: load-older-messages pagination + reconnect catch-up","description":"Server has before cursor + GET /messages/since. Web loads one page, no scroll-back, and never calls /messages/since on reconnect. Add both.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:06Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:00Z","closed_at":"2026-06-04T23:59:00Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.9","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:06Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.8","title":"Web: link previews + @mentions + date separators","description":"Messages arrive with linkPreviews[] (ignored by web MessageList); no @mention autocomplete in web MessageInput; web message list is a flat map with no day dividers. Port the three rendering niceties.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:05Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:59Z","closed_at":"2026-06-04T23:58:59Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.8","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:04Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.7","title":"Web: voice messages (record + playback)","description":"Server presign supports audio MIME; mobile audioRecorder + VoiceMessageBubble. Web MessageInput accepts images only.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:03Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:58Z","closed_at":"2026-06-04T23:58:58Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.7","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:02Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.6","title":"Web: block/unblock + DM contact profile panel","description":"Subsumes openchat-8iw. Web api has no block methods; DM header not tappable; no contact-profile view. Add tappable DM header -\u003e profile panel (presence, block, report, shared media later).","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:01Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:56Z","closed_at":"2026-06-04T23:58:56Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.6","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:01Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-bmp.5","title":"Web: mute conversation","description":"Server PATCH /participants/me with mutedUntil; mobile has UI. Web has no call/UI. Add to conversation row menu.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:00Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:55Z","closed_at":"2026-06-04T23:58:55Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.5","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:59Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-0b8","title":"Phase 2/3: extract packages/{types,protocol,api-client}","description":"Now that OpenChat is a monorepo (branch monorepo-migration, openchat-3jq.5), extract shared code into packages/. This was the original motivation for the migration β€” protocol changes currently land in two places.\n\nPhase 2 (types + protocol):\n- packages/types: canonical Conversation/Message/User/AgentKey/scopes shapes\n- packages/protocol: route paths, the content|text field alias, socket event names\n- re-export from server/web/mobile, delete duplicates one surface at a time, tsc-check each\n\nPhase 3 (api-client):\n- Diff apps/web/src/api.ts vs apps/mobile/src/api/client.ts (independent reimpls)\n- Build one packages/api-client parameterized by platform adapters (storage, fetch, socket impl)\n- web injects localStorage adapter; mobile injects expo-secure-store adapter\n- Swap web + mobile to @openchat/api-client; delete originals\n\nFollow the migration plan Β§3 Phases 2 and 3 in docs/monorepo-migration-plan.md.","notes":"Each subtask should leave both apps building and tests passing. Per the plan, api-client unify is 'the meatiest' phase β€” budget for a focused session.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T13:47:14Z","created_by":"tmad4000","updated_at":"2026-06-04T13:47:14Z","dependencies":[{"issue_id":"openchat-0b8","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:18Z","created_by":"auto-import","metadata":"{}"},{"issue_id":"openchat-0b8","depends_on_id":"openchat-p24","type":"blocks","created_at":"2026-06-04T06:47:19Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-p24","title":"Validate native iOS EAS build under monorepo (apps/mobile)","description":"The monorepo migration (openchat-3jq.5, branch monorepo-migration) moved openchat-mobile in via git subtree to apps/mobile and added a monorepo-aware metro.config.js (watchFolders, nodeModulesPaths, disableHierarchicalLookup). Validated locally with 'expo export --platform web' (Metro resolves monorepo paths). NOT validated: native iOS EAS build via scripts/local-build.sh, because that script auto-submits to TestFlight and the autonomous run was under a no-deploy guardrail. A human should run a one-off EAS build from apps/mobile (TMPDIR=/private/tmp/ocbuild bash scripts/local-build.sh --no-bump or eas build --local --platform ios --profile preview) to confirm symlink hoist + nodeModules resolution work end-to-end before merging monorepo-migration to main.","notes":"Risk: EAS/Xcode resolution of hoisted node_modules may need extra config (.npmrc node-linker=hoisted-only or per-app symlink); failure usually shows as 'Unable to resolve module X' with module living at workspace root rather than apps/mobile/node_modules.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T13:46:59Z","created_by":"tmad4000","updated_at":"2026-06-04T20:33:05Z","started_at":"2026-06-04T20:27:57Z","closed_at":"2026-06-04T20:33:05Z","close_reason":"VALIDATED: monorepo eas build reached Archive Succeeded (projectRoot apps/mobile); Metro resolved hoisted node_modules, 101 pods compiled, xcarchive produced (OpenChat 2026-06-04 13.28.30.xcarchive). No nohoist/.npmrc needed. TMPDIR=$HOME/.ocbuild-tmp.","dependencies":[{"issue_id":"openchat-p24","depends_on_id":"openchat-3jq.5","type":"blocks","created_at":"2026-06-04T06:47:03Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":1,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.10","title":"Web: Settings parity (profile edit, account delete, export, agent keys, notifications, feedback)","description":"Web SettingsModal = version + one toggle. Mobile has profile edit, account deletion, export, agent-keys (3 screens), notifications, feedback-\u003eWIT. Bring web settings to parity.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:08Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:02Z","closed_at":"2026-06-04T23:59:02Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.10","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:07Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.9","title":"Web: load-older-messages pagination + reconnect catch-up","description":"Server has before cursor + GET /messages/since. Web loads one page, no scroll-back, and never calls /messages/since on reconnect. Add both.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:06Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:00Z","closed_at":"2026-06-04T23:59:00Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.9","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:06Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.8","title":"Web: link previews + @mentions + date separators","description":"Messages arrive with linkPreviews[] (ignored by web MessageList); no @mention autocomplete in web MessageInput; web message list is a flat map with no day dividers. Port the three rendering niceties.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:05Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:59Z","closed_at":"2026-06-04T23:58:59Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.8","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:04Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.7","title":"Web: voice messages (record + playback)","description":"Server presign supports audio MIME; mobile audioRecorder + VoiceMessageBubble. Web MessageInput accepts images only.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:03Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:58Z","closed_at":"2026-06-04T23:58:58Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.7","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:02Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.6","title":"Web: block/unblock + DM contact profile panel","description":"Subsumes openchat-8iw. Web api has no block methods; DM header not tappable; no contact-profile view. Add tappable DM header -\u003e profile panel (presence, block, report, shared media later).","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:01Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:56Z","closed_at":"2026-06-04T23:58:56Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.6","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:55:01Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-bmp.5","title":"Web: mute conversation","description":"Server PATCH /participants/me with mutedUntil; mobile has UI. Web has no call/UI. Add to conversation row menu.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:00Z","created_by":"tmad4000","updated_at":"2026-06-04T23:58:55Z","closed_at":"2026-06-04T23:58:55Z","close_reason":"Web parity wave 2 shipped (mute, block+profile, voice messages, link previews+@mentions+date separators, pagination+reconnect catch-up, settings parity). Merged + deploying.","dependencies":[{"issue_id":"openchat-bmp.5","depends_on_id":"openchat-bmp","type":"parent-child","created_at":"2026-06-04T05:54:59Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-2rn","title":"Contacts/People directory (browse all contacts)","description":"No dedicated contacts browser on web or mobile β€” the new-conversation composer is the only place to see people. Standard apps have a People/Contacts view: browse all, search, see profile, start a chat. With /contacts now returning everyone (incl. self) this is straightforward. Add a Contacts screen (mobile tab/menu + web sidebar section) listing all users with quick 'message'. Parity both surfaces.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:48:50Z","created_by":"tmad4000","updated_at":"2026-06-04T22:36:22Z","closed_at":"2026-06-04T22:36:22Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-8iw","title":"Web: tappable DM chat header -\u003e contact profile (parity with mobile)","description":"Mobile: tapping the chat header opens ContactProfile (DM) or GroupSettings (group). Web only opens GroupSettings for groups (ChatPage.tsx onClick={()=\u003eisGroup \u0026\u0026 setGroupSettingsOpen(true)}) β€” a 1:1 DM header does nothing and there's no web contact-profile view. Standard chat UX (iMessage/WhatsApp/Telegram/Signal/Slack all have a tappable header -\u003e details). Add a web DM header click -\u003e contact profile panel (name, avatar, presence, block, shared media later).","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:48:48Z","created_by":"tmad4000","updated_at":"2026-06-04T12:55:36Z","closed_at":"2026-06-04T12:55:36Z","close_reason":"Superseded by openchat-bmp.6 (web block/unblock + DM contact profile) in the web-parity epic.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-qjx","title":"Display Thought labels (tags) in web + mobile Thoughts UI","description":"Server now stores free-form hashtag labels on Thoughts (t.tags) distinct from kind/type (openchat-1mo follow-up, any-tag change 2026-06-04). API returns tags[]. Clients should render labels (chips) on Thought cards + ideally filter by label. Also consider: manual thought create accepting tags; a 'reserved type tags' UX so users learn #decision=type vs #projectx=label. Web (RN-desktop) + mobile.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:56:52Z","created_by":"tmad4000","updated_at":"2026-06-04T12:19:37Z","closed_at":"2026-06-04T12:19:37Z","close_reason":"Thoughts tab now renders tag chips (tappable -\u003e filter) + a debounced search box (?q= text|tag). Mobile + RN-web. Server side (tags metadata, don't-strip, ?q=) live; client merged to openchat-mobile main. Ships to /d on deploy, native on next build/OTA.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-8md.3","title":"Audit + sync openchat-mcp-server with current API","description":"openchat-mcp-server exists (github.com/tmad4000/openchat-mcp-server, pushed 2026-06-01) and McpSetupCard points users at it. Audit: does it cover all current tools (list/read/send/edit/delete messages, conversations incl. self-DM create, search, contacts, /messages/since, agent-keys, and the NEW /api/feedback)? Verify it tracks the text|content alias + scopes. Post-monorepo, have it consume packages/api-client/protocol so it can't drift from the server. File concrete gaps as subtasks after the audit.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:17Z","created_by":"tmad4000","updated_at":"2026-06-04T11:38:17Z","dependencies":[{"issue_id":"openchat-8md.3","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:17Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-8md.2","title":"openchat CLI over the REST API","description":"A thin 'openchat' CLI (Node, npx-able / brew or npm) wrapping the REST API with oc_ agent-key auth: list/read/send messages, conversations, /messages/since poll, agent-keys, feedback. Mirror the ergonomics of noos/bd/wit CLIs. BUILD ON packages/api-client AFTER the monorepo migration so it shares one typed client (avoid a 3rd reimplementation). Blocked-ish by openchat-3jq.5.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:15Z","created_by":"tmad4000","updated_at":"2026-06-04T11:38:15Z","dependencies":[{"issue_id":"openchat-8md.2","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:15Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-8md.1","title":"Documented API: OpenAPI spec + complete endpoint reference","description":"Produce a real API reference. Generate an OpenAPI 3 spec from the Express routes (auth, chat: conversations/messages/contacts/presence, agent-keys, feedback, push, thoughts, ai, legal), serve it at /api/openapi.json + a docs page (or expand connect-your-bot.md into a full reference). Document the resolveActor auth (JWT or oc_ agent key), the text|content alias, agent-key scopes. Highest priority β€” lowest drift, everything else derives from it. Can be done pre-monorepo.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:14Z","created_by":"tmad4000","updated_at":"2026-06-04T11:43:30Z","started_at":"2026-06-04T11:41:31Z","closed_at":"2026-06-04T11:43:30Z","close_reason":"OpenAPI 3.1 spec (server/src/openapi.ts, 14 agent-facing paths) + GET /api/openapi.json + GET /api/docs (Redoc) on main. Server build clean. Goes live on next deploy. Hand-authored v1; post-monorepo can generate from packages/protocol.","dependencies":[{"issue_id":"openchat-8md.1","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:13Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-8md.3","title":"Audit + sync openchat-mcp-server with current API","description":"openchat-mcp-server exists (github.com/tmad4000/openchat-mcp-server, pushed 2026-06-01) and McpSetupCard points users at it. Audit: does it cover all current tools (list/read/send/edit/delete messages, conversations incl. self-DM create, search, contacts, /messages/since, agent-keys, and the NEW /api/feedback)? Verify it tracks the text|content alias + scopes. Post-monorepo, have it consume packages/api-client/protocol so it can't drift from the server. File concrete gaps as subtasks after the audit.","status":"open","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:17Z","created_by":"tmad4000","updated_at":"2026-06-04T11:38:17Z","dependencies":[{"issue_id":"openchat-8md.3","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:17Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-8md.2","title":"openchat CLI over the REST API","description":"A thin 'openchat' CLI (Node, npx-able / brew or npm) wrapping the REST API with oc_ agent-key auth: list/read/send messages, conversations, /messages/since poll, agent-keys, feedback. Mirror the ergonomics of noos/bd/wit CLIs. BUILD ON packages/api-client AFTER the monorepo migration so it shares one typed client (avoid a 3rd reimplementation). Blocked-ish by openchat-3jq.5.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:15Z","created_by":"tmad4000","updated_at":"2026-06-04T11:38:15Z","dependencies":[{"issue_id":"openchat-8md.2","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:15Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-8md.1","title":"Documented API: OpenAPI spec + complete endpoint reference","description":"Produce a real API reference. Generate an OpenAPI 3 spec from the Express routes (auth, chat: conversations/messages/contacts/presence, agent-keys, feedback, push, thoughts, ai, legal), serve it at /api/openapi.json + a docs page (or expand connect-your-bot.md into a full reference). Document the resolveActor auth (JWT or oc_ agent key), the text|content alias, agent-key scopes. Highest priority β€” lowest drift, everything else derives from it. Can be done pre-monorepo.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:14Z","created_by":"tmad4000","updated_at":"2026-06-04T11:43:30Z","started_at":"2026-06-04T11:41:31Z","closed_at":"2026-06-04T11:43:30Z","close_reason":"OpenAPI 3.1 spec (server/src/openapi.ts, 14 agent-facing paths) + GET /api/openapi.json + GET /api/docs (Redoc) on main. Server build clean. Goes live on next deploy. Hand-authored v1; post-monorepo can generate from packages/protocol.","dependencies":[{"issue_id":"openchat-8md.1","depends_on_id":"openchat-8md","type":"parent-child","created_at":"2026-06-04T04:38:13Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-8md","title":"OpenChat agent surfaces: API reference, CLI, MCP audit","description":"Make OpenChat's programmatic surface first-class + coherent (per CLAUDE.md agent-first-surfaces pattern). Findings 2026-06-04: MCP server EXISTS (github.com/tmad4000/openchat-mcp-server); NO CLI; API docs are only the human-readable connect-your-bot.md (no OpenAPI spec). Strategic note: build CLI/SDKs on the shared packages/api-client AFTER the monorepo migration (openchat-3jq.5) so they don't become a 3rd hand-rolled client (more drift).","status":"open","priority":2,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:38:10Z","created_by":"tmad4000","updated_at":"2026-06-04T11:38:10Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-4hq","title":"Enter=send, Shift+Enter=newline in message composers (web surfaces, both repos)","description":"Standardize composer key behavior. OpenChat legacy web client uses a single-line \u003cinput\u003e (no newline possible) β€” convert to \u003ctextarea\u003e with onKeyDown: Enterβ†’send+preventDefault, Shift+Enterβ†’newline. openchat-mobile ChatScreen composer is already a multiline TextInput but has NO key handler (KeyboardShortcutsScreen.web documents Enter=send/Shift+Enter=newline but it's unimplemented) β€” add web-only onKeyPress handling. Native iOS keeps return=newline + send button (Enter-to-send breaks soft-keyboard multiline). Surfaces: OpenChat /legacy + RN-web /m,/d.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T11:26:09Z","created_by":"tmad4000","updated_at":"2026-06-04T11:32:06Z","closed_at":"2026-06-04T11:32:06Z","close_reason":"Shipped + verified. Legacy web client: \u003cinput\u003eβ†’\u003ctextarea\u003e + onKeyDown (Enter sends, Shift+Enter newline, IME isComposing/229 guard). openchat-mobile ChatScreen: web-only onKeyPress (same behavior; native keeps return=newline+send button). Deployed to /legacy,/m,/d. Browser-verified on /d: Enter sent+cleared composer; Shift+Enter inserted newline without sending. Commits: OpenChat cc397bd, openchat-mobile fdb7030.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-u0k","title":"Make local-build.sh self-heal Node version (don't rely on machine-local .xcode.env.local)","description":"TestFlight build failed twice with 'Unable to resolve module index.ts' because the Xcode 'Bundle React Native code and images' phase ran under Node 25 (brew auto-bumped the unversioned node keg). Expo SDK 54/RN 0.81/Metro need Node 20/22/24.\n\nKey gotcha: the Xcode build phase sources ios/.xcode.env which does NODE_BINARY=$(command -v node) in a PATH-sanitized shell β€” so prepending node@22 to PATH in the launching shell does NOT reach the phase. Fix that worked: ios/.xcode.env.local with 'export NODE_BINARY=/opt/homebrew/opt/node@22/bin/node'. But that file is machine-local + gitignored, so other machines/agents will hit this again.\n\nDurable fix options (pick one):\n1. local-build.sh detects $(node -v) major not in {20,22,24} and writes ios/.xcode.env.local pinning to an installed LTS (brew --prefix node@22) before building.\n2. Commit a versioned .xcode.env that prefers node@22 if present.\n3. Add an engines/Volta pin + docs.\nRecommend option 1 (self-healing script). Also pinned repo via .node-version=22 (committed) β€” but Xcode's NODE_BINARY ignores .node-version, hence the script guard.","notes":"TRUE root cause of headless build failure is NOT node β€” it's TMPDIR. Claude Code's TMPDIR=/tmp/claude-501 causes a /tmp vs /private/tmp symlink mismatch that breaks Metro's absolute --entry-file resolution. Durable fix for local-build.sh: at the top, if TMPDIR resolves under /tmp, re-point it to a canonical /private/tmp dir (mkdir -p /private/tmp/ocbuild; export TMPDIR=/private/tmp/ocbuild). Combine with the node@22 LTS guard. Then headless/agent (nohup) builds work without NoMachine.","status":"closed","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:58:29Z","created_by":"tmad4000","updated_at":"2026-06-04T10:22:35Z","closed_at":"2026-06-04T10:22:35Z","close_reason":"Added TMPDIR + Node self-heal guards to local-build.sh (openchat-mobile commit). TMPDIR repin to $HOME/.ocbuild-tmp was the real fix (avoids /tmp\u003c-\u003e/private/tmp Metro resolution bug); Node-LTS PATH guard as secondary. Headless nohup build now archives + submits to TestFlight without NoMachine. Verified v0.1.14 build 71.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-oc8.3","title":"Feedback chat -\u003e auto-create WIT issue (v1)","description":"No Feedback conversation exists today (checked via agent key: 20 convs, none titled feedback/support/bug). \n\nv1: a 'Feedback' entry (Settings row or a pinned Feedback conversation) where a user message auto-creates an issue on worldissuetracker.com (WIT). Use the WIT agent key at ~/.config/wit/agent-key (header X-Agent-Key) -\u003e POST create-issue. Resolves to Jacob's WIT user.\nFuture: route feedback to an OpenChat-native agent that can converse back-and-forth in the chat (ties to agent-sidebar epic).\nAcceptance v1: sending feedback creates a WIT issue and confirms to the user with the issue link.","notes":"Dedicated WIT key DONE 2026-06-04: minted 'openchat-feedback' (id 544a8c27, owner=Jacob's WIT user) by replicating register-agent's service-role insert (register-agent needs a JWT we don't have headlessly). Swapped into /opt/openchat/.env WIT_AGENT_KEY + recreated container; /api/feedback smoke-tested live with the dedicated key. Key stored ~/.config/wit/openchat-feedback-key (0600) + README. Procedure saved as bd memory wit-mint-agent-key-headless.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:10Z","created_by":"tmad4000","updated_at":"2026-06-04T12:32:56Z","started_at":"2026-06-04T10:27:54Z","closed_at":"2026-06-04T11:10:59Z","close_reason":"Implemented end-to-end: server POST /api/feedback -\u003e WIT create-issue (server/src/routes/feedback.ts, on OpenChat main c3aa5ad; WIT API verified live) + mobile 'Send feedback' Settings row (merged to mobile main 9314b90). tsc + server build clean. DEPLOY GATE: set WIT_AGENT_KEY in backend prod env + deploy server; route returns 503 (row shows graceful error) until then.","dependencies":[{"issue_id":"openchat-oc8.3","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:09Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-oc8.2","title":"App update strategy: EAS Update OTA + in-app 'update available' nudge","description":"Implement layered update story so users rarely update manually:\n1. EAS Update (OTA) for JS/asset-only changes β€” instant, no new TestFlight build. (overlaps epic openchat-3jq.1). Set runtimeVersion policy.\n2. Document/encourage TestFlight 'Automatic Updates' toggle (can't be forced server-side).\n3. In-app 'update available' banner for NATIVE binary bumps: app checks a backend/version endpoint (or EAS Update manifest) comparing runtimeVersion/build vs latest available; non-intrusive banner -\u003e deep link to TestFlight/App Store. Per global rule 'Update Available Indicator': visible not intrusive, one-click, non-blocking.\nPitfalls: OTA can't ship native module changes; runtimeVersion must bump when native changes; don't OTA-push a JS bundle incompatible with the installed native runtime.","notes":"Gemini (flash) + corrections. Layered: (a) EAS Update OTA (checkAutomatically ON_LOAD) for JS/asset changes; (b) TestFlight 'Automatic Downloads' (can't force; builds expire ~90d); (c) in-app 'update available' check comparing runtimeVersion/build vs backend latest, deep-link to TestFlight.\nCORRECTION: Gemini said use a NON-DISMISSIBLE modal for native bumps. OVERRIDE per Jacob global rule 'Update Available Indicator = visible but NOT intrusive, dot/badge not modal, non-blocking'. Use a dismissible banner, not a blocking modal.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:08Z","created_by":"tmad4000","updated_at":"2026-06-04T11:10:57Z","started_at":"2026-06-04T10:27:55Z","closed_at":"2026-06-04T11:10:57Z","close_reason":"Implemented: expo-updates + EAS Update OTA config (app.config.js updates url/checkAutomatically ON_LOAD, runtimeVersion appVersion), eas.json channels, dismissible in-app UpdateBanner wired app-wide. Merged to mobile main (8f83600). tsc clean. Activates on the TestFlight build now in flight; after that, JS-only fixes ship via 'eas update'. Native-binary nudge deferred (needs backend latest-version endpoint).","dependencies":[{"issue_id":"openchat-oc8.2","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:07Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-oc8.1","title":"Simplify 'Connect an agent' card; lead with Copy-prompt CTA","description":"Make the connect-agent card cleaner and put 'Copy prompt for agent' front-and-center (Jacob likes the blue accent). Likely changes in src/components/McpSetupCard.tsx (mobile):\n- Single prominent primary CTA: copy the tool-less 'Any LLM' onboarding blob (the thing that works in plain ChatGPT).\n- Collapse MCP/CLI config tabs (Claude Desktop/Cursor/Codex/Claude Code/curl) behind an 'Advanced / other clients' disclosure.\n- Keep the blue hero styling.\n- Live-key-in-clipboard safety: warn inline + offer quick revoke; mint-per-copy naming so each is individually revocable.\nIncorporate Gemini's second opinion (captured in epic notes) + an alternate layout. Needs Jacob's eye on final visual.","notes":"Gemini (flash) second opinion + my corrections:\nLAYOUT (agreed): 1) headline 'Connect an AI Agent' 2) big blue primary CTA 'Copy agent setup prompt' 3) horizontal pill selector (ChatGPT/Claude/Cursor...) that swaps clipboard content 4) small security footer. Push curl/Codex/raw endpoints behind 'Advanced'.\nCORRECTION: Gemini suggested short-lived 24-48h tokens. OVERRIDE β€” OpenChat keys are intentionally re-viewable + non-expiring (connect-your-bot.md) and Jacob wants agents to 'do everything'; forced TTL breaks long-running agents. Instead: mint-per-copy (named, individually revocable) + inline 'contains a live key' warning + one-tap revoke. No forced expiry.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:06Z","created_by":"tmad4000","updated_at":"2026-06-04T12:39:02Z","started_at":"2026-06-04T12:33:12Z","closed_at":"2026-06-04T12:39:02Z","close_reason":"Connect-an-agent card simplified: primary blue CTA copies the tool-less ChatGPT/Any-LLM REST blob; MCP/CLI config tabs + the coding-agent one-shot prompt collapsed under 'Advanced' (default closed). Merged to openchat-mobile main; deploying /d.","dependencies":[{"issue_id":"openchat-oc8.1","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:05Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-oc8.3","title":"Feedback chat -\u003e auto-create WIT issue (v1)","description":"No Feedback conversation exists today (checked via agent key: 20 convs, none titled feedback/support/bug). \n\nv1: a 'Feedback' entry (Settings row or a pinned Feedback conversation) where a user message auto-creates an issue on worldissuetracker.com (WIT). Use the WIT agent key at ~/.config/wit/agent-key (header X-Agent-Key) -\u003e POST create-issue. Resolves to Jacob's WIT user.\nFuture: route feedback to an OpenChat-native agent that can converse back-and-forth in the chat (ties to agent-sidebar epic).\nAcceptance v1: sending feedback creates a WIT issue and confirms to the user with the issue link.","notes":"Dedicated WIT key DONE 2026-06-04: minted 'openchat-feedback' (id 544a8c27, owner=Jacob's WIT user) by replicating register-agent's service-role insert (register-agent needs a JWT we don't have headlessly). Swapped into /opt/openchat/.env WIT_AGENT_KEY + recreated container; /api/feedback smoke-tested live with the dedicated key. Key stored ~/.config/wit/openchat-feedback-key (0600) + README. Procedure saved as bd memory wit-mint-agent-key-headless.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:10Z","created_by":"tmad4000","updated_at":"2026-06-04T12:32:56Z","started_at":"2026-06-04T10:27:54Z","closed_at":"2026-06-04T11:10:59Z","close_reason":"Implemented end-to-end: server POST /api/feedback -\u003e WIT create-issue (server/src/routes/feedback.ts, on OpenChat main c3aa5ad; WIT API verified live) + mobile 'Send feedback' Settings row (merged to mobile main 9314b90). tsc + server build clean. DEPLOY GATE: set WIT_AGENT_KEY in backend prod env + deploy server; route returns 503 (row shows graceful error) until then.","dependencies":[{"issue_id":"openchat-oc8.3","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:09Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-oc8.2","title":"App update strategy: EAS Update OTA + in-app 'update available' nudge","description":"Implement layered update story so users rarely update manually:\n1. EAS Update (OTA) for JS/asset-only changes β€” instant, no new TestFlight build. (overlaps epic openchat-3jq.1). Set runtimeVersion policy.\n2. Document/encourage TestFlight 'Automatic Updates' toggle (can't be forced server-side).\n3. In-app 'update available' banner for NATIVE binary bumps: app checks a backend/version endpoint (or EAS Update manifest) comparing runtimeVersion/build vs latest available; non-intrusive banner -\u003e deep link to TestFlight/App Store. Per global rule 'Update Available Indicator': visible not intrusive, one-click, non-blocking.\nPitfalls: OTA can't ship native module changes; runtimeVersion must bump when native changes; don't OTA-push a JS bundle incompatible with the installed native runtime.","notes":"Gemini (flash) + corrections. Layered: (a) EAS Update OTA (checkAutomatically ON_LOAD) for JS/asset changes; (b) TestFlight 'Automatic Downloads' (can't force; builds expire ~90d); (c) in-app 'update available' check comparing runtimeVersion/build vs backend latest, deep-link to TestFlight.\nCORRECTION: Gemini said use a NON-DISMISSIBLE modal for native bumps. OVERRIDE per Jacob global rule 'Update Available Indicator = visible but NOT intrusive, dot/badge not modal, non-blocking'. Use a dismissible banner, not a blocking modal.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:08Z","created_by":"tmad4000","updated_at":"2026-06-04T11:10:57Z","started_at":"2026-06-04T10:27:55Z","closed_at":"2026-06-04T11:10:57Z","close_reason":"Implemented: expo-updates + EAS Update OTA config (app.config.js updates url/checkAutomatically ON_LOAD, runtimeVersion appVersion), eas.json channels, dismissible in-app UpdateBanner wired app-wide. Merged to mobile main (8f83600). tsc clean. Activates on the TestFlight build now in flight; after that, JS-only fixes ship via 'eas update'. Native-binary nudge deferred (needs backend latest-version endpoint).","dependencies":[{"issue_id":"openchat-oc8.2","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:07Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-oc8.1","title":"Simplify 'Connect an agent' card; lead with Copy-prompt CTA","description":"Make the connect-agent card cleaner and put 'Copy prompt for agent' front-and-center (Jacob likes the blue accent). Likely changes in src/components/McpSetupCard.tsx (mobile):\n- Single prominent primary CTA: copy the tool-less 'Any LLM' onboarding blob (the thing that works in plain ChatGPT).\n- Collapse MCP/CLI config tabs (Claude Desktop/Cursor/Codex/Claude Code/curl) behind an 'Advanced / other clients' disclosure.\n- Keep the blue hero styling.\n- Live-key-in-clipboard safety: warn inline + offer quick revoke; mint-per-copy naming so each is individually revocable.\nIncorporate Gemini's second opinion (captured in epic notes) + an alternate layout. Needs Jacob's eye on final visual.","notes":"Gemini (flash) second opinion + my corrections:\nLAYOUT (agreed): 1) headline 'Connect an AI Agent' 2) big blue primary CTA 'Copy agent setup prompt' 3) horizontal pill selector (ChatGPT/Claude/Cursor...) that swaps clipboard content 4) small security footer. Push curl/Codex/raw endpoints behind 'Advanced'.\nCORRECTION: Gemini suggested short-lived 24-48h tokens. OVERRIDE β€” OpenChat keys are intentionally re-viewable + non-expiring (connect-your-bot.md) and Jacob wants agents to 'do everything'; forced TTL breaks long-running agents. Instead: mint-per-copy (named, individually revocable) + inline 'contains a live key' warning + one-tap revoke. No forced expiry.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:06Z","created_by":"tmad4000","updated_at":"2026-06-04T12:39:02Z","started_at":"2026-06-04T12:33:12Z","closed_at":"2026-06-04T12:39:02Z","close_reason":"Connect-an-agent card simplified: primary blue CTA copies the tool-less ChatGPT/Any-LLM REST blob; MCP/CLI config tabs + the coding-agent one-shot prompt collapsed under 'Advanced' (default closed). Merged to openchat-mobile main; deploying /d.","dependencies":[{"issue_id":"openchat-oc8.1","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:05Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-wm7","title":"Enforce read/write scopes in resolveActor (agent keys)","description":"Agent keys store read/write scopes (server/src/routes/agentKeys.ts) but resolveActor authenticates WITHOUT enforcing them per-route β€” a 'read-only' key can currently write. Flagged by Codex during the connect-agent merge (2026-06-04).\n\nPre-existing on the investigate-url-sync-issue-2 branch, not introduced by the merge. Currently errs toward MORE capability, which is acceptable per Jacob's 'agent should be able to do everything' stance β€” but scope toggles in the UI are misleading until enforced.\n\nFix: in resolveActor, after resolving the key, attach its scopes to req; add a requireScope('write') guard on mutating chat routes (POST/PATCH/DELETE messages, POST conversations, participants). Read routes require 'read'. Keep default keys read+write so nothing breaks.","status":"open","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:44:37Z","created_by":"tmad4000","updated_at":"2026-06-04T08:44:37Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-aec.3","title":"Share-a-self-DM link that lands an agent/human with instructions","description":"Shareable deep link to a conversation (starting with the self-DM) that 'lands' the recipient with the right context. Two audiences:\n- Human: opens the app/PWA to that conversation (deep link openchat://conversation/\u003cid\u003e or https deep link).\n- Agent: a companion flow that bundles the link + onboarding blob (openchat-aec child) so you can throw an agent straight into a specific chat with instructions pre-filled.\n\nBuilds on the self-marking work (openchat-wa9) so the self-DM is clearly labeled. Ties into the copy-paste blob: 'Copy for agent' from within a conversation should include that conversation's id.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:17Z","created_by":"tmad4000","updated_at":"2026-06-04T08:32:17Z","dependencies":[{"issue_id":"openchat-aec.3","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:16Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-aec.3","title":"Share-a-self-DM link that lands an agent/human with instructions","description":"Shareable deep link to a conversation (starting with the self-DM) that 'lands' the recipient with the right context. Two audiences:\n- Human: opens the app/PWA to that conversation (deep link openchat://conversation/\u003cid\u003e or https deep link).\n- Agent: a companion flow that bundles the link + onboarding blob (openchat-aec child) so you can throw an agent straight into a specific chat with instructions pre-filled.\n\nBuilds on the self-marking work (openchat-wa9) so the self-DM is clearly labeled. Ties into the copy-paste blob: 'Copy for agent' from within a conversation should include that conversation's id.","status":"open","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:32:17Z","created_by":"tmad4000","updated_at":"2026-06-04T08:32:17Z","dependencies":[{"issue_id":"openchat-aec.3","depends_on_id":"openchat-aec","type":"parent-child","created_at":"2026-06-04T01:32:16Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-yci","title":"Reconcile beads issue prefix: 'openchat-' vs 'OpenChat-'","description":"Commits on investigate-url-sync-issue-2 reference tickets with prefix 'OpenChat-' (e.g. OpenChat-7c9, OpenChat-hq2, OpenChat-zi1). Current beads workspace in ~/code/OpenChat uses 'openchat-' (lowercase) because I ran 'bd init --reinit-local --prefix openchat' today (2026-06-01) to unblock ticket creation β€” this may have wiped the prior canonical prefix.\n\nNeed to:\n1. Determine which prefix is canonical (check git history of .beads/config.yaml and .beads/issues.jsonl)\n2. If 'OpenChat-' was canonical, restore that prefix and re-export/re-import the 4 tickets I created today (openchat-67y, openchat-nqi, openchat-wa9, openchat-ia9) under the OpenChat- prefix\n3. Otherwise, rewrite the historical commit-message references β€” except commits are immutable, so the practical fix is to accept that historical OpenChat-xxx IDs are dangling references in the new lowercase namespace\n\nRecommend option 1 (restore canonical prefix) since dozens of historical commits already reference OpenChat-xxx.","status":"open","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T20:33:55Z","created_by":"tmad4000","updated_at":"2026-06-01T20:33:55Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.6","title":"Document tester update behavior and limits","description":"Document what can update automatically for testers and what cannot: EAS OTA updates, TestFlight automatic updates controlled by testers, internal vs external tester limits, and when Beta App Review applies.","acceptance_criteria":"README/AGENTS/release docs explain OTA-safe changes versus native binary changes; tester instructions mention enabling TestFlight automatic updates; internal/external tester limitations are recorded; release operator checklist is current.","status":"closed","priority":2,"issue_type":"chore","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:52:01Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:06Z","closed_at":"2026-06-04T23:59:06Z","close_reason":"Tester docs added (docs/testers.md): tiers, update behavior, feedback flow.","labels":["docs","expo","monorepo","release","testflight"],"dependencies":[{"issue_id":"openchat-3jq.6","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:52:01Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.5","title":"Plan and execute OpenChat monorepo migration","description":"Move toward a single repository/workspace layout so server, Expo app, shared API client, shared types, and deploy scripts are versioned together.","acceptance_criteria":"Target workspace layout is documented; migration order is defined; openchat-mobile can be built from the unified checkout; deploy and EAS paths are updated; shared packages are introduced only where they reduce drift.","notes":"MIGRATION COMPLETED on branch monorepo-migration (commit b4260a0, pushed to origin). HARDENING (openchat-mono staging 622d166): turborepo + react19-align + monorepo metro all green incl. expo export --platform web.\n\nOpenChat branch lands:\n- apps/{server,web,mobile} (mobile via git subtree from openchat-mobile main, history preserved)\n- infra/{Dockerfile, docker-compose.prod.yml, deploy.sh} (paths repointed to apps/*)\n- packages/ scaffolded (.gitkeep) for upcoming api-client/types/protocol\n- turbo.json at root; npm workspaces apps/*+packages/*\n- web aligned to React 19 (matches mobile) β€” no tsconfig paths band-aid\n- mobile metro.config.js monorepo-aware (watchFolders, nodeModulesPaths, disableHierarchicalLookup)\n- apps/server build: cp ../../docs/connect-your-bot.md (monorepo-root docs/ kept canonical)\n- scripts/dev.mjs + root package.json workspace refs updated\n\nValidated locally: root npm install, apps/server build, apps/web build (React 19), apps/mobile tsc --noEmit, apps/mobile expo export --platform web. NOT validated: native iOS EAS build (deploy guardrail blocks local-build.sh which auto-submits to TestFlight), deploy.sh end-to-end. Follow-ups filed for both. Main branch untouched; openchat-mobile main untouched. Needs human review before merging branch -\u003e main.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:58Z","created_by":"tmad4000","updated_at":"2026-06-04T20:33:03Z","started_at":"2026-06-04T10:27:52Z","closed_at":"2026-06-04T20:33:03Z","close_reason":"Monorepo migration CUT OVER to main 2026-06-04: main IS the monorepo (apps/{server,web,mobile}+infra), force-pushed dc011e3, prod chat.globalbr.ai deployed from it and verified (/ /m /d /legacy /api all 200 w/ content). Two cutover bugs fixed (google fix port + server static-serve paths). openchat-mobile frozen (MIGRATED.md).","labels":["architecture","expo","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.5","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:58Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":3,"comment_count":0} -{"_type":"issue","id":"openchat-3jq.3","title":"Show app/update provenance in Settings","description":"Expose enough version/update metadata in the app to answer why two testers or web/native surfaces are seeing different behavior.","acceptance_criteria":"Settings shows app version, native build number, runtime version, update channel, update id or created-at when available, and commit SHA/build source when available; values degrade gracefully in local/dev builds.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:54Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:05Z","closed_at":"2026-06-04T23:59:05Z","close_reason":"App/update provenance in Settings (version/build/channel/commit) β€” web + mobile.","labels":["debuggability","expo","mobile","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.3","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:53Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.6","title":"Document tester update behavior and limits","description":"Document what can update automatically for testers and what cannot: EAS OTA updates, TestFlight automatic updates controlled by testers, internal vs external tester limits, and when Beta App Review applies.","acceptance_criteria":"README/AGENTS/release docs explain OTA-safe changes versus native binary changes; tester instructions mention enabling TestFlight automatic updates; internal/external tester limitations are recorded; release operator checklist is current.","status":"closed","priority":2,"issue_type":"chore","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:52:01Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:06Z","closed_at":"2026-06-04T23:59:06Z","close_reason":"Tester docs added (docs/testers.md): tiers, update behavior, feedback flow.","labels":["docs","expo","monorepo","release","testflight"],"dependencies":[{"issue_id":"openchat-3jq.6","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:52:01Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.5","title":"Plan and execute OpenChat monorepo migration","description":"Move toward a single repository/workspace layout so server, Expo app, shared API client, shared types, and deploy scripts are versioned together.","acceptance_criteria":"Target workspace layout is documented; migration order is defined; openchat-mobile can be built from the unified checkout; deploy and EAS paths are updated; shared packages are introduced only where they reduce drift.","notes":"MIGRATION COMPLETED on branch monorepo-migration (commit b4260a0, pushed to origin). HARDENING (openchat-mono staging 622d166): turborepo + react19-align + monorepo metro all green incl. expo export --platform web.\n\nOpenChat branch lands:\n- apps/{server,web,mobile} (mobile via git subtree from openchat-mobile main, history preserved)\n- infra/{Dockerfile, docker-compose.prod.yml, deploy.sh} (paths repointed to apps/*)\n- packages/ scaffolded (.gitkeep) for upcoming api-client/types/protocol\n- turbo.json at root; npm workspaces apps/*+packages/*\n- web aligned to React 19 (matches mobile) β€” no tsconfig paths band-aid\n- mobile metro.config.js monorepo-aware (watchFolders, nodeModulesPaths, disableHierarchicalLookup)\n- apps/server build: cp ../../docs/connect-your-bot.md (monorepo-root docs/ kept canonical)\n- scripts/dev.mjs + root package.json workspace refs updated\n\nValidated locally: root npm install, apps/server build, apps/web build (React 19), apps/mobile tsc --noEmit, apps/mobile expo export --platform web. NOT validated: native iOS EAS build (deploy guardrail blocks local-build.sh which auto-submits to TestFlight), deploy.sh end-to-end. Follow-ups filed for both. Main branch untouched; openchat-mobile main untouched. Needs human review before merging branch -\u003e main.","status":"closed","priority":2,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:58Z","created_by":"tmad4000","updated_at":"2026-06-04T20:33:03Z","started_at":"2026-06-04T10:27:52Z","closed_at":"2026-06-04T20:33:03Z","close_reason":"Monorepo migration CUT OVER to main 2026-06-04: main IS the monorepo (apps/{server,web,mobile}+infra), force-pushed dc011e3, prod chat.globalbr.ai deployed from it and verified (/ /m /d /legacy /api all 200 w/ content). Two cutover bugs fixed (google fix port + server static-serve paths). openchat-mobile frozen (MIGRATED.md).","labels":["architecture","expo","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.5","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:58Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":3,"comment_count":0} +{"_type":"issue","id":"openchat-3jq.3","title":"Show app/update provenance in Settings","description":"Expose enough version/update metadata in the app to answer why two testers or web/native surfaces are seeing different behavior.","acceptance_criteria":"Settings shows app version, native build number, runtime version, update channel, update id or created-at when available, and commit SHA/build source when available; values degrade gracefully in local/dev builds.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:51:54Z","created_by":"tmad4000","updated_at":"2026-06-04T23:59:05Z","closed_at":"2026-06-04T23:59:05Z","close_reason":"App/update provenance in Settings (version/build/channel/commit) β€” web + mobile.","labels":["debuggability","expo","mobile","monorepo","release"],"dependencies":[{"issue_id":"openchat-3jq.3","depends_on_id":"openchat-3jq","type":"parent-child","created_at":"2026-06-01T03:51:53Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-wa9","title":"Self user as special case in user search and DM composer","description":"User's own row in user search/composer is indistinguishable from a normal contact (shows as e.g. 'tmad4000@gmail.com@ThoughtStreams.local'). Make self a clear special case:\n\n- Composer search: typing 'self' or 'me' matches the current user as top result\n- Row badged '(You)' / '(self)' alongside display name\n- Self selectable so users can DM themselves in one flow (today requires manual workaround β€” see companion ticket on agent-key scope)\n- Same self-badge anywhere user identity renders (participants list, mentions, sender chips)\n\nDon't change underlying identity rendering β€” add self-marker layer on top.","status":"closed","priority":2,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:41:10Z","created_by":"tmad4000","updated_at":"2026-06-01T10:49:14Z","started_at":"2026-06-01T10:48:04Z","closed_at":"2026-06-01T10:49:14Z","close_reason":"Self/me search now returns and ranks the current user; UI displays self markers in composer, conversation headers/lists, group members, and sender chips.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-nqi","title":"Fix connect-your-bot docs: messages POST field is 'content' not 'text'","description":"/about/connect-your-bot shows POST body {\"text\":\"...\"} but API requires {\"content\":\"...\"}; sending 'text' returns 'content or attachments is required'. Either update docs or accept 'text' as alias. Also document that agent key sends messages as the owning user (senderId == user id), not a separate bot identity.","status":"closed","priority":2,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:41:07Z","created_by":"tmad4000","updated_at":"2026-06-01T10:50:44Z","started_at":"2026-06-01T10:49:49Z","closed_at":"2026-06-01T10:50:44Z","close_reason":"Message POST accepts text as a compatibility alias; connect-your-bot docs now show content and clarify agent-key messages use the owning user identity.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-5xq","title":"[P2] OpenChat MCP server (sibling to wikihub-mcp-server)","description":"Build a thin MCP adapter over the OpenChat REST API so any MCP-aware client (Claude Desktop, Cursor, Cline, etc.) can talk to OpenChat with one config snippet. Parallel to wikihub/mcp-server/ β€” same shape.\n\nLOCATION: ~/code/openchat-mcp-server/ (new sibling repo, not in openchat or openchat-mobile)\n\nTOOL SURFACE (initial):\n- oc_list_conversations(): your conversations\n- oc_get_messages(conversationId, limit?): recent messages\n- oc_send_message(conversationId, text, attachments?): send (write)\n- oc_react(messageId, emoji): tap-back\n- oc_create_dm(userEmail): start a 1:1\n- oc_register_agent(name, scopes?): mint a new key β€” uses caller's OAuth or JWT\n\nTRANSPORT:\n- stdio (for Claude Desktop)\n- HTTP (for Cursor / hosted clients)\n\nAUTH:\n- Reads OPENCHAT_API_KEY env var OR Authorization: Bearer \u003ckey\u003e header\n- Falls back to credentials file ~/.openchat/credentials.json\n\nDOCS:\n- One-line install: 'npx -y @openchat/mcp-server' (publish to npm later)\n- README with Claude Desktop config:\n {\n \"mcpServers\": {\n \"openchat\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@openchat/mcp-server\"],\n \"env\": { \"OPENCHAT_API_KEY\": \"oc_…\" }\n }\n }\n }\n\nREFERENCES:\n- /Users/jacobcole/code/wikihub/mcp-server/src/ (TypeScript MCP server template β€” copy structure)\n- /Users/jacobcole/code/wikihub/docs/MCP_CONNECTOR_BLUEPRINT.md\n\nDEPENDS ON: OpenChat-7c9 (agent keys must exist first for auth)","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-06-01T09:58:53Z","created_by":"Jacob Cole","updated_at":"2026-06-01T10:04:34Z","started_at":"2026-06-01T10:04:28Z","closed_at":"2026-06-01T10:04:34Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-5xq","depends_on_id":"OpenChat-7c9","type":"blocks","created_at":"2026-06-01T03:58:58Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-5xq","title":"[P2] OpenChat MCP server (sibling to wikihub-mcp-server)","description":"Build a thin MCP adapter over the OpenChat REST API so any MCP-aware client (Claude Desktop, Cursor, Cline, etc.) can talk to OpenChat with one config snippet. Parallel to wikihub/mcp-server/ β€” same shape.\n\nLOCATION: ~/code/openchat-mcp-server/ (new sibling repo, not in openchat or openchat-mobile)\n\nTOOL SURFACE (initial):\n- oc_list_conversations(): your conversations\n- oc_get_messages(conversationId, limit?): recent messages\n- oc_send_message(conversationId, text, attachments?): send (write)\n- oc_react(messageId, emoji): tap-back\n- oc_create_dm(userEmail): start a 1:1\n- oc_register_agent(name, scopes?): mint a new key β€” uses caller's OAuth or JWT\n\nTRANSPORT:\n- stdio (for Claude Desktop)\n- HTTP (for Cursor / hosted clients)\n\nAUTH:\n- Reads OPENCHAT_API_KEY env var OR Authorization: Bearer \u003ckey\u003e header\n- Falls back to credentials file ~/.openchat/credentials.json\n\nDOCS:\n- One-line install: 'npx -y @openchat/mcp-server' (publish to npm later)\n- README with Claude Desktop config:\n {\n \"mcpServers\": {\n \"openchat\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@openchat/mcp-server\"],\n \"env\": { \"OPENCHAT_API_KEY\": \"oc_…\" }\n }\n }\n }\n\nREFERENCES:\n- /Users/jacobcole/code/wikihub/mcp-server/src/ (TypeScript MCP server template β€” copy structure)\n- /Users/jacobcole/code/wikihub/docs/MCP_CONNECTOR_BLUEPRINT.md\n\nDEPENDS ON: OpenChat-7c9 (agent keys must exist first for auth)","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-06-01T09:58:53Z","created_by":"Jacob Cole","updated_at":"2026-06-01T10:04:34Z","started_at":"2026-06-01T10:04:28Z","closed_at":"2026-06-01T10:04:34Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-5xq","depends_on_id":"OpenChat-7c9","type":"blocks","created_at":"2026-06-01T03:58:58Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-5za","title":"[P2] QR code + web URL on login screen for app sharing","description":"On the blank login screen, add a small QR code + tappable URL pointing to https://chat.globalbr.ai/m/ so users can scan + share the app easily. Two purposes: (a) onboard friends fast β€” they scan, get the mobile web version, sign in, no install needed, (b) share the app to non-iOS users (Android web users, anyone).","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-06-01T09:41:30Z","created_by":"Jacob Cole","updated_at":"2026-06-01T09:42:42Z","closed_at":"2026-06-01T09:42:42Z","close_reason":"Shipped in openchat-mobile commit 9346c37. QR code + tappable URL + Share button on login screen.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-7cm","title":"[P2] Tap DM header β†’ contact profile screen","description":"Currently in a DM, the chat header (avatar + name + presence) is rendered but disabled β€” tapping it does nothing. For groups, tapping opens GroupSettings. Fix: make DM headers tappable, opening a ContactProfile screen.\n\nCONTACT PROFILE SCREEN (new):\n- Large avatar centered at top\n- Display name + bot badge if applicable\n- Email\n- Status message (if set)\n- Presence status (online/offline + lastSeenAt)\n- Action rows:\n - Message (closes β€” already there)\n - Block user (calls api.blockUser, leaves the chat)\n - Report user (opens existing report sheet)\n- Hidden on web for now (just hide tap target there, parity with native)\n\nWIRING:\n- ChatScreen.tsx:425 β€” enable tap when !isGroup, navigate to ContactProfile with { userId, user }\n- Pass user object via nav params so we render immediately without a fetch\n- Refresh details (presence, statusMessage) from server on screen mount\n\nALSO covers Steve Echtmann feedback about WhatsApp-style sender labels β€” that's already shipped in build 30 (commit d879e40); Steve was looking at build 16.","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-06-01T09:38:50Z","created_by":"Jacob Cole","updated_at":"2026-06-01T09:40:37Z","closed_at":"2026-06-01T09:40:37Z","close_reason":"Shipped in openchat-mobile commit b149bc1. ContactProfileScreen + DM header tap + β“˜ indicator. Ships in next build (31+).","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-hhc","title":"[P2] Message forwarding","description":"Long press a message β†’ ActionSheet has 'Forward' β†’ opens conversation picker β†’ forwards to selected conversation with 'Forwarded' label. AC: works on text/image/voice messages; forward chain shows original sender; works in DMs + groups. Server: new endpoint POST /api/chat/messages/:id/forward { toConversationId } that creates a new Message in the target conv with forwardedFromMessageId + forwardedFromSenderId set.","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-06-01T06:06:51Z","created_by":"Jacob Cole","updated_at":"2026-06-01T06:14:03Z","started_at":"2026-06-01T06:08:16Z","closed_at":"2026-06-01T06:14:03Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} @@ -140,28 +143,28 @@ {"_type":"issue","id":"OpenChat-84u","title":"Homepage QR code: share chat.globalbr.ai easily + deep-link redirect chain","description":"A QR on the homepage / signed-out landing that encodes https://chat.globalbr.ai β€” anyone scanning it gets the web app and can sign in to start chatting. Also: when a user scans a per-user QR (OpenChat-wtb) or per-group invite QR (OpenChat-240) while NOT signed in, the deep link must survive the OAuth round trip so they land on the intended add-friend / join-group action AFTER login.\n\nSCOPE:\n\n1. Homepage QR (root /) β€” small QR + 'Scan to install / sign in' UX on the Vite landing page. Pure marketing/utility. Probably a static-ish component that uses a JS QR lib. Could also have a dedicated /share or /qr page.\n\n2. Deep-link sign-in redirect chain β€” the real engineering work:\n - User scans openchat://user/\u003cid\u003e or openchat://invite/\u003ctoken\u003e\n - Web universal-link or app deep-link fires\n - If signed in β†’ execute the action (open DM / show invite preview)\n - If NOT signed in β†’ stash the intended action (sessionStorage / URL query param), bounce to /login, after OAuth completes, resume the original action\n - Edge: web (Vite root + /m/ + /d/) vs native iOS (URL scheme + Universal Link)\n\nACCEPTANCE:\n- [ ] Homepage (root /) shows a QR encoding https://chat.globalbr.ai (or whatever the share URL is)\n- [ ] Scanning user QR while signed out β†’ after sign-in, lands on/creates the 1:1 DM\n- [ ] Scanning group invite QR while signed out β†’ after sign-in, lands on invite preview screen\n- [ ] Works on all three web surfaces (root Vite, /m/, /d/) AND native iOS\n- [ ] Resume URL is whitelisted (no open-redirect β€” only openchat:// or chat.globalbr.ai paths)\n\nDEPENDS ON: OpenChat-wtb (defines the user QR payload schema), OpenChat-240 (group invite payload)","status":"open","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T20:20:17Z","created_by":"Jacob Cole","updated_at":"2026-05-31T20:20:17Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-on1","title":"Sync main β†’ desktop-responsive + redeploy /d/","description":"Merge 5 commits from openchat-mobile main into desktop-responsive branch and redeploy /d/ on chat.globalbr.ai.\n\nThe 5 commits to land on desktop-responsive:\n- 906a6ed feat(mobile): Settings β†’ Notifications section (OpenChat-jzc)\n- e8e22c2 fix(mobile): at-bottom-aware chat scroll + new-messages pill (OpenChat-b4z)\n- 7225a44 fix(auth): iOS Google sign-in β€” register reverse-client-id URL scheme + drop overriding redirectUri β¬… THIS FIXES /d/ DOUBLE-POPUP\n- d879e40 feat(mobile): WhatsApp-style sender identification in group chats\n- 9f0b9f1 feat(mobile): explicit group rename Save button + confirmation alert\n\nKNOWN CONFLICT: ChatScreen.tsx β€” desktop-responsive refactored it into a header-config wrapper around ChatPane.tsx. The scroll behavior + WhatsApp identifier changes from main need to be ported into ChatPane.tsx where they live now (~503-line diff).\n\nAfter merge:\n1. npx tsc --noEmit (verify)\n2. npx expo export --platform web --output-dir dist (build /d/)\n3. Copy build into openchat server's static-served /d/ path\n4. Push + redeploy openchat server\n5. Verify /d/ Google sign-in is single-popup\n\nAcceptance:\n- [ ] desktop-responsive contains all 5 commits' logical changes\n- [ ] /d/ deployed and reachable on https://chat.globalbr.ai/d/\n- [ ] Google sign-in on /d/ shows ONE popup, not two\n- [ ] Scroll behavior matches /m/ (at-bottom pin + new-messages pill)\n- [ ] No regression on the desktop layout (sidebar collapse, max-width, Cmd-K/N shortcuts)","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:24:48Z","created_by":"Jacob Cole","updated_at":"2026-05-31T20:27:30Z","closed_at":"2026-05-31T20:27:30Z","close_reason":"Merged all 5 commits from main into desktop-responsive (merge commit c94e043 on branch desktop-responsive). Manual port to ChatPane.tsx: scroll behavior (isAtBottom, NewMessagesPill, handleScroll, Keyboard.keyboardDidShow), WhatsApp group identifiers (colorForUserId, isLastInRun, avatarSlot). LoginScreen: dropped AuthSession import + redirectUri override β€” critical fix for /d/ double-popup Google sign-in. app.json: added CFBundleURLTypes reverse-client-id. SettingsScreen: Notifications section. GroupSettingsScreen: explicit Save button + confirmation. New files: NewMessagesPill.tsx, colorForUserId.ts. TypeScript clean. Build hash: 1ebd27382c2703705d94dfcf6e896f99. Deployed to chat.globalbr.ai/d/ β€” HTTP 200 confirmed.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-jzc","title":"Settings: re-request notification permission button","description":"Build a Notifications section in SettingsScreen that surfaces permission status and provides recovery paths.\n\nDEFINITIVE AUDIT (2026-05-31):\n- App DOES request push permission post-login (App.tsx:63-68 β†’ notifications.ts:104-171)\n- SettingsScreen.tsx has NO notifications UI today (verified file in full, 122 lines: only signed-in row, theme picker, sign-out, version footer)\n- iOS does NOT re-prompt after a denial β€” user must go to iOS Settings β†’ OpenChat β†’ Notifications. App offers no path to that.\n- Prior ticket OpenChat-cb2 was filed for WEB PWA version; never implemented. Native (this ticket) was implicitly covered under OpenChat-vg7 but the Settings UI was skipped.\n\nIMPLEMENTATION:\n- Add a 'Notifications' section to SettingsScreen.tsx\n- On mount, call Notifications.getPermissionsAsync() and render one of:\n * granted β†’ checkmark + 'Notifications are on' (+ optional 'Send test' button)\n * undetermined β†’ 'Enable notifications' button β†’ calls registerForPushNotificationsAsync()\n * denied β†’ 'Notifications are off. Open iOS Settings' button β†’ Linking.openSettings()\n- Re-poll permission state on screen focus (useFocusEffect) so toggling iOS Settings and returning shows the new state without reboot.\n- Web platform: hide the section (Notifications module is no-op there).\n\nACCEPTANCE:\n- [ ] Settings shows current notification permission status\n- [ ] If undetermined, tapping the button triggers the iOS prompt and updates the row on grant\n- [ ] If denied, tapping the button opens iOS Settings deep-link\n- [ ] Returning to the app after toggling in iOS Settings refreshes the row state\n- [ ] No web regression (section hidden on web)\n- [ ] No simulator regression (Device.isDevice gating preserved)\n\nEVIDENCE: /Users/Jacob/code/openchat-mobile/src/services/notifications.ts:104-171, /Users/Jacob/code/openchat-mobile/src/screens/SettingsScreen.tsx:1-122, /Users/Jacob/code/openchat-mobile/App.tsx:54-68","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:30Z","created_by":"Jacob Cole","updated_at":"2026-05-31T12:22:41Z","closed_at":"2026-05-31T12:22:41Z","close_reason":"Shipped in openchat-mobile commit on main. Build 18 incoming.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-240","title":"QR code to invite to group chat","description":"Group-invite QR / link flow. Unified with QR1 scanner (same camera UI; payload path discriminates user-vs-invite).\n\nPAYLOAD: openchat://invite/\u003ctoken\u003e (also https://chat.globalbr.ai/i/\u003ctoken\u003e)\n\nSERVER (new):\n- Node :GroupInvite {token, conversationId, createdBy, createdAt, expiresAt, usesLeft, revokedAt}\n- (c:Conversation)-[:HAS_INVITE]-\u003e(:GroupInvite)\n- POST /api/chat/conversations/:id/invites β€” OWNER ONLY. Returns {token, url, expiresAt, usesLeft}. Defaults: 7d expiry, 50 uses.\n- GET /api/chat/invites/:token β€” authed; returns {conversationId, conversationTitle, memberCount, expiresAt}. No participant PII.\n- POST /api/chat/invites/:token/accept β€” authed; MERGE caller as PARTICIPATES_IN with role='member', decrement usesLeft, emit 'participant:added'.\n- DELETE /api/chat/conversations/:id/invites/:token β€” owner only, revokes.\n\nMOBILE:\n- GroupSettingsScreen: 'Invite via QR / link' button (owner-only). Modal shows QR + 'Copy link' + 'Revoke'.\n- Shared QR scanner from QR1 routes invite tokens here; show confirm screen then call accept.\n\nACCEPTANCE:\n- [ ] Owner can create an invite link, share it, and another user can join by scanning/tapping\n- [ ] Non-owners CANNOT create invites (403)\n- [ ] Expired/revoked/depleted tokens return 410 Gone\n- [ ] Invite preview shows title + member count but no PII beyond that\n- [ ] Joining emits participant:added so existing members refresh in real time\n- [ ] Web (chat.globalbr.ai) honors /i/\u003ctoken\u003e\n\nDEPENDS ON: QR1 (shared scanner)","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:06Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:50:36Z","started_at":"2026-06-01T05:44:25Z","closed_at":"2026-06-01T05:50:36Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-240","depends_on_id":"OpenChat-wtb","type":"blocks","created_at":"2026-05-31T06:20:03Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-240","title":"QR code to invite to group chat","description":"Group-invite QR / link flow. Unified with QR1 scanner (same camera UI; payload path discriminates user-vs-invite).\n\nPAYLOAD: openchat://invite/\u003ctoken\u003e (also https://chat.globalbr.ai/i/\u003ctoken\u003e)\n\nSERVER (new):\n- Node :GroupInvite {token, conversationId, createdBy, createdAt, expiresAt, usesLeft, revokedAt}\n- (c:Conversation)-[:HAS_INVITE]-\u003e(:GroupInvite)\n- POST /api/chat/conversations/:id/invites β€” OWNER ONLY. Returns {token, url, expiresAt, usesLeft}. Defaults: 7d expiry, 50 uses.\n- GET /api/chat/invites/:token β€” authed; returns {conversationId, conversationTitle, memberCount, expiresAt}. No participant PII.\n- POST /api/chat/invites/:token/accept β€” authed; MERGE caller as PARTICIPATES_IN with role='member', decrement usesLeft, emit 'participant:added'.\n- DELETE /api/chat/conversations/:id/invites/:token β€” owner only, revokes.\n\nMOBILE:\n- GroupSettingsScreen: 'Invite via QR / link' button (owner-only). Modal shows QR + 'Copy link' + 'Revoke'.\n- Shared QR scanner from QR1 routes invite tokens here; show confirm screen then call accept.\n\nACCEPTANCE:\n- [ ] Owner can create an invite link, share it, and another user can join by scanning/tapping\n- [ ] Non-owners CANNOT create invites (403)\n- [ ] Expired/revoked/depleted tokens return 410 Gone\n- [ ] Invite preview shows title + member count but no PII beyond that\n- [ ] Joining emits participant:added so existing members refresh in real time\n- [ ] Web (chat.globalbr.ai) honors /i/\u003ctoken\u003e\n\nDEPENDS ON: QR1 (shared scanner)","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:06Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:50:36Z","started_at":"2026-06-01T05:44:25Z","closed_at":"2026-06-01T05:50:36Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-240","depends_on_id":"OpenChat-wtb","type":"blocks","created_at":"2026-05-31T06:20:03Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-wtb","title":"QR code to add user (mobile)","description":"Show-my-QR on Settings + scan-QR flow that opens/creates a 1:1 DM with the scanned user.\n\nPAYLOAD: openchat://user/\u003cuserId\u003e?v=1 (also resolvable as https://chat.globalbr.ai/u/\u003cuserId\u003e)\n\nNO signed token in v1 β€” user IDs are already enumerable via GET /api/chat/contacts (server/src/routes/chat.ts:610). Revisit signing when a real friend-graph privacy model exists.\n\nUI:\n- Settings: 'My QR code' row β†’ fullscreen modal rendering QR via react-native-qrcode-svg\n- Settings: 'Scan QR' row β†’ expo-camera scanner screen\n- NewConversationScreen empty state: secondary 'Scan QR' button\n\nSCAN HANDLER:\n- Parse openchat://user/\u003cid\u003e β†’ call api.createConversation({type:'direct', participants:[id]}) (already idempotent)\n- Parse openchat://invite/\u003ctoken\u003e β†’ defer to OpenChat-QR2 (group invite)\n- Anything else β†’ toast 'Not a valid OpenChat code'\n\nDEPS TO ADD: expo-camera (~latest stable \u003e1mo old), react-native-qrcode-svg\nNO server changes required for v1.\n\nACCEPTANCE:\n- [ ] Settings has 'My QR code' showing a scannable QR encoding my user id\n- [ ] Settings has 'Scan QR' opening expo-camera scanner\n- [ ] Scanning another user's QR opens the 1:1 chat with them\n- [ ] Scanning a malformed/unknown QR shows a non-fatal error\n- [ ] Works on iOS (TestFlight) and the RN-web /m/ build (web fallback: paste URL)","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:18:58Z","created_by":"Jacob Cole","updated_at":"2026-05-31T20:24:49Z","started_at":"2026-05-31T20:21:25Z","closed_at":"2026-05-31T20:24:49Z","close_reason":"Closed","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"OpenChat-jvh","title":"[desktop /d/] Polish: max-width on chat pane + collapsible sidebar + keyboard shortcuts","description":"Today /d/ has master-detail layout but no max-width on the chat pane, so on wide monitors messages stretch edge-to-edge (ugly). Standard chat-app patterns to add:\n\n1. Max-width on message column: messages capped at ~720px so text doesn't span entire screen on wide monitors\n2. Padded gutters: content stays centered within the chat pane when window is very wide\n3. Optional sidebar collapse: tap an icon to hide the sidebar entirely β†’ chat pane gets full width (still capped). Discord pattern.\n4. Keyboard shortcuts (Cmd-K already added for search; add: Cmd-N for new conv, Cmd-/ for help/shortcuts list, j/k or ↑/↓ to navigate conversation list)\n\nLives on the desktop-responsive branch of openchat-mobile, deployed at chat.globalbr.ai/d/. Touch src/components/MasterDetailLayout.tsx and ChatPane.tsx primarily.\n\nAcceptance: open /d/ on a 1440px+ monitor. Message bubbles in a conversation are bounded ~720px wide, centered. Sidebar can collapse to icon-only mode. Cmd-K opens search modal. The same view at 768px width falls back to mobile stack layout (existing behavior).","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T11:15:48Z","created_by":"Jacob Cole","updated_at":"2026-05-31T11:21:27Z","started_at":"2026-05-31T11:17:02Z","closed_at":"2026-05-31T11:21:27Z","close_reason":"Landed on desktop-responsive in openchat-mobile-desktop (commit 193ce5e). Max-width 720px on chat bubbles + composer; collapsible sidebar 320\u003c-\u003e56 with AsyncStorage persistence under openchat_sidebar_collapsed; web shortcuts Cmd-N (+ Cmd-Shift-O fallback) / Cmd-, / Cmd-/ in addition to existing Cmd-K. tsc --noEmit clean; expo export --platform web succeeds. Deploy left to Jacob.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-2xf","title":"[mobile] WhatsApp-style sender identification in group chats","description":"In a group chat with multiple participants, it should be obvious who sent each message. Today on mobile (ChatScreen.tsx) we show 'sender name' on the first message of a run from a given author, but the styling is subtle.\n\nDesired (WhatsApp pattern):\n- Colored sender name above each non-own message in groups (each person gets a stable color derived from their userId β€” e.g. a hash β†’ hue)\n- Avatar shown to the LEFT of each non-own bubble (small, 28-32px), only on the LAST message of a run (so consecutive messages from the same person have ONE avatar at the bottom)\n- Own messages stay right-aligned, no name shown, no avatar\n- In DMs, no sender name (it's always the other person)\n\nImplementation:\n- New utility colorForUserId(id: string) -\u003e string (deterministic hash β†’ HSL hue, fixed S/L per scheme so colors don't clash with the dark/light theme)\n- Update src/screens/ChatScreen.tsx renderItem: for non-own group messages, show colored sender name above first-of-run; show avatar to the left on last-of-run\n- Web client should get the same treatment in client/src/components/MessageList.tsx (file a sibling ticket if scope grows)\n\nAcceptance: in a 3+ person group chat on iPhone, glanceably tell who said what; consecutive messages from the same person don't repeat sender chrome; colors are consistent for a given person across app sessions.","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T09:52:28Z","created_by":"Jacob Cole","updated_at":"2026-05-31T10:08:57Z","started_at":"2026-05-31T10:05:00Z","closed_at":"2026-05-31T10:08:57Z","close_reason":"Added src/utils/colorForUserId.ts (deterministic FNV-1a -\u003e HSL hue per userId, scheme-tuned S/L). ChatScreen renders sender name in that color for non-own messages in group chats, and shows a small 28px avatar to the left of the bubble on the last message of each run (with a reserved-width slot keeping non-last rows aligned). DMs unchanged, own messages unchanged. Committed d879e40 on openchat-mobile/main.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-wra","title":"[mobile] Rename group chat: option missing / not available on mobile","description":"On the iOS app (and likely RN-web /m), the option to rename a group conversation appears to be missing or not active when expected. Web client has this in GroupSettings.tsx (owner-only edit field for conversation.title).\n\nMobile equivalent is src/screens/GroupSettingsScreen.tsx. It does have a draftTitle TextInput, but it may be: (a) disabled when it shouldn't be, (b) not accessible from the chat header on mobile, or (c) not reactive to ownership state changes.\n\nVerify what is actually broken:\n- Is GroupSettingsScreen reachable on mobile? (Tappable header on group conversation)\n- Is the title TextInput enabled for the owner?\n- Does the save (onBlur / onSubmitEditing) actually fire?\n- Does the renamed title propagate to other participants in real-time (server emits conversation:updated)?\n\nAcceptance: as the group owner on the iOS app, tap the chat header, edit the group name, see the new name immediately on your phone AND propagate to other devices/users in the group within ~2 seconds.","status":"closed","priority":2,"issue_type":"bug","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T09:52:28Z","created_by":"Jacob Cole","updated_at":"2026-05-31T10:08:55Z","started_at":"2026-05-31T10:05:00Z","closed_at":"2026-05-31T10:08:55Z","close_reason":"Rename pipeline was actually working end-to-end (TextInput -\u003e renameConversation -\u003e API -\u003e conversation:updated socket -\u003e ChatContext -\u003e header/list re-render). The reported issue was discoverability: save only fired on onBlur/onSubmitEditing with no visible commit affordance or feedback. Added explicit Save button (enabled when dirty) + success Alert + clearer section label + dimmed input for non-owners. Committed 9f0b9f1 on openchat-mobile/main.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-sgb","title":"[openchat-agent] Production deploy: parallel-bot or swap-out","description":"openchat-agent ready to deploy. Two paths in ~/code/openchat-agent/README.md:\n(a) PARALLEL: new :User node (e.g. picortex2@bot.globalbr.ai), test live, retire picortex when verified. Pros: zero downtime, clean rollback.\n(b) SWAP-OUT: stop picortex on picortex-v1, start openchat-agent with same JWT + bot user. Pros: clean. Cons: in-flight conv contexts re-read from API anyway.\nRecommend (b). Need: scp dist + .env to host (picortex-v1 or new VM), systemd unit, watch ~5 message:new events.","status":"open","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T07:02:31Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:31Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.5","title":"[next] Open design questions for Thoughts (Q1-Q5)","description":"Five design questions still unresolved after the 2026-05-30 design conversation. See ~/code/openchat/docs/thoughts-design.md for full context.\n\nQ1 β€” Should open-threads-with-others ('I owe Eric a reply') be optionally visible to that other person? Visibility-set model supports it trivially; question is whether to ship the share-affordance + the social posture. Leaning opt-in shareable, default private. Needs Jacob's call.\n\nQ2 β€” Relationship between OpenChat Thoughts and the existing Thoughtstreams app (ts.globalbr.ai). Three options:\n (a) Completely separate products\n (b) Same data store, two views (most elegant; needs schema alignment)\n (c) Thoughts is OpenChat-only, Thoughtstreams untouched (cheapest)\n\nQ3 β€” When user summons an agent (picortex etc) in a chat, can the agent read user's Thoughts? Needed for agent-driven time-shifted surfacing. Requires new permission scope { personal: bool, conversations: [...] } with explicit consent on first invocation. Privacy implication: prompt injection could leak thoughts; agents must cite ('I recall…') not verbatim-quote.\n\nQ4 β€” Citation / leak posture for bot replies that use memories or thoughts. Should be a hard rule in picortex's reply pipeline: reference, not verbatim-quote.\n\nQ5 β€” When user leaves a group: do thoughts they authored visible-to-that-group stay visible to remaining members? Instinct yes (parity with chat messages) but unconfirmed.\n\nACTION: each Q gets discussed with Jacob then resolved into the design doc + appropriate sub-ticket. Close this ticket when all five have answers in the design doc.","status":"open","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:38Z","created_by":"Jacob Cole","updated_at":"2026-05-31T02:56:38Z","dependencies":[{"issue_id":"OpenChat-3kr.5","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T20:56:38Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.5","title":"[next] Open design questions for Thoughts (Q1-Q5)","description":"Five design questions still unresolved after the 2026-05-30 design conversation. See ~/code/openchat/docs/thoughts-design.md for full context.\n\nQ1 β€” Should open-threads-with-others ('I owe Eric a reply') be optionally visible to that other person? Visibility-set model supports it trivially; question is whether to ship the share-affordance + the social posture. Leaning opt-in shareable, default private. Needs Jacob's call.\n\nQ2 β€” Relationship between OpenChat Thoughts and the existing Thoughtstreams app (ts.globalbr.ai). Three options:\n (a) Completely separate products\n (b) Same data store, two views (most elegant; needs schema alignment)\n (c) Thoughts is OpenChat-only, Thoughtstreams untouched (cheapest)\n\nQ3 β€” When user summons an agent (picortex etc) in a chat, can the agent read user's Thoughts? Needed for agent-driven time-shifted surfacing. Requires new permission scope { personal: bool, conversations: [...] } with explicit consent on first invocation. Privacy implication: prompt injection could leak thoughts; agents must cite ('I recall…') not verbatim-quote.\n\nQ4 β€” Citation / leak posture for bot replies that use memories or thoughts. Should be a hard rule in picortex's reply pipeline: reference, not verbatim-quote.\n\nQ5 β€” When user leaves a group: do thoughts they authored visible-to-that-group stay visible to remaining members? Instinct yes (parity with chat messages) but unconfirmed.\n\nACTION: each Q gets discussed with Jacob then resolved into the design doc + appropriate sub-ticket. Close this ticket when all five have answers in the design doc.","status":"open","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:38Z","created_by":"Jacob Cole","updated_at":"2026-05-31T02:56:38Z","dependencies":[{"issue_id":"OpenChat-3kr.5","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T20:56:38Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-kma","title":"Search: messages, contacts, conversations","description":"No search anywhere right now. At minimum need: (a) sidebar search by conversation title / participant name on web + mobile. (b) inside a conversation, search messages in this thread. (c) global Cmd-K search across messages + contacts. Server: GET /api/chat/search?q=\u0026scope=conversation|thread|global with Neo4j full-text index on Message.content + User.name. Web first, mobile follows. Important enough for testers β€” the app feels broken without it once you have 8+ conversations.","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:06Z","created_by":"Jacob Cole","updated_at":"2026-05-31T06:41:57Z","started_at":"2026-05-31T06:32:45Z","closed_at":"2026-05-31T06:41:57Z","close_reason":"Shipped: server GET /api/chat/search (Cypher CONTAINS, gated by PARTICIPATES_IN access check) + web sidebar search panel (commit faa8ea8) + mobile SearchScreen modal (commit a2a02db on openchat-mobile). Three buckets returned together (messages/conversations/contacts) so the UI renders one search panel. Min 2 chars, debounced 300ms, prior results kept visible while typing. Next pass: Neo4j full-text index for performance, scroll-to-message-id on message hit.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-5o0","title":"[mobile] Google sign-in on iOS (parity with web)","description":"The web app at chat.globalbr.ai has Google OAuth sign-in via /api/auth/google/url + /api/auth/google/exchange (epic OpenChat-hwi). Mobile app only has Noos email/password. Wire expo-auth-session/providers/google against the same GCP client (874749606899-..., project boreal-conquest-464203-v2). On success POST the code to /api/auth/google/exchange (same backend route) β€” same JWT comes back. Add Continue with Google button on LoginScreen above the email/password form. Authoritative client secret at M5:~/.config/openchat-accounts.json (mode 600).","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:05Z","created_by":"Jacob Cole","updated_at":"2026-05-31T06:42:05Z","started_at":"2026-05-31T06:32:44Z","closed_at":"2026-05-31T06:42:05Z","close_reason":"Shipped: openchat-mobile commit ff73bc7 wires expo-auth-session/providers/google in LoginScreen using the same GCP client (874749606899-...) as the web app. Auth code POSTs to /api/auth/google/exchange (same server endpoint web uses, no server changes needed). FOLLOW-UP REQUIRED before iOS native works end-to-end: add 'com.jacobcole.openchat:/oauth2redirect' to authorized redirect URIs on the GCP OAuth client in project boreal-conquest-464203-v2 β€” otherwise iOS gets redirect_uri_mismatch from Google. Web flow unchanged.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.1","title":"[next] Thoughts tab in OpenChat (web + mobile): notes feed alongside chats","description":"Add a second top-level tab/section to OpenChat (web sidebar + mobile bottom-tab) called 'Thoughts' (or similar). Stream of the user's: ad-hoc notes captured from any context, links to their open beads issues, persistent memories (bd memories), and contextual snippets. Feed shape mirrors Thoughtstreams. Each item can be referenced into a chat message. Goal: tighter loop between thinking solo and sharing thinking with others/agents. Web: new route /thoughts. Mobile: bottom tab bar replacing the current single-stack root.","status":"open","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:21Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:21Z","dependencies":[{"issue_id":"OpenChat-3kr.1","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:21Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.1","title":"[next] Thoughts tab in OpenChat (web + mobile): notes feed alongside chats","description":"Add a second top-level tab/section to OpenChat (web sidebar + mobile bottom-tab) called 'Thoughts' (or similar). Stream of the user's: ad-hoc notes captured from any context, links to their open beads issues, persistent memories (bd memories), and contextual snippets. Feed shape mirrors Thoughtstreams. Each item can be referenced into a chat message. Goal: tighter loop between thinking solo and sharing thinking with others/agents. Web: new route /thoughts. Mobile: bottom tab bar replacing the current single-stack root.","status":"open","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:21Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:21Z","dependencies":[{"issue_id":"OpenChat-3kr.1","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:21Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-3kr","title":"[epic] OpenChat next: thought-stream tab + agentic + NVC","description":"The bigger redesign work, captured 2026-05-30 from Jacob: OpenChat grows a SECOND TAB next to chats β€” a thought-stream feed of the user's notes, beads issues, persistent memories, captured ideas. Same UX shape as Thoughtstreams (ideaflow ts.globalbr.ai) but contextualized by the user's chat life. Plus deeper agentic features (bot-summoning, automation flows, agents that watch streams) and an NVC (Non-Violent Communication) composer mode. Work lives on the 'next' branch in both openchat and openchat-mobile repos; worktrees at ~/code/openchat-next and ~/code/openchat-mobile-next. Main keeps shipping polish to chat.globalbr.ai + TestFlight.","notes":"DESIGN DOC: ~/code/openchat/docs/thoughts-design.md (source of truth)\nRAW TRANSCRIPT: ~/memory/research/2026-05-30-openchat-thoughts-design-conversation.md\n\nDECISIONS RESOLVED 2026-05-30:\nD1 β€” one stream + filter chip for status-having items, no separate tab\nD2 β€” bd issues are a toggleable source, not killed; default off, Jacob default on\nD3 β€” visibility set model (author immutable, visibility:Set\u003cUser|Conv\u003e), not hard scope\nD4 β€” v1 = manual notes + LLM extraction from chats; bd sync deferred to v1.1\nD5 β€” kind taxonomy: fact / decision / commitment / reminder / observation\nD6 β€” open-threads-to-self flow into personal stream by default with conv-id ref\nD7 β€” real-time: v1 5-min cron, v1.5 bd hooks, v2 socket.io fan-out\nD8 β€” source toggles default: note:on memory:on issue:off snippet:on; Jacob: issue:on\n\nDIFFERENTIATING MOVES (the actually-novel features, not just notes-tab):\n1. LLM extraction from chats with 'add to thoughts?' suggestions\n2. Time-shifted contextual surfacing (chat header shows 'recent context')\n3. Compose-from-thoughts (multi-select β†’ LLM drafts a message)\n4. Peer-to-peer thought sharing (not just chat-sharing)\n\nOPEN QUESTIONS still unresolved β€” see OpenChat-3kr.5 ticket.","status":"open","priority":2,"issue_type":"epic","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:20Z","created_by":"Jacob Cole","updated_at":"2026-05-31T02:56:37Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-hwi.3","title":"Config: wire GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET into server env","description":"Update server/.env.example with GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI placeholders. Update docker-compose.prod.yml to forward these env vars into the noos_api container (same pattern as VAPID vars). Set actual values in production env file. Document where the values come from (M5:~/.config/openchat-accounts.json).","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:53Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:16Z","closed_at":"2026-05-30T16:03:16Z","close_reason":"server/.env.example updated with GOOGLE_CLIENT_ID/SECRET placeholders, docker-compose.prod.yml forwards them with same pattern as VAPID vars, local server/.env created (mode 600, gitignored).","dependencies":[{"issue_id":"OpenChat-hwi.3","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:52Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-hwi.4","title":"GCP OAuth client: fix redirect URIs (29231 for dev, chat.globalbr.ai for prod)","description":"Current OAuth client (874749606899-...) has redirect URIs http://localhost:5173/auth/google/callback and https://globalbr.ai/api/auth/google/callback. These do NOT match OpenChat's actual hosts β€” dev is localhost:29231 (per vite.config.ts), prod frontend is chat.globalbr.ai. Use the Mac mini β†’ M5 aqua tmux Chrome bridge to ADD http://localhost:29231/auth/google/callback and https://chat.globalbr.ai/auth/google/callback. Keep the existing entries (Noos may still use them).","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:53Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:16Z","started_at":"2026-05-30T15:56:59Z","closed_at":"2026-05-30T16:03:16Z","close_reason":"Added http://localhost:29231 (JS origin), http://localhost:29231/auth/google/callback and https://chat.globalbr.ai/auth/google/callback (redirect URIs) to client 874749606899-f2epm744j73anm2dnf59j6igehhlku0a via M5 aqua tmux Chrome bridge. Verified by reopening client and reading page text.","dependencies":[{"issue_id":"OpenChat-hwi.4","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:53Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-hwi.2","title":"Frontend: Google sign-in button + callback page","description":"Add 'Continue with Google' button on LoginPage. New route /auth/google/callback parses code+state, POSTs to backend exchange endpoint via api.googleExchange, sets token+user, navigates to redirect target. Add VITE_GOOGLE_CLIENT_ID to client env (not strictly required if backend builds the URL, but useful for one-tap upgrade later). Follows existing SSOCallback shape.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:52Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:15Z","closed_at":"2026-05-30T16:03:15Z","close_reason":"Implemented (client/src/App.tsx + ChatContext.tsx + api.ts). Build clean, Google button + /auth/google/callback route both wired.","dependencies":[{"issue_id":"OpenChat-hwi.2","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:51Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-hwi.1","title":"Backend: Google OAuth endpoints (auth URL + code exchange)","description":"Add two server routes: GET /api/auth/google/url returns the Google authorization URL with state+scopes, and POST /api/auth/google/exchange exchanges code for Google tokens, fetches userinfo, MERGEs the User in Neo4j by email, returns OpenChat JWT in the existing shape. Env: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI. Reuse jwt secret + nanoid pattern from /api/auth/dev-login.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:51Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:14Z","started_at":"2026-05-30T15:56:58Z","closed_at":"2026-05-30T16:03:14Z","close_reason":"Implemented in commit (server/src/routes/auth.ts: GET /api/auth/google/url + POST /api/auth/google/exchange). Smoke test passes 13/13 checks against real Google endpoint.","dependencies":[{"issue_id":"OpenChat-hwi.1","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:50Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-hwi.3","title":"Config: wire GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET into server env","description":"Update server/.env.example with GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI placeholders. Update docker-compose.prod.yml to forward these env vars into the noos_api container (same pattern as VAPID vars). Set actual values in production env file. Document where the values come from (M5:~/.config/openchat-accounts.json).","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:53Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:16Z","closed_at":"2026-05-30T16:03:16Z","close_reason":"server/.env.example updated with GOOGLE_CLIENT_ID/SECRET placeholders, docker-compose.prod.yml forwards them with same pattern as VAPID vars, local server/.env created (mode 600, gitignored).","dependencies":[{"issue_id":"OpenChat-hwi.3","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:52Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-hwi.4","title":"GCP OAuth client: fix redirect URIs (29231 for dev, chat.globalbr.ai for prod)","description":"Current OAuth client (874749606899-...) has redirect URIs http://localhost:5173/auth/google/callback and https://globalbr.ai/api/auth/google/callback. These do NOT match OpenChat's actual hosts β€” dev is localhost:29231 (per vite.config.ts), prod frontend is chat.globalbr.ai. Use the Mac mini β†’ M5 aqua tmux Chrome bridge to ADD http://localhost:29231/auth/google/callback and https://chat.globalbr.ai/auth/google/callback. Keep the existing entries (Noos may still use them).","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:53Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:16Z","started_at":"2026-05-30T15:56:59Z","closed_at":"2026-05-30T16:03:16Z","close_reason":"Added http://localhost:29231 (JS origin), http://localhost:29231/auth/google/callback and https://chat.globalbr.ai/auth/google/callback (redirect URIs) to client 874749606899-f2epm744j73anm2dnf59j6igehhlku0a via M5 aqua tmux Chrome bridge. Verified by reopening client and reading page text.","dependencies":[{"issue_id":"OpenChat-hwi.4","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:53Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-hwi.2","title":"Frontend: Google sign-in button + callback page","description":"Add 'Continue with Google' button on LoginPage. New route /auth/google/callback parses code+state, POSTs to backend exchange endpoint via api.googleExchange, sets token+user, navigates to redirect target. Add VITE_GOOGLE_CLIENT_ID to client env (not strictly required if backend builds the URL, but useful for one-tap upgrade later). Follows existing SSOCallback shape.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:52Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:15Z","closed_at":"2026-05-30T16:03:15Z","close_reason":"Implemented (client/src/App.tsx + ChatContext.tsx + api.ts). Build clean, Google button + /auth/google/callback route both wired.","dependencies":[{"issue_id":"OpenChat-hwi.2","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:51Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-hwi.1","title":"Backend: Google OAuth endpoints (auth URL + code exchange)","description":"Add two server routes: GET /api/auth/google/url returns the Google authorization URL with state+scopes, and POST /api/auth/google/exchange exchanges code for Google tokens, fetches userinfo, MERGEs the User in Neo4j by email, returns OpenChat JWT in the existing shape. Env: GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI. Reuse jwt secret + nanoid pattern from /api/auth/dev-login.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:51Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:03:14Z","started_at":"2026-05-30T15:56:58Z","closed_at":"2026-05-30T16:03:14Z","close_reason":"Implemented in commit (server/src/routes/auth.ts: GET /api/auth/google/url + POST /api/auth/google/exchange). Smoke test passes 13/13 checks against real Google endpoint.","dependencies":[{"issue_id":"OpenChat-hwi.1","depends_on_id":"OpenChat-hwi","type":"parent-child","created_at":"2026-05-30T09:56:50Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-hwi","title":"[epic] Google OAuth sign-in for OpenChat","description":"Add Google as a sign-in / sign-up provider for OpenChat, in addition to the existing Noos SSO and dev-login paths. OAuth 2.0 Web Client already created in GCP project boreal-conquest-464203-v2 (clientId 874749606899-f2epm744j73anm2dnf59j6igehhlku0a; secret stored at M5:~/.config/openchat-accounts.json). End state: a 'Continue with Google' button on the LoginPage that completes a sign-up or sign-in in one flow and lands users in the chat.","status":"closed","priority":2,"issue_type":"epic","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-30T15:56:36Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:10:15Z","started_at":"2026-05-30T15:56:57Z","closed_at":"2026-05-30T16:10:15Z","close_reason":"Shipped to prod. End-to-end Google sign-up verified through M5 Chrome bridge: logged out previous user β†’ clicked Continue with Google on chat.globalbr.ai β†’ Google chooser β†’ picked tmad4000@gmail.com β†’ consent (openid/email/profile only, no surprise scopes) β†’ redirected back β†’ chat UI loaded with new user session. Backend, frontend, env wiring, GCP redirect URIs, prod deploy all clean. 13/13 unit smoke + 1 real e2e all green.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-su5","title":"[Mobile] Ship openchat-mobile RN app to TestFlight","description":"Get the Expo SDK 54 React Native scaffold of OpenChat into TestFlight via EAS Build + EAS Submit. Reference: murmur testflight.sh pattern at ~/code/murmur/scripts/testflight.sh on M5 β€” uses Team ID JESMXK96LG, ASC API key KWJX4896S5, asc_app.py to create the App Store Connect app record.\\n\\nDifferences vs Murmur:\\n- Murmur is native Swift; openchat-mobile is Expo RN. Use EAS Build cloud (not local xcodebuild).\\n- Bundle ID: app.com.jacobcole.openchat (to align with com.jacobcole.murmur convention).\\n- eas submit will upload to ASC + TestFlight automatically.\\n\\nSteps:\\n1. rsync ~/code/openchat-mobile from Mac mini to M5\\n2. Install eas-cli on M5\\n3. Set bundle ID + name in app.json\\n4. eas build:configure to generate eas.json (production profile + ios distribution)\\n5. eas build --platform ios --profile production (cloud)\\n6. eas submit --platform ios (uploads to TestFlight)\\n\\nApple Developer Team: JESMXK96LG (IdeaFlow, Inc.).\\nASC API key: ~/.appstoreconnect/private_keys/AuthKey_KWJX4896S5.p8 on M5.\\nExpo account: already authenticated at M5 ~/.expo/state.json.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-30T13:21:05Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:21:18Z","started_at":"2026-05-30T13:21:11Z","closed_at":"2026-05-30T16:21:18Z","close_reason":"TestFlight first build SHIPPED. EAS build 3 (v0.1.0) uploaded to App Store Connect via 'eas submit', Apple processed (state=VALID), beta review submitted (state=WAITING_FOR_REVIEW). Internal 'Founders' group + external 'Friends and Family' group created. Both tmad4000@gmail.com and srini.spagidyala@gmail.com added as external testers β€” they receive TestFlight invite emails as soon as Apple approves the beta review (~24h). Jacob also has ADMIN access on team JESMXK96LG so he can install via the App Store Connect mobile app immediately without waiting.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-bo6","title":"register() and ssoExchange() drop refreshToken from the return β€” session is non-refreshable from birth","description":"client/src/api.ts:240-269 (register) and 293-324 (ssoExchange) destructure { accessToken, user } from the Noos response and don't include refreshToken. Caller in ChatContext.noosRegister / ssoLogin can't persist it, so localStorage.openchat_refresh_token is never set for those auth paths.\n\nConsequence: users who registered via Noos OR signed in via SSO (the 'Continue with Noos' button on chat.globalbr.ai) get a session that can never refresh. Their first 401 β†’ can't refresh β†’ forced logout. Only password-login users currently get refresh.\n\nFix: in stash@{0} β€” both methods return { token, refreshToken, user } and the ChatContext call sites localStorage.setItem('openchat_refresh_token', result.refreshToken). Could be cherry-picked from the bigger 401 fix.","status":"closed","priority":2,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-05-30T12:13:53Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:28:53Z","closed_at":"2026-05-30T16:28:53Z","close_reason":"Shipped in eff5ca1 β€” 401 cascade fix from stash@{2} re-applied on top of Google OAuth merge, conflicts resolved, build clean. Includes single-flight refresh, refresh-loop guard, refreshToken persistence in register/ssoExchange (-bo6), getMe URL fix (-924), trust-proxy for express (-9jm), dismissible toast helper. Google OAuth smoke test 13/13 still green.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-dpy","title":"[UX] Dark mode for OpenChat web app","description":"Add proper dark mode to OpenChat's web client. The app is currently bg-white / text-gray-900 across all surfaces β€” fine in daylight, harsh at night, and obviously not parity with the iMessage / WhatsApp / Telegram default that users expect.\\n\\n## Approach\\n- Enable Tailwind dark mode: 'class' strategy in tailwind.config.js (not 'media' β€” we want user override, not system-only).\\n- Toggle in user menu (ChatSidebar's user dropdown): Light / Dark / System. Default 'System'.\\n- Persist choice in localStorage 'openchat_theme'. On boot, main.tsx applies the saved/derived class to \u003chtml\u003e.\\n- React to system pref changes (matchMedia('(prefers-color-scheme: dark)').addEventListener) when in System mode.\\n- Update the existing \u003cmeta name='theme-color'\u003e from #3b82f6 to also have a dark variant (use media-attribute form: \u003cmeta name='theme-color' content='#1e293b' media='(prefers-color-scheme: dark)'\u003e) so the iOS Safari URL-bar tints correctly.\\n- Update manifest.webmanifest theme_color + background_color to have light/dark counterparts where browsers support it (only some do; safe to keep current light defaults).\\n\\n## Files to audit for hardcoded colors\\nEvery component that currently uses bg-white / bg-gray-50 / text-gray-* / border-gray-* needs dark: variants. Inventory from grep:\\n- client/src/pages/ChatPage.tsx (bg-gray-50 outer, header bg-white)\\n- client/src/components/ChatSidebar.tsx (bg-white, gray borders, status dropdown)\\n- client/src/components/ConversationList.tsx\\n- client/src/components/MessageList.tsx (bg-blue-500 own bubbles -\u003e stays; bg-gray-100 other bubbles -\u003e dark:bg-gray-700; text-gray-900 -\u003e dark:text-gray-100)\\n- client/src/components/MessageInput.tsx (bg-white form, border-gray-200, border-gray-300 input)\\n- client/src/components/GroupSettings.tsx (modal bg-white)\\n- client/src/components/PresenceIndicator.tsx (presence dot colors β€” likely keep)\\n- client/src/components/InstallPrompt.tsx (sheet bg-white)\\n- client/src/App.tsx Toaster (already uses bg-red-100 / bg-green-100 β€” those work in both modes but darker variants would be cleaner)\\n- client/src/index.css base body bg\\n- The Noos feedback widget is 3rd-party; can't directly themed. data-theme='auto' is already set in index.html so it should respect prefers-color-scheme automatically.\\n\\n## UX details\\n- Switch should be near-instant (no flash of unstyled content). Apply theme class BEFORE React mounts β€” in a small inline \u003cscript\u003e in index.html that reads localStorage and applies the class to \u003chtml\u003e synchronously.\\n- Bubble color choice for dark mode: own messages stay blue, others go to dark-gray (e.g. bg-slate-700). Sender-name labels go to slate-400.\\n- Status indicators (green/yellow/red/gray dots) stay the same vivid colors in both modes.\\n- Floating Noos widget data-theme='auto' should pick up the change.\\n\\n## Acceptance\\n- Toggle in user menu works (Light / Dark / System).\\n- System mode tracks OS preference live (no reload needed).\\n- No flash of light theme on dark-mode-saved cold load.\\n- All conversation surfaces (list / chat / group settings modal / install prompt / login) look polished in dark.\\n- iOS Safari URL-bar tints with the theme.\\n\\n## Phase\\nPhase 1 polish β€” chunky-but-not-blocking. Ship before declaring mobile UX 'done.' Roughly half a day of careful component-by-component audit + a couple of hours for the theme toggle infrastructure.","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T11:36:18Z","created_by":"Jacob Cole","updated_at":"2026-06-04T22:36:21Z","closed_at":"2026-06-04T22:36:21Z","close_reason":"Done by web agent + merged to main (3402be8): edit/delete+action menu, reply/quote, reactions, read receipts+unread badges, dark mode (light/system/dark toggle), contacts directory. Build green; deploying.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-0jy","title":"[Group chat] @-mentions: parsing, autocomplete, highlight, notifications","description":"Group conversations are noisy without mentions. Implement: @ trigger in MessageInput opens autocomplete of conversation participants, mention is stored as a structured token in the message (e.g. \u003c@userId\u003e) so it survives display name changes, MessageList renders mentions as styled chips, mentioned users get a notification/unread bump even if conversation is muted. Files: client/src/components/MessageInput.tsx, MessageList.tsx, server/src/routes/chat.ts (notification logic), server/src/socket/chatHandler.ts.","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:28Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:33:37Z","started_at":"2026-06-01T05:28:32Z","closed_at":"2026-06-01T05:33:37Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-0jy","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:26Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-6ha","title":"[Mobile] PWA manifest + installable on iOS/Android","description":"No manifest.webmanifest or service worker. Add: manifest with name/icons/theme-color/display=standalone, apple-touch-icon, basic service worker for offline shell + asset caching (vite-plugin-pwa is the easy path). Once installable, the app can sit on the home screen and behave like a native chat app β€” meaningful complement to OpenChat-2om (TestFlight WebView wrapper). Files: client/public/, client/index.html, client/vite.config.ts.","status":"open","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:58Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:09:58Z","dependencies":[{"issue_id":"OpenChat-6ha","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:05Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-xry","title":"[Mobile] Mobile chat view: full-screen + back navigation","description":"On mobile, selecting a conversation should take user to a full-screen chat view with a back button to return to conversation list (rather than splitting the small screen). Pattern: list-detail with stack navigation under md breakpoint. Useful for one-handed use. Files: client/src/pages/ChatPage.tsx, ChatSidebar.tsx.","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:53Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-xry","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:00Z","created_by":"tmad4000","metadata":"{}"},{"issue_id":"OpenChat-xry","depends_on_id":"OpenChat-pmb","type":"blocks","created_at":"2026-04-25T04:11:42Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-0jy","title":"[Group chat] @-mentions: parsing, autocomplete, highlight, notifications","description":"Group conversations are noisy without mentions. Implement: @ trigger in MessageInput opens autocomplete of conversation participants, mention is stored as a structured token in the message (e.g. \u003c@userId\u003e) so it survives display name changes, MessageList renders mentions as styled chips, mentioned users get a notification/unread bump even if conversation is muted. Files: client/src/components/MessageInput.tsx, MessageList.tsx, server/src/routes/chat.ts (notification logic), server/src/socket/chatHandler.ts.","status":"closed","priority":2,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:28Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:33:37Z","started_at":"2026-06-01T05:28:32Z","closed_at":"2026-06-01T05:33:37Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-0jy","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:26Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-6ha","title":"[Mobile] PWA manifest + installable on iOS/Android","description":"No manifest.webmanifest or service worker. Add: manifest with name/icons/theme-color/display=standalone, apple-touch-icon, basic service worker for offline shell + asset caching (vite-plugin-pwa is the easy path). Once installable, the app can sit on the home screen and behave like a native chat app β€” meaningful complement to OpenChat-2om (TestFlight WebView wrapper). Files: client/public/, client/index.html, client/vite.config.ts.","status":"open","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:58Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:09:58Z","dependencies":[{"issue_id":"OpenChat-6ha","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:05Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-xry","title":"[Mobile] Mobile chat view: full-screen + back navigation","description":"On mobile, selecting a conversation should take user to a full-screen chat view with a back button to return to conversation list (rather than splitting the small screen). Pattern: list-detail with stack navigation under md breakpoint. Useful for one-handed use. Files: client/src/pages/ChatPage.tsx, ChatSidebar.tsx.","status":"closed","priority":2,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:09:53Z","created_by":"Jacob Cole","updated_at":"2026-04-25T10:29:17Z","closed_at":"2026-04-25T04:29:17Z","close_reason":"Shipped in v0.2.0: responsive sidebar drawer + mobile stack nav; touch targets / safe-area / iOS keyboard; multi-select group creation; member API with WS participant:added/removed events + auto socket join/leave; group settings panel (rename, add, remove, leave). Build passes. Awaiting deploy to chat.globalbr.ai.","dependencies":[{"issue_id":"OpenChat-xry","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:00Z","created_by":"auto-import","metadata":"{}"},{"issue_id":"OpenChat-xry","depends_on_id":"OpenChat-pmb","type":"blocks","created_at":"2026-04-25T04:11:42Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":2,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-u7c","title":"Noos feedback widget overlaps chat composer / floating UI on chat.globalbr.ai","description":"The Noos feedback widget (added in commit a040211, 2026-01-25) is embedded in client/index.html and renders in the bottom-right of chat.globalbr.ai. Jacob reports it overlaps the chat composer Send button.\n\nFix options:\n1. Bump the widget's CSS bottom offset so it clears the composer (simple, one CSS var)\n2. Hide the widget in the chat route (keep it on /settings etc.)\n3. Move the composer up by env(safe-area-inset-bottom) + 64px fixed floating-UI clearance (same pattern picortex just adopted in commit f74da92)\n\nRecommended: option 1 for the quick fix, option 3 as the defensible long-term posture.\n\nCross-ref: picortex applied the same defensive composer pattern in picortex-4l6 / picortex-npp β€” the CSS var is --bottom-floating-ui-clearance, defaults 0 desktop / 56px mobile.","status":"closed","priority":2,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-04-24T08:22:11Z","created_by":"Jacob Cole","updated_at":"2026-04-24T08:30:15Z","closed_at":"2026-04-24T02:30:15Z","close_reason":"Widget launcher repositioned via data-bottom-offset=80 (acaf45e) + composer pr-20/sm:pr-24 (e5be07a). Confirmed in deployed build: CSS contains padding-right:5rem (.pr-20) and 6rem (.pr-24); widget HTML includes data-bottom-offset=80. Send button is clear of the 48-56px fixed launcher on both mobile (375px) and desktop viewports.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-aoy","title":"[Group chats] Validate picortex bot works in group conversations end-to-end","description":"Sibling of picortex-hal (P2, picortex-side group-chat validation pass). Today picortex is only tested/used in DMs (type: 'direct') on chat.globalbr.ai. The bot auto-joins any conversation it's a participant in via polling GET /api/chat/conversations, but OpenChat may have different routing semantics for group vs direct conversations and there is no 'add bot to group' flow.\n\nScope\n- Verify end-to-end: bot added as participant in a type='group' Conversation, message:new fires for bot on group messages, bot's message:send via socket broadcasts correctly to all group participants.\n- Audit server/src/routes/chat.ts and server/src/websocket/chatHandler.ts for any branch that treats type='group' differently from type='direct' (permission checks, room membership, deduplication, etc.).\n- Test scenarios: (a) bot in group from creation, (b) bot added to existing group after creation, (c) bot removed from group, (d) multiple humans + bot in same group, (e) bot-only messages vs human-to-human messages (discriminate/mention-only behavior).\n\nLikely implementation gaps\n- UI: no 'add bot to group' flow in the OpenChat web client (see OpenChat-88z new-conversation contact picker for nearby UX).\n- Server: no participant:added socket event emitted when a user is added to an existing conversation β€” bot would miss it until next 30s poll (same race as the first-message bug, see sibling ticket 'First message to picortex gets no reply').\n- Server: no discrimination between 'bot should reply to every message in DM' vs 'bot should only reply when mentioned/addressed in group'. Add per-conversation bot-behavior flags (quiet mode, mention-only).\n\nDependencies\n- Blocked-by / related-to: sibling bug ticket 'First message to picortex gets no reply' β€” same discovery race affects newly-added participants in groups.\n- Related: picortex-hal (picortex-side validation pass, P2, filed earlier today)\n- Related: OpenChat-3ld (picortex OpenChatChannel impl) β€” v0.2 bullet already lists 'listen for conversation:added event'; that event should also cover participant:added for groups.\n- Related: OpenChat-8bk (picortex bot user flow)\n\nAcceptance\n- Green e2e: human creates group with bot, sends message, bot receives and replies. Same again after bot is added mid-conversation.\n- Documented bot-behavior defaults for groups (mention-only by default is reasonable).\n- Any server changes land behind feature flag until picortex-hal ships the matching client-side support.","status":"closed","priority":2,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-04-24T03:38:55Z","created_by":"Jacob Cole","updated_at":"2026-05-30T17:11:12Z","closed_at":"2026-05-30T17:11:12Z","close_reason":"Shipped. Server already emits participant:added / conversation:created (confirmed). picortex now LISTENS for them (patched openchat.ts on the VM β€” auto-joins on add, drops on remove) AND routes outbound through the originating channel (fixed dispatcher.ts where every reply was being silently sent through Linq instead of OpenChat β€” the actual cause of 'first message gets no reply'). Verified end-to-end via Chrome bridge: tmad4000 sent 'Reply test 2 β€” say pong', picortex replied 'pong' within seconds. OpenChat web client also renders BotBadge for isBot users in contact picker, sidebar, conversation header, and group settings. Picortex source snapshots saved to /Users/Jacob/code/picortex/deployed-snapshots/2026-05-30-agent-chat-fix/.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-if6","title":"Sync SSO flow with Thoughtstreams / latest Noos pattern","description":"OpenChat SSO diverges from Thoughtstreams:\\n\\n1. Thoughtstreams proxies /api/auth/sso-exchange through its own server; OpenChat calls Noos directly from the browser (cross-origin, requires CORS, leaks Noos URL, bakes in VITE_NOOS_URL at build time). Refactor OpenChat to POST to /api/auth/sso-exchange on its own server and have the server talk to Noos internally via NOOS_API_URL (already in docker-compose). Benefits: no cross-origin fetch, no VITE_NOOS_URL dependency for the exchange path, matches Thoughtstreams.\\n\\n2. Thoughtstreams calls /auth/session-check on load to auto-resume a Noos session. OpenChat does not β€” users must click Continue with Noos even if already signed in on ts.globalbr.ai. Add session-check for true cross-app SSO.\\n\\n3. Consider extracting a shared noos-sso npm module (used by OpenChat, Thoughtstreams, thoughtstream-gemini-jacob) so auth drift stops happening per-app. Tracked under noos-sso-ecosystem epic.","status":"open","priority":2,"issue_type":"feature","created_at":"2026-04-23T22:43:30Z","updated_at":"2026-04-23T22:43:30Z","dependency_count":0,"dependent_count":0,"comment_count":0} @@ -174,23 +177,23 @@ {"_type":"issue","id":"OpenChat-coo","title":"Implement SSO redirect for Thoughtstreams login","description":"Mirror the SSO redirect flow from OpenChat-es7 for Thoughtstreams.\n\nWhen implementing OpenChat SSO redirect, ensure the same pattern works for Thoughtstreams:\n1. User visits Thoughtstreams without auth β†’ redirect to Noos login\n2. Noos authenticates β†’ redirects back to Thoughtstreams with token\n3. Thoughtstreams exchanges token for session\n\nThis should share the same Noos SSO infrastructure.\n\n**Dependency:** Implement after OpenChat-es7 (use it as template)\n**Affects:** Thoughtstreams repo (~/code/Thoughtstreams)","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-21T11:30:25Z","updated_at":"2026-01-24T02:27:31Z","closed_at":"2026-01-23T18:27:31Z","close_reason":"Thoughtstreams SSO implemented in Thoughtstreams-kwu - using same pattern as OpenChat","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-es7","title":"Implement SSO redirect flow for OpenChat login","description":"The OpenChat login page should redirect to Noos for authentication instead of having its own login form.\n\n**Current state**: Uses /api/auth/dev-login for development, placeholder /api/auth/login endpoint exists\n\n**Target flow**:\n1. User visits OpenChat without auth β†’ redirect to Noos login page\n2. After Noos login β†’ redirect back to OpenChat with token (via callback URL)\n3. If already logged in to Noos β†’ seamless redirect with token exchange\n4. Handle ?redirect_uri param to return user to the original OpenChat page they were trying to access\n\n**Implementation**:\n- Standard OAuth/SSO redirect pattern\n- OpenChat frontend: detect no token β†’ redirect to Noos with return URL\n- Noos: add OpenChat to SSO_APPS config\n- OpenChat: /auth/callback route to receive and store token\n- Consider using existing Noos SSO infrastructure","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-21T11:27:14Z","updated_at":"2026-01-22T01:41:35Z","closed_at":"2026-01-21T17:41:35Z","close_reason":"Login now redirects to Noos SSO authorize with state/redirect; callback exchanges code for session.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-ok5","title":"Global tagged-message stream with tag filter (all #tags across all chats)","description":"A broader view (separate button/tab from Thoughts): a stream of ALL tagged messages across all the user's chats, with tag-filter behavior (tap a tag β†’ see everything tagged that way). Distinct from Thoughts (which are the extracted note objects) β€” this is the raw cross-chat tagged-message feed. Jacob: 'literally all stuff that was in all my chats with this tag-filter behavior β€” another feature, add as a button.' Respect access-control (only chats the user is in).","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-08T07:42:28Z","created_by":"tmad4000","updated_at":"2026-06-08T07:42:28Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-j0o.5","title":"Public bot endpoint + agent-to-agent messaging","description":"Per-user public-facing bot endpoint ('message Jacob's assistant') answering only from public/approved info + skills. Agent-to-agent: your assistant @mentions/DMs another's bot; their bot replies under its owner's permission scope. Builds on /api/assistant/forward + @agent (ug6).","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:03Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:03Z","dependencies":[{"issue_id":"openchat-j0o.5","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:03Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-j0o.5","title":"Public bot endpoint + agent-to-agent messaging","description":"Per-user public-facing bot endpoint ('message Jacob's assistant') answering only from public/approved info + skills. Agent-to-agent: your assistant @mentions/DMs another's bot; their bot replies under its owner's permission scope. Builds on /api/assistant/forward + @agent (ug6).","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-05T00:07:03Z","created_by":"tmad4000","updated_at":"2026-06-05T00:07:03Z","dependencies":[{"issue_id":"openchat-j0o.5","depends_on_id":"openchat-j0o","type":"parent-child","created_at":"2026-06-04T17:07:03Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-gp9","title":"Standard chat features missing on BOTH web + mobile","description":"From the 2026-06-04 audit β€” features users expect from iMessage/WhatsApp/Telegram/Signal/Slack that OpenChat lacks entirely (decompose as prioritized): (1) in-conversation search [server scope=conversation exists, unused by both]; (2) archive conversation [no schema]; (3) pin conversation [no schema]; (4) draft persistence per-conversation; (5) shared-media gallery in contact/group profile; (6) non-image file attachments [server MIME allowlist = images+audio only]; (7) group avatar/photo; (8) starred/saved messages; (9) Slack-style threads; (10) arbitrary emoji reactions (currently 6 fixed); (11) delete/leave a DM (only groups today); (12) search hit highlighting/scroll-to-match. Contacts directory tracked separately (openchat-2rn).","status":"open","priority":3,"issue_type":"epic","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:55:29Z","created_by":"tmad4000","updated_at":"2026-06-04T12:55:29Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-69d","title":"Document agent-key minting on the World Issue Tracker site","description":"Per Jacob 2026-06-04: WIT should document how to mint an agent key. Today /about/connect-your-agent is a stub (title only) and register-agent requires a signed-in JWT with no documented self-serve path β€” had to replicate the service-role insert to mint a key headlessly (see bd memory wit-mint-agent-key-headless). Add a connect-your-agent doc page on worldissuetracker.com (mirror OpenChat's /about/connect-your-bot): how to get a JWT / use /account/agent-keys UI, the X-Agent-Key header, write endpoints, scopes. Repo: ~/code/world-issue-tracker (separate project + deploy).","status":"open","priority":3,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:32:58Z","created_by":"tmad4000","updated_at":"2026-06-04T12:32:58Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-1un","title":"Desktop-web: Thoughts tab has no desktop layout (looks mobile-shrunk)","description":"From desktop-UX audit. ThoughtsScreen.tsx has no .web variant/master-detail; on desktop it renders mobile cards full-width + FAB, inconsistent with the Chats master-detail. Fix: desktop Thoughts layout (centered column via MaxWidthContent, or master-detail with an editor pane). A few sessions. Ties to openchat-qjx (label chips).","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:04:59Z","created_by":"tmad4000","updated_at":"2026-06-04T12:04:59Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-9rp","title":"Desktop-web: cap chat line length on wide monitors (wire up MaxWidthContent)","description":"From desktop-UX audit 2026-06-04. MaxWidthContent.tsx (720px cap) is written but imported nowhere; chat bubbles only cap at 78% of pane, so on 1920px+ monitors lines are uncomfortably long. Fix: wrap message list + composer in ChatScreen.tsx with MaxWidthContent behind a desktop/embedded guard (shared mobile+web screen β€” don't affect mobile). ~1 session.","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:04:57Z","created_by":"tmad4000","updated_at":"2026-06-04T12:04:57Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-2fx","title":"Thoughts API uses requireAuth (JWT-only) β€” agents can't read/write Thoughts","description":"GET/POST/PATCH/DELETE /api/thoughts use requireAuth, so oc_ agent keys get 'Invalid or expired token' (chat routes use resolveActor and work). For the 'agents can do everything' goal + the agent-sidebar (oc8.4), Thoughts routes should use resolveActor too. Low-risk swap mirroring chat.ts.","status":"open","priority":3,"issue_type":"bug","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:00:26Z","created_by":"tmad4000","updated_at":"2026-06-04T12:00:26Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"openchat-oc8.4","title":"Agent sidebar: chat-with-your-agent (search history; act on your behalf)","description":"A sidebar/panel to converse with an agent that can: (v1) semantic/keyword search across YOUR message history and answer questions; (future) send messages on your behalf.\n\nIdentity model (Jacob): every user has a bot that represents them and can jump into any chat. Default posting identity is 'as you'; allow 'message as \u003cbot\u003e' explicitly. (Jacob's phrasing: bot can act as you no matter the chat; 'message as me' would be the override vs the bot identity β€” confirm exact default with Jacob.)\n\nDepends on: agent-key/resolveActor (done), message search (exists server-side OpenChat-kma), and a bot-actor posting path (bot users are first-class, OpenChat-aoy). \nPlan only for now; needs Jacob input on identity default + scope. Decompose after design.","notes":"DECISION 2026-06-04: default posting identity = AS THE BOT (clearly-labeled agent/bot identity), with 'message as me' as the explicit override. Transparent to recipients by default.","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:12Z","created_by":"tmad4000","updated_at":"2026-06-04T12:26:53Z","dependencies":[{"issue_id":"openchat-oc8.4","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:11Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"openchat-oc8.4","title":"Agent sidebar: chat-with-your-agent (search history; act on your behalf)","description":"A sidebar/panel to converse with an agent that can: (v1) semantic/keyword search across YOUR message history and answer questions; (future) send messages on your behalf.\n\nIdentity model (Jacob): every user has a bot that represents them and can jump into any chat. Default posting identity is 'as you'; allow 'message as \u003cbot\u003e' explicitly. (Jacob's phrasing: bot can act as you no matter the chat; 'message as me' would be the override vs the bot identity β€” confirm exact default with Jacob.)\n\nDepends on: agent-key/resolveActor (done), message search (exists server-side OpenChat-kma), and a bot-actor posting path (bot users are first-class, OpenChat-aoy). \nPlan only for now; needs Jacob input on identity default + scope. Decompose after design.","notes":"DECISION 2026-06-04: default posting identity = AS THE BOT (clearly-labeled agent/bot identity), with 'message as me' as the explicit override. Transparent to recipients by default.","status":"open","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T08:55:12Z","created_by":"tmad4000","updated_at":"2026-06-04T12:26:53Z","dependencies":[{"issue_id":"openchat-oc8.4","depends_on_id":"openchat-oc8","type":"parent-child","created_at":"2026-06-04T01:55:11Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-njg","title":"Mobile resilience follow-ups from Codex review (stale-socket recycle, text-restore race)","description":"Deferred minor items from Codex review of openchat-5q1/-60y: (1) reconnect-on-resume only calls connect() when !socket.connected; it does not force-recycle a socket that is stale-but-still-marked-connected (presence/typing/receive can sit stale). Consider a ping/pong liveness probe on resume. (2) MessageInput text-restore race: if a user submits msg A (clears input), starts typing msg B, then A's send fails, A's content can repopulate the intentionally-in-progress composer. Low severity.","status":"open","priority":3,"issue_type":"task","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T02:28:06Z","created_by":"tmad4000","updated_at":"2026-06-04T02:28:06Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-ia9","title":"Make app version visible in Settings (and optional top-bar flag)","description":"Version is currently 'really tiny and at the bottom' in dev. Add a dedicated About section in Settings with version, build date, and (dev only) commit SHA. Add a setting flag for showing version in the top bar (default off in prod, on in dev). Source version from package.json at build time via Vite define.","status":"closed","priority":3,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-01T10:41:08Z","created_by":"tmad4000","updated_at":"2026-06-01T10:52:26Z","started_at":"2026-06-01T10:51:06Z","closed_at":"2026-06-01T10:52:26Z","close_reason":"Settings now has a prominent About section with build metadata, top-bar version visibility is configurable, and Vite injects package/build/git values.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-dlt","title":"[P3] Admin view for reports","description":"Reports from OpenChat-wgl are written to :Report nodes in Neo4j but Jacob has no UI/CLI to triage them. Volume is currently zero; defer until reports exist.\n\nOPTIONS (pick later):\n- Slack webhook to #moderation (set REPORT_SLACK_WEBHOOK_URL env var on server)\n- Admin-only /api/admin/reports endpoint + simple HTML page\n- bd command 'bd openchat:reports' that queries Neo4j\n\nDECISION DEFERRED 2026-06-01: low priority because user base is ~5 friends-and-family.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-06-01T04:35:19Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:35:19Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-ap3","title":"Explore expo-contacts integration + write tradeoffs","description":"Investigation only β€” produce a recommendation, do not implement.\n\nQUESTION: Should OpenChat mobile request iOS Contacts access to power friend-discovery?\n\nKEY FACTS:\n- expo-contacts NOT installed\n- iOS Contacts permission decline rate: 40-60% on cold prompts; 'Limited Access' further fragments matching\n- WITHOUT phone-number sign-in, matching falls back to email β€” most iOS contacts don't have email β€” match rate ~5-10%\n\nRECOMMENDATION (preview): defer until phone-number sign-in decision lands. If phone sign-in defers, this defers. If phone sign-in ships, then build with:\n 1. Ask permission CONTEXTUALLY on 'Find friends' tap (not at launch)\n 2. Hash phone numbers client-side (sha256 of E.164), POST batch to /api/chat/contacts/match\n 3. Show matches with explicit 'Send invite' / 'Start chat' (no auto-friend)\n 4. Server stores hashes only; no address-book copy\n\nACCEPTANCE:\n- [ ] Recommendation documented in this ticket\n- [ ] Tradeoffs (privacy, decline rate, value-without-phone-sign-in) captured\n- [ ] If go-ahead: spawn implementation epic blocked-by phone-sign-in ticket\n\nBLOCKED BY: phone-sign-in decision","status":"open","priority":3,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:21Z","created_by":"Jacob Cole","updated_at":"2026-05-31T12:19:21Z","dependencies":[{"issue_id":"OpenChat-ap3","depends_on_id":"OpenChat-xf4","type":"blocks","created_at":"2026-05-31T06:20:05Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-ap3","title":"Explore expo-contacts integration + write tradeoffs","description":"Investigation only β€” produce a recommendation, do not implement.\n\nQUESTION: Should OpenChat mobile request iOS Contacts access to power friend-discovery?\n\nKEY FACTS:\n- expo-contacts NOT installed\n- iOS Contacts permission decline rate: 40-60% on cold prompts; 'Limited Access' further fragments matching\n- WITHOUT phone-number sign-in, matching falls back to email β€” most iOS contacts don't have email β€” match rate ~5-10%\n\nRECOMMENDATION (preview): defer until phone-number sign-in decision lands. If phone sign-in defers, this defers. If phone sign-in ships, then build with:\n 1. Ask permission CONTEXTUALLY on 'Find friends' tap (not at launch)\n 2. Hash phone numbers client-side (sha256 of E.164), POST batch to /api/chat/contacts/match\n 3. Show matches with explicit 'Send invite' / 'Start chat' (no auto-friend)\n 4. Server stores hashes only; no address-book copy\n\nACCEPTANCE:\n- [ ] Recommendation documented in this ticket\n- [ ] Tradeoffs (privacy, decline rate, value-without-phone-sign-in) captured\n- [ ] If go-ahead: spawn implementation epic blocked-by phone-sign-in ticket\n\nBLOCKED BY: phone-sign-in decision","status":"open","priority":3,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:21Z","created_by":"Jacob Cole","updated_at":"2026-05-31T12:19:21Z","dependencies":[{"issue_id":"OpenChat-ap3","depends_on_id":"OpenChat-xf4","type":"blocks","created_at":"2026-05-31T06:20:05Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-xf4","title":"Decision: phone-number sign-in (WhatsApp-style)?","description":"DECISION ticket, not implementation. Decide whether/when to add SMS-OTP sign-in alongside Google OAuth.\n\nCURRENT STATE: Google OAuth only (iOS + web). No phoneNumber field on :User. ~5 users.\n\nTRADEOFF MATRIX:\n| Dim | Google (today) | Phone+OTP | Both |\n|---------------------------|----------------|--------------------------|---------------------|\n| Onboarding friction | Medium | Low | Low |\n| Cost | $0 | $0.005-0.04/SMS | Marginal |\n| Dev/test | Easy | Hard | Hard |\n| Abuse surface | Low | SIM swap, toll fraud | Both |\n| Contacts matching | Useless | High value | High value |\n| Portability | Stable | Numbers recycle | Both |\n| iOS App Store | Fine | Triggers SIWA req | SIWA req |\n| Time-to-ship | N/A | 1-2 weeks | Same |\n\nRECOMMENDATION: DEFER. Stay Google-only for ~3 months. Revisit triggers:\n (a) \u003e100 users AND contacts-matching is top growth lever, OR\n (b) Specific repeat user blocked by no-Google option.\n\nWHEN BUILT: use Twilio Verify (not raw Programmable SMS) + add Sign in with Apple simultaneously (App Store rule). Design account-merge UX BEFORE first SMS goes out.\n\nDO-NOW PREP (low effort, future-proofs):\n- [ ] Add nullable phoneNumber (E.164) + phoneNumberVerifiedAt fields to :User in Neo4j (no migration needed)\n- [ ] Add phoneNumberHash (sha256(E.164)) index\n\nACCEPTANCE:\n- [ ] Decision documented in resolution comment\n- [ ] If 'defer': close with rationale + revisit-trigger; phoneNumber field added prophylactically\n- [ ] If 'build now': spawn epic with sub-tickets for Twilio Verify wiring, SIWA, account-merge UX, abuse controls","status":"open","priority":3,"issue_type":"task","owner":"tmad4000@gmail.com","created_at":"2026-05-31T12:19:16Z","created_by":"Jacob Cole","updated_at":"2026-05-31T12:19:16Z","dependency_count":0,"dependent_count":1,"comment_count":0} {"_type":"issue","id":"OpenChat-cdg","title":"[web Vite] Match chat scroll behavior to mobile (if not deprecated first)","description":"Sibling of the mobile scroll behavior ticket. The Vite client at chat.globalbr.ai/ has the same problem if it has the same problem β€” verify and fix if so. Lower priority than mobile because: (a) mobile is where most testers use it, (b) the Vite client may be deprecated as we go all-in on RN-web. File so we don't forget if we keep Vite around.\n\nTouch: client/src/components/MessageList.tsx in the openchat repo.","status":"open","priority":3,"issue_type":"chore","owner":"tmad4000@gmail.com","created_at":"2026-05-31T11:15:49Z","created_by":"Jacob Cole","updated_at":"2026-05-31T11:15:49Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.7","title":"[openchat-agent] Thoughts integration once OpenChat-3kr server lands","description":"openchat-agent should: (1) read recent Thoughts visible to the conversation per visibility-set, (2) citation posture: reference, not verbatim-quote (per codex Q4), (3) optionally propose 'add to thoughts?' for important things it says. Blocked by OpenChat-3kr server endpoints. When those land, wire agent to read on each turn.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T07:02:33Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:33Z","dependencies":[{"issue_id":"OpenChat-3kr.7","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-31T01:02:33Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.7","title":"[openchat-agent] Thoughts integration once OpenChat-3kr server lands","description":"openchat-agent should: (1) read recent Thoughts visible to the conversation per visibility-set, (2) citation posture: reference, not verbatim-quote (per codex Q4), (3) optionally propose 'add to thoughts?' for important things it says. Blocked by OpenChat-3kr server endpoints. When those land, wire agent to read on each turn.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T07:02:33Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:33Z","dependencies":[{"issue_id":"OpenChat-3kr.7","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-31T01:02:33Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-ham","title":"[openchat-agent] Per-user agent identity (BetterGPT direction)","description":"Today openchat-agent is one shared bot identity. BetterGPT (~/code/cortex/mockups/bettergpt/SPEC.md) is each user has their own personal agent. Factoring: agent instance keyed by humanUserId, separate or shared-rate-limited Anthropic API key, per-user memory + Thoughts visibility, per-user system prompt. Not v1.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T07:02:32Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:32Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-g52","title":"[openchat-agent] Tools / function calling in llm.ts","description":"Extracted openchat-agent at ~/code/openchat-agent has TODO placeholder for tools in src/llm.ts. picortex didn't have tools either; fine for v1. When the agent starts needing real capabilities (search Thoughts, query bd memories, calendar, etc), add Anthropic tool_use: tools array, parse tool_use blocks, execute, append tool_result, loop.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T07:02:30Z","created_by":"Jacob Cole","updated_at":"2026-05-31T07:02:30Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.6","title":"[next] Allow capturing a Thought inside a group conversation but keeping it private","description":"Codex (2026-05-31) flagged that a single visibility-set can't distinguish between 'note captured in a group, kept private to me' (group context, private visibility) and 'group note shared with the group' (group context, group visibility). v1 ships the simpler model: capturing inside a group defaults to group-visible.\n\nFuture feature: when you #idea inside a group, give an option to keep the item private to you (still pointing to the source conversation in refExtra so chat-side surfacing works, but not visible to other group members).\n\nSchema-wise this is either:\n (a) extend visibility-set semantics β€” visibility:{} stays private even if sourceConversationId=group\n (b) move to codex's two-axis homeScope+visibility model\n\nDecide schema approach when this becomes urgent. Defer until then (v1 doesn't need it).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T06:52:39Z","created_by":"Jacob Cole","updated_at":"2026-05-31T06:52:39Z","dependencies":[{"issue_id":"OpenChat-3kr.6","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-31T00:52:39Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.6","title":"[next] Allow capturing a Thought inside a group conversation but keeping it private","description":"Codex (2026-05-31) flagged that a single visibility-set can't distinguish between 'note captured in a group, kept private to me' (group context, private visibility) and 'group note shared with the group' (group context, group visibility). v1 ships the simpler model: capturing inside a group defaults to group-visible.\n\nFuture feature: when you #idea inside a group, give an option to keep the item private to you (still pointing to the source conversation in refExtra so chat-side surfacing works, but not visible to other group members).\n\nSchema-wise this is either:\n (a) extend visibility-set semantics β€” visibility:{} stays private even if sourceConversationId=group\n (b) move to codex's two-axis homeScope+visibility model\n\nDecide schema approach when this becomes urgent. Defer until then (v1 doesn't need it).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-31T06:52:39Z","created_by":"Jacob Cole","updated_at":"2026-05-31T06:52:39Z","dependencies":[{"issue_id":"OpenChat-3kr.6","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-31T00:52:39Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-x2s","title":"Onboarding / first-run experience","description":"A new user signs up via Google and lands on an empty Chats screen with no guidance. Need: first-run onboarding card explaining how to start a chat, with a CTA to compose. Maybe: auto-create a DM with picortex on first sign-in so the user has someone to talk to immediately. Maybe: a quick 'find people you know' step pulling from Google contacts (deferred β€” privacy review needed).","status":"closed","priority":3,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:12Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:52:47Z","started_at":"2026-06-01T05:45:11Z","closed_at":"2026-06-01T05:52:47Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-q9h","title":"Edit and delete messages","description":"Sent messages are immutable today. Need: long-press / hover own message β†’ Edit or Delete. Edits show 'edited' marker + editedAt timestamp; deletes leave a 'message deleted' tombstone (or hard-delete for v1, simpler). PATCH / DELETE /api/chat/messages/:id. Socket events: message:updated, message:deleted.","status":"closed","priority":3,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:11Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:55:02Z","started_at":"2026-06-01T04:39:43Z","closed_at":"2026-06-01T04:55:02Z","close_reason":"Edit + Delete own messages shipped β€” server PATCH/DELETE /api/chat/messages/:id + mobile ActionSheet entries. Verified in tree.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-6bg","title":"File and image attachments in messages","description":"No way to send a file or image right now. Server: S3/GCS upload via /api/chat/upload (use GCS Interop with existing fastxyz pattern β€” see ~/.claude/rules/gcp.md). Message gets attachments[] field. Mobile: expo-image-picker + expo-document-picker. Web: dropzone + paste. Render inline thumbnails for images, file cards for non-image.","status":"closed","priority":3,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-31T02:56:10Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:54:09Z","started_at":"2026-06-01T04:40:47Z","closed_at":"2026-06-01T04:54:09Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} @@ -199,16 +202,16 @@ {"_type":"issue","id":"OpenChat-bji","title":"[stable] Manual dark-mode toggle in mobile (in addition to system follow)","description":"Codex #13: mobile only follows useColorScheme. Add a Settings screen with Light / Dark / System toggle, persisted in AsyncStorage. Web client already has this. Stable-branch work.","status":"closed","priority":3,"issue_type":"chore","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:26Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:45:39Z","closed_at":"2026-05-30T23:45:39Z","close_reason":"Shipped β€” ThemeProvider with light/dark/system pref persisted in AsyncStorage; SettingsScreen with radio card; βš™οΈŽ gear button in Conversations header. All screens migrated from useColorScheme() to useTheme().scheme so manual override propagates.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-ghr","title":"[stable] expo-secure-store for JWT instead of AsyncStorage","description":"Codex #12: mobile stores the JWT in AsyncStorage which is plaintext on rooted devices. Move to expo-secure-store (iOS Keychain / Android Keystore). Migration: on app boot, if JWT exists in AsyncStorage, copy to SecureStore and delete the AsyncStorage entry. Stable-branch work.","status":"closed","priority":3,"issue_type":"chore","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:26Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:45:40Z","closed_at":"2026-05-30T23:45:40Z","close_reason":"Shipped β€” JWT now in SecureStore (Keychain on iOS) at key openchat_jwt_v1. Migration on first read promotes legacy AsyncStorage token + deletes old key. Graceful AsyncStorage fallback if SecureStore is unavailable.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-vjc","title":"[stable] Message pagination: server before-cursor + mobile load-earlier","description":"Codex #9: api.getMessages has no 'before' parameter. Long conversations either truncate or load slow. Add server-side cursor (?before=\u003cmsgId\u003e\u0026limit=50) to GET /api/chat/conversations/:id/messages. Mobile + web: inverted FlatList / scroll-to-top to fetch older. Stable-branch work β€” should ship to TestFlight build 7.","status":"closed","priority":3,"issue_type":"task","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:25Z","created_by":"Jacob Cole","updated_at":"2026-06-01T05:35:23Z","started_at":"2026-06-01T05:29:09Z","closed_at":"2026-06-01T05:35:23Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.4","title":"[next] Beads + memories surface inside OpenChat","description":"Inside the Thoughts tab, render the user's open beads issues + persistent memories (bd memories) as first-class feed items. Click into an issue or memory opens a side-panel with full detail + ability to add a chat message that references it. Server: thin proxy to bd CLI on the openchat server host (the prod openchat runs on lightsail; bd repo is local-only on Jacob's mac mini, so this needs a syncing layer or a hosted bd instance).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:24Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:24Z","dependencies":[{"issue_id":"OpenChat-3kr.4","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:24Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.3","title":"[next] Agentic features: summon-an-agent UI, agent-watches-stream, automation rules","description":"Beyond picortex-as-a-DM, design and ship: (1) explicit 'summon agent into this chat' affordance β€” pick an agent (picortex / nvc-coach / future), choose a behavior (always-respond / mention-only / on-keyword). (2) Agents that watch a Thoughts stream and surface relevant memories/issues into the current chat. (3) Per-conversation automation rules (e.g. 'mention {topic} β†’ ping {agent}'). Server: per-conversation bot_behavior table. Mobile + web: agent picker, rule editor. Aligns with picortex's existing attention-mode design (always vs. mentions-only).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:23Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:23Z","dependencies":[{"issue_id":"OpenChat-3kr.3","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:23Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-3kr.2","title":"[next] NVC composer mode (observation/feeling/need/request scaffold)","description":"Optional composer mode that scaffolds messages in NVC (Marshall Rosenberg's Non-Violent Communication) form: Observation, Feeling, Need, Request. Toggle in the composer. The bot side (picortex or a dedicated NVC agent) can coach when toggled or when invoked by '@nvc' mention. Useful for difficult conversations / partner \u0026 team chats. Stretch: when the toggle is on, the OUTBOUND message can be reflected back to sender as a draft to revise before send (NVC self-empathy check).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:22Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:22Z","dependencies":[{"issue_id":"OpenChat-3kr.2","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:22Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.4","title":"[next] Beads + memories surface inside OpenChat","description":"Inside the Thoughts tab, render the user's open beads issues + persistent memories (bd memories) as first-class feed items. Click into an issue or memory opens a side-panel with full detail + ability to add a chat message that references it. Server: thin proxy to bd CLI on the openchat server host (the prod openchat runs on lightsail; bd repo is local-only on Jacob's mac mini, so this needs a syncing layer or a hosted bd instance).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:24Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:24Z","dependencies":[{"issue_id":"OpenChat-3kr.4","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:24Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.3","title":"[next] Agentic features: summon-an-agent UI, agent-watches-stream, automation rules","description":"Beyond picortex-as-a-DM, design and ship: (1) explicit 'summon agent into this chat' affordance β€” pick an agent (picortex / nvc-coach / future), choose a behavior (always-respond / mention-only / on-keyword). (2) Agents that watch a Thoughts stream and surface relevant memories/issues into the current chat. (3) Per-conversation automation rules (e.g. 'mention {topic} β†’ ping {agent}'). Server: per-conversation bot_behavior table. Mobile + web: agent picker, rule editor. Aligns with picortex's existing attention-mode design (always vs. mentions-only).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:23Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:23Z","dependencies":[{"issue_id":"OpenChat-3kr.3","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:23Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-3kr.2","title":"[next] NVC composer mode (observation/feeling/need/request scaffold)","description":"Optional composer mode that scaffolds messages in NVC (Marshall Rosenberg's Non-Violent Communication) form: Observation, Feeling, Need, Request. Toggle in the composer. The bot side (picortex or a dedicated NVC agent) can coach when toggled or when invoked by '@nvc' mention. Useful for difficult conversations / partner \u0026 team chats. Stretch: when the toggle is on, the OUTBOUND message can be reflected back to sender as a draft to revise before send (NVC self-empathy check).","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T23:42:22Z","created_by":"Jacob Cole","updated_at":"2026-05-30T23:42:22Z","dependencies":[{"issue_id":"OpenChat-3kr.2","depends_on_id":"OpenChat-3kr","type":"parent-child","created_at":"2026-05-30T17:42:22Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-74g","title":"[mobile] openchat-mobile app.json + deps need experiments.baseUrl=/m + react-dom + react-native-web committed","description":"Background: /m/ on chat.globalbr.ai now serves the RN web build of openchat-mobile (commit landed in openchat repo). For the deploy to keep working, openchat-mobile/app.json needs experiments.baseUrl=/m and its package.json needs react-dom + react-native-web + @expo/metro-runtime in dependencies. These changes are present on Mac mini /Users/Jacob/code/openchat-mobile working tree right now but mixed in with Jacob's other pre-existing WIP (version downgrades to expo 54, package-lock.json regen, LoginScreen.tsx edits), so I didn't commit them. Action: Jacob (or future agent with full context) should split the WIP into clean commits and ensure baseUrl + web deps land on both Mac mini and M5 copies before next mobile deploy.","status":"open","priority":3,"issue_type":"chore","owner":"tmad4000@gmail.com","created_at":"2026-05-30T17:30:46Z","created_by":"Jacob Cole","updated_at":"2026-05-30T17:30:46Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-9jm","title":"[hygiene] Set express trust proxy so default redirect_uri uses https behind Cloudflare","description":"In server/src/index.ts, add app.set('trust proxy', true) so req.protocol returns https when behind the chat.globalbr.ai Cloudflare proxy. Currently the /api/auth/google/url default redirect_uri falls back to http:// when the client doesn't explicitly pass one. Doesn't affect the real sign-in flow (the React client always sends https://chat.globalbr.ai/auth/google/callback via window.location.origin), but it's a paper-cut for raw curl tests and any future redirect-aware code. P3.","status":"closed","priority":3,"issue_type":"chore","owner":"tmad4000@gmail.com","created_at":"2026-05-30T16:10:16Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:28:53Z","closed_at":"2026-05-30T16:28:53Z","close_reason":"Shipped in eff5ca1 β€” 401 cascade fix from stash@{2} re-applied on top of Google OAuth merge, conflicts resolved, build clean. Includes single-flight refresh, refresh-loop guard, refreshToken persistence in register/ssoExchange (-bo6), getMe URL fix (-924), trust-proxy for express (-9jm), dismissible toast helper. Google OAuth smoke test 13/13 still green.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-924","title":"getMe() hits /api/chat/me instead of /api/auth/me (URL bug)","description":"client/src/api.ts:273 calls this.fetch('/me'.replace('/chat', '/auth'))) β€” but path is just '/me' (replace matches nothing), then fetch prepends API_BASE = '/api/chat', so the actual request goes to /api/chat/me (which 404s).\n\nSymptom: getMe() always fails. Probably masked because the call sites have fallbacks or aren't hit on most flows.\n\nFix: in stash@{0}, getMe() uses `/me` directly with its own auth headers + 401-retry logic. Could be cherry-picked out of the bigger 401 work if you want to fix it independently.","status":"closed","priority":3,"issue_type":"bug","owner":"tmad4000@gmail.com","created_at":"2026-05-30T12:13:52Z","created_by":"Jacob Cole","updated_at":"2026-05-30T16:28:53Z","closed_at":"2026-05-30T16:28:53Z","close_reason":"Shipped in eff5ca1 β€” 401 cascade fix from stash@{2} re-applied on top of Google OAuth merge, conflicts resolved, build clean. Includes single-flight refresh, refresh-loop guard, refreshToken persistence in register/ssoExchange (-bo6), getMe URL fix (-924), trust-proxy for express (-9jm), dismissible toast helper. Google OAuth smoke test 13/13 still green.","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-ri4","title":"[Mobile] Dark mode for the React Native app (when it lands)","description":"When the React Native prototype (OpenChat-dv0) becomes a real shipping app, it needs dark mode parity with the web app.\\n\\n## Approach\\n- React Native: useColorScheme() from 'react-native' (Appearance API) gives system preference live.\\n- Theme provider context (or just a useThemed hook) exposing semantic tokens (background, surface, primary, textPrimary, textSecondary, divider, bubbleOwn, bubbleOther, bubbleOwnText, bubbleOtherText, etc.).\\n- Persist user override (Light / Dark / System) via AsyncStorage / MMKV.\\n- All shared design tokens should match the web app's dark palette one-to-one so cross-platform users see the same colors.\\n- Native side benefits the web app can't easily get:\\n - Status bar style (light/dark content) via StatusBar component.\\n - iOS navigation bar tint (UIBarStyle / scheme on the wrapper).\\n - Apple's smart-invert handled by the system.\\n - Native blur effects on dark surfaces (BlurView) where appropriate.\\n\\n## Cross-platform consistency\\n- Pick the design tokens BEFORE writing the web dark mode (OpenChat-?? sibling ticket). Web and RN should share a single color spec, not diverge.\\n- Document the spec in a single ~/code/openchat/docs/theme.md or similar.\\n- If we later add a Capacitor or full-RN shell, the same tokens apply.\\n\\n## Phase\\nPhase 2 β€” does NOT need to land until the RN prototype itself does (OpenChat-dv0). Filed now so it's not forgotten when the RN work begins.\\n\\nDepends on OpenChat-dv0 (RN prototype) + the web dark mode sibling ticket for the source-of-truth color spec.","status":"open","priority":3,"issue_type":"feature","owner":"tmad4000@gmail.com","created_at":"2026-05-30T11:36:34Z","created_by":"Jacob Cole","updated_at":"2026-05-30T11:36:34Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-0nj","title":"[Group chat] Read receipts / seen-by indicators","description":"In a group it's useful to see who has seen a message. Track last-read message per participant per conversation; render small avatars or 'Seen by X, Y' under the latest message. Builds on existing PARTICIPATES_IN relationship β€” add a lastReadMessageId or lastReadAt field. Files: server schema, server/src/routes/chat.ts, server/src/socket/chatHandler.ts (message:read event), client MessageList.tsx.","status":"closed","priority":3,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:33Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:47:32Z","started_at":"2026-06-01T04:39:35Z","closed_at":"2026-06-01T04:47:32Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-0nj","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:32Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-0nj","title":"[Group chat] Read receipts / seen-by indicators","description":"In a group it's useful to see who has seen a message. Track last-read message per participant per conversation; render small avatars or 'Seen by X, Y' under the latest message. Builds on existing PARTICIPATES_IN relationship β€” add a lastReadMessageId or lastReadAt field. Files: server schema, server/src/routes/chat.ts, server/src/socket/chatHandler.ts (message:read event), client MessageList.tsx.","status":"closed","priority":3,"issue_type":"feature","assignee":"Jacob Cole","owner":"tmad4000@gmail.com","created_at":"2026-04-25T10:10:33Z","created_by":"Jacob Cole","updated_at":"2026-06-01T04:47:32Z","started_at":"2026-06-01T04:39:35Z","closed_at":"2026-06-01T04:47:32Z","close_reason":"Closed","dependencies":[{"issue_id":"OpenChat-0nj","depends_on_id":"OpenChat-ph4","type":"blocks","created_at":"2026-04-25T04:11:32Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":1,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-sas","title":"Jacob Test quick-login returns Invalid password on Noos","description":"On https://globalbr.ai/auth/authorize the \"Jacob Test\" quick-login button (fills tmad4000@gmail.com) returns \"Invalid password\". Alice and Bob work. Either the test-account seed password drifted or tmad4000@gmail.com is the real Jacob account (not a test account) and should be relabeled. Noos-side fix, not OpenChat.","status":"open","priority":3,"issue_type":"bug","created_at":"2026-04-23T22:43:42Z","updated_at":"2026-04-23T22:43:42Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-l3t","title":"Add dev-login support for AI agent testing","description":"Enable AI agents and automated tests to authenticate quickly by using Noos's dev-login endpoint.\n\n## Options\n1. **Direct usage** - Document that agents can call Noos dev-login directly and use the returned JWT\n2. **Proxy endpoint** - Add `POST /api/auth/dev-login` that proxies to Noos\n\n## Implementation (if proxy)\n```typescript\n// POST /api/auth/dev-login\nrouter.post('/dev-login', async (req, res) =\u003e {\n if (process.env.NODE_ENV === 'production') {\n return res.status(403).json({ error: 'Disabled in production' });\n }\n const noosRes = await fetch(`${NOOS_URL}/api/auth/dev-login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: req.body.email })\n });\n const data = await noosRes.json();\n res.json(data);\n});\n```\n\n## Note\nOpenChat-ip2 (closed) was for manual token paste. This ticket is for programmatic dev-login.\n\n## Depends on\n- Noos dev-login endpoint (already implemented)\n\n## Part of\nnoos-3p57: SSO Ecosystem","status":"closed","priority":3,"issue_type":"feature","created_at":"2026-01-24T02:04:49Z","updated_at":"2026-01-24T03:50:11Z","closed_at":"2026-01-23T19:50:11Z","close_reason":"Already implemented - POST /api/auth/dev-login exists in server/src/routes/auth.ts","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"OpenChat-0o1","title":"Update DESIGN_INTENT to match current contact search and port defaults","description":"Design doc still states client-side contact filtering and old port defaults. Align with current behavior or update defaults.","acceptance_criteria":"- DESIGN_INTENT reflects server-side contact search\n- Port defaults documented accurately","status":"closed","priority":3,"issue_type":"chore","created_at":"2026-01-22T01:14:43Z","updated_at":"2026-01-22T01:41:25Z","closed_at":"2026-01-21T17:41:25Z","close_reason":"Updated DESIGN_INTENT to reflect server-side contact search and port defaults.","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"OpenChat-ad3","title":"Add system-adaptive dark mode support","description":"Implement dark mode that follows system preferences.\n\nFeatures:\n- Detect prefers-color-scheme media query\n- Toggle between light/dark based on system setting\n- Optional manual override in settings\n- Apply to all components via Tailwind dark: variants\n\nReference: TailwindCSS dark mode docs\n\n**Note:** Also implement for Thoughtstreams (~/code/Thoughtstreams)","status":"closed","priority":3,"issue_type":"feature","created_at":"2026-01-21T11:49:49Z","updated_at":"2026-05-30T11:37:11Z","closed_at":"2026-05-30T11:37:11Z","dependencies":[{"issue_id":"OpenChat-ad3","depends_on_id":"OpenChat-dpy","type":"supersedes","created_at":"2026-05-30T05:37:10Z","created_by":"tmad4000","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"OpenChat-ad3","title":"Add system-adaptive dark mode support","description":"Implement dark mode that follows system preferences.\n\nFeatures:\n- Detect prefers-color-scheme media query\n- Toggle between light/dark based on system setting\n- Optional manual override in settings\n- Apply to all components via Tailwind dark: variants\n\nReference: TailwindCSS dark mode docs\n\n**Note:** Also implement for Thoughtstreams (~/code/Thoughtstreams)","status":"closed","priority":3,"issue_type":"feature","created_at":"2026-01-21T11:49:49Z","updated_at":"2026-05-30T11:37:11Z","closed_at":"2026-05-30T11:37:11Z","dependencies":[{"issue_id":"OpenChat-ad3","depends_on_id":"OpenChat-dpy","type":"supersedes","created_at":"2026-05-30T05:37:10Z","created_by":"auto-import","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"openchat-4yt","title":"Desktop-web: modals render full-screen (Search/New/Settings)","description":"From desktop-UX audit. react-navigation presentation:'modal' = full-screen card on web; a centered width/height-capped dialog with dimmed backdrop would feel desktop-native. Add a web modal-container wrapper. ~1 session. Low-medium.","status":"open","priority":4,"issue_type":"feature","owner":"dev.jacobcole@gmail.com","created_at":"2026-06-04T12:05:00Z","created_by":"tmad4000","updated_at":"2026-06-04T12:05:00Z","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/apps/server/src/legal/privacy.md b/apps/server/src/legal/privacy.md index 4950cd4..651a44b 100644 --- a/apps/server/src/legal/privacy.md +++ b/apps/server/src/legal/privacy.md @@ -1,6 +1,6 @@ # Privacy Policy -**Last updated: June 1, 2026** +**Last updated: July 12, 2026** This Privacy Policy describes how OpenChat (operated by chat.globalbr.ai) collects, uses, and handles your information when you use our service. @@ -8,36 +8,54 @@ This Privacy Policy describes how OpenChat (operated by chat.globalbr.ai) collec **Account information.** When you sign up, we collect your email address and display name. If you sign in with Google or Apple, we receive your profile information from that provider. -**Messages.** We store the messages you send and receive so conversations persist across sessions. Message content is stored on our servers. +**Messages and attachments.** We store the messages you send and receive so conversations persist across sessions. Message content, reactions, image attachments, voice messages, voice-message transcripts, link previews, and related conversation metadata are stored on our servers. -**Usage data.** We collect basic presence information (online/offline status) and the timestamp of your last activity. +**Profile and app activity.** We collect profile details you provide, such as display name, avatar, status message, onboarding state, blocked users, report submissions, feedback submissions, and the timestamp of your last activity. **Push notification tokens.** If you enable push notifications on a mobile device, we store a device token to deliver notifications. +**Diagnostics.** The app may send diagnostic logs, error details, stack traces, user agent details, request metadata, and crash/error context to help us debug and operate the service. + ## How We Use Your Information - To operate the chat service and deliver your messages. - To send push notifications when you receive new messages. - To show your presence status to people you have conversations with. +- To provide user safety features such as reporting, blocking, and moderation review. +- To provide AI features you choose to use, including AI assistant replies, message rewriting, semantic search, and voice-message transcription. +- To debug, secure, and improve service reliability. - To respond to support requests sent to support@chat.globalbr.ai. -## Third-Party AI +## Third-Party Processors + +We do not sell personal information and we do not use your information to track you across other companies' apps or websites. We use service providers to operate OpenChat: -Some conversations include an AI assistant powered by Anthropic's Claude model. When you send a message in a conversation that includes the AI bot, your message content is sent to Anthropic's API to generate a reply. Anthropic's use of that data is governed by [Anthropic's Privacy Policy](https://www.anthropic.com/privacy). Conversations containing an AI participant are marked in the app so you always know when AI is present. +- **Anthropic.** Some conversations include an AI assistant powered by Anthropic's Claude model. When you send a message in a conversation that includes the AI bot, or use the message-rewrite tools, relevant message text is sent to Anthropic to generate a reply or rewrite. Anthropic's use of that data is governed by [Anthropic's Privacy Policy](https://www.anthropic.com/privacy). Conversations containing an AI participant are marked in the app so you always know when AI is present. +- **OpenAI.** OpenChat may send message text to OpenAI to generate embeddings for semantic search, and voice-message audio to OpenAI Whisper to produce transcripts. These features are used for app functionality, not advertising or model training by OpenChat. +- **Expo.** If you enable push notifications, Expo receives push tokens and notification payloads needed to deliver notifications. +- **Apple and Google.** If you sign in with Apple or Google, those providers process authentication information and provide OpenChat with account identifiers such as email, name, and provider-specific IDs. +- **AWS/S3-compatible storage and Neo4j Aura.** OpenChat uses hosted infrastructure to store and process app data, including account data, messages, attachments, and conversation metadata. +- **World Issue Tracker and Slack/webhook tooling.** If you submit feedback or a safety report, the submitted text and relevant report metadata may be routed to team review tools so we can respond. ## Data Retention -We retain your account data and messages for as long as your account is active. You can delete your account at any time (see below), which removes all your personal information and redacts the content of your messages from shared conversations. +We retain your account data, messages, attachments, and related conversation metadata for as long as your account is active or as needed to operate the service. You can delete your account at any time (see below), which removes your profile, push tokens, sessions, and credentials, and redacts the content of messages you authored from shared conversations. Some operational logs, backups, reports, and security records may remain for a limited period where needed for reliability, safety, abuse prevention, or legal compliance. ## Your Rights **Delete your account.** In the app, go to Settings β†’ Delete My Account. This permanently deletes your account, push tokens, and all message content you authored. Conversation structure (other participants' messages) is preserved, but your messages are replaced with "Message deleted." -**Data requests.** To request a copy of your data or ask questions about privacy, email support@chat.globalbr.ai. +**Data export and requests.** You can export account and conversation data from the app. To request a copy of your data or ask questions about privacy, email support@chat.globalbr.ai. + +**Reports and blocking.** You can report messages or users in the app and block users you do not want to hear from. Reports are reviewed by the OpenChat team. ## Data Security -We use industry-standard transport encryption (TLS/HTTPS) for all data in transit. Your data is stored in a database accessible only to the application server. +We use industry-standard transport encryption (TLS/HTTPS) for data in transit. Your data is stored in databases and object storage accessible only to the application server and authorized operators. + +## International Transfers + +OpenChat is operated from the United States and uses infrastructure that may process or store data in the United States, including AWS Lightsail in US East and Neo4j Aura. If you use OpenChat from outside the United States, your information may be transferred to and processed in the United States. ## Children diff --git a/docs/app-store-launch-readiness.md b/docs/app-store-launch-readiness.md new file mode 100644 index 0000000..4d48f04 --- /dev/null +++ b/docs/app-store-launch-readiness.md @@ -0,0 +1,86 @@ +# OpenChat App Store Launch Readiness + +Last audited: 2026-07-12 for `apps/mobile/app.config.js` v0.1.23 and bundle id `com.jacobcole.openchat`. + +This checklist is for the first public Apple App Store submission. It is separate from TestFlight release operations in `docs/testers.md`. + +## Ready In Code + +- Sign in with Apple is present on iOS and backed by `POST /api/auth/apple/idtoken-exchange`. +- Google sign-in and email/password sign-in are available from the login screen. +- Account deletion is available from Settings and backed by `DELETE /api/auth/me`. +- Data export is available for account and conversation data. +- User-generated content controls are present: report message, report user, block user, unblock from Settings, and server-side report storage/webhook notification. +- AI disclosure is present for conversations containing bot users. +- Legal links are exposed from Settings and served at `https://chat.globalbr.ai/legal/privacy` and `https://chat.globalbr.ai/legal/terms`. +- Native permissions are explained in `app.config.js`: camera for QR scanning, photo library for image sharing, microphone for voice messages, remote notification background mode for push. +- TestFlight/native release scripts and EAS submit configuration exist in `apps/mobile/scripts/local-build.sh` and `apps/mobile/eas.json`. + +## Human/App Store Connect Blockers + +- Create and verify the reviewer account `openchat-reviewer@globalbr.ai` in production. +- Seed reviewer-visible demo data. The current `apps/server/src/seed-test-data.ts` only targets Alice/Bob test accounts, so reviewer data must be created manually or the script must be extended before submission. +- Store the reviewer password in 1Password and paste it only into App Store Connect Review Notes at submission time. +- Confirm `support@chat.globalbr.ai` is monitored. +- Prepare App Store screenshots for required iPhone sizes. No screenshot set was found in the repo during this audit. +- Fill App Store Connect metadata: app description, keywords, support URL, marketing URL if desired, copyright, age rating, category, review notes, privacy labels, and version release notes. +- Confirm the production backend at `https://chat.globalbr.ai` is live, healthy, and using production env vars for Google, Apple, Anthropic/OpenAI features, push, reports, and feedback. +- Obtain explicit approval before submitting for App Review. + +## Recommended Review Notes + +Paste only after the reviewer account exists and has demo data: + +```text +OpenChat is a messaging app with optional AI assistant features. + +Demo account: +Email: openchat-reviewer@globalbr.ai +Password: + +Sign in with the email/password form on the login screen. Sign in with Apple is also available on iOS and Google sign-in is available as a third-party login option. + +Demo coverage: +- Direct and group chats with seeded messages +- Image attachments and voice messages +- Report/block flows from message actions and user profiles +- Account deletion in Settings -> Legal & Account -> Delete my account +- Privacy Policy and Terms links in Settings +- AI assistant disclosure appears in conversations that include a bot user + +Backend services are live at https://chat.globalbr.ai. The app requires network access for sign-in, messaging, push registration, attachments, and AI features. +``` + +## Submission Commands + +Do not run these until screenshots, reviewer credentials, App Store Connect metadata, and final approval are complete. + +Web/server/RN-web deploy: + +```bash +cd /Users/jacobcole/.treehouse/OpenChat-a02908/1/OpenChat +bash infra/deploy.sh +``` + +Native iOS build, TestFlight submit, and tester publication: + +```bash +cd /Users/jacobcole/.treehouse/OpenChat-a02908/1/OpenChat/apps/mobile +TMPDIR="$HOME/.ocbuild-tmp" bash scripts/local-build.sh +``` + +Local build constraints: + +- Do not run `scripts/local-build.sh` under tmux. +- Use Node 22. +- Expect the script to bump the app version, commit, push, build locally, submit to App Store Connect, and publish to the configured TestFlight testers. + +## App Review Readiness Verdict + +OpenChat is not ready for App Review submission until the human/App Store Connect blockers above are cleared. The minimum blocker list is: + +1. Reviewer account exists, credentials are available in App Store Connect Review Notes, and demo data is seeded. +2. App Store screenshots and metadata are complete. +3. Privacy labels are entered in App Store Connect from `docs/app-store-privacy-labels.md`. +4. Production backend and legal URLs are verified live. +5. Explicit approval is given to submit for App Review. diff --git a/docs/app-store-privacy-labels.md b/docs/app-store-privacy-labels.md index 7657709..cfc23f3 100644 --- a/docs/app-store-privacy-labels.md +++ b/docs/app-store-privacy-labels.md @@ -2,7 +2,7 @@ > **Audience:** the person filling in App Store Connect β†’ App Privacy. > **Source of truth:** OpenChat-d8w. Update whenever data collection changes. -> **Last audit:** 2026-06-01 against build 39 (v0.1.7). +> **Last audit:** 2026-07-12 against `apps/mobile/app.config.js` v0.1.23. Apple's "App Privacy" section ("nutrition labels") is a structured answer to: *what does your app collect, and is it linked to the user?* These answers must @@ -19,10 +19,11 @@ when filling out the ASC form. - **Privacy Policy URL:** https://chat.globalbr.ai/legal/privacy - **Terms of Service URL:** https://chat.globalbr.ai/legal/terms -- **Support URL:** mailto:support@chat.globalbr.ai +- **Support URL:** https://chat.globalbr.ai (contact: support@chat.globalbr.ai) - **App category:** Social Networking (primary), Productivity (secondary) - **Sign-in providers:** Google OAuth, Sign in with Apple, email/password (via Noos SSO) -- **Server location:** AWS Lightsail (US East), Neo4j Aura +- **Server location:** AWS Lightsail (US East), Neo4j Aura, S3-compatible object storage +- **Current App Store blocker:** reviewer account credentials, production seed/demo data, screenshots, and final App Store Connect metadata approval remain human/App Store Connect actions. --- @@ -67,13 +68,13 @@ when filling out the ASC form. |---|---|---|---|---| | Photos or Videos | YES (image attachments) | YES | NO | App Functionality | | Audio Data (voice messages) | YES | YES | NO | App Functionality | -| Other User Content (chat messages, reactions) | YES | YES | NO | App Functionality | +| Other User Content (chat messages, reactions, reports, feedback, thoughts, status/profile text) | YES | YES | NO | App Functionality, Other Purposes (safety review for reports) | **Notes:** -- Messages, voice notes, reactions, and image attachments are stored in Neo4j (server-side) so they sync across devices. +- Messages, voice notes, reactions, reports, feedback, thoughts, and image attachments are stored server-side so they sync across devices and can be reviewed when users report safety issues. - Images live in S3-compatible storage with presigned-URL access. - We do NOT use this content for advertising, analytics, or model training. -- Bot-routed messages (when a user invites an AI agent into a conversation) are sent to Anthropic for response generation only β€” see Section 9. +- Bot-routed messages and message transform requests are sent to Anthropic for response generation or rewriting only; voice messages may be sent to OpenAI Whisper for transcription; message text/search queries may be sent to OpenAI for semantic-search embeddings. --- @@ -123,13 +124,13 @@ when filling out the ASC form. | Data Type | Collected? | Linked to user? | Used for tracking? | Purposes | |---|---|---|---|---| -| Crash Data | NO (Sentry not yet shipped β€” pending OpenChat-7um) | β€” | β€” | β€” | +| Crash Data | YES (mobile/web client logger forwards uncaught errors and crash/error context to `/api/client-logs`) | YES when signed in | NO | App Functionality | | Performance Data | NO | β€” | β€” | β€” | -| Other Diagnostic Data | YES (`/api/client-logs` browser errors) | YES (when signed in) | NO | App Functionality | +| Other Diagnostic Data | YES (`/api/client-logs`, server request/error logs) | YES when signed in or present in request context | NO | App Functionality | **Notes:** -- `/api/client-logs` accepts forwarded browser error events for debugging. Contains stack traces + browser metadata. Tied to user only when sender is signed-in. -- Sentry crash reporting will land in OpenChat-7um. When it does, flip Crash Data to YES (Linked / App Functionality). Anthropic, the upstream Sentry vendor, has its own data processing terms. +- `/api/client-logs` accepts forwarded web and mobile error events for debugging. Contains error messages, stack traces, request metadata, device/app context, and user agents. Tied to a user only when the event includes signed-in context. +- Sentry is still not shipped; the current crash/error path is OpenChat's own client logger plus server logs. --- @@ -142,11 +143,14 @@ when filling out the ASC form. | Vendor | Data Shared | Purpose | |---|---|---| | **Anthropic** (claude-haiku-4-5) | Message content of conversations where an AI agent participates; pre-send transform requests | AI assistant replies, message rewriting | +| **OpenAI** (`text-embedding-3-small`, `whisper-1`) | Message text/search text for embeddings; voice-message audio for transcription | Semantic search, voice-message transcripts | | **Expo** (push delivery) | Push notification token, conversation ID, message preview | App Functionality (delivering notifications to iOS/Android) | | **Apple** (Sign in with Apple) | Email (or Apple email-relay), name on first sign-in | Account creation | -| **Google** (OAuth + maybe `gpt-image-1`) | Email, name, profile picture; OAuth code exchange | Account creation | +| **Google** (OAuth) | Email, name, profile picture; OAuth code exchange | Account creation | | **AWS** (Lightsail server, S3-compatible storage) | All app data (messages, images, voice notes, profile info) | App Functionality (server infrastructure) | +| **Neo4j Aura** | Account, conversation, message, report, block, and app metadata | App Functionality (database infrastructure) | | **Noos SSO** (`globalbr.ai`) | Email + password verification | Authentication | +| **World Issue Tracker / Slack webhook tooling** | Feedback, report text, reporter/target metadata, operational error context when configured | Support, safety review, operations | --- @@ -155,19 +159,18 @@ when filling out the ASC form. App Store Connect β†’ App Information β†’ Notes for Reviewer. ``` -Sign in: tap "Continue with Google" on the login screen +Sign in: use the email/password form on the login screen Reviewer account: Email: openchat-reviewer@globalbr.ai Password: -ALTERNATIVELY, you can use the email/password form: - Email: openchat-reviewer@globalbr.ai - Password: +If Apple asks to verify third-party login parity, Sign in with Apple is available +on iOS from the same login screen. Google sign-in is also available. The account has all in-app features enabled, including: - Voice messages - Image attachments - - AI agent integration via MCP (agent keys in Settings β†’ DEVELOPER) + - AI agent integration via MCP / agent keys in Settings - Group chat with 2 seed conversations - 3 fixture messages in each thread @@ -181,9 +184,9 @@ WhatsApp Business, or Slack. ``` **ACTION FOR JACOB:** -- [ ] Create `openchat-reviewer@globalbr.ai` via Noos SSO sign-up +- [ ] Create `openchat-reviewer@globalbr.ai` via the production email/password sign-up path - [ ] Generate a strong reviewer password; store in 1Password under "OpenChat App Store Reviewer" -- [ ] Seed the reviewer account with 2 demo conversations + 3 messages each (script: `cd ~/code/openchat/server && npm run seed -- --user=reviewer`) +- [ ] Seed the reviewer account with 2 demo conversations + 3 messages each. The current `apps/server/src/seed-test-data.ts` only seeds Alice/Bob test accounts, so either extend it for `openchat-reviewer@globalbr.ai` or create the reviewer demo data manually before submission. - [ ] Paste the password into App Store Connect β†’ Notes for Reviewer at submission time - [ ] Confirm the support email `support@chat.globalbr.ai` is monitored (forward to Jacob's primary?) @@ -193,15 +196,15 @@ WhatsApp Business, or Slack. The privacy policy at https://chat.globalbr.ai/legal/privacy MUST contain: -- [ ] "Data Collected" section listing all of Section 1, 4, 6, 9 above -- [ ] "Third-Party Processors" subsection listing all of Section 10 above -- [ ] "User Rights" β€” account deletion path (already shipped: Settings β†’ Delete account) -- [ ] "Data Retention" β€” how long messages are retained, deletion policy -- [ ] "International Transfers" β€” note that data may flow through AWS US-East -- [ ] "Contact" β€” support@chat.globalbr.ai -- [ ] Last-updated date +- [x] "Data Collected" section listing all of Section 1, 4, 6, 9 above +- [x] "Third-Party Processors" subsection listing all of Section 10 above +- [x] "User Rights" β€” account deletion path (already shipped: Settings β†’ Delete account) +- [x] "Data Retention" β€” how long messages are retained, deletion policy +- [x] "International Transfers" β€” note that data may flow through AWS US-East / Neo4j Aura +- [x] "Contact" β€” support@chat.globalbr.ai +- [x] Last-updated date -Audit `/Users/Jacob/code/openchat/server/src/legal/privacy.md` and update to match these requirements before submission. +Audited and updated `apps/server/src/legal/privacy.md` on 2026-07-12 for the v0.1.23 launch-readiness pass. --- @@ -212,7 +215,7 @@ Re-audit this doc when ANY of these change: - New data type collected (e.g. contacts, location, health data) - New third-party processor added (e.g. Mixpanel, Stripe, Twilio) - New user-content surface added (e.g. video calls would add "Video data") -- Sentry / crash reporting lands (OpenChat-7um) β†’ flip Section 9 Crash Data to YES +- Sentry or another third-party crash SDK ships β†’ add that processor and update Section 9 notes - Phone-number sign-in lands (OpenChat-xf4) β†’ flip Section 1 Phone Number to YES - Contacts integration lands (OpenChat-ap3) β†’ flip Section 3 Contacts to YES - Any new third-party SDK added to mobile or web client diff --git a/docs/testers.md b/docs/testers.md index b377c61..1893a33 100644 --- a/docs/testers.md +++ b/docs/testers.md @@ -7,6 +7,10 @@ EAS Updates, and the web builds at `/m` and `/d`. Tracking epic: **openchat-3jq** (release/update pipeline + web↔mobile parity). Ticket: **openchat-3jq.6**. +For the first public App Store submission checklist, reviewer notes, metadata +blockers, and explicit approval gates, see +[`app-store-launch-readiness.md`](./app-store-launch-readiness.md). + --- ## 1. How testers get builds